Compare commits

...

315 Commits
2.0.1 ... 2.3.0

Author SHA1 Message Date
Alex Schroeder
25989f78a5 Merge branch 'as/no-more-page-subdirectories' 2014-06-21 21:30:27 +02:00
Aki Goto
afdb7a9dcb form_timeout.pl: an anti-spam module for Oddmuse
This is an anti-spam module for Oddmuse using form timeout. Edit
permission times out after a specified duration (the default is 30
minutes). When edit content is posted directly by a spam bot without
viewing the edit form, edit will be denied.
2014-06-21 12:18:26 +02:00
Alex Schroeder
2e79a843c8 oddmuse-curl.el: Fix URL 2014-06-21 12:01:08 +02:00
Alex Schroeder
54370da235 oddmuse-curl.el: whitespace 2014-06-21 12:00:26 +02:00
Alex Schroeder
43839ac1aa upgrade.t: Testing for the changes to upgrade.pl 2014-06-21 10:45:21 +02:00
Alex Schroeder
3c2f96250b upgrade.pl: Use variables; print utf8.
Instead of fiddling with @MyInitVariables, set the options naming
pages to the empty string.
2014-06-21 04:44:33 -04:00
Alex Schroeder
9def2d2eb2 upgrade.pl: Disable some module initialisations
Some modules read a page file when initializing. As these cannot be
found before the upgrade, we need to disable them.
2014-06-21 04:18:16 -04:00
Alex Schroeder
3ad40b84fb .gitignore: .DS_Store 2014-06-20 22:39:37 +02:00
Alex Schroeder
ecda4c3d98 oddmuse-curl.el: Preview shows just the preview
Don't show the header, footer and textarea; show just the preview div.
2014-06-20 22:36:09 +02:00
Alex Schroeder
74a0576c5d oddmuse-curl.el: Font lock restructuring
All the font-locking functions are now modifying font-lock-defaults
instead of calling font-lock-add-keywords because that's what it says
in the elisp manual.
2014-06-20 21:23:30 +02:00
Alex Schroeder
a6e07a9886 oddmuse-curl.el: Preview command
The preview command uses shr, a built in HTML renderer.
2014-06-20 18:31:33 +02:00
Alex Schroeder
b76b61dc86 .gitignore: .DS_Store 2014-06-19 23:11:04 +02:00
Alex Schroeder
c3cb434973 upgrade.pl: handle name spaces 2014-06-19 23:00:18 +02:00
Alex Schroeder
62f82c2af2 upgrade.pl: New interface.
Don't rely on a separate upgrade action. Any request except for login
and unlock will trigger an upgrade, if you're an admin. Once the upgrade
is complete, the module will rename itself such that it will no longer
load.
2014-06-17 13:14:13 +02:00
Alex Schroeder
d454973294 oddmuse-curl.el: fix order of font-locking
oddmuse-basic-markup must come last (which prepends its rules to the
front) such that links get precedence over other markup.
2014-06-17 12:26:50 +02:00
Alex Schroeder
cba29c8981 oddmuse-curl.el: added oddmuse-new
A function to make it easy to blog by offering the current ISO date as
page name.
2014-06-17 10:39:05 +02:00
Alex Schroeder
4a812931c8 oddmuse-curl.el: do not break links
Added a fill-nobreak-predicate to prevent links from breaking. This uses
the face property and checks for the link face.
2014-06-17 10:37:57 +02:00
Alex-Daniel Jakimenko
093a6da63d askpage.pl: Don't keep old value of $NewComment
Resetting the value was dead code. Instead of fixing this, the old value
is now discarded. There is no point in keeping it around.
2014-06-16 15:40:13 +02:00
Aki Goto
0ab5261bc6 load-lang.pl: add $LoadLanguageDir
The new option $LoadLanguageDir specifies a directory for the language
files.
2014-06-16 15:33:53 +02:00
Alex Schroeder
1d4f3e4a28 Ask Page extension
This is a simple extension to create a page for asking questions. The
process of writing a question is similar to writing a comment, for the
only exception that after pressing the ‘Save’ button the user will be
redirected to the newly created page containing his question.
2014-06-16 11:25:13 +02:00
Alex Jakimenko
6babcffd00 Consistency in file permissions.
Some modules are executable where as others are not. This patch fixes
this.
2014-06-16 11:19:24 +02:00
Alex Jakimenko
977cbba251 Fix two issues with $NewComment.
Display $NewComment above comment textarea.

'c' is now an access key to focus comment textarea.
2014-06-16 11:06:20 +02:00
Alex Schroeder
2fc4f4b054 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse into as/no-more-page-subdirectories 2014-06-16 10:32:31 +02:00
Alex Schroeder
53566c8434 Use a function instead of $ENV{REMOTE_ADDR}
When the webserver is behind a reverse proxy, $ENV{REMOTE_ADDR} is not
the actual remote client's address but the reverse proxy's address. The
actual remote client's address is available from an environment
variable. The name of this variable depends on the proxy, e.g. pound
uses $ENV{HTTP_X_FORWARDED_FOR}.

As suggested by tyatsumi on the wiki, all access $ENV{REMOTE_ADDR} now
happens via a new function which allows users to override it in their
config file.
2014-06-16 09:50:05 +02:00
Alex Schroeder
563e5cd9c6 upgrade.pl: delete empty directories after upgrade 2014-06-07 17:08:18 +02:00
Alex Schroeder
365d33b602 Get rid of one letter sub-directories.
Recent GNU/Linux systems use ext3 or ext4 file systems. These use HTree
to index files. Wikipedia says: "HTree indexing improved the scalability
of Linux ext2 based filesystems from a practical limit of a few thousand
files, into the range of tens of millions of files per directory. [...]
HTree indexes are available in ext3 when the dir_index feature is
enabled. [...] HTree indexes are turned on by default in ext4."

Thus, instead of working on balanced-page-directories.pl, we decided to
get rid of these sub-directories altogether.

Unfortunately, this is backwards incompatible. Users wanting to upgrade
will need to install the upgrade.pl extension in order to upgrade the
file database.
2014-06-06 17:32:44 +02:00
Alex Schroeder
eef56e435d questionasker.t: fixed number of tests 2014-06-05 17:07:15 +02:00
Alex Schroeder
2044564981 Merge branch 'master' of ssh://git.sv.gnu.org/srv/git/oddmuse 2014-06-05 05:34:08 -04:00
Aki Goto
50c9b79858 balanced-page-directories: reset GetPageDirectory
The test for migration sets GetPageDirectory; when the test fails and
we're not migrating, we need to reset GetPageDirectory to its old value.
2014-06-04 16:14:26 +02:00
Alex Schroeder
d99f62ea7e balanced-page-directories: fix page creation
Previously, no new pages could be created because of a deadlock. The
code mistakenly attempted to start migrating when a new page was
created, and since DoPost already held the main lock, migration failed.
The check was now fixed such that migration is not started when a new
page is being created.
2014-06-04 09:58:37 +02:00
Alex Schroeder
c11188fd3e fixed documentation typo 2014-06-03 16:17:07 +02:00
Alex Schroeder
dd22a852eb balanced-page-directories: new module 2014-06-03 16:14:48 +02:00
Alex Schroeder
62b2e22da8 Questionasker: encoding issue with hidden fields
We need to get rid of $q->hidden when using Unicode, as suggested by
tyatsumi on the wiki.
2014-06-03 11:19:50 +02:00
Alex Schroeder
5483bbf386 joiner: fix URL 2014-06-02 09:37:55 +02:00
Alex Schroeder
8608464863 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-06-02 09:22:38 +02:00
Aki Goto
b0d983c817 joiner: user registration module 2014-06-02 09:21:15 +02:00
Aki Goto
5f58256543 Updated Japanese translation. 2014-05-27 14:45:50 +02:00
Alex Jakimenko
c5c088deb1 Do not rehash the password for every entry. 2014-04-23 17:41:44 +02:00
Alex Schroeder
a5b5af9c07 Add $PassHashFunction and $PassSalt
This allows users to have the passwords encrypted in their config
file, as suggested by Alex Jakimenko.
2014-04-23 10:32:36 +02:00
Alex Jakimenko
0dcf49e2cf Add $CommentsPattern to supplement $CommentsPrefix
$CommentsPrefix is used in the code in two contexts:

- as a string added to the original page name to create links (used as
  a plain string)

- and as a way to detect whether the page has comments or not (used as
  a regular expression)

It feels natural to split this functionality into two separate
variables. $CommentsPattern is now the regular expression. No more
CommentsPrefix='.*' hacks!

For example, now you can do some complex stuff like this:

    $CommentsPrefix = 'Comments_on_';
    $CommentsPattern = '^(?|Comments_on_(.*)|Rant_About_(.*)|\d\d\d\d-\d\d-\d\d.*|FAQ)$';

Comments_on_ , Rant_About_ and journal pages will work correctly as
comments pages, but you can also specify some other pages as well, like
FAQ. Basically it can get as complex as one wants. $1 will be used to
create a link to the original page, which means that in this particular
example both Comments_on_Test and Rant_About_Test will have a link to
Test page, while FAQ will have no link to the original page at all.

Of course, by default there will only be "$CommentsPrefix . $id" link in
the footer, so you have to provide links to Rant_About_ pages elsewhere
yourself.

If you don't want to provide a regular expression pattern, you can leave
it undefined. It will be created automatically, keeping functionality
backwards compatible. If you were using $CommentsPrefix='.*' you should
now change it to $CommentsPattern='.*'.
2014-04-21 18:43:40 +02:00
Alex Jakimenko
f3885aa213 OpenPage: Remove useless test. 2014-04-20 00:26:29 +02:00
Alex Schroeder
6136b399a6 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-04-15 07:45:01 +02:00
Alex Schroeder
5cc7d55152 License, dependencies. 2014-04-15 07:39:01 +02:00
Alex Schroeder
4112d2acc4 New URL, trimmed wiki list. 2014-04-15 07:38:01 +02:00
Alex Jakimenko
f270a3ced4 Two small fixes
User input needs to be HTML quoted when printed.
The regular expression matching needs the ignore case flag.
2014-04-15 07:31:50 +02:00
Alex Schroeder
7f74d3c211 Use smaller headers 2014-04-09 08:34:14 -04:00
Alex Jakimenko
375c844e37 Specifying the number of entries for More...
This patch addes a new parameter to PrintJournal
such that a journal can have a certain number of
entries but when the user clicks on the More...
link, pagination happens with a different number.
<Journal 1,5>
2014-04-08 10:43:28 +02:00
Alex Jakimenko
efce35e250 Simplify FreeToNormal and remove if statement 2014-04-06 15:14:59 +02:00
Alex Schroeder
cff4f1fd28 Enabling diff usince C-x v = 2014-04-04 18:12:04 +02:00
Alex Schroeder
6f9ded7e41 vc-oddmuse.el added with support for C-x v l 2014-04-04 15:15:00 +02:00
Alex Jakimenko
40c01683fd Split pageidx file using space
Previously, we split it using whitespace (/\s+/). This caused a problem
if somebody managed to create a page containing non-breaking whitespace.
2014-03-29 09:42:00 +01:00
Alex Schroeder
08a4861dc3 Get rid of cloud icon. 2014-03-21 07:43:24 +01:00
Alex Schroeder
d7c40d4dbe Fix dead comment links
If the comment page does not exist, the static copy contains an anchor
element with no href attribute. Better avoid this situation.
2014-03-18 13:01:27 +01:00
Alex Schroeder
f8360bebad Produce static.css as well when exporting 2014-03-18 12:47:16 +01:00
Alex Schroeder
45a0558fcc Fixing the UTF-8 encoding issues for static export 2014-03-18 11:49:28 +01:00
Alex Schroeder
f4ff56e69f Fix HTML output for static export 2014-03-18 11:21:08 +01:00
Alex Schroeder
0d7236c047 More tests regarding local links in static exports 2014-03-18 10:32:22 +01:00
Alex Schroeder
686f24251b Fix static export of HTML pages
Apparently the html=1 parameter got lost so that you could not force an
export of all the pages.
2014-03-18 09:26:04 +01:00
Alex Schroeder
0841c834b9 Escape URL of More... links
When computing the More... link at the end of a journal, we need to URL
escape all user input. In this case, that's the regexp and search
parameter.
2014-03-17 09:52:30 +01:00
Alex Schroeder
5225bded01 Revert "Homepage URL fixing works recognizes https."
I must have been hallucinating. Instead of committing the change I
wanted to commit, I added a file that wasn't ready.

This reverts commit 670b69c118.
2014-03-17 09:51:11 +01:00
Alex Schroeder
e0d18c31e2 Homepage URL fixing works recognizes https.
When leaving a comment, users are given the option of providing a
homepage to link their name to. A common error is to just provide a
domain like "oddmuse.org" instead of a real URL. The resulting markup
used to be [oddmuse.org YourName] which doesn't do what the user
expected. That's why a piece of code used to check whether the homepage
starts with "http://" and if it doesn't, it prefixes it, resulting in
"[http://oddmuse.org YourName]". If the homepage started with
"https://", however, the code did the wrong thing. That's why we're now
checking whether the homepage starts with any known URL-protocol and a
colon.
2014-03-17 09:50:32 +01:00
Alex Schroeder
670b69c118 Homepage URL fixing works recognizes https.
When leaving a comment, users are given the option of providing a
homepage to link their name to. A common error is to just provide a
domain like "oddmuse.org" instead of a real URL. The resulting markup
used to be [oddmuse.org YourName] which doesn't do what the user
expected. That's why a piece of code used to check whether the homepage
starts with "http://" and if it doesn't, it prefixes it, resulting in
"[http://oddmuse.org YourName]". If the homepage started with
"https://", however, the code did the wrong thing. That's why we're now
checking whether the homepage starts with any known URL-protocol and a
colon.
2014-03-16 08:48:36 +01:00
Alex Schroeder
f4d0f300e6 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse
Conflicts:
	modules/translations/chinese_cn-utf8.pl
2014-03-07 09:02:41 +01:00
Andy Stewart
53a7a9a80c chinese_cn-utf8.pl: Updated translation
Simplified Chinese, fixed.
2014-03-07 08:38:15 +01:00
Alex Schroeder
4f675de687 oddmuse-curl.el: Fix following page links. 2014-03-07 08:31:08 +01:00
Alex Schroeder
dffe5e3053 Updated with new texts. 2014-03-06 17:15:35 +01:00
Alex Schroeder
201970ba0b Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-03-06 16:28:27 +01:00
Alex Schroeder
7e9137c6f8 Changing 回復 to 回滾 after feedback from Andy Stewart. 2014-03-06 16:23:04 +01:00
Alex Schroeder
9d81a1e3d2 DoDuckDuckGoSearch uses UrlEncode on the argument.
Drew Adams reported that clicking on the title of a page with a + in
its name had the + replaced by a space. This commit fixes this issue.
2014-03-03 08:30:21 +01:00
Alex Schroeder
2f58de9aa4 $NewText and $NewComment can be translated.
As suggested by Dexasys on the wiki.
2014-02-01 23:49:48 +01:00
Alex Schroeder
5ca2bf3efb Fix tests for fix-encoding. 2014-01-26 11:39:06 +01:00
Alex Schroeder
96bc4e14fa Fix the number of tests. 2014-01-25 18:27:10 +01:00
Alex Schroeder
ad1059dbb2 Revert the last commit.
The output has to be encoded as well.
2014-01-25 18:16:06 +01:00
Alex Schroeder
508396d1d1 New module. 2014-01-24 23:19:58 +01:00
Alex Schroeder
6d457ff87b Fix newline handling. 2014-01-24 23:19:37 +01:00
Alex Schroeder
860cb15324 Lighter RecentChanges. More spacing. 2014-01-22 01:52:43 +01:00
Alex Schroeder
56e76a4883 Get rid of special cases for RecentChanges. 2014-01-22 01:43:44 +01:00
Alex Schroeder
3fa8e0a6b0 New. 2014-01-21 08:06:56 -05:00
Alex Schroeder
4c4ab98d47 Merge branch 'master' of ssh://git.sv.gnu.org/srv/git/oddmuse 2013-12-23 05:18:56 -05:00
Alex Schroeder
ca62cbf446 Add .toc 2013-12-23 05:18:45 -05:00
Alex Schroeder
ef3bde90ac Fix documentation URL 2013-12-21 20:01:58 +01:00
Alex Schroeder
7771c541bb oddmuse-curl.el requires info for the faces.
Fixed the regular expressions for extended markup.
Fixed the regular expression for oddmuse-link-pattern.
Use goto-address when looking at a history page.
Use a list instead of an alist for the list of pagenames.
2013-12-06 11:00:42 +01:00
Alex Schroeder
6adabedefe oddmuse-curl.el merged with the current version on Emacs Wiki. 2013-12-06 09:36:46 +01:00
Alex Schroeder
a776c67cd6 oddmuse-curl.el, an Oddmuse client for Emacs, based on version 1.3
with an improved doc-string for oddmuse-wikis.
2013-12-06 09:31:16 +01:00
Alex Schroeder
0ddc1770a3 Merge branch 'master' of ssh://git.sv.gnu.org/srv/git/oddmuse 2013-11-30 18:59:39 -05:00
Alex Schroeder
44fa8cfb5a Handle empty lines in broken oldrc.log files. 2013-11-30 18:59:31 -05:00
Alex Schroeder
96c21c2240 Removed wikipipi: No idea how this is supposed to work. 2013-12-01 00:21:20 +01:00
Alex Schroeder
1c25325257 Anonymizing older entries in the list of recent changes.
When the maintenance action runs, it copies all the older entries in
rc.log to oldrc.log. Older entries are the entries that will usually
not get used by a typical display of recent changes. Any entry older
than the largest value of @RcDays is moved to oldrc.log (defaults to
90 days).

The idea is that you would only need hostnames or IP numbers to fight
spam and vandalism: Add regular expressions matching either hostname
or IP number of spammers or vandals to $BannedHosts and prevent the
attack from continuing. After a few days, however, this information is
no longer required. In this day and age of privacy invasion, I think
software should take a pro-active stance and therefore the entries
moved to oldrc.log will have their hostname or IP number replaced by
"Anonymous".

The existing entries in oldrc.log are not changed. If you want to do
the right thing, there's a script called anonymize.pl in the contrib
directory.
2013-11-30 23:56:10 +01:00
Alex Schroeder
fd5b4e84b1 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-11-30 22:51:00 +01:00
Alex Schroeder
9beff3748b Set @IndexOptions via @MyInitVariables.
With commit deec99c353 @InitOptions can
no longer be set at load time. Setting it at load time also disables
translations unless they get loaded earlier. Thus, @MyInitVariables.
2013-11-30 22:50:31 +01:00
Alex Schroeder
87dedeab85 Add button. 2013-11-28 01:33:20 -05:00
Alex Schroeder
1e73ae22d3 Show the menu only when a username is provided. 2013-11-21 14:31:24 +01:00
Alex Schroeder
5e9b02b5b1 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2013-11-17 23:34:43 +01:00
Alex Schroeder
deec99c353 Delaying the setting of @IndexOptions.
This change was suggested by toomas on the wiki because the
%Translations hash was not set at the time that @IndexOptions was set.
It is now set in InitVariables.
2013-11-17 23:32:00 +01:00
Alex Schroeder
d1b0ac4ccb Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-10-25 03:22:47 -04:00
Alex Schroeder
06881768c3 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-10-25 08:50:51 +02:00
Alex Schroeder
8e1f6c92e3 Static action now takes $StaticAlways into account. 2013-10-25 08:49:13 +02:00
Alex Schroeder
1ebc5192ff ReCAPTCHA introduced HTML escaping problems. 2013-10-20 20:27:12 +02:00
Alex Schroeder
7c52b7b4c2 Add facility to fix HTML escaping. 2013-10-20 20:00:30 +02:00
Alex Schroeder
2936ace022 Test for an encoding bug in recaptcha.pl 2013-10-09 23:28:13 +02:00
Alex Schroeder
4504ef43ac Avoid the use of $q->hidden() and use $q->input and GetParam() instead. 2013-10-09 23:09:47 +02:00
Alex Schroeder
50b71adf2d Add a summary when showing a diff in RSS output.
When looking at an URL like action=rss;full=1;page=0;diff=1;days=1 we
expect to see a diff, and with the diff we expect a summary.  RssItem
calls PageHtml if full is set.  PageHtml opens the page and calls
PrintPageDiff.  If diff is set, it calls PrintHtmlDiff.  Since the
page is already open, PrintHtmlDiff will use GetCacheDiff and skip the
calling of GetTextRevision which would have produced a summary. That's
why we use the open page's summary if none has been set.
2013-09-23 16:44:22 +02:00
Alex Schroeder
8bb0475ba2 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-08-31 21:35:16 +02:00
Alex Schroeder
0e66af495b bbCodeRule must come after PortraitSupportRule
If bbCode is interpreted first, it tries to handle [new].
2013-08-31 21:33:42 +02:00
Alex Schroeder
be6752116b Added support for tt distinct from code. 2013-08-25 00:36:41 +02:00
Alex Schroeder
36577490a7 Fix off by one bug recently introduced by changes to rollbacks.
Rollbacks of large sections count down $i to find the right place to
stop. When the for loop continues, however, $i is decremented once
more. Added $i++ in order to compensate.
2013-08-24 16:20:41 +02:00
Alex Schroeder
8e4dcc2240 Rewrote the code that skips over multiple pages.
When we're within a large rollback, $end used to point to the end of
the block that would eventually be stripped. It's a relative pointer.
While we were escanning downwards, we would sometimes strip single
pages even if we were within a larger rollback. Every time this
happened, $end was not shortened.

The current rewrite start skipping lines immediately and does away
with $skip_to and $end.
2013-08-24 15:38:11 +02:00
Alex Schroeder
dc4de8212a Rollback must roll back previously rolled back changes as well. 2013-08-24 13:53:10 +02:00
Alex Schroeder
ba2de753dd Rollback must roll back to minor changes as well. 2013-08-24 13:39:34 +02:00
Alex Schroeder
6dd1b7e125 Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-08-22 08:02:05 -04:00
Alex Schroeder
aec6e9fb30 Add 14pt font-size for comments. 2013-08-22 14:01:38 +02:00
Alex Schroeder
7b7d90f9f9 Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-08-22 06:51:41 -04:00
Alex Schroeder
c937258922 Commented the 'no bleeding' section. 2013-08-22 06:51:36 -04:00
Alex Schroeder
08aa098203 Add whitespace above the "Comments" header. 2013-08-22 12:49:44 +02:00
Alex Schroeder
b0fc1e4cc0 Take minor edits into accounts when proposing list of contributors to ban. 2013-08-21 12:10:18 +02:00
Alex Schroeder
ca9eef8c09 Get rid of undefined behaviour as indicated by Perl 5.18. 2013-08-21 11:55:20 +02:00
Alex Schroeder
b90b6e9651 Used another XPath expression in the test to make it more robust. 2013-08-21 11:49:33 +02:00
Alex Schroeder
f10bbb4f81 Fix test for %Namespaces as suggested by a Perl 5.18 warning. 2013-08-21 10:44:42 +02:00
Alex Schroeder
0116618e36 Fix number of skipped tests if LWP::UserAgent is not available. 2013-08-21 10:42:27 +02:00
Alex Schroeder
d864045815 Use $PERLBREW_PATH if available.
Try to guess which Perl we should be using. Since we loaded wiki.pl,
our $ENV{PATH} is set to /bin:/usr/bin in order to find diff and grep.
Prepending /usr/local/bin is one option, using $PERLBREW_PATH is
another.
2013-08-21 10:41:51 +02:00
Alex Schroeder
294e5745e7 Fixed syntax problem as warned by Perl 5.18 2013-08-21 10:19:45 +02:00
Alex Schroeder
afc4f7ecba Replaced oddmuse.css with default.css. 2013-08-21 09:52:26 +02:00
Alex Schroeder
d249792866 Changed the default CSS to oddmuse.org/default.css
I was often confused as to whether oddmuse.org/oddmuse.css referred to
the CSS used by oddmuse.org or to the CSS used by Oddmuse
installations without CSS setting.
2013-08-19 11:46:11 +02:00
Alex Schroeder
59cad086e7 Removed ban-yourself.pl because that was just an idea without any code. 2013-08-16 00:32:27 +02:00
Alex Schroeder
cfac228f57 Test for ban-quick-editors.pl 2013-08-16 00:31:28 +02:00
Alex Schroeder
a4bd6383a2 Quote the unquoted string "commenthidden". 2013-08-16 00:30:58 +02:00
Alex Schroeder
df0f470998 Don't delete pages that are "lock on creation".
This is meant to protect BannedContent and BannedHost from deletion.
2013-08-16 00:29:32 +02:00
Alex Schroeder
d61bf19b15 New module: don't allow quick editing by an IP or username. 2013-08-15 23:46:31 +02:00
Alex Schroeder
e0659c4d60 Made regular expression test more robust. 2013-08-05 10:02:06 +02:00
Alex Schroeder
70baed8088 Testing: Add tests to verify the process of banning URL fragments. 2013-08-02 17:27:50 +02:00
Alex Schroeder
ab3e187354 Bugfix: Banned URLs are added to BannedContent, not BannedHosts.
Added a separate link to add host or IP number to BannedHosts.
2013-08-02 17:13:44 +02:00
Alex Schroeder
f17a67d817 Convenience: List URLs rolled back and offer entry of regexp.
If you are an admin and rolled back a single page, this will list the
URLs your rollback removed (assuming that those URLs are part of the
spam) and it will allow you to provide a regular expression that will
be added to BannedHosts.
2013-08-02 16:55:49 +02:00
Alex Schroeder
601218c0b1 Added ban-contributors extension and tests. 2013-07-30 17:40:57 +02:00
Alex Schroeder
8af5095ff5 Hide Google+ stuff when printing. 2013-07-24 07:43:56 -04:00
Alex Schroeder
0a6cbfa20d Fix link given by raw history page. 2013-06-05 16:18:10 +02:00
Alex Schroeder
1630b64fa5 Fix critical bug in private-pages.pl.
Private pages were deleted whenever maintenance ran. This has been
fixed.
2013-05-30 16:15:01 +02:00
Alex Schroeder
ff4ad6e151 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-05-23 09:03:13 +02:00
Alex Schroeder
cc07341463 DoRollback prints a footer for a specific page if called for one page only.
The typical workflow when reverting spam:
1. view RecentChanges
2. click History button
3. click Rollback button
4. click Administration
5. click Ban contributors
6. click Ban!

This requires that the Administration link in #4 contains the page
id. This commit ensures it.
2013-05-23 09:02:46 +02:00
Alex Schroeder
9fd20a9e93 A new rollback testing idea. 2013-05-19 16:13:37 +02:00
Alex Schroeder
1a561c3cb1 Fix tagcloud bug in tags.pl.
The hash value wasn't being decoded before being split which resultet
in count being 1 in all cases.
2013-05-19 15:32:54 +02:00
Alex Schroeder
ca3740ca86 Add RuleOrder to prevent conflict with markup.pl. 2013-05-19 14:43:23 +02:00
Alex Schroeder
7a69437443 Italy: removed Festa della Repubblica, added Liberation Day instead. 2013-05-17 10:38:51 +02:00
Alex Schroeder
671f00701b Anniversary of the Unification of Italy 2013-05-17 00:42:48 +02:00
Alex Schroeder
af28957796 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-05-16 23:20:13 +02:00
Alex Schroeder
28c56373f6 DuckDuckGo module.
duckduckgo-search.pl and duckduckgo-search.t based on google-search.pl
and google-search.t to use DuckDuckGo for the search action via a
redirect.
2013-05-16 23:18:23 +02:00
Alex Schroeder
d5fa00f1e2 The admin menu should only list links for actions that are actually
defined. This makes it easier to undefine and hide them.
2013-05-10 00:20:55 +02:00
Alex Schroeder
66fe91efed Expire keep files and delete pages during maintenance without main lock. 2013-05-09 23:46:06 +02:00
Alex Schroeder
3d07062e1f Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-05-08 22:19:12 +02:00
Alex Schroeder
f7b94272bf Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-05-08 22:16:48 +02:00
Alex Schroeder
9e2353aebc Add access keys for articles and comments, if enabled.
If $CommentsPrefix is set, the wiki knows about article pages and
comment pages. The link in GetFooterLinks now uses 'a' and 'c' as
access keys. The access key is passed to GetPageLink and to
ScriptLink.
2013-05-08 22:16:22 +02:00
Alex Schroeder
bf83cc5ca1 Don't use a global $form. 2013-05-07 10:18:12 +02:00
Alex Schroeder
d5e7d58d7e Use EB Garamond hosted by Google if necessary 2013-04-15 03:40:21 -04:00
Alex Schroeder
806a8ba89b DEL no longer uses grey. 2013-04-12 23:09:25 +02:00
Alex Schroeder
8602dfb324 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-04-12 23:03:08 +02:00
Alex Schroeder
6647d52e88 Handle markup singles before handling forced pairs. 2013-04-12 22:59:50 +02:00
Alex Schroeder
3dcf08a850 Fixed %s error in one message reported by Juanma MP. 2013-04-03 11:18:20 +02:00
Alex Schroeder
2a5454a732 New: wikipipe 2013-03-25 14:03:23 +01:00
Alex Schroeder
ee239428d9 Update copyright year. 2013-03-13 18:46:09 +01:00
Alex Schroeder
dd731569d3 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse
Conflicts:
	t/diff.t
2013-03-10 00:52:22 +01:00
Alex Schroeder
d9640c2ef7 Display summary of the change when displaying a diff.
GetTextRevision returns a third parameter (the summary). PrintHtmlDiff
takes a fifth parameter (the summary) and prints it. Test added.
2013-03-10 00:46:49 +01:00
Alex Schroeder
a57d26f520 Whitespace. 2013-03-05 23:13:04 +01:00
Alex Schroeder
98f5b48ceb Add support for -q, -a and -z options.
Rewrote the help message to list the options instead of having
multiple paragraphs of text. Renamed PostRaw to post and added support
for the new options. Pass the new options through copy.
2013-03-05 23:10:35 +01:00
Alex Schroeder
4e790f7847 Fix justification of cells.
The code used to detect whitespace in sibling cells. Thus, if any of
the remaining cells on this line was centered or right justified, this
cell was also getting right justified. If the current cell was both
left and right justified, the result was that it got centered. Added a
test to check for this.
2013-03-05 23:07:23 +01:00
Alex Schroeder
355874edad Add git action to call GitCleanup directly. Add more print statements explaining what git is doing. 2013-02-28 10:44:26 +01:00
Alex Schroeder
91cdb9888a Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-14 16:25:47 +01:00
Alex Schroeder
ff28c5f79e no background color for sister site logos 2013-02-14 16:25:28 +01:00
Alex Schroeder
004b0c0831 URL encode keys and values in the tag database.
Depending on your version of the Berkley DB, non-ASCII or non-Latin-1 characters could crash Oddmuse.
2013-02-12 06:00:06 -05:00
Alex Schroeder
01d9cdf4e3 Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-02-12 04:14:08 -05:00
Alex Schroeder
0226a82dca Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-01 15:37:44 +01:00
Alex Schroeder
31fcd5dc99 Avoid a javascript error. 2013-02-01 15:30:31 +01:00
Alex Schroeder
2c69716295 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-01 15:29:42 +01:00
Alex Schroeder
e772254293 Make sure we don't create an empty TOC element if there aren't enough sections. 2013-02-01 15:26:02 +01:00
Alex Schroeder
f8df77d1a6 Remove the TOC if we don't have enough sections. 2013-02-01 15:17:52 +01:00
Alex Schroeder
de4af94e89 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-01 15:16:32 +01:00
Alex Schroeder
cdee73b859 At least two siblings or parent and child nodes required. 2013-02-01 15:12:54 +01:00
Alex Schroeder
70895ed631 Only print outline when there is more than one element. 2013-02-01 15:08:54 +01:00
Alex Schroeder
14a6cc4e2f Find existing TOC from toc.pl using the class attribute. 2013-02-01 15:05:04 +01:00
Alex Schroeder
83eaa45077 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-01 14:21:28 +01:00
Alex Schroeder
3a9b92f4a3 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-01 14:17:46 +01:00
Alex Schroeder
6e82239616 An extension to generate a table of content. 2013-02-01 14:09:59 +01:00
Alex Schroeder
8e2da8a1a9 Save $1 to prevent it from being overwritten by Tss. 2013-01-31 09:50:11 +01:00
Alex Schroeder
872b914c90 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-31 09:43:43 +01:00
Alex Schroeder
1e6f732fa9 Use LogWrite. 2013-01-31 09:43:05 +01:00
Alex Schroeder
925f0788fb Add $1 to the explanation if such a group is part of the regular
expression.
2013-01-31 09:29:25 +01:00
Alex Schroeder
3c0c79a526 logbannedcontent.pl: Logging BannedHosts as well.
Renamed wrappers to make sure all have the Log prefix.

Moved log writing to a separate sub. Provide a little wrapper text for
banned hosts.

Using TimeToW3 to use a standard date and time format.

Use the id if no page has been opened yet (since DoEdit calls
UserIsBanned and DoPost calls UserCanEdit before either calls
OpenPage).
2013-01-31 09:21:54 +01:00
Alex Schroeder
88e66e825e Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-01-30 17:04:24 -05:00
Alex Schroeder
fb7566ae53 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-30 16:04:47 +01:00
Alex Schroeder
9b05ea62c5 Protect TZget against crashes if the timestamp is undefined. 2013-01-30 16:03:40 +01:00
Alex Schroeder
4feccd6484 Testing for encoding problems in diff output. 2013-01-25 19:07:11 +01:00
Alex Schroeder
7d166842f0 Make sure banning happens without logging in RegexpNewBannedContent. 2013-01-25 00:03:51 +01:00
Alex Schroeder
c6943cad7b Package Oddmuse. 2013-01-24 23:51:12 +01:00
Alex Schroeder
c29037a9d6 Delete code that doesn't belong. 2013-01-24 23:50:31 +01:00
Alex Schroeder
e1b429c3b7 New 2013-01-24 23:45:24 +01:00
Alex Schroeder
c17c622c97 Intro 2013-01-24 23:31:11 +01:00
Alex Schroeder
9d11d42e5e New 2013-01-24 23:30:32 +01:00
Alex Schroeder
270e0f4932 Invert the loop when scanning for banned content. 2013-01-24 23:04:35 +01:00
Alex Schroeder
d1f6e1bb37 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-24 22:46:57 +01:00
Alex Schroeder
47e4ad5e41 New. 2013-01-24 22:46:18 +01:00
Alex Schroeder
78dd013fc0 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-23 23:58:06 +01:00
Alex Schroeder
c04403ca66 Download style for a.download. 2013-01-23 23:57:42 +01:00
Alex Schroeder
8c8e23b21a Fix comment. 2013-01-14 23:06:19 +01:00
Alex Schroeder
fd9a715634 Another fix for mail.pl... 2013-01-13 01:04:19 +01:00
Alex Schroeder
957729fd5d Fix subscription migration for mail.pl 2013-01-13 00:57:58 +01:00
Alex Schroeder
23fb0cf18b Added migration of subscriptions to mail.pl and tests. 2013-01-13 00:45:58 +01:00
Alex Schroeder
8e72af0a45 Fix encoding issues with the use of DB_File in mail.pl.
This also fixes the tests. Also get rid of wide character in print by
Test::Builder by adding the fix mentioned in the Test::More manpage.

The DB_File issue was necessary because a page name with an EN DASH
caused the script to crash, thus not printing the footer.
Unfortunately, this is solved by URL-encoding keys and values. This
means that your old mail.db is going to be invalid!
2013-01-12 23:55:08 +01:00
Alex Schroeder
26135820e1 UrlDecode doesn't need utf8::decode. 2013-01-12 23:50:59 +01:00
Alex Schroeder
2c3abffd2e Removed $Id$ from info-ref. 2013-01-12 23:50:11 +01:00
Alex Schroeder
4b46c5385e Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-01-11 04:45:30 -05:00
Alex Schroeder
5b7fdbdea4 Reading files using :utf8 instead of :encoding(utf-8).
This is discouraged because :utf8 does not validate the input. The
problem is that in some cases you can end up with invalid UTF-8 if
your wiki was created with a copy of Oddmuse that allowed raw bytes.
There, we requested users to provide UTF-8 input and printed it back
claiming that it was UTF-8, but in the end it was just a convention.
Spammers and vandals could upload anything they liked. This is why
your rc.log (and all other sorts of files) may contain invalid UTF-8
bytes. This is particularly troublesome in the case of your rc.log
files as these will never go away and they are read very often. The
resulting warnings will fill up your web server logs.
2013-01-11 10:40:35 +01:00
Alex Schroeder
61dae58368 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-11 10:34:18 +01:00
Alex Schroeder
6958b66bc5 twitter is a CGI script to process RSS feeds.
It strips the description of an item if it contains the same info as
the title, and it strips the username from the title, if you want.
2013-01-11 10:30:57 +01:00
Alex Schroeder
512cbf4ae9 Get rid of a warning.
Use response->decoded_content.
Add more sources.
Get rid of $Id.
2013-01-11 10:10:19 +01:00
Alex Schroeder
e188665a9b No longer validate the UTF-8 from rc.log files in GetRcLinesFor.
If the rc.log file contained invalid UTF-8, this would fill the server
logs with thousands of warnings. There is nothing we can do about
these (they probably originated from an older copy of the script).
Therefore, <:utf8 is now used instead of <:encoding(UTF-8).
2013-01-10 14:25:56 +01:00
Alex Schroeder
4898f970b0 Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-01-07 07:53:12 -05:00
Alex Schroeder
d9a2db5b8d Added support for sub and sup tags. 2013-01-07 13:51:39 +01:00
Alex Schroeder
7b518f14f0 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-07 13:41:23 +01:00
Alex Schroeder
ff4b889f1c Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-01-06 12:34:17 -05:00
Alex Schroeder
b4b6435826 Fix entities for superscripts and vulgar fractions. 2013-01-06 18:18:16 +01:00
Alex Schroeder
011953370a Print fractions. 2013-01-06 18:13:53 +01:00
Alex Schroeder
40a0b7104a Fixing encoding for RSS feed inclusion using HTTP::Response->decoded_content. 2013-01-01 14:24:44 +01:00
Alex Schroeder
964f8c38c0 Typo in a comment. 2013-01-01 14:13:06 +01:00
Alex Schroeder
e46c89e90f rc2mail now adds some newlines to the HTML mail being sent. 2012-12-21 11:14:09 +01:00
Alex Schroeder
99d8ff2b01 GetRaw uses HTTP::Response's decoded_content to fix encoding issues. 2012-12-11 04:53:51 -05:00
Alex Schroeder
dfbd5ad47e Fix encoding menu disappears if page is missing. 2012-11-28 07:39:14 +01:00
Alex Schroeder
68ea223940 No encoding to fix for non-existing pages
Add more tests to show that fix-encoding does not create a page if it
is missing.
2012-11-28 07:33:20 +01:00
Alex Schroeder
4fc84fa623 Make sure fix encoding doesn't save if nothing has changed 2012-11-21 21:39:13 +01:00
Alex Schroeder
33aa81d9c9 Fix encoding issues with translation links. 2012-11-21 21:29:41 +01:00
Alex Schroeder
58690662df Private pages no longer accessible using revision parameter 2012-11-21 21:11:49 +01:00
Alex Schroeder
b2194ebdac Added some tests for translation links. 2012-11-21 21:01:06 +01:00
Alex Schroeder
d584c4dc68 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-11-20 19:46:45 +01:00
Alex Schroeder
105ccdf323 Add header back to bulgarian-utf8.pl and chinese-utf8.pl 2012-11-20 15:47:03 +01:00
Alex Schröder
cb6d1cc17d Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-11-20 15:38:51 +01:00
Alex Schroeder
be4bddab30 No longer recreate -utf8 files. 2012-11-16 21:49:56 +01:00
Alex Schroeder
465b278303 Fix a loophole where using <include "..."> allowed you to see hidden pages. 2012-11-16 18:38:27 +01:00
Alex Schroeder
a52bebdcd2 Fix docstring. 2012-11-16 17:56:25 +01:00
Alex Schroeder
1caa4c55c0 Private pages! 2012-11-16 17:12:12 +01:00
Alex Schroeder
9c77e56568 Whitespace. 2012-11-16 15:51:56 +01:00
Alex Schroeder
f5e86f4ddc Prevent double "Showing revision X" by passing QUIET to GetTextRevision. 2012-11-16 15:51:19 +01:00
Alex Schroeder
f10dde33c8 No bullet point before div.refer a elements. 2012-11-14 17:35:52 +01:00
Alex Schröder
ff64a0ed82 Update by Hervé Robin 2012-11-05 13:56:03 +01:00
Alex Schroeder
a046436a50 Deutsche Übersetzung auf Vordermann gebracht. 2012-10-27 13:56:40 +02:00
Alex Schroeder
bcb9721499 New extension. 2012-10-27 13:28:13 +02:00
Alex Schroeder
609f037345 Added link to documentation online. 2012-10-27 12:55:30 +02:00
Alex Schroeder
4ed8c4fb25 Fixed whitespace when setting %Tex.
Made %Tex public so it can be used in a test.
2012-10-26 23:59:54 +02:00
Alex Schroeder
45ebd07cf4 testing encoding of the cookie 2012-10-26 16:46:18 +02:00
Alex Schroeder
51223c6297 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-10-26 16:39:37 +02:00
Alex Schroeder
08b7674ab4 Use decoded_content for HTTP::Response 2012-10-26 16:38:22 +02:00
Alex Schroeder
a8780e75f5 Also handles other parameter per feed, eg. ignore_in_feed = updated 2012-10-26 16:20:30 +02:00
Alex Schröder
dc43759ebd Many additions by Aurélien Desbrières. 2012-10-25 10:21:01 +02:00
Alex Schroeder
e8ba28bffe Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-10-25 08:55:10 +02:00
Alex Schroeder
f3266288e1 Add module description. 2012-10-25 08:54:53 +02:00
Alex Schroeder
8482c47383 user tables without 4em margin 2012-10-23 19:30:30 -04:00
Alex Schroeder
1e4268597d no longer need to encode UTF-8 strings: it's the default 2012-10-22 11:28:26 -04:00
Alex Schroeder
dd05f824a8 Switch tex.pl to rules instead of macros. 2012-10-18 23:36:44 +02:00
Alex Schroeder
6b2d119481 Commented utf8::encode in DoTagsReindex
This was recommended by Erik on the wiki because he found Latin-1
encoded page names in the Tag DB.
2012-09-30 09:39:37 +02:00
Alex Schroeder
37bdb62db8 Added svg to $ImageExtensions.
Apparently this now works; I tested it on an up to date Firefox.
2012-08-18 12:03:29 +02:00
Alex Schroeder
30c5c3798f Use xpath to extract oldtime parameter.
The last change to GetHiddenValue changed the HTML output. Using XPath
will find the right parameter even if the order of the parameters
changed.
2012-08-15 19:32:10 +02:00
Alex Schroeder
0f55e3d59e Fixed GetHiddenValue encoding errors.
GetHiddenValue was returning strings that had lost their UTF-8 flag or
something like that. In order to fix this, I needed to replace the call
to $q->hidden with a call to $q->input with -type=>"hidden".
2012-08-15 18:47:10 +02:00
Alex Schroeder
60a5a8fcee git.pl: run "git add ." as part of maintenance. 2012-08-14 21:41:19 +02:00
Alex Schroeder
598b5e06f6 Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2012-08-14 09:06:16 -04:00
Alex Schroeder
f451e62d30 Delay writing of the timestamp. 2012-08-14 09:05:22 -04:00
Alex Schroeder
a41920a5fd Add another test regarding UTF-8 pagenames.
Use binmode(":pop:raw") because this appears to be necessary for
Windows users -- Ingo Belka was using ActivePerl versions 5.10.1 and
5.14.2 to test it.
2012-08-13 16:00:47 +02:00
Alex Schroeder
e8683fdb02 Making sure that the charset parameter is only added when necessary.
It's only added to the content-type if it's text/plain, text/html or
RSS (application/xml).
2012-08-07 17:26:12 +02:00
Alex Schroeder
f08a404bde clear_page unsets @IndexList
Without this, running t/tags.t will alternate between running ok and
producing an error: "Cannot open test-data/page/I/InterMap.pg: No such
file or directory"
2012-08-05 02:28:39 +02:00
Alex Schroeder
e1f0d909c1 In DoTagsReindex, call utf8::encode on the id before adding it to the index.
I'm not sure why this is necessary. My tests in t/test.t work just
fine on my Mac with mac.pl installed. Without it, reindexing results
in a silent crash of Perl on the machine where emacswiki.org is
installed.
2012-08-05 01:59:20 +02:00
Alex Schroeder
3ab606d96a Fixed UTF-8 support in various automated tests.
Issues:

- the Mac layer was masking issues because of the NFC/NFD difference and existing compatiblity hacks in mac.pl
- drafts.pl was suffering from a double encoding issue
- crossbar.t and download.t tests were failing because I had recently fixed DoDownload output to be raw instead of encoded
- test.pl now has a way to capture the raw, unencoded output produced by DoDownload
- tags.t got some tests to prove that recent changes to wiki.pl actually work
2012-07-30 23:30:27 +02:00
Alex Schroeder
93dc6b415f Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-07-30 21:12:44 +02:00
Alex Schroeder
6d8314cb39 Fix regular expression using character class. 2012-07-30 21:12:06 +02:00
Alex Schroeder
ce18377109 Use utf8::decode on filenames passed to PageIsUploadedFile
Without this, search will break on pagenames with non-ASCII characters.
I noted this in conjunction with tags.pl. There, I needed to encode
the page names for search to work correctly.
2012-07-30 18:18:29 +02:00
Alex Schroeder
d4edb159ae Use binmode to set stdout to raw when printing uploaded files.
The bug involved uploaded images not being decoded correctly.
2012-07-25 13:43:48 +02:00
Alex Schroeder
16198f8784 Filenames also need to be encoded such that the bytes are used.
Otherwise pages containing non-ASCII names cannot be read or written.
2012-07-21 11:55:45 -04:00
Alex Schroeder
03e08464bb New test to verify that bsd_glob works on dotfiles.
The question is whether bsd_glob("$PageDir/*/*.pg") will find
page/other/.emacs.pg -- and apparently it does not, so that had to be
added back in.
2012-07-21 00:58:27 +02:00
Alex Schroeder
7ca0f6172b Use bsd_glob instead of glob.
Glob will split patterns on whitespace and non-breaking spaces are now
treated as whitespace.
2012-07-21 00:40:42 +02:00
Alex Schroeder
276c1c2076 Handle namespaces containing a non-breaking space.
Since the non-breaking space is now recognized as a whitespace
character, the behaviour of the glob function has changed. Use
bsd_glob instead!
2012-07-20 02:14:36 +02:00
Alex Schroeder
9c996cee04 No longer call oddtrans when modules are changed because of encoding errors introduced. 2012-07-19 09:07:59 -04:00
Alex Schroeder
6c813b8297 $q->path_info lacks UTF-8 decoding.
Fix other encoding issues with namespaces.
2012-07-19 09:05:07 -04:00
Alex Schroeder
ec4cba6fb3 Move binmode calls to the top of the file. 2012-07-19 08:28:51 -04:00
Alex Schroeder
76c50674f5 Handle encoding and avoid "wide character in print" when running oddtrans." 2012-07-19 08:06:41 -04:00
Alex Schroeder
a73a9e4a96 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-07-19 14:01:04 +02:00
Alex Schroeder
f27ec6c142 Use utf8::encode when creating a directory.
There is no way to provide an encoding layer to directory names.
Therefore they need to be raw bytes and not characters. This becomes
apparent when creating namespaces containing non-ASCII characters.
2012-07-19 13:58:58 +02:00
Alex Schroeder
37c32783f3 Changed \x{ffff} to \x{fffd} in all regular expressions.
Using Perl 5.8.8 resulted in a crash when compiling regular expressions referring to \x{ffff}.
2012-07-19 06:01:30 -04:00
Alex Schroeder
f922c0ae9a Fixed encoding of brazilian-portuguese-utf8.pl.
Some left-over texts for bulgarian-utf8.pl and chinese-utf8.pl.
2012-07-19 05:42:03 -04:00
Alex Schroeder
b46fcb3c90 Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2012-07-19 05:29:19 -04:00
Alex Schroeder
b885287ea2 Use binmode utf8 when sending files. 2012-07-19 10:53:13 +02:00
Alex Schroeder
67d68a370a Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse
Conflicts:

	Makefile
2012-07-19 04:49:13 -04:00
Alex Schroeder
ccef879ac1 Added "prepare" target to Makefile to add version info to all the sources.
.gitignore added build directory and stuff created by the Mac disk image rules.
2012-07-18 18:34:57 +02:00
Alex Schroeder
e8b9708f40 Set $ModulesDescription to an appropriate link for all translation files. 2012-07-18 18:16:57 +02:00
Alex Schroeder
d4f1e27cae Add a space to the META HTTP-EQUIV tag. Add an encoding test. 2012-07-18 10:59:58 +02:00
Alex Schroeder
b0a8e49975 Add link to documentation for %Smilies. 2012-07-18 10:58:58 +02:00
Alex Schroeder
9383adcba5 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-07-06 15:40:36 +02:00
Alex Schroeder
cde2d41dd1 Worked on encoding errors in PageHtml
I was getting "wide character in print" warnings when printing the RSS feed.
This should fix it.
2012-07-06 15:39:27 +02:00
Alex Schroeder
6e5766f431 On some encoding problems
The TOC extension causes problems when including non-ASCII Text.
2012-07-04 21:36:56 +02:00
Alex Schroeder
a2fe639a57 Removed statement that had no effect but caused an error when opening a non-ASCII page
The page in question was "Übersicht" on Emacs Wiki.
2012-07-04 17:14:51 +02:00
Alex Schroeder
f452d99e2f Removed $VERSION 2012-07-04 16:45:12 +02:00
Alex Schroeder
49f0c6d200 duplicate use utf8 removed 2012-07-04 16:43:12 +02:00
Alex Schroeder
f9efba3976 use utf8; 2012-07-04 15:26:08 +02:00
Alex Schroeder
36ef964d0d Removed $Id$ in wiki.pl because it was no longer being updated. 2012-07-04 11:30:21 +02:00
Alex Schroeder
eb4a4653a2 Support "half" class, eg. [[image/half/center:...]] 2012-06-27 16:52:07 +02:00
Alex Schroeder
741601489f Fix cookie encoding issues
If the username was set to Schröder, the wiki would keep reporting the
username as changed. This was caused by encoding errors if cookie
values. This change also allows non-ASCII parameters to be stored in
the cookie.
2012-06-23 01:08:46 +02:00
Alex Schroeder
217055fab2 Pod fix.
Changed =head to =head2 as suggested by anonymous visitor to the wiki.
2012-06-22 18:23:51 +02:00
Alex Schroeder
8f68442db1 Fix UTF-8 decoding issue when using toc.pl
The output of ApplyRules is no explicitly decoded as UTF8.
2012-06-22 02:54:29 +02:00
Alex Schroeder
b9d0c60080 Added copyright year. 2012-06-14 10:21:40 +02:00
Alex Schroeder
2b2e45b952 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-06-14 10:20:17 +02:00
Alex Schroeder
dfc3555184 Merge branch 'add-thumbs' 2012-06-14 10:19:33 +02:00
Alex Schroeder
474798c5cd Handle the new file format for uploaded files
Recently, uploaded files don't just contain #FILE and a MIME type --
the MIME type is followed by a space and optionally more information.
I replaced the hand-coded parsing with a call to TextIsFile and added
better error checking and fixed the error messages (they used $s
instead of %s).
2012-06-14 10:04:54 +02:00
Alex Schroeder
0a54f14a6f From the wiki
Taken the version from the wiki and added the standard
$ModulesDescription.
2012-06-14 08:39:25 +02:00
Alex Schroeder
04cdf0be24 Fixed cookie decoding
If the username contained a non-ASCII character, eg. Schröder, then
the script would keep printing the cookie message, telling the user
that the cookie had changed when in fact it had not.
2012-05-25 17:41:01 +02:00
Alex Schroeder
e531f9d569 Encoding the cookie and fixing drafts.pl
Drafts are saved using the username as filename. This must also be
encoded and decoded correctly. Because of NFC and NFD issues on Mac
HFS, an appropriate normalization was added to mac.pl.

As the username is also part of the cookie, this showed that the
Cookie content wasn't being encoded correctly, so that was fixed, too.
2012-05-25 11:56:46 +02:00
Alex Schroeder
4f6407fd38 Resolved conflict. 2012-05-25 08:29:34 +02:00
Alex Schroeder
3174e184f9 Fix an encoding error in namespaces.pl on Debian
The Debian installation uses ext3 and therefore raw bytes for
filenames unlike the HFS filesystem of Mac OSX.

Copyright years were updated. The maintenance output of for drafts was
cleaned up.
2012-05-25 01:00:10 +02:00
Alex Schroeder
8d94a0a50f Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse
Conflicts:
	modules/mac.pl
	t/encoding.t
	wiki.pl
2012-05-24 18:31:44 +02:00
Alex Schroeder
67650e3dc8 More UTF-8 fixes
All the source files containing non-ASCII characters needed to have
utf8 added. This will be necessary for user config files as well! The
regular expressions identifying page names had to be changed.
UrlEncode translates the string back to bytes before encoding it.
Cached RSS files are saved with UTF-8 encoding and therefore need
their meta-data changed (using the XML::RSS module to do this
correctly didn't work for some of the test files). The CGI object's
parameters, keywords and info_path are decoded correctly. File access
uses the UTF-8 layer (reading, writing, appending, access to the log
of recent changes, running sub processes with grep and diff).

The mac compatibility extension will also disable the use of grep if
non-ASCII characters are searched for because of an unexplained
problem with grep.
2012-05-24 18:08:42 +02:00
Alex Schroeder
700d412a01 More UTF-8 fixes
All the source files containing non-ASCII characters needed to have
utf8 added. This will be necessary for user config files as well! The
regular expressions identifying page names had to be changed.
UrlEncode translates the string back to bytes before encoding it.
Cached RSS files are saved with UTF-8 encoding and therefore need
their meta-data changed (using the XML::RSS module to do this
correctly didn't work for some of the test files). The CGI object's
parameters, keywords and info_path are decoded correctly. File access
uses the UTF-8 layer (reading, writing, appending, access to the log
of recent changes, running sub processes with grep and diff).

The mac compatibility extension will also disable the use of grep,
because I could not get it to work (and I don't think there will be
large Oddmuse installations running on Apple's HFS).
2012-05-24 16:58:10 +02:00
Alex Schroeder
cd2b4d624e Remove $HttpCharset and moved everything to UTF-8
This also required some changes to the tests where explicit UTF-8
encoding had been used in the past.
2012-05-22 11:50:23 +02:00
Alex Schroeder
17dbca2353 current.pl target now depends on always
The identifier added changes with every commit. A dependency
on wiki.pl alone doesn't work. That's why it now depends on
"always" which is phony.
2012-04-25 04:22:38 -04:00
165 changed files with 11862 additions and 2389 deletions

View File

@@ -1,8 +0,0 @@
.DS_Store
oddmuse-1.*
oddmuse-inkscape-1.*
*.patch
*.patch.gz
*.diff
*.diff.gz
test-data

6
.gitignore vendored
View File

@@ -1,4 +1,8 @@
*~
/current.pl
/build/
\#*\#
/test-data
/Mac/pkg/
*.dmg
*.pkg
.DS_Store

View File

@@ -1 +0,0 @@
pkg

View File

@@ -2,28 +2,55 @@
# Make sure the CVS keywords for the sed command on the next line are not expanded.
VERSION_NO=$(shell git describe --tags)
VERSION=oddmuse-$(VERSION_NO)
UPLOADVERSION=oddmuse-inkscape-$(VERSION_NO)
TRANSLATIONS=$(wildcard modules/translations/[a-z]*-utf8.pl$)
MODULES=$(wildcard modules/*.pl)
BUILD=build/wiki.pl $(foreach file, $(notdir $(MODULES)) $(notdir $(TRANSLATIONS)), build/$(file))
# PREPARE/BUILD: this creates copies of wiki.pl and all the modules
# and translations in the build subdirectory. These copies all contain
# a reference to the revision they were created from (git describe
# --tags).
prepare: build $(BUILD)
build:
mkdir -p build
build/wiki.pl: wiki.pl
sed "s/\\\$$q->a({-href=>'http:\/\/www.oddmuse.org\/'}, 'Oddmuse')/\\\$$q->a({-href=>'http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tag\/?id=$(VERSION_NO)'}, 'wiki.pl') . ' ($(VERSION_NO)), see ' . &/" < $< > $@
build/%-utf8.pl: modules/translations/%-utf8.pl
sed "s/<a href=\"http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tree\/modules\/translations\/\\(.*\\).pl\">\\(.*\\).pl<\/a>/<a href=\"http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tree\/modules\/translations\/\\1.pl?id=$(VERSION_NO)\">\\1.pl<\/a> (for $(VERSION_NO))/" < $< > $@
# Currently oddtrans introduces encoding errors!
# %-utf8.pl: wiki.pl $(MODULES)
# perl oddtrans -l $@ $^ > $@-new && mv $@-new $@
# from: http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/namespaces.pl
# to: http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/namespaces.pl?id=2.1-11-gd4f1e27
build/%.pl: modules/%.pl
sed "s/<a href=\"http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tree\/modules\/\\(.*\\).pl\">\\(.*\\).pl<\/a>/<a href=\"http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tree\/modules\/\\1.pl?id=$(VERSION_NO)\">\\1.pl<\/a> (for $(VERSION_NO))/" < $< > $@
# UNTESTED/OBSOLETE: these targets have not been tested in a long time
# and are potentially obsolete.
VERSION=oddmuse-$(VERSION_NO)
UPLOADVERSION=oddmuse-inkscape-$(VERSION_NO)
INKSCAPE=GPL $(wildcard inkscape/*.py inkscape/*.inx inkscape/*.sh)
PACKAGEMAKER=/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker
PWD=$(shell pwd)
DIST=$(VERSION).tar.gz $(VERSION).tar.gz.sig \
contrib/simple-install/$(VERSION)-simple.tar.gz \
contrib/simple-install/$(VERSION)-simple.tar.gz.sig
# These targets no longer work are have not been verified in a long time.
OLDDIST=$(VERSION).dmg $(VERSION).dmg.sig \
$(VERSION).tar.gz $(VERSION).tar.gz.sig \
$(VERSION).tgz $(VERSION).tgz.sig \
$(UPLOADVERSION).tar.gz $(UPLOADVERSION).tar.gz.sig
$(VERSION).tgz $(VERSION).tgz.sig
PWD=$(shell pwd)
dist: $(DIST)
current.pl: wiki.pl
sed "s/\\\$$q->a({-href=>'http:\/\/www.oddmuse.org\/'}, 'Oddmuse')/\\\$$q->a({-href=>'http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tag\/?id=$(VERSION_NO)'}, 'wiki.pl') . ', see ' . &/" < $< > $@
upload: $(DIST)
for f in $^; do \
scp $$f as@dl.sv.nongnu.org:/releases/oddmuse/; \
@@ -107,9 +134,6 @@ $(VERSION).tgz: wiki.pl modules/creole.pl Mac/config Mac/wiki
sudo chmod 775 Slack/var/www/cgi-bin/wiki
cd Slack && tar czf ../$@ var install
%-utf8.pl: wiki.pl $(MODULES)
perl oddtrans -l $@ $^ > $@-new && mv $@-new $@
update-translations: $(TRANSLATIONS)
upload-translations: always
@@ -119,8 +143,6 @@ upload-translations: always
"http://www.oddmuse.org/cgi-bin/oddmuse/raw/$$f" < $$f; \
done
.PHONY: always
deb:
equivs-build control

View File

@@ -1,2 +0,0 @@
install
var

90
contrib/anonymize.pl Normal file
View File

@@ -0,0 +1,90 @@
#! /usr/bin/perl -w
# Copyright (C) 2013 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
=head1 Anonymize oldrc.log Files
This script will read your oldrc.log file and replace the host field
with 'Anonymous'. This is what the main script started doing
2013-11-30.
When you run this script, it sets the main lock to prevent maintenance
from running. You can therefore run it on a live system.
=cut
use strict;
sub verify_setup {
if (not -f 'oldrc.log') {
die "Run this script in your data directory.\n"
. "The oldrc.log file should be in the same directory.\n";
}
if (not -d 'temp') {
die "Run this script in your data directory.\n"
. "The temp directory should be in the same directory.\n";
}
}
sub request_lock {
if (-d 'temp/lockmain') {
die "The wiki is currently locked.\n"
. "Rerun this script later.\n";
}
mkdir('temp/lockmain') or die "Could not create 'temp/lockmain'.\n"
. "You probably don't have the file permissions necessary.\n";
}
sub release_lock {
rmdir('temp/lockmain') or die "Could not remove 'temp/lockmain'.\n"
}
sub anonymize {
open(F, 'oldrc.log') or die "Could not open 'oldrc.log' for reading.\n";
open(B, '>oldrc.log~') or die "Could not open 'oldrc.log~' for writing.\n"
. "I will not continue without having a backup available.\n";
my $FS = "\x1e"; # The FS character is the RECORD SEPARATOR control char
my @lines = ();
while (my $line = <F>) {
next if $line eq "\n"; # some rc.log files are broken and contain empty lines
my ($ts, $id, $minor, $summary, $host, @rest) = split(/$FS/o, $line);
if ($id eq '[[rollback]]') {
# rollback markers are very different
push(@lines, $line);
} else {
# anonymize
push(@lines, join($FS, $ts, $id, $minor, $summary, 'Anonymous', @rest));
}
print B $line;
}
close(F);
open(F, '>', 'oldrc.log') or die "Could not open 'oldrc.log' for writing.\n";
for my $line (@lines) {
print F $line; # @rest ends with a newline
}
close(F);
print "Wrote anonymized 'oldrc.log'.\n";
print "Saved a backup as 'oldrc.log~'\n";
}
sub main {
verify_setup();
request_lock();
anonymize();
release_lock();
}
main();

View File

@@ -1,6 +1,6 @@
#!/usr/bin/perl
# Copyright (C) 2010 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2010, 2012 Alex Schroeder <alex@gnu.org>
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
@@ -17,6 +17,7 @@
package OddMuse;
use URI;
use LWP::UserAgent;
use utf8;
# load Oddmuse core
$RunCGI = 0;
@@ -61,16 +62,16 @@ sub parse_blogs {
return %cached_blogs if %cached_blogs;
my @data = split(/\n/, GetRaw($src));
my $url;
my $name;
my $paramref;
foreach $_ (@data) {
if (/^\[(.+)\]/) {
$url = $1;
$name = undef;
} elsif (/^name *= *(.+)/) {
$name = $1;
$paramref = {};
} elsif (/^([a-z_]+) *= *(.+)/) {
$paramref->{$1} = $2;
}
if ($url && $name) {
$cached_blogs{$url} = $name;
if ($url && $paramref->{name}) {
$cached_blogs{$url} = $paramref;
}
}
return %cached_blogs;
@@ -84,8 +85,16 @@ sub host_exists {
}
}
sub debug_url {
my $url = $q->url(-path_info=>1) . "?debug=1;";
$url .= join(";", map { $_ . "=" . GetParam($_) }
qw(username confirmed candidate url));
return $url;
}
sub check_url {
my $url = shift;
print $q->p("Debug: url=$url") if GetParam("debug");
my $frown = $q->img({-src=>"http://emacswiki.org/pics/smiles/sad.png",
-alt=>":("});
my $smile = $q->img({-src=>"http://emacswiki.org/pics/smiles/smile.png",
@@ -97,26 +106,24 @@ sub check_url {
$u = URI->new($url);
eval {$u->host };
}
# - not an url
# - it's campaign wiki site
# - no username
# or read Feeds page and
# - it's a duplicate
# - it's a partial match: continue with confirmed=1
# or read the list of alternatives from the url
# - one of the feeds listed is known: continue with confirmed=2
# - no feeds were listed: url is a feed or report it
# - one feed was listed: try it
# - some feeds were listed: pick one
if ($@) {
# the prefixing of http:// above should make it really hard to reach this code
print $q->p($q->a({-href=>$url}, $url) . qq{
seems to be <strong>invalid</strong>. $frown Make sure you use something
like the following: <tt>http://grognardia.blogspot.com/</tt>});
} elsif (not GetParam('username', '')) {
print $q->p(qq{As an anti-spam measure I'd really like you to <strong>provide a name</strong> for the log file. Sorry about that. $frown});
} else {
my %blogs = parse_blogs();
my $duplicate = host_exists($u->host, %blogs);
if ($duplicate
&& !$blogs{$url}
&& !GetParam('confirmed')) {
print $q->p("We have a partial match: ",
$q->a({-href=>$duplicate}, $duplicate));
print GetFormStart();
print $q->hidden('confirmed', 1);
print $q->hidden('url', $url);
print $q->submit('go', 'Proceed anyway!');
print $q->end_form();
} elsif ($url =~ /campaignwiki\.org/i) {
print $q->p(qq{
This looks <strong>familiar</strong>!
@@ -124,17 +131,35 @@ I do not think that adding any of the wikis on this site is the right
thing to do, though.});
print $q->p(qq{Thanks for testing it. }
. $q->img({-src=>"http://www.emacswiki.org/pics/grin.png"}));
} elsif (not GetParam('username', '')) {
print $q->p(qq{As an anti-spam measure I'd really like you to
<strong>provide a name</strong> for the log file. Sorry about that. $frown});
} else {
my %blogs = parse_blogs();
my $duplicate = host_exists($u->host, %blogs);
if ($blogs{$url}) {
print $q->p("We already list ",
$q->a({-href=>$duplicate}, $duplicate));
} elsif ($duplicate && !GetParam('confirmed')) {
print $q->p("We have a partial match: ",
$q->a({-href=>$duplicate}, $duplicate));
print GetFormStart();
print $q->hidden('confirmed', 1);
print $q->hidden('url', $url);
print $q->submit('go', 'Proceed anyway!');
print $q->end_form();
} else {
my @alternatives = get_feeds($url, keys %blogs);
if ($#alternatives > 0 && !GetParam('candidate')) {
my ($status, @alternatives) = get_feeds($url, %blogs);
if ($status eq 'known' && GetParam('confirmed') < 2) {
print $q->p($q->a({-href=>$url},
"The page you submitted")
. " lists "
. $q->a({-href=>$alternatives[0]},
"a known feed") . ".");
print GetFormStart();
print $q->hidden('confirmed', 1);
print $q->hidden('confirmed', 2);
print $q->hidden('url', $url);
print $q->p("You need to pick one of the candidates:");
print $q->p(join($q->br(), map {
$q->input({-type=>"radio", -name=>"candidate", -value=>$_},
$q->a({-href=>$_}, QuoteHtml($_))) } @alternatives));
print $q->submit('go', 'Submit');
print $q->submit('go', 'Proceed anyway!');
print $q->end_form();
} elsif ($#alternatives < 0) {
if (is_feed($url)) {
@@ -143,20 +168,31 @@ thing to do, though.});
print $q->p("Apparently " . $q->a({-href=>$url}, QuoteHtml($url))
. " is not a feed and doesn't link to any feed. "
. "There is nothing for me to add. " . $frown);
print $q->p("If you feel like it, you could try to "
. $q->a({-href=>debug_url()}, "debug")
. " this.");
}
} elsif ($#alternatives == 0) {
print $q->p($q->a({-href=>$url}, "The page you submitted")
. " lists "
. $q->a({-href=>$alternatives[0]},
"one new feed")
. ".");
print GetFormStart();
print $q->hidden('url', $alternatives[0]);
print $q->submit('go', 'Take it!');
print $q->end_form();
print $q->p("If you feel like it, you could try to "
. $q->a({-href=>debug_url()}, "debug")
. " this.");
} else {
my $candidate = GetParam('candidate');
$candidate = $alternatives[0] unless $candidate;
if (is_feed($candidate)) {
post_addition($candidate);
} else {
print $q->p($q->a({-href=>$candidate}, "The page you submitted")
. " listed "
. $q->a({-href=>$candidate}, QuoteHtml($candidate))
. " as one of its feeds. "
. "But it turns out that this is not a valid feed! "
. "I can't add an invalid feed. " . $frown);
}
print GetFormStart();
print $q->p("You need to pick one of the candidates:");
print $q->p(join($q->br(), map {
$q->input({-type=>"radio", -name=>"url", -value=>$_},
$q->a({-href=>$_}, QuoteHtml($_))) } @alternatives));
print $q->submit('go', 'Submit');
print $q->end_form();
}
}
}
@@ -172,23 +208,73 @@ sub is_feed {
sub get_feeds {
my $url = shift;
my %others = map { $_ => 1 } @_;
my @links = GetRaw($url) =~ /<link\b *(.*?)>/g;
my %others = @_;
my $html = GetRaw($url);
my @links = $html =~ /<link\b *(.*?)>/g;
print $q->p("Debug: " . scalar(@links) . " links found") if GetParam("debug");
print $q->pre($html) unless scalar(@links);
print $q->p("Debug: no content returned") if GetParam("debug") and not $html;
my @feeds;
foreach my $link (@links) {
my %link;
foreach (split(/ /, lc($link))) {
my ($attr, $val) = split(/=/, $_, 2);
# strip quotes and garbage: "foo"/ -> foo
my $to = index($val, substr($val, 0, 1), 1);
$val = substr($val, 1, $to -1) if $to >= 0;
$link{$attr} = $val;
print $q->p("Debug: $link")
if GetParam("debug");
if ($link !~ /\brel=(['"])alternate\1/i) {
print $q->p("Debug: missing rel='alternate'")
if GetParam("debug");
next;
}
next unless $link{rel} eq 'alternate';
next unless $valid_content_type{$link{type}};
push(@feeds, $link{href}) unless $others{$link{href}};
$link =~ /\btype=(['"])(.*?)\1/i;
my $type = $2;
if (not $valid_content_type{$type}) {
print $q->p("Debug: type parameter is invalid ($type)")
if GetParam("debug");
next;
}
$link =~ /\bhref=(['"])(.*?)\1/i;
my $href = $2;
# clean up blogspot urls and prefer atom format
$href =~ s/\?alt=rss$//i if $href =~ /blogspot/i;
if (not $href) {
print $q->p("Debug: href missing")
if GetParam("debug");
next;
}
if ($others{$href}) {
print $q->p("Debug: feed already known ($href)")
if GetParam("debug");
if ($q->param('confirmed') >= 2) {
next;
} else {
# don't look for other alternatives!
return 'known', $href;
}
}
push(@feeds, $href);
}
return @feeds;
print $q->p("Debug: returning " . scalar(@feeds) . " links found")
if GetParam("debug");
return 'ok', @feeds;
}
sub config {
my %blogs = @_;
my $result = qq{#! config file for the RPG Planet
# format:
# Feed URL in square brackets, followed by name = and the name of the feed
};
foreach my $url (sort {lc($blogs{$a}->{name}) cmp lc($blogs{$b}->{name})} keys %blogs) {
$result .= "[$url]\n";
$paramref = $blogs{$url};
foreach my $key (sort keys %{$paramref}) {
$result .= $key . " = " . $paramref->{$key} . "\n";
}
}
return $result;
}
sub post_addition {
@@ -206,14 +292,9 @@ sub post_addition {
$title = $final_url unless $title;
print $q->p("Adding ",
$q->a({-href=>$final_url}, $title));
$blogs{$url} = $title;
my $result = qq{#! config file for the RPG Planet
# format:
# Feed URL in square brackets, followed by name = and the name of the feed
};
foreach $url (sort {lc($blogs{$a}) cmp lc($blogs{$b})} keys %blogs) {
$result .= "[$url]\nname = " . $blogs{$url} . "\n";
}
my %param = (name => $title);
$blogs{$url} = \%param;
my $result = config(%blogs);
my $ua = LWP::UserAgent->new;
my %params = (text => $result,
title => $page,
@@ -250,16 +331,18 @@ sub main {
if ($q->path_info eq '/source') {
seek DATA, 0, 0;
print "Content-type: text/plain; charset=UTF-8\r\n\r\n", <DATA>;
} elsif ($q->path_info eq '/test') {
print "Content-type: text/plain; charset=UTF-8\r\n\r\n";
print config(parse_blogs());
} else {
$UserGotoBar .= $q->a({-href=>$q->url . '/source'}, 'Source');
print GetHeader('', 'Submit a new blog');
print $q->start_div({-class=>'content index'});
if (not GetParam('url')
or not GetParam($HoneyPotOk)) {
if (not GetParam('url')) {
print $q->p("Debug: no url parameter provided.") if GetParam("debug");
default();
} else {
SetParam('title', 'Feeds'); # required to trigger HoneyPotInspection()
HoneyPotInspection();
check_url(GetParam('url'));
}
print $q->p('Questions? Send mail to Alex Schröder <'

View File

@@ -1,21 +1,17 @@
#!/usr/bin/perl
# Copyright (C) 2005, 2006, 2007 Alex Schroeder <alex@emacswiki.org>
# Copyright (C) 2005, 2006, 2007, 2012 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
use strict;
use warnings;
@@ -38,6 +34,42 @@ my %indexes = (
=> 'GNU Emacs Lisp reference manual, Index',
'http://www.gnu.org/software/emacs/manual/html_node/elisp/index.html'
=> 'GNU Emacs Lisp reference manual, Top Menu',
'http://www.gnu.org/software/emacs/manual/html_node/message/Index.html'
=> 'Message Manual, Index',
'http://www.gnu.org/software/emacs/manual/html_node/gnus/Index.html'
=> 'The Gnus Newsreader, Index',
'http://www.gnu.org/software/emacs/manual/html_node/cl/Function-Index.html'
=> 'Common Lisp Extensions, Function Index',
'http://www.gnu.org/software/emacs/manual/html_node/ccmode/Variable-Index.html'
=> 'CC Mode Manual, Variable Index',
'http://www.gnu.org/software/emacs/manual/html_node/ccmode/Concept-and-Key-Index.html'
=> 'CC Mode Manual, Command and Function Index',
'http://www.gnu.org/software/emacs/manual/html_node/org/Index.html'
=> 'Org Mode Manual, Index',
'http://www.gnu.org/software/auctex/manual/auctex/Function-Index.html'
=> 'AUCTeX Manual, Function Index',
'http://www.gnu.org/software/auctex/manual/auctex/Variable-Index.html'
=> 'AUCTeX Manual, Variable Index',
'http://www.gnu.org/software/auctex/manual/auctex/Concept-Index.html'
=> 'AUCTeX Manual, Concept Index',
'http://www.gnu.org/software/texinfo/manual/texinfo/html_node/index.html'
=> 'Texinfo, Command and Variable Index',
'http://www.gnu.org/software/texinfo/manual/texinfo/html_node/General-Index.html'
=> 'Texinfo, General Index',
'http://www.gnu.org/software/texinfo/manual/info/html_node/Index.html'
=> 'Info, Index',
'http://www.gnu.org/software/emacs/manual/html_node/dired-x/Command-Index.html'
=> 'Dired Extra, Function Index',
'http://www.gnu.org/software/emacs/manual/html_node/dired-x/Variable-Index.html'
=> 'Dired Extra, Variable Index',
'http://www.gnu.org/software/coreutils/manual/html_node/Concept-index.html'
=> 'Coreutils, Index',
'http://www.gnu.org/software/diffutils/manual/html_node/Index.html'
=> 'Diffutils, Index',
'http://www.gnu.org/software/findutils/manual/html_node/find_html/Primary-Index.html'
=> 'Findutils, Primary Index',
'http://www.gnu.org/software/emacs/manual/html_node/ediff/Index.html'
=> 'Edfiff, Index',
);
my $db = '/org/org.emacswiki/htdocs/emacs/info-ref.dat';
@@ -63,7 +95,9 @@ sub ProcessRequest {
sub ShowForm {
print $q->header, $q->start_html,
$q->start_form, "Index entry: ", $q->textfield('find'), $q->submit, $q->end_form,
$q->p('$Id: info-ref,v 1.1 2007/07/13 23:20:57 as Exp $'),
$q->p($q->a({-href=>"http://www.emacswiki.org/scripts/info-ref"}, "Source"), $q->br(),
'Last DB update: ', TimeToText((stat($db))[9]),
' (' . $q->a({-href=>$q->url . '?init=1'}, "update") . ')'),
$q->end_html;
}
@@ -74,9 +108,11 @@ sub Find {
foreach my $line (split(/$nl/, $data)) {
my ($key, $rest) = split(/$fs/, $line);
$map{$key} = ();
foreach my $a (split(/$gs/, $rest)) {
my ($link, $label) = split(/$rs/, $a);
$map{$key}{$link} = $label;
if ($rest) {
foreach my $a (split(/$gs/, $rest)) {
my ($link, $label) = split(/$rs/, $a);
$map{$key}{$link} = $label;
}
}
}
my @links = keys %{$map{$str}};
@@ -150,7 +186,7 @@ sub GetRaw {
return unless eval { require LWP::UserAgent; };
my $ua = LWP::UserAgent->new;
my $response = $ua->get($uri);
return $response->content;
return $response->decoded_content;
}
sub ReadFile {
@@ -189,3 +225,18 @@ sub ReportError { # fatal!
print $q->start_html, $q->h2($errmsg), $q->end_html;
exit (1);
}
sub CalcDay {
my ($sec, $min, $hour, $mday, $mon, $year) = gmtime(shift);
return sprintf('%4d-%02d-%02d', $year+1900, $mon+1, $mday);
}
sub CalcTime {
my ($sec, $min, $hour, $mday, $mon, $year) = gmtime(shift);
return sprintf('%02d:%02d UTC', $hour, $min);
}
sub TimeToText {
my $t = shift;
return CalcDay($t) . ' ' . CalcTime($t);
}

871
contrib/oddmuse-curl.el Normal file
View File

@@ -0,0 +1,871 @@
;;; oddmuse-curl.el -- edit pages on an Oddmuse wiki using curl
;;
;; Copyright (C) 20062014 Alex Schroeder <alex@gnu.org>
;; (C) 2007 rubikitch <rubikitch@ruby-lang.org>
;;
;; Latest version:
;; http://git.savannah.gnu.org/cgit/oddmuse.git/plain/contrib/oddmuse-curl.el
;; Discussion, feedback:
;; http://www.emacswiki.org/wiki/OddmuseCurl
;;
;; This program is free software: you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by the Free
;; Software Foundation, either version 3 of the License, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
;; more details.
;;
;; You should have received a copy of the GNU General Public License along
;; with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; A simple mode to edit pages on Oddmuse wikis using Emacs and the command-line
;; HTTP client `curl'.
;;
;; Since text formatting rules depend on the wiki you're writing for, the
;; font-locking can only be an approximation.
;;
;; Put this file in a directory on your `load-path' and
;; add this to your init file:
;; (require 'oddmuse)
;; (oddmuse-mode-initialize)
;; And then use M-x oddmuse-edit to start editing.
;;; Code:
(eval-when-compile
(require 'cl)
(require 'sgml-mode)
(require 'skeleton))
(require 'goto-addr); URL regexp
(require 'info); link face
(require 'shr); preview
(require 'xml); preview munging
(defcustom oddmuse-directory "~/.emacs.d/oddmuse"
"Directory to store oddmuse pages."
:type '(string)
:group 'oddmuse)
(defcustom oddmuse-wikis
'(("EmacsWiki" "http://www.emacswiki.org/cgi-bin/emacs"
utf-8 "uihnscuskc" nil)
("OddmuseWiki" "http://www.oddmuse.org/cgi-bin/oddmuse"
utf-8 "question" nil))
"Alist mapping wiki names to URLs.
The elements in this list are:
NAME, the name of the wiki you provide when calling `oddmuse-edit'.
URL, the base URL of the script used when posting. If the site
uses URL rewriting, then you need to extract the URL from the
edit page. Emacs Wiki, for example, usually shows an URL such as
http://www.emacswiki.org/emacs/Foo, but when you edit the page
and examine the page source, you'll find this:
<form method=\"post\" action=\"http://www.emacswiki.org/cgi-bin/emacs\"
enctype=\"multipart/form-data\" accept-charset=\"utf-8\"
class=\"edit text\">...</form>
Thus, the correct value for URL is
http://www.emacswiki.org/cgi-bin/emacs.
ENCODING, a symbol naming a coding-system.
SECRET, the secret the wiki uses if it has the Question Asker
extension enabled. If you're getting 403 responses (edit denied)
eventhough you can do it from a browser, examine your cookie in
the browser. For Emacs Wiki, for example, my cookie says:
euihnscuskc%251e1%251eusername%251eAlexSchroeder
Use `split-string' and split by \"%251e\" and you'll see that
\"euihnscuskc\" is the odd one out. The parameter name is the
relevant string (its value is always 1).
USERNAME, your optional username to provide. It defaults to
`oddmuse-username'."
:type '(repeat (list (string :tag "Wiki")
(string :tag "URL")
(choice :tag "Coding System"
(const :tag "default" utf-8)
(symbol :tag "specify"
:validate (lambda (widget)
(unless (coding-system-p
(widget-value widget))
(widget-put widget :error
"Not a valid coding system")))))
(choice :tag "Secret"
(const :tag "default" "question")
(string :tag "specify"))
(choice :tag "Username"
(const :tag "default" nil)
(string :tag "specify"))))
:group 'oddmuse)
(defcustom oddmuse-username user-full-name
"Username to use when posting.
Setting a username is the polite thing to do."
:type '(string)
:group 'oddmuse)
(defcustom oddmuse-password ""
"Password to use when posting.
You only need this if you want to edit locked pages and you
know an administrator password."
:type '(string)
:group 'oddmuse)
(defcustom oddmuse-use-always-minor nil
"When t, set all the minor mode bit to all editions.
This can be changed for each edition using `oddmuse-toggle-minor'."
:type '(boolean)
:group 'oddmuse)
(defvar oddmuse-get-command
"curl --silent %w\"?action=browse;raw=2;\"id=%t"
"Command to use for publishing pages.
It must print the page to stdout.
%? '?' character
%w URL of the wiki as provided by `oddmuse-wikis'
%t URL encoded pagename, eg. HowTo, How_To, or How%20To")
(defvar oddmuse-history-command
"curl --silent %w\"?action=history;raw=1;\"id=%t"
"Command to use for reading the history of a page.
It must print the history to stdout.
%? '?' character
%w URL of the wiki as provided by `oddmuse-wikis'
%t URL encoded pagename, eg. HowTo, How_To, or How%20To")
(defvar oddmuse-rc-command
"curl --silent %w\"?action=rc;raw=1\""
"Command to use for Recent Changes.
It must print the RSS 3.0 text format to stdout.
%? '?' character
%w URL of the wiki as provided by `oddmuse-wikis'")
(defvar oddmuse-post-command
(concat "curl --silent --write-out '%{http_code}'"
" --form title='%t'"
" --form summary='%s'"
" --form username='%u'"
" --form password='%p'"
" --form %q=1"
" --form recent_edit=%m"
" --form oldtime=%o"
" --form text='<-'"
" '%w'")
"Command to use for publishing pages.
It must accept the page on stdin and print the HTTP status code
on stdout.
%? '?' character
%t pagename
%s summary
%u username
%p password
%q question-asker cookie
%m minor edit
%o oldtime, a timestamp provided by Oddmuse
%w URL of the wiki as provided by `oddmuse-wikis'")
(defvar oddmuse-preview-command
(concat "curl --silent"
" --form title='%t'"
" --form username='%u'"
" --form password='%p'"
" --form %q=1"
" --form recent_edit=%m"
" --form oldtime=%o"
" --form Preview=Preview"; the only difference
" --form text='<-'"
" '%w'")
"Command to use for previewing pages.
It must accept the page on stdin and print the HTML on stdout.
%? '?' character
%t pagename
%u username
%p password
%q question-asker cookie
%m minor edit
%o oldtime, a timestamp provided by Oddmuse
%w URL of the wiki as provided by `oddmuse-wikis'")
(defvar oddmuse-link-pattern
"\\<[[:upper:]]+[[:lower:]]+\\([[:upper:]]+[[:lower:]]*\\)+\\>"
"The pattern used for finding WikiName.")
(defvar oddmuse-wiki nil
"The current wiki.
Must match a key from `oddmuse-wikis'.")
(defvar oddmuse-page-name nil
"Pagename of the current buffer.")
(defvar oddmuse-pages-hash (make-hash-table :test 'equal)
"The wiki-name / pages pairs.")
(defvar oddmuse-index-get-command
"curl --silent %w\"?action=index;raw=1\""
"Command to use for publishing index pages.
It must print the page to stdout.
%? '?' character
%w URL of the wiki as provided by `oddmuse-wikis'
")
(defvar oddmuse-minor nil
"Is this edit a minor change?")
(defvar oddmuse-revision nil
"The ancestor of the current page.
This is used by Oddmuse to merge changes.")
(defun oddmuse-mode-initialize ()
(add-to-list 'auto-mode-alist
`(,(expand-file-name oddmuse-directory) . oddmuse-mode)))
(defun oddmuse-creole-markup ()
"Implement markup rules for the Creole markup extension."
(setcar font-lock-defaults
(append
'(("^=[^=\n]+"
0 '(face info-title-1
help-echo "Creole H1")); = h1
("^==[^=\n]+"
0 '(face info-title-2
help-echo "Creole H2")); == h2
("^===[^=\n]+"
0 '(face info-title-3
help-echo "Creole H3")); === h3
("^====+[^=\n]+"
0 '(face info-title-4
help-echo "Creole H4")); ====h4
("\\_<//\\(.*\n\\)*?.*?//"
0 '(face italic
help-echo "Creole italic")); //italic//
("\\*\\*\\(.*\n\\)*?.*?\\*\\*"
0 '(face bold
help-echo "Creole bold")); **bold**
("__\\(.*\n\\)*?.*?__"
0 '(face underline
help-echo "Creole underline")); __underline__
("|+=?"
0 '(face font-lock-string-face
help-echo "Creole table cell"))
("\\\\\\\\[ \t]+"
0 '(face font-lock-warning-face
help-echo "Creole line break"))
("^#+ "
0 '(face font-lock-constant-face
help-echo "Creole ordered list"))
("^- "
0 '(face font-lock-constant-face
help-echo "Creole ordered list")))
(car font-lock-defaults))))
(defun oddmuse-bbcode-markup ()
"Implement markup rules for the bbcode markup extension."
(setcar font-lock-defaults
(append
`(("\\[b\\]\\(.*\n\\)*?.*?\\[/b\\]"
0 '(face bold
help-echo "BB code bold"))
("\\[i\\]\\(.*\n\\)*?.*?\\[/i\\]"
0 '(face italic
help-echo "BB code italic"))
("\\[u\\]\\(.*\n\\)*?.*?\\[/u\\]"
0 '(face underline
help-echo "BB code underline"))
(,(concat "\\[url=" goto-address-url-regexp "\\]")
0 '(face font-lock-builtin-face
help-echo "BB code url"))
("\\[/?\\(img\\|url\\)\\]"
0 '(face font-lock-builtin-face
help-echo "BB code url or img"))
("\\[s\\(trike\\)?\\]\\(.*\n\\)*?.*?\\[/s\\(trike\\)?\\]"
0 '(face strike
help-echo "BB code strike"))
("\\[/?\\(left\\|right\\|center\\)\\]"
0 '(face font-lock-constant-face
help-echo "BB code alignment")))
(car font-lock-defaults))))
(defun oddmuse-usemod-markup ()
"Implement markup rules for the Usemod markup extension."
(setcar font-lock-defaults
(append
'(("^=[^=\n]+=$"
0 '(face info-title-1
help-echo "Usemod H1"))
("^==[^=\n]+==$"
0 '(face info-title-2
help-echo "Usemod H2"))
("^===[^=\n]+===$"
0 '(face info-title-3
help-echo "Usemod H3"))
("^====+[^=\n]+====$"
0 '(face info-title-4
help-echo "Usemod H4"))
("^ .+?$"
0 '(face font-lock-comment-face
help-echo "Usemod block"))
("^[#]+ "
0 '(face font-lock-constant-face
help-echo "Usemod ordered list")))
(car font-lock-defaults))))
(defun oddmuse-usemod-html-markup ()
"Implement markup rules for the HTML option in the Usemod markup extension."
(setcar font-lock-defaults
(append
'(("<\\(/?[a-z]+\\)"
1 '(face font-lock-function-name-face
help-echo "Usemod HTML")))
(car font-lock-defaults)))
(set (make-local-variable 'sgml-tag-alist)
`(("b") ("code") ("em") ("i") ("strong") ("nowiki")
("pre" \n) ("tt") ("u")))
(set (make-local-variable 'skeleton-transformation) 'identity))
(defun oddmuse-extended-markup ()
"Implement markup rules for the Markup extension."
(setcar font-lock-defaults
(append
'(("\\*\\w+[[:word:]-%.,:;\'\"!? ]*\\*"
0 '(face bold
help-echo "Markup bold"))
("\\_</\\w+[[:word:]-%.,:;\'\"!? ]*/"
0 '(face italic
help-echo "Markup italic"))
("_\\w+[[:word:]-%.,:;\'\"!? ]*_"
0 '(face underline
help-echo "Markup underline")))
(car font-lock-defaults))))
(defun oddmuse-basic-markup ()
"Implement markup rules for the basic Oddmuse setup without extensions.
This function should come come last in `oddmuse-markup-functions'
because of such basic patterns as [.*] which are very generic."
(setcar font-lock-defaults
(append
`((,oddmuse-link-pattern
0 '(face link
help-echo "Basic wiki name"))
("\\[\\[.*?\\]\\]"
0 '(face link
help-echo "Basic free link"))
(,(concat "\\[" goto-address-url-regexp "\\( .+?\\)?\\]")
0 '(face link
help-echo "Basic external free link"))
("^\\([*]+\\)"
0 '(face font-lock-constant-face
help-echo "Basic bullet list")))
(car font-lock-defaults))))
;; Should determine this automatically based on the version? And cache
;; it per wiki? http://emacswiki.org/wiki?action=version
(defvar oddmuse-markup-functions
'(oddmuse-creole-markup
oddmuse-usemod-markup
oddmuse-bbcode-markup
oddmuse-extended-markup
oddmuse-basic-markup
goto-address)
"The list of functions to call when `oddmuse-mode' runs.
If these functions add font-locking, they should modify
`font-lock-defaults'. See `font-lock-keywords' for documentation.
If these functions all prepend their keywords, you should list
the most important function last.
Here's a template for your code:
\(setcar font-lock-defaults
(append
'((REGEXP
0 '(face FACE
help-echo DOCSTRING)))
(car font-lock-defaults)))")
(defun oddmuse-nobreak-p ()
"Prevent line break of links.
This depends on the `link' face."
(let ((face (get-text-property (point) 'face)))
(if (listp face)
(memq 'link face)
(eq 'link face))))
(define-derived-mode oddmuse-mode text-mode "Odd"
"Simple mode to edit wiki pages.
Use \\[oddmuse-follow] to follow links. With prefix, allows you
to specify the target page yourself.
Use \\[oddmuse-post] to post changes. With prefix, allows you to
post the page to a different wiki.
Use \\[oddmuse-edit] to edit a different page. With prefix,
forces a reload of the page instead of just popping to the buffer
if you are already editing the page.
Customize `oddmuse-wikis' to add more wikis to the list.
Font-locking is controlled by `oddmuse-markup-functions'.
\\{oddmuse-mode-map}"
(setq font-lock-defaults '(nil))
(mapc 'funcall oddmuse-markup-functions)
(font-lock-mode 1)
(when buffer-file-name
(set (make-local-variable 'oddmuse-wiki)
(file-name-nondirectory
(substring (file-name-directory buffer-file-name) 0 -1)))
(set (make-local-variable 'oddmuse-page-name)
(file-name-nondirectory buffer-file-name)))
(set (make-local-variable 'oddmuse-minor)
oddmuse-use-always-minor)
(set (make-local-variable 'oddmuse-revision)
(save-excursion
(goto-char (point-min))
(if (looking-at
"\\([0-9]+\\) # Do not delete this line when editing!\n")
(prog1 (match-string 1)
(replace-match "")
(set-buffer-modified-p nil)))))
(set (make-local-variable 'fill-nobreak-predicate)
'(oddmuse-nobreak-p))
(setq indent-tabs-mode nil))
(autoload 'sgml-tag "sgml-mode" t)
(define-key oddmuse-mode-map (kbd "C-c C-t") 'sgml-tag)
(define-key oddmuse-mode-map (kbd "C-c C-o") 'oddmuse-follow)
(define-key oddmuse-mode-map (kbd "C-c C-n") 'oddmuse-new)
(define-key oddmuse-mode-map (kbd "C-c C-m") 'oddmuse-toggle-minor)
(define-key oddmuse-mode-map (kbd "C-c C-c") 'oddmuse-post)
(define-key oddmuse-mode-map (kbd "C-c C-p") 'oddmuse-preview)
(define-key oddmuse-mode-map (kbd "C-x C-v") 'oddmuse-revert)
(define-key oddmuse-mode-map (kbd "C-c C-f") 'oddmuse-edit)
(define-key oddmuse-mode-map (kbd "C-c C-i") 'oddmuse-insert-pagename)
(define-key oddmuse-mode-map (kbd "C-c C-h") 'oddmuse-history)
(define-key oddmuse-mode-map (kbd "C-c C-r") 'oddmuse-rc)
;; This has been stolen from simple-wiki-edit
;;;###autoload
(defun oddmuse-toggle-minor (&optional arg)
"Toggle minor mode state."
(interactive)
(let ((num (prefix-numeric-value arg)))
(cond
((or (not arg) (equal num 0))
(setq oddmuse-minor (not oddmuse-minor)))
((> num 0) (set 'oddmuse-minor t))
((< num 0) (set 'oddmuse-minor nil)))
(message "Oddmuse Minor set to %S" oddmuse-minor)
oddmuse-minor))
(add-to-list 'minor-mode-alist
'(oddmuse-minor " [MINOR]"))
(defun oddmuse-format-command (command)
"Internal: Substitute oddmuse format flags according to `url',
`oddmuse-page-name', `summary', `oddmuse-username', `question',
`oddmuse-password', `oddmuse-revision'."
(let ((hatena "?"))
(dolist (pair '(("%w" . url)
("%t" . oddmuse-page-name)
("%s" . summary)
("%u" . oddmuse-username)
("%m" . oddmuse-minor)
("%p" . oddmuse-password)
("%q" . question)
("%o" . oddmuse-revision)
("%r" . regexp)
("%\\?" . hatena)))
(when (and (boundp (cdr pair)) (stringp (symbol-value (cdr pair))))
(setq command (replace-regexp-in-string (car pair)
(symbol-value (cdr pair))
command t t))))
command))
(defun oddmuse-read-wiki-and-pagename (&optional required default)
"Read an wikiname and a pagename of `oddmuse-wikis' with completion.
If provided, REQUIRED and DEFAULT are passed along to `oddmuse-read-pagename'."
(let ((wiki (completing-read "Wiki: " oddmuse-wikis nil t oddmuse-wiki)))
(list wiki (oddmuse-read-pagename wiki required default))))
;;;###autoload
(defun oddmuse-history (wiki pagename)
"Show a page's history on a wiki using `view-mode'.
WIKI is the name of the wiki as defined in `oddmuse-wikis',
PAGENAME is the pagename of the page you want the history of.
Use a prefix argument to force a reload of the page."
(interactive (oddmuse-read-wiki-and-pagename t oddmuse-page-name))
(let ((name (concat wiki ":" pagename " [history]")))
(if (and (get-buffer name)
(not current-prefix-arg))
(pop-to-buffer (get-buffer name))
(let* ((wiki-data (assoc wiki oddmuse-wikis))
(url (nth 1 wiki-data))
(oddmuse-page-name pagename)
(command (oddmuse-format-command oddmuse-history-command))
(coding (nth 2 wiki-data))
(buf (get-buffer-create name)))
(set-buffer buf)
(erase-buffer)
(let ((max-mini-window-height 1))
(shell-command command buf))
(pop-to-buffer buf)
(goto-address)
(view-mode)))))
;;;###autoload
(defun oddmuse-edit (wiki pagename)
"Edit a page on a wiki.
WIKI is the name of the wiki as defined in `oddmuse-wikis',
PAGENAME is the pagename of the page you want to edit.
Use a prefix argument to force a reload of the page."
(interactive (oddmuse-read-wiki-and-pagename))
(make-directory (concat oddmuse-directory "/" wiki) t)
(let ((name (concat wiki ":" pagename)))
(if (and (get-buffer name)
(not current-prefix-arg))
(pop-to-buffer (get-buffer name))
(let* ((wiki-data (assoc wiki oddmuse-wikis))
(url (nth 1 wiki-data))
(oddmuse-page-name pagename)
(command (oddmuse-format-command oddmuse-get-command))
(coding (nth 2 wiki-data))
(buf (find-file-noselect (concat oddmuse-directory "/" wiki "/"
pagename)))
(coding-system-for-read coding)
(coding-system-for-write coding))
;; don't use let for dynamically bound variable
(set-buffer buf)
(unless (equal name (buffer-name)) (rename-buffer name))
(erase-buffer)
(let ((max-mini-window-height 1))
(oddmuse-run "Loading" command buf))
(pop-to-buffer buf)
(oddmuse-mode)))))
(defalias 'oddmuse-go 'oddmuse-edit)
;;;###autoload
(defun oddmuse-new (wiki pagename)
"Create a new page on a wiki.
WIKI is the name of the wiki as defined in `oddmuse-wikis'.
The pagename begins with the current date."
(interactive
(list (completing-read "Wiki: " oddmuse-wikis nil t oddmuse-wiki)
(replace-regexp-in-string
" +" "_"
(read-from-minibuffer "Pagename: "
(format-time-string "%Y-%m-%d ")))))
(oddmuse-edit wiki pagename))
(autoload 'word-at-point "thingatpt")
;;;###autoload
(defun oddmuse-follow (arg)
"Figure out what page we need to visit
and call `oddmuse-edit' on it."
(interactive "P")
(let ((pagename (or (and arg (oddmuse-read-pagename oddmuse-wiki))
(oddmuse-pagename-at-point)
(oddmuse-read-pagename oddmuse-wiki))))
(oddmuse-edit (or oddmuse-wiki
(read-from-minibuffer "URL: "))
pagename)))
(defun oddmuse-current-free-link-contents ()
"Free link contents if the point is between [[ and ]]."
(save-excursion
(let* ((pos (point))
(start (search-backward "[[" nil t))
(end (search-forward "]]" nil t)))
(and start end (>= end pos)
(replace-regexp-in-string
" " "_"
(buffer-substring (+ start 2) (- end 2)))))))
(defun oddmuse-pagename-at-point ()
"Page name at point."
(let ((pagename (word-at-point)))
(or (oddmuse-current-free-link-contents)
(oddmuse-wikiname-p pagename))))
(defun oddmuse-wikiname-p (pagename)
"Whether PAGENAME is WikiName or not."
(when pagename
(let (case-fold-search)
(when (string-match (concat "^" oddmuse-link-pattern "$") pagename)
pagename))))
;; (oddmuse-wikiname-p nil)
;; (oddmuse-wikiname-p "WikiName")
;; (oddmuse-wikiname-p "not-wikiname")
;; (oddmuse-wikiname-p "notWikiName")
(defun oddmuse-run (mesg command buf &optional on-region expected-code)
"Print MESG and run COMMAND on the current buffer.
MESG should be appropriate for the following uses:
\"MESG...\"
\"MESG...done\"
\"MESG failed: REASON\"
Save outpout in BUF and report an appropriate error.
ON-REGION indicates whether the commands runs on the region
such as when posting, or whether it just runs by itself such
as when loading a page.
If ON-REGION is not nil, the command output is compared to
EXPECTED-CODE. The command is supposed to print the HTTP status
code on stdout, so usually we want to provide either 302 or 200
as EXPECTED-CODE."
(message "%s using %s..." mesg command)
(when (numberp expected-code)
(setq expected-code (number-to-string expected-code)))
;; If ON-REGION, the resulting HTTP CODE is found in BUF, so check
;; that, too.
(if (and (= 0 (if on-region
(shell-command-on-region (point-min) (point-max)
command buf)
(shell-command command buf)))
(or (not on-region)
(not expected-code)
(string= expected-code
(with-current-buffer buf
(buffer-string)))))
(message "%s...done" mesg)
(let ((err "Unknown error"))
(with-current-buffer buf
(when (re-search-forward "<h1>\\(.*?\\)\\.?</h1>" nil t)
(setq err (match-string 1))))
(error "Error %s: %s" mesg err))))
;;;###autoload
(defun oddmuse-post (summary)
"Post the current buffer to the current wiki.
The current wiki is taken from `oddmuse-wiki'."
(interactive "sSummary: ")
;; when using prefix or on a buffer that is not in oddmuse-mode
(when (or (not oddmuse-wiki) current-prefix-arg)
(set (make-local-variable 'oddmuse-wiki)
(completing-read "Wiki: " oddmuse-wikis nil t)))
(when (not oddmuse-page-name)
(set (make-local-variable 'oddmuse-page-name)
(read-from-minibuffer "Pagename: " (buffer-name))))
(let* ((list (assoc oddmuse-wiki oddmuse-wikis))
(url (nth 1 list))
(oddmuse-minor (if oddmuse-minor "on" "off"))
(coding (nth 2 list))
(coding-system-for-read coding)
(coding-system-for-write coding)
(question (nth 3 list))
(oddmuse-username (or (nth 4 list)
oddmuse-username))
(command (oddmuse-format-command oddmuse-post-command))
(buf (get-buffer-create " *oddmuse-response*"))
(text (buffer-string)))
(and buffer-file-name (basic-save-buffer))
(oddmuse-run "Posting" command buf t 302)))
;;;###autoload
(defun oddmuse-preview ()
"Preview the current buffer for the current wiki.
The current wiki is taken from `oddmuse-wiki'."
(interactive)
;; when using prefix or on a buffer that is not in oddmuse-mode
(when (or (not oddmuse-wiki) current-prefix-arg)
(set (make-local-variable 'oddmuse-wiki)
(completing-read "Wiki: " oddmuse-wikis nil t)))
(when (not oddmuse-page-name)
(set (make-local-variable 'oddmuse-page-name)
(read-from-minibuffer "Pagename: " (buffer-name))))
(let* ((list (assoc oddmuse-wiki oddmuse-wikis))
(url (nth 1 list))
(oddmuse-minor (if oddmuse-minor "on" "off"))
(coding (nth 2 list))
(coding-system-for-read coding)
(coding-system-for-write coding)
(question (nth 3 list))
(oddmuse-username (or (nth 4 list)
oddmuse-username))
(command (oddmuse-format-command oddmuse-preview-command))
(buf (get-buffer-create " *oddmuse-response*"))
(text (buffer-string)))
(and buffer-file-name (basic-save-buffer))
(oddmuse-run "Previewing" command buf t); no status code on stdout
(message "Rendering...")
(pop-to-buffer "*Preview*")
(erase-buffer)
(shr-insert-document
(with-current-buffer (get-buffer " *oddmuse-response*")
(let ((html (libxml-parse-html-region (point-min) (point-max))))
(oddmuse-find-node
(lambda (node)
(and (eq (xml-node-name node) 'div)
(string= (xml-get-attribute node 'class) "preview")))
html))))
(goto-char (point-min))
(message "Rendering...done")))
(defun oddmuse-find-node (test node)
"Return the child of NODE that satisfies TEST.
TEST is a function that takes a node as an argument. NODE is a
node as returned by `libxml-parse-html-region' or
`xml-parse-region'. The function recurses through the node tree."
(if (funcall test node)
node
(dolist (child (xml-node-children node))
(when (listp child)
(let ((result (oddmuse-find-node test child)))
(when result
(return result)))))))
(defun oddmuse-make-completion-table (wiki)
"Create pagename completion table for WIKI.
If available, return precomputed one."
(or (gethash wiki oddmuse-pages-hash)
(oddmuse-compute-pagename-completion-table wiki)))
(defun oddmuse-compute-pagename-completion-table (&optional wiki-arg)
"Really fetch the list of pagenames from WIKI.
This command is used to reflect new pages to `oddmuse-pages-hash'."
(interactive)
(let* ((wiki (or wiki-arg
(completing-read "Wiki: " oddmuse-wikis nil t oddmuse-wiki)))
(url (cadr (assoc wiki oddmuse-wikis)))
(command (oddmuse-format-command oddmuse-index-get-command))
table)
(message "Getting index of all pages...")
(prog1
(setq table (split-string (shell-command-to-string command)))
(puthash wiki table oddmuse-pages-hash)
(message "Getting index of all pages...done"))))
(defun oddmuse-read-pagename (wiki &optional require default)
"Read a pagename of WIKI with completion.
Optional arguments REQUIRE and DEFAULT are passed on to `completing-read'.
Typically you would use t and a `oddmuse-page-name', if that makes sense."
(completing-read (if default
(concat "Pagename [" default "]: ")
"Pagename: ")
(oddmuse-make-completion-table wiki)
nil require nil nil default))
;;;###autoload
(defun oddmuse-rc (&optional include-minor-edits)
"Show Recent Changes.
With universal argument, reload."
(interactive "P")
(let* ((wiki (or oddmuse-wiki
(completing-read "Wiki: " oddmuse-wikis nil t)))
(name (concat "*" wiki " RC*")))
(if (and (get-buffer name)
(not current-prefix-arg))
(pop-to-buffer (get-buffer name))
(let* ((wiki-data (assoc wiki oddmuse-wikis))
(url (nth 1 wiki-data))
(command (oddmuse-format-command oddmuse-rc-command))
(coding (nth 2 wiki-data))
(buf (get-buffer-create name))
(coding-system-for-read coding)
(coding-system-for-write coding))
(set-buffer buf)
(unless (equal name (buffer-name)) (rename-buffer name))
(erase-buffer)
(let ((max-mini-window-height 1))
(oddmuse-run "Load recent changes" command buf))
(oddmuse-rc-buffer)
(set (make-local-variable 'oddmuse-wiki) wiki)))))
(defun oddmuse-rc-buffer ()
"Parse current buffer as RSS 3.0 and display it correctly."
(let (result)
(dolist (item (cdr (split-string (buffer-string) "\n\n")));; skip first item
(let ((data (mapcar (lambda (line)
(when (string-match "^\\(.*?\\): \\(.*\\)" line)
(cons (match-string 1 line)
(match-string 2 line))))
(split-string item "\n"))))
(setq result (cons data result))))
(erase-buffer)
(dolist (item (nreverse result))
(insert "[[" (cdr (assoc "title" item)) "]] "
(cdr (assoc "generator" item)) "\n"))
(goto-char (point-min))
(oddmuse-mode)))
;;;###autoload
(defun oddmuse-revert ()
"Revert this oddmuse page."
(interactive)
(let ((current-prefix-arg 4))
(oddmuse-edit oddmuse-wiki oddmuse-page-name)))
;;;###autoload
(defun oddmuse-insert-pagename (pagename)
"Insert a PAGENAME of current wiki with completion."
(interactive (list (oddmuse-read-pagename oddmuse-wiki)))
(insert pagename))
;;;###autoload
(defun emacswiki-post (&optional pagename summary)
"Post the current buffer to the EmacsWiki.
If this command is invoked interactively: with prefix argument,
prompts for pagename, otherwise set pagename as basename of
`buffer-file-name'.
This command is intended to post current EmacsLisp program easily."
(interactive)
(let* ((oddmuse-wiki "EmacsWiki")
(oddmuse-page-name (or pagename
(and (not current-prefix-arg)
buffer-file-name
(file-name-nondirectory buffer-file-name))
(oddmuse-read-pagename oddmuse-wiki)))
(summary (or summary (read-string "Summary: "))))
(oddmuse-post summary)))
(defun oddmuse-url (wiki pagename)
"Get the URL of oddmuse wiki."
(condition-case v
(concat (or (cadr (assoc wiki oddmuse-wikis)) (error)) "/" pagename)
(error nil)))
;;;###autoload
(defun oddmuse-browse-page (wiki pagename)
"Ask a WWW browser to load an Oddmuse page.
WIKI is the name of the wiki as defined in `oddmuse-wikis',
PAGENAME is the pagename of the page you want to browse."
(interactive (oddmuse-read-wiki-and-pagename))
(browse-url (oddmuse-url wiki pagename)))
;;;###autoload
(defun oddmuse-browse-this-page ()
"Ask a WWW browser to load current oddmuse page."
(interactive)
(oddmuse-browse-page oddmuse-wiki oddmuse-page-name))
;;;###autoload
(defun oddmuse-kill-url ()
"Make the URL of current oddmuse page the latest kill in the kill ring."
(interactive)
(kill-new (oddmuse-url oddmuse-wiki oddmuse-page-name)))
(provide 'oddmuse)
;;; oddmuse-curl.el ends here

View File

@@ -1,5 +0,0 @@
current.pl
FDL
GPL
*.tar.gz
*.tar.gz.sig

51
contrib/twitter Normal file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/perl
# Copyright (C) 2009, 2012 Alex Schroeder <alex@gnu.org>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
use CGI qw/:standard/;
use CGI::Carp qw(fatalsToBrowser);
use LWP::UserAgent;
use XML::RSS;
if (not param('feed')) {
print header(),
start_html('Description Stripping'),
h1('Description Stripping'),
p('Removes the description of an article if it matches the title. This is most useful for Twitter and other microblogging services.'),
p('Example input:', code('http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=kensanata')),
start_form(-method=>'GET'),
p('Feed: ', textfield('feed', '', 40), checkbox('Strip username'),
submit()),
end_form(),
end_html();
exit;
}
$ua = LWP::UserAgent->new;
$request = HTTP::Request->new('GET', param('feed'));
$response = $ua->request($request);
$data = $response->content;
exit unless $data;
print header(-type=>$response->content_type);
$rss = new XML::RSS;
$rss->parse($data);
foreach my $i (@{$rss->{items}}) {
$i->{description} = undef if $i->{description} eq $i->{title};
$i->{title} =~ s/^.*?: // if param('Strip username');
}
print $rss->as_string;

187
contrib/vc-oddmuse.el Normal file
View File

@@ -0,0 +1,187 @@
;;; vc-oddmuse.el -- add VC support to oddmuse-curl
;;
;; Copyright (C) 2014 Alex Schroeder <alex@gnu.org>
;;
;; Latest version:
;; http://git.savannah.gnu.org/cgit/oddmuse.git/plain/contrib/vc-oddmuse.el
;; Discussion, feedback:
;; http://www.emacswiki.org/cgi-bin/wiki/OddmuseCurl
;;
;; This program is free software: you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by the Free
;; Software Foundation, either version 3 of the License, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
;; more details.
;;
;; You should have received a copy of the GNU General Public License along
;; with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; Add the following to your init file:
;;
;; (add-to-list 'vc-handled-backends 'oddmuse)
(add-to-list 'vc-handled-backends 'oddmuse)
(require 'oddmuse)
(require 'diff)
(defun vc-oddmuse-revision-granularity () 'file)
(defun vc-oddmuse-registered (file)
"Handle files in `oddmuse-directory'."
(string-match (concat "^" (expand-file-name oddmuse-directory))
(file-name-directory file)))
(defun vc-oddmuse-state (file)
"No idea."
'up-to-date)
(defun vc-oddmuse-working-revision (file)
"No idea")
(defun vc-oddmuse-checkout-model (files)
"No locking."
'implicit)
(defun vc-oddmuse-create-repo (file)
(error "You cannot create Oddmuse wikis using Emacs."))
(defun vc-oddmuse-register (files &optional rev comment)
"This always works.")
(defun vc-oddmuse-revert (file &optional contents-done)
"No idea"
nil)
(defvar vc-oddmuse-log-command
"curl --silent %w\"?action=rc;showedit=1;all=1;from=1;raw=1;match=%r\""
"Command to use for publishing index pages.
It must print the page to stdout.
%? '?' character
%w URL of the wiki as provided by `oddmuse-wikis'
%r Regular expression, URL encoded, of the pages to limit ourselves to.
This uses the free variable `regexp'.")
(defun vc-oddmuse-print-log (files buffer &optional shortlog
start-revision limit)
"Load complete recent changes for the files."
(let* ((wiki (or oddmuse-wiki
(completing-read "Wiki: " oddmuse-wikis nil t)))
(wiki-data (assoc wiki oddmuse-wikis))
(url (nth 1 wiki-data))
(regexp (concat
"^(" ;; Perl regular expression!
(mapconcat 'file-name-nondirectory files "|")
")$"))
(command (oddmuse-format-command vc-oddmuse-log-command))
(coding (nth 2 wiki-data))
(coding-system-for-read coding)
(coding-system-for-write coding)
(max-mini-window-height 1))
(oddmuse-run "Getting recent changes" command buffer nil))
;; Parse current buffer as RSS 3.0 and display it correctly.
(save-excursion
(with-current-buffer buffer
(let (result)
(dolist (item (cdr (split-string (buffer-string) "\n\n")));; skip first item
(let ((data (mapcar (lambda (line)
(when (string-match "^\\(.*?\\): \\(.*\\)" line)
(cons (match-string 1 line)
(match-string 2 line))))
(split-string item "\n"))))
(setq result (cons data result))))
(dolist (item (nreverse result))
(insert "title: " (cdr (assoc "title" item)) "\n"
"version: " (cdr (assoc "revision" item)) "\n"
"generator: " (cdr (assoc "generator" item)) "\n"
"timestamp: " (cdr (assoc "last-modified" item)) "\n\n"
" " (or (cdr (assoc "description" item)) ""))
(fill-paragraph)
(insert "\n\n"))
(goto-char (point-min))))))
(defun vc-oddmuse-log-outgoing ()
(error "This is not supported."))
(defun vc-oddmuse-log-incoming ()
(error "This is not supported."))
(defvar vc-oddmuse-get-revision-command
"curl --silent %w\"?action=browse;id=%t;revision=%o;raw=1\""
"Command to use to get older revisions of a page.
It must print the page to stdout.
%? '?' character
%w URL of the wiki as provided by `oddmuse-wikis'
%t Page title as provided by `oddmuse-page-name'
%o Revision to retrieve as provided by `oddmuse-revision'")
(defvar vc-oddmuse-get-history-command
"curl --silent %w\"?action=history;id=%t;raw=1\""
"Command to use to get the history of a page.
It must print the page to stdout.
%? '?' character
%w URL of the wiki as provided by `oddmuse-wikis'
%t Page title as provided by `oddmuse-page-name'")
(defun vc-oddmuse-diff (files &optional rev1 rev2 buffer)
"Report the differences for FILES."
(setq buffer (or buffer (get-buffer-create "*vc-diff*")))
(dolist (file files)
(setq oddmuse-page-name (file-name-nondirectory file)
oddmuse-wiki (or oddmuse-wiki
(file-name-nondirectory
(directory-file-name
(file-name-directory file)))))
(let* ((wiki-data (or (assoc oddmuse-wiki oddmuse-wikis)
(error "Cannot find data for wiki %s" oddmuse-wiki)))
(url (nth 1 wiki-data)))
(unless rev1
;; Since we don't know the most recent revision we have to fetch
;; it from the server every time.
(with-temp-buffer
(let ((max-mini-window-height 1))
(oddmuse-run "Determining latest revision"
(oddmuse-format-command vc-oddmuse-get-history-command)
(current-buffer) nil))
(if (re-search-forward "^revision: \\([0-9]+\\)$" nil t)
(setq rev1 (match-string 1))
(error "Cannot determine the latest revision from the page history"))))
(dolist (rev (list rev1 rev2))
(when (and rev
(not (file-readable-p (concat oddmuse-directory
"/" oddmuse-wiki "/"
oddmuse-page-name
".~" rev "~"))))
(let* ((oddmuse-revision rev)
(command (oddmuse-format-command vc-oddmuse-get-revision-command))
(coding (nth 2 wiki-data))
(filename (concat oddmuse-directory "/" oddmuse-wiki "/"
oddmuse-page-name ".~" rev "~"))
(coding-system-for-read coding)
(coding-system-for-write coding))
(with-temp-buffer
(let ((max-mini-window-height 1))
(oddmuse-run (concat "Downloading revision " rev)
command (current-buffer) nil))
(write-file filename)))))
(diff-no-select
(if rev1
(concat oddmuse-directory "/" oddmuse-wiki "/" oddmuse-page-name ".~" rev1 "~")
file)
(if rev2
(concat oddmuse-directory "/" oddmuse-wiki "/" oddmuse-page-name ".~" rev2 "~")
file)
nil
(vc-switches 'oddmuse 'diff)
buffer))))
(provide 'vc-oddmuse)

View File

@@ -1,15 +1,18 @@
@font-face {
font-family: 'Garamond';
font-style: normal;
font-weight: 400;
src: local('Garamond'), local('GaramondNo8'), local('EB Garamond'), local('EBGaramond'), url(https://themes.googleusercontent.com/static/fonts/ebgaramond/v4/kYZt1bJ8UsGAPRGnkXPeFdIh4imgI8P11RFo6YPCPC0.woff) format('woff');
}
body, rss {
font-family: Garamond, GaramondNo8, "Bookman Old Style", Cochin, Baskerville, serif;
font-family: Garamond, serif;
font-size: 16pt;
line-height: 20pt;
margin:1em 3em;
padding:0;
}
body.sans {
font-family: Franklin Gothic Book, Corbel, Arial, sans-serif;
}
/* headings: we can use larger sizes if we use a lighter color.
we cannot inherit the font-family because header and footer use a narrow font. */
@@ -149,9 +152,6 @@ div.refer {
line-height: 13pt;
}
div.refer a:first-child:before { content: "" }
div.refer a:before { content: "• " }
div.message {
background-color:#fee;
color:#000;
@@ -179,7 +179,6 @@ div.sister hr {
}
div.sister img {
border:none;
background-color:#ffe;
}
div.near, div.definition {
@@ -197,9 +196,6 @@ div.sidebar ul {
/* replacements, features */
del {
color: #666;
}
ins {
color: #b33;
text-decoration: none;
@@ -232,6 +228,12 @@ div.commentshown {
p.comment {
margin-bottom: 0;
}
div.comment {
font-size: 14pt;
}
div.comment h2 {
margin-top: 5em;
}
/* comment pages with username, homepage, and email subscription */
.comment span { display: block; }
.comment span label { display: inline-block; width: 10em; }
@@ -336,6 +338,7 @@ div.image span.caption {
.left { float:left; margin-right: 1em; }
.right { float:right; margin-left: 1em; }
.half a img { height: 50%; width: 50%; }
div.left .left, div.right .right {
float:none;
}
@@ -383,78 +386,78 @@ div.left p + p { display:table-caption; caption-side:bottom; }
p.table a { float:left; width:20ex; }
p.table + p { clear:both; }
/* no bleeding
@media screen {
/* no bleeding */
div.content, div.rc {
overflow:hidden;
}
}
} */
@media print {
body {
font-size: 12pt;
line-height: 13pt;
color: #000;
background-color: #fff;
}
font-size: 12pt;
line-height: 13pt;
color: #000;
background-color: #fff;
}
/* hide all the crap */
div.diff, div.diff+hr, div.refer, div.near, div.definition, div.sister,
div.cal, div.footer, span.specialdays, span.gotobar, a.edit, a.number span,
div.rc form, form.tiny, p.comment {
display:none;
div.rc form, form.tiny, p.comment, p#plus1, div.g-plusone {
display:none;
}
a,
a:visited,
div.content a.near:link,
div.content a.near:visited,
div.content a.near:active {
color:inherit;
font-weight: bold;
color:inherit;
font-weight: bold;
}
div.content a.feed {
display: none;
display: none;
}
div.content a.book,
div.content a.movie {
text-decoration: none;
text-decoration: none;
}
a cite {
font-style: italic;
font-style: italic;
}
/* no difference */
pre, code, tt {
font-size: inherit;
line-height: inherit;
font-size: inherit;
line-height: inherit;
}
/* no dotted underlines */
acronym, abbr {
border: none;
text-decoration: none;
border: none;
text-decoration: none;
}
/* headings */
h1 {
color: inherit;
margin-top: 2em;
}
h2 {
color:inherit;
margin: 1em 0;
font-variant: small-caps;
}
h3 {
font-weight:inherit;
font-style:italic;
color:inherit;
margin: 1em 0;
}
h1 a, h2 a, h3 a {
color: inherit;
}
div.journal h1 a:visited,
div.journal h2 a:visited,
div.journal h3 a:visited {
color: inherit;
color: inherit;
margin-top: 2em;
}
h2 {
color:inherit;
margin: 1em 0;
font-variant: small-caps;
}
h3 {
font-weight:inherit;
font-style:italic;
color:inherit;
margin: 1em 0;
}
h1 a, h2 a, h3 a {
color: inherit;
}
div.journal h1 a:visited,
div.journal h2 a:visited,
div.journal h3 a:visited {
color: inherit;
}
}

View File

@@ -108,6 +108,35 @@ a:active {
color:#a41;
background-color: inherit;
}
.button {
display: inline-block;
font-size: 150%;
cursor: pointer;
padding: 0.3em 0.5em;
text-shadow: 0px -1px 0px #ccc;
background-color: #cfa;
border: 1px solid #9d8;
border-radius: 5px;
box-shadow: 0px 1px 3px white inset,
0px 1px 3px black;
}
.button a {
text-decoration: none;
font-weight: normal;
}
/* table of contents */
.toc {
font-size: smaller;
border-left: 1em solid #886;
}
.toc ol {
list-style-type: none;
padding-left: 1em;
}
.toc a {
font-weight: normal;
}
/* images with links, captions, etc */
div.image { display: inline; margin: 1em; font-size: 90%; text-align: center; }
@@ -179,7 +208,7 @@ div.rc hr { display: none; }
/* Tables */
table.user {
margin: 1em 4em;
margin: 1em 0;
padding: 0 1em;
border-top: 1px solid black;
border-bottom: 1px solid black;

View File

@@ -237,9 +237,6 @@ a.near:link {
a.near:visited {
color:#550;
}
a.tag:before {
content:"\2601\ ";
}
ol, ul, dl {
padding-top:0.5em;
}
@@ -249,7 +246,7 @@ dd, li {
/* elisp files and other scripts for download */
p.download a {
p.download a, a.download {
padding: 0.5em;
color: black;
text-decoration: none;

213
css/oddmuse-2013.css Normal file
View File

@@ -0,0 +1,213 @@
@font-face {
font-family: 'Gentium Basic';
font-style: normal;
font-weight: 400;
src: local('Gentium Basic'), local('GentiumBasic'), url(http://themes.googleusercontent.com/static/fonts/gentiumbasic/v5/KCktj43blvLkhOTolFn-MVhr3SzZVY8L1R-AhaesIwA.woff) format('woff');
}
@font-face {
font-family: 'Gentium Basic';
font-style: normal;
font-weight: 700;
src: local('Gentium Basic Bold'), local('GentiumBasic-Bold'), url(http://themes.googleusercontent.com/static/fonts/gentiumbasic/v5/2qL6yulgGf0wwgOp-UqGyKuvVGpDTHxx0YlM6XbRIFE.woff) format('woff');
}
@font-face {
font-family: 'Gentium Basic';
font-style: italic;
font-weight: 400;
src: local('Gentium Basic Italic'), local('GentiumBasic-Italic'), url(http://themes.googleusercontent.com/static/fonts/gentiumbasic/v5/qoFz4NSMaYC2UmsMAG3lyajIwExuvJl80GezUi4i-sM.woff) format('woff');
}
@font-face {
font-family: 'Gentium Basic';
font-style: italic;
font-weight: 700;
src: local('Gentium Basic Bold Italic'), local('GentiumBasic-BoldItalic'), url(http://themes.googleusercontent.com/static/fonts/gentiumbasic/v5/8N9-c_aQDJ8LbI1NGVMrwjBWbH-5CKom31QWlI8zOIM.woff) format('woff');
}
body {
background:#fff;
padding:2% 5%;
margin:0;
font-family: "Gentium Basic", "Bookman Old Style", "Times New Roman", serif;
font-size: 16pt;
}
div.header h1 {
margin-top:2ex;
}
a {
text-decoration: none;
color: #a00;
}
a:visited {
color: #d88;
}
div.header h1 a:hover, h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover,
a:hover, span.caption a.image:hover {
background:#fee;
}
img.logo {
float: right;
clear: right;
border-style:none;
background-color:#fff;
}
img {
padding: 0.5em;
margin: 0 1em;
}
a.image:hover {
background:inherit;
}
a.image:hover img {
background:#fee;
}
/* a.definition soll aussehen wie h2 */
h2, p a.definition {
display:block;
clear:both;
}
/* Such Link im h1 soll nicht auffallen. */
h1, h2, h3, h4, h1 a, h1 a:visited, p a.definition {
color:#666;
font-size: 30pt;
font-weight: normal;
margin: 4ex 0 1ex 0;
padding: 0;
border-bottom: 1px solid #000;
}
h3, h4 {
font-size: inherit;
}
div.diff {
padding: 1em 3em;
}
div.old {
background-color:#FFFFAF;
}
div.new {
background-color:#CFFFCF;
}
div.old p, div.new p {
padding: 0.5em 0;
}
div.refer { padding-left:5%; padding-right:5%; font-size:smaller; }
div[class="content refer"] p { margin-top:2em; }
div.content div.refer hr { display:none; }
div.content div.refer { padding:0; font-size:medium; }
div.content div.refer p { margin:0; }
div.refer a { display:block; }
table.history { border-style:none; }
td.history { border-style:none; }
table.user {
border-style: none;
margin-left: 3em;
}
table.user tr td {
border-style: none;
padding:0.5ex 1ex;
}
dt {
font-weight:bold;
}
dd {
margin-bottom:1ex;
}
textarea {
width:100%;
height:80%;
font-size: 12pt;
}
textarea#summary { height: 3em; }
input {
font-size: 12pt;
}
div.image span.caption {
margin: 0 1em;
}
li img, img.smiley, .noborder img {
border:none;
padding:0;
margin:0;
background:#fff;
color:#000;
}
/* Google +1 */
a#plus1 img {
background-color: #fff;
padding: 0;
margin: 0;
border: none;
}
div.header img, div.footer img { border:0; padding:0; margin:0; }
.left { float:left; }
.right { float:right; }
div.left .left, div.right .right {
float:none;
}
.center { text-align:center; }
span.author {
color: #501;
}
span.bar a {
padding-right:1ex;
}
.rc .author {
color: #655;
}
.rc strong {
font-weight: normal;
color: inherit;
}
.rc li {
position:relative;
padding: 1ex 0;
}
hr {
border:none;
color:black;
background-color:#000;
height:2px;
margin-top:2ex;
}
div.footer hr {
height:4px;
margin: 2em 0 1ex 0;
}
pre {
padding: 0.5em;
margin-left: 1em;
margin-right: 2em;
white-space: pre;
overflow:hidden;
font-size: smaller;
}
div.footer hr {
clear:both;
}

View File

@@ -1 +0,0 @@
.DS_Store

0
modules/aawrapperdiv.pl Executable file → Normal file
View File

View File

@@ -12,7 +12,7 @@
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/anchors.pl">anchors.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Comments_on_Local_Anchor_Extension">Comments on Local Anchor Extension</a></p>';
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/anchors.pl">anchors.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Local_Anchor_Extension">Local Anchor Extension</a></p>';
push(@MyRules, \&AnchorsRule);

0
modules/antispam.pl Executable file → Normal file
View File

64
modules/askpage.pl Normal file
View File

@@ -0,0 +1,64 @@
# Copyright (C) 2014 Alex-Daniel Jakimenko <alex.jakimenko@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/askpage.pl">askpage.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Ask_Page_Extension">Ask Page Extension</a></p>';
use Fcntl qw(:DEFAULT :flock);
use vars qw($AskPage $QuestionPage $NewQuestion);
# Don't forget to set your $CommentsPattern to include both $AskPage and $QuestionPage
$AskPage = 'Ask';
$QuestionPage = 'Question_';
$NewQuestion = 'Write your question here:';
sub IncrementInFile {
my $filename = shift;
sysopen my $fh, $filename, O_RDWR|O_CREAT or die "can't open $filename: $!";
flock $fh, LOCK_EX or die "can't flock $filename: $!";
my $num = <$fh> || 1;
seek $fh, 0, 0 or die "can't rewind $filename: $!";
truncate $fh, 0 or die "can't truncate $filename: $!";
(print $fh $num+1, "\n") or die "can't write $filename: $!";
close $fh or die "can't close $filename: $!";
return $num;
}
*OldAskPageDoPost=*DoPost;
*DoPost=*NewAskPageDoPost;
sub NewAskPageDoPost {
my $id = FreeToNormal(shift);
if ($id eq $AskPage and not GetParam('text', undef)) {
my $currentId = IncrementInFile("$DataDir/curquestion");
$currentQuestion =~ s/[\s\n]//g;
return OldAskPageDoPost($QuestionPage . $currentQuestion, @_);
} else {
return OldAskPageDoPost($id, @_);
}
}
*OldAskPageGetCommentForm=*GetCommentForm;
*GetCommentForm=*NewAskPageGetCommentForm;
sub NewAskPageGetCommentForm {
my ($id, $rev, $comment) = @_;
$NewComment = $NewQuestion if $id eq $AskPage;
return OldAskPageGetCommentForm(@_);
}
*OldAskPageJournalSort=*JournalSort;
*JournalSort=NewAskPageJournalSort;
sub NewAskPageJournalSort {
return OldAskPageJournalSort() unless $a =~ m/^$QuestionPage\d+$/ and $b =~ m/^$QuestionPage\d+$/;
($b =~ m/$QuestionPage(\d+)/)[0] <=> ($a =~ m/$QuestionPage(\d+)/)[0];
}

View File

@@ -55,7 +55,7 @@ sub DoAtomIntrospection {
push(@types, @UploadTypes) if $UploadAllowed;
my $upload = '<accept>' . join(', ', @types) . '</accept>';
print <<EOT;
<?xml version="1.0" encoding='$HttpCharset'?>
<?xml version="1.0" encoding='UTF-8'?>
<service xmlns="http://purl.org/atom/app#">
<workspace title="Wiki" >
<collection title="$SiteName" href="$ScriptName/atom/wiki">
@@ -79,7 +79,7 @@ sub GetRcAtom {
my $historyPrefix = QuoteHtml($ScriptName) . "?action=history;id=";
my $limit = GetParam("rsslimit", 15); # Only take the first 15 entries
my $count = 0;
my $feed = qq{<?xml version="1.0" encoding="$HttpCharset"?>\n};
my $feed = qq{<?xml version="1.0" encoding="UTF-8"?>\n};
if ($RssStyleSheet =~ /\.(xslt?|xml)$/) {
$feed .= qq{<?xml-stylesheet type="text/xml" href="$RssStyleSheet" ?>\n};
} elsif ($RssStyleSheet) {

0
modules/backlinks.pl Executable file → Normal file
View File

View File

@@ -0,0 +1,175 @@
# Copyright (C) 2014 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2014 Aki Goto <tyatsumi@gmail.com>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
=head1 Balanced Page Directories
B<WARNING: This module is deprecated.> Oddmuse no longer disperses
page data files into 27 directories based on the first character of
the page name. The directories used to be "A" to "Z", and "other". If
you uses your wiki as a blog, all the pages starting with a date ended
up in "other". If your page names started with letters other than "A"
to "Z", all the pages ended up in "other". If you were using comment
pages, all your comment pages ended in "C". This module was intended
to create more subdirectories and spread them more evenly. This is no
longer necessary, as the typical filesystem's performance no longer
degrades with tens of thousands of files in a directory. I'm assuming
most Oddmuse hosts to use some form of GNU/Linux with ext3 or ext4
with dir_index option.
The remaining info for this module is all deprecated.
=over
The ext2 inode specification allows for over 100 trillion files to
reside in a single directory, however because of the current
linked-list directory implementation, only about 10-15 thousand files
can realistically be stored in a single directory. L<haversian-ga on
09 Dec 2002 22:56
PST|http://answers.google.com/answers/threadview?id=122241>
=back
CAUTION: When this extension is installed, your data structure I<must>
change. Make sure you have a backup of your data directory somewhere.
=head2 Finding the right directory
On the command line, finding the right subdirectory can be a problem.
Here's how to use md5sum. Note that the -n option to echo prevents the
trailing newline. Its inclusion would change the checksum.
echo -n HomePage | md5sum | cut -c 1-2
c1
echo -n ホームページ | md5sum | cut -c 1-2
10
=head2 $BalancedPageDirectoriesSize
If you have more than 2560000 pages (w00t!) you might want to set
$BalancedPageDirectoriesSize to 3. This will give you 16× more
directories, which should let you have 40960000 pages. Also, please
let us know about your wiki. :)
=head2 Migration
Once you install the code, reload any page. This should trigger
migration. No output is produced during migration. Migration is
triggered whenever a page file isn't found but a page is found at the
default old location. If, for example, $PageDir/c1/HomePage.pg doesn't
exist but $PageDir/h/HomePage.pg does, and the wiki can be locked, the
wiki is locked and migration is started.
=cut
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/balanced-page-directories.pl">balanced-page-directories.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Balanced_Page_Directories_Extension">Balanced Page Directories Extension</a>';
use Digest::MD5 qw(md5_hex);
use File::Find qw(finddepth);
use vars qw($BalancedPageDirectoriesSize);
$BalancedPageDirectoriesSize = 2;
*OldBalancedPageDirectoriesGetPageDirectory = *GetPageDirectory;
*GetPageDirectory = *NewBalancedPageDirectoriesGetPageDirectory;
sub NewBalancedPageDirectoriesGetPageDirectory {
my $id = shift;
utf8::encode($id);
return substr(md5_hex($id), 0, $BalancedPageDirectoriesSize);
}
*OldBalancedPageDirectoriesOpenPage = *OpenPage;
*OpenPage = *NewBalancedPageDirectoriesOpenPage;
sub NewBalancedPageDirectoriesOpenPage {
my $id = shift;
if (! -f GetPageFile($id)) {
BalancedPageDirectoriesMigrate($id);
}
return OldBalancedPageDirectoriesOpenPage($id, @_);
}
sub BalancedPageDirectoriesMigrate {
my $id = shift;
# This code is called if the page file does not exist. Perhaps we
# need to migrate? Check if the old page file exists. If it does
# not, there is no point in migration.
*GetPageDirectory = *OldBalancedPageDirectoriesGetPageDirectory;
if (not -f GetPageFile($id)) {
*GetPageDirectory = *NewBalancedPageDirectoriesGetPageDirectory;
return;
}
# Make sure we can change the data structure now.
RequestLockOrError();
# Now we know that we need to migrate. The list of pages is scanned
# using globbing.
SetParam('refresh', 1);
for $id (AllPagesList()) {
*GetPageDirectory = *OldBalancedPageDirectoriesGetPageDirectory;
my $page_from = GetPageFile($id);
my $keep_from = GetKeepDir($id);
my $lock_from = GetLockedPageFile($id);
my $joiner_from = $JoinerDir . '/' . GetPageDirectory($username) if $JoinerDir;
my $joiner_email_from = $JoinerEmailDir . '/' . GetPageDirectory($username) if $JoinerEmailDir;
my $referrer_from = $RefererDir . '/' . GetPageDirectory($id) if $RefererDir;
*GetPageDirectory = *NewBalancedPageDirectoriesGetPageDirectory;
my $page_to = GetPageFile($id);
my $keep_to = GetKeepDir($id);
my $lock_to = GetLockedPageFile($id);
my $joiner_to = $JoinerDir . '/' . GetPageDirectory($username) if $JoinerDir;
my $joiner_email_to = $JoinerEmailDir . '/' . GetPageDirectory($username) if $JoinerEmailDir;
my $referrer_to = $RefererDir . '/' . GetPageDirectory($id) if $RefererDir;
# no clobbering
if (! -f $page_to) {
CreatePageDir($PageDir, $id);
rename $page_from, $page_to || ReportError("Cannot rename $page_from");
}
if (-f $lock_from and ! -f $lock_to) {
rename $lock_from, $lock_to || ReportError("Cannot rename $lock_from");
}
if (-d $keep_from and ! -d $keep_to) {
CreateKeepDir($KeepDir, $id);
rename $keep_from, $keep_to || ReportError("Cannot rename $keep_from");
}
if ($joiner_from and -d $joiner_from and ! -d $joiner_to) {
CreatePageDir($JoinerDir, $id);
rename $joiner_from, $joiner_to || ReportError("Cannot rename $joiner_from");
}
if ($joiner_email_from and -d $joiner_email_from and ! -d $joiner_email_to) {
CreatePageDir($JoinerEmailDir, $id);
rename $joiner_email_from, $joiner_email_to || ReportError("Cannot rename $joiner_email_from");
}
if ($referrer_from and -d $referrer_from and ! -d $referrer_to) {
CreateRefererDir($RefererDir, $id);
rename $referrer_from, $referrer_to || ReportError("Cannot rename $referrer_from");
}
}
# Delete empty subdirectories. Actually, attempt to delete all the
# directories, depth first. It will simply fail for the non-empty
# directories. http://www.perlmonks.org/?node_id=520791
for my $parent ($PageDir, $KeepDir, $JoinerDir, $JoinerEmailDir, $RefererDir) {
next unless $parent;
finddepth(sub { rmdir $_ if -d }, $parent);
}
ReleaseLock();
}

157
modules/ban-contributors.pl Normal file
View File

@@ -0,0 +1,157 @@
# Copyright (C) 2013 Alex Schroeder <alex@gnu.org>
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
=head1 Ban Contributors Extension
This module adds "Ban contributors" to the administration page. If you
click on it, it will list all the recent contributors to the page
you've been looking at. Each contributor (IP or hostname) will be
compared to the list of regular expressions on the C<BannedHosts> page
(see C<$BannedHosts>). If the contributor is already banned, this is
mentioned. If the contributor is not banned, you'll see a button
allowing you to ban him or her immediately. If you click the button,
the IP or hostname will be added to the C<BannedHosts> page for you.
=cut
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/ban-contributors.pl">ban-contributors.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Ban_Contributors_Extension">Ban Contributors Extension</a></p>';
push(@MyAdminCode, \&BanMenu);
sub BanMenu {
my ($id, $menuref, $restref) = @_;
if ($id and UserIsAdmin()) {
push(@$menuref, ScriptLink('action=ban;id=' . UrlEncode($id),
T('Ban contributors')));
}
}
$Action{ban} = \&DoBanHosts;
sub IsItBanned {
my ($it, $regexps) = @_;
my $re = undef;
foreach my $regexp (@$regexps) {
eval { $re = qr/$regexp/i; };
if (defined($re) && $it =~ $re) {
return $it;
}
}
}
sub DoBanHosts {
my $id = shift;
my $content = GetParam('content', '');
my $host = GetParam('host', '');
if ($content) {
SetParam('text', GetPageContent($BannedContent)
. $content . " # " . CalcDay($Now) . " "
. NormalToFree($id) . "\n");
SetParam('summary', NormalToFree($id));
DoPost($BannedContent);
} elsif ($host) {
$host =~ s/\./\\./g;
SetParam('text', GetPageContent($BannedHosts)
. "^" . $host . " # " . CalcDay($Now) . " "
. NormalToFree($id) . "\n");
SetParam('summary', NormalToFree($id));
DoPost($BannedHosts);
} else {
ValidIdOrDie($id);
print GetHeader('', Ts('Ban Contributors to %s', NormalToFree($id)));
SetParam('rcidonly', $id);
SetParam('all', 1);
SetParam('showedit', 1);
my %contrib = ();
for my $line (GetRcLines()) {
$contrib{$line->[4]}->{$line->[5]} = 1 if $line->[4];
}
my @regexps = ();
foreach (split(/\n/, GetPageContent($BannedHosts))) {
if (/^\s*([^#]\S+)/) { # all lines except empty lines and comments, trim whitespace
push(@regexps, $1);
}
}
print '<div class="content ban">';
foreach (sort(keys %contrib)) {
my $name = $_;
delete $contrib{$_}{''};
$name .= " (" . join(", ", sort(keys(%{$contrib{$_}}))) . ")";
if (IsItBanned($_, \@regexps)) {
print $q->p(Ts("%s is banned", $name));
} else {
print GetFormStart(undef, 'get', 'ban'),
GetHiddenValue('action', 'ban'),
GetHiddenValue('id', $id),
GetHiddenValue('host', $_),
GetHiddenValue('recent_edit', 'on'),
$q->p($name, $q->submit(T('Ban!'))), $q->end_form();
}
}
}
PrintFooter();
}
=head2 Rollback
If you are an admin and rolled back a single page, this extension will
list the URLs your rollback removed (assuming that those URLs are part
of the spam) and it will allow you to provide a regular expression
that will be added to BannedHosts.
=cut
*OldBanContributorsWriteRcLog = *WriteRcLog;
*WriteRcLog = *NewBanContributorsWriteRcLog;
sub NewBanContributorsWriteRcLog {
my ($tag, $id, $to) = @_;
if ($tag eq '[[rollback]]' and $id and $to > 0
and $OpenPageName eq $id and UserIsAdmin()) {
# we currently have the clean page loaded, so we need to reload
# the spammed revision (there is a possible race condition here)
my ($old) = GetTextRevision($Page{revision}-1, 1);
my %urls = map {$_ => 1 } $old =~ /$UrlPattern/og;
# we open the file again to force a load of the despammed page
foreach my $url ($Page{text} =~ /$UrlPattern/og) {
delete($urls{$url});
}
# we also remove any candidates that are already banned
my @regexps = ();
foreach (split(/\n/, GetPageContent($BannedContent))) {
if (/^\s*([^#]\S+)/) { # all lines except empty lines and comments, trim whitespace
push(@regexps, $1);
}
}
foreach my $url (keys %urls) {
delete($urls{$url}) if IsItBanned($url, \@regexps);
}
if (keys %urls) {
print $q->p(Ts("These URLs were rolled back. Perhaps you want to add a regular expression to %s?",
GetPageLink($BannedContent)));
print $q->pre(join("\n", sort keys %urls));
print GetFormStart(undef, 'get', 'ban'),
GetHiddenValue('action', 'ban'),
GetHiddenValue('id', $id),
GetHiddenValue('recent_edit', 'on'),
$q->p($q->label({-for=>'content'}, T('Regular expression:')), " ",
$q->textfield(-name=>'content', -size=>30), " ",
$q->submit(T('Ban!'))),
$q->end_form();
};
print $q->p(T("Consider banning the hostname or IP number as well: "),
ScriptLink('action=ban;id=' . UrlEncode($id), T('Ban contributors')));
};
return OldBanContributorsWriteRcLog(@_);
}

View File

@@ -0,0 +1,37 @@
# Copyright (C) 2013 Alex Schroeder <alex@gnu.org>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
#
# This file must load before logbannedcontent.pl such that quick
# editors will be logged.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/ban-quick-editors.pl">ban-quick-editors.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Banning_Quick_Editors">Banning Quick Editors</a></p>';
*BanQuickOldUserIsBanned = *UserIsBanned;
*UserIsBanned = *BanQuickNewUserIsBanned;
sub BanQuickNewUserIsBanned {
my $rule = BanQuickOldUserIsBanned(@_);
if (not $rule
and $SurgeProtection # need surge protection
and GetParam('title')) {
my $name = GetParam('username', GetRemoteAddress());
my @entries = @{$RecentVisitors{$name}};
# $entry[0] is $Now after AddRecentVisitor
my $ts = $entries[1];
if ($Now - $ts < 5) {
return "fast editing spam bot";
}
}
return $rule;
}

84
modules/banned-regexps.pl Normal file
View File

@@ -0,0 +1,84 @@
# Copyright (C) 2012 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
package OddMuse;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/banned-regexps.pl">banned-regexps.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Banning_Regular_Expressions">Banning Regular Expressions</a></p>';
=h1 Compatibility
This extension works with logbannedcontent.pl.
=h1 Example content for the BannedRegexps page:
# This page lists regular expressions that prevent the saving of a page.
# The regexps are matched against any page or comment submitted.
# The format is simple: # comments to the end of the line. Empty lines are ignored.
# Everything else is a regular expression. If the regular expression is followed by
# a comment, this is used as the explanation when a user is denied editing. If the
# comment starts with a date, this date is not included in the explanation.
# The date could help us decide which regular expressions to delete in the future.
# In other words:
# ^\s*([^#]+?)\s*(#\s*(\d\d\d\d-\d\d-\d\d\s*)?(.*))?$
# Group 1 is the regular expression to use.
# Group 4 is the explanation to use.
порно # 2012-12-31 Russian porn
<a\s+href=["']?http # 2012-12-31 HTML anchor tags usually mean spam
\[url= # 2012-12-31 bbCode links usually mean spam
\s+https?:\S+[ .\r\n]*$ # 2012-12-31 ending with a link usually means spam
(?s)\s+https?:\S+.*\s+https?:\S+.*\s+https?:\S+.* # 2012-12-31 three naked links usually mean spam
=cut
use vars qw($BannedRegexps);
$BannedRegexps = 'BannedRegexps';
push(@MyInitVariables, sub {
$AdminPages{$BannedRegexps} = 1;
$LockOnCreation{$BannedRegexps} = 1;
$PlainTextPages{$BannedRegexps} = 1;
});
*RegexpOldBannedContent = *BannedContent;
*BannedContent = *RegexpNewBannedContent;
# the above also changes the mapping for the variable!
$BannedContent = $RegexpOldBannedContent;
sub RegexpNewBannedContent {
my $str = shift;
my $rule = RegexpOldBannedContent($str, @_);
if (not $rule) {
foreach (split(/\n/, GetPageContent($BannedRegexps))) {
next unless m/^\s*([^#]+?)\s*(#\s*(\d\d\d\d-\d\d-\d\d\s*)?(.*))?$/;
my ($regexp, $comment, $re) = ($1, $4, undef);
eval { $re = qr/$regexp/i; };
if (defined($re) && $str =~ $re) {
my $group1 = $1;
my $explanation = ($group1
? Tss('Regular expression "%1" matched "%2" on this page.', QuoteHtml($regexp), $group1)
: Ts('Regular expression "%s" matched on this page.', QuoteHtml($regexp)));
$rule = $explanation . ' '
. ($comment ? Ts('Reason: %s.', $comment) : T('Reason unknown.')) . ' '
. Ts('See %s for more information.', GetPageLink($BannedRegexps));
last;
}
}
}
LogWrite($rule) if $rule and $BannedFile;
return $rule if $rule;
return 0;
}

View File

@@ -1,22 +1,23 @@
# Copyright (C) 2007, 2008 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2007, 2008, 2013 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/bbcode.pl">bbcode.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/bbCode_Extension">bbCode Extension</a></p>';
push(@MyRules, \&bbCodeRule);
$RuleOrder{\&bbCodeRule} = 100; # must come after PortraitSupportRule
use vars qw($bbBlock);
my %bbTitle = qw(h1 1 h2 1 h3 1 h4 1 h5 1 h6 1);
@@ -37,6 +38,12 @@ sub bbCodeRule {
. qq{font-style: normal;"}); }
elsif ($tag eq 's' or $tag eq 'strike') {
return AddHtmlEnvironment('del'); }
elsif ($tag eq 'tt') {
return AddHtmlEnvironment('tt'); }
elsif ($tag eq 'sub') {
return AddHtmlEnvironment('sub'); }
elsif ($tag eq 'sup') {
return AddHtmlEnvironment('sup'); }
elsif ($tag eq 'color') {
return AddHtmlEnvironment('em', qq{style="color: $option; }
. qq{font-style: normal;"}); }
@@ -96,7 +103,8 @@ sub bbCodeRule {
%translate = qw{b b i i u em color em size em font span url a
quote blockquote h1 h1 h2 h2 h3 h3 h4 h4 h5 h5
h6 h6 center div left div right div list ul
s del strike del highlight strong};
s del strike del sub sub sup sup highlight strong
tt tt};
# closing a block level element closes all elements
if ($bbBlock eq $translate{$tag}) {
/\G([ \t]*\n)*/cg; # eat whitespace after closing block level element

0
modules/blockquote.pl Executable file → Normal file
View File

View File

@@ -18,6 +18,8 @@
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/canonical.pl">canonical.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Canonical_Names">Canonical Names</a></p>';
use utf8;
*OldCanonicalResolveId = *ResolveId;
*ResolveId = *NewCanonicalResolveId;
@@ -39,14 +41,9 @@ sub NewCanonicalResolveId {
# If the page AlexSchröder exists, [[alexschroder]] will link to it.
use utf8;
use Encode;
sub CanonicalName {
my $str = shift;
$DebugInfo .= ' ' . $str;
$str = decode('utf-8', $str);
$str =~ tr/äáàâëéèêïíìîöóòôüúùû/aaaaeeeeiiiioooouuuu/;
$str = lc($str);
$DebugInfo .= '->' . $str;
return $str;
}

0
modules/clustermap.pl Executable file → Normal file
View File

View File

@@ -29,25 +29,21 @@ sub DoConfig {
\$EditPass = "";
};
my $source = GetRaw('http://www.emacswiki.org/scripts/current');
foreach my $var qw($HomePage $MaxPost $HttpCharset $StyleSheet
$StyleSheetPage $NotFoundPg $NewText $NewComment
$EditAllowed $BannedHosts $BannedCanRead
$BannedContent $WikiLinks $FreeLinks $BracketText
$BracketWiki $NetworkFile $AllNetworkFiles
$PermanentAnchors $InterMap $NearMap
$RssInterwikiTranslate $SurgeProtection
$SurgeProtectionTime $SurgeProtectionViews
foreach my $var qw($HomePage $MaxPost $StyleSheet $StyleSheetPage $NotFoundPg
$NewText $NewComment $EditAllowed $BannedHosts
$BannedCanRead $BannedContent $WikiLinks $FreeLinks
$BracketText $BracketWiki $NetworkFile $AllNetworkFiles
$PermanentAnchors $InterMap $NearMap $RssInterwikiTranslate
$SurgeProtection $SurgeProtectionTime $SurgeProtectionViews
$DeletedPage $RCName @RcDays $RcDefault $KeepDays
$KeepMajor $SummaryHours $SummaryDefaultLength
$ShowEdits $UseLookup $RecentTop $RecentLink
$PageCluster $InterWikiMoniker $SiteDescription
$RssImageUrl $RssRights $RssExclude
$RssCacheHours $RssStyleSheet $UploadAllowed
@UploadTypes $EmbedWiki $FooterNote $EditNote
$TopLinkBar @UserGotoBarPages $UserGotoBar
$ValidatorLink $CommentsPrefix $HtmlHeaders
$IndentLimit $LanguageLimit $JournalLimit
$SisterSiteLogoUrl %SpecialDays %Smilies
$KeepMajor $SummaryHours $SummaryDefaultLength $ShowEdits
$UseLookup $RecentTop $RecentLink $PageCluster
$InterWikiMoniker $SiteDescription $RssImageUrl $RssRights
$RssExclude $RssCacheHours $RssStyleSheet $UploadAllowed
@UploadTypes $EmbedWiki $FooterNote $EditNote $TopLinkBar
@UserGotoBarPages $UserGotoBar $ValidatorLink
$CommentsPrefix $HtmlHeaders $IndentLimit $LanguageLimit
$JournalLimit $SisterSiteLogoUrl %SpecialDays %Smilies
%Languages) {
my $default = undef;
my $re = quotemeta($var);

View File

@@ -156,7 +156,7 @@ sub CreoleInit {
# $FullUrlPattern = "((?:$UrlProtocols:|/)$UrlChars+)";
# Permit page authors to link to other pages having semicolons in their names.
# my $LinkCharsSansZero = "-;,.()' _1-9A-Za-z\x80-\xff";
# my $LinkCharsSansZero = "-;,.()' _1-9A-Za-z\x{0080}-\x{fffd}";
# my $LinkChars = $LinkCharsSansZero.'0';
# $FreeLinkPattern = "([$LinkCharsSansZero]|[$LinkChars][$LinkChars]+)";
}
@@ -391,7 +391,7 @@ sub CreoleRule {
my $is_right_justified = $3;
# Now that we've retrieved all numbered matches, match another lookahead.
my $is_left_justified = m/\G(?=.*?[ \t]+\|)/;
my $is_left_justified = m/\G(?=[^\n|]*?[ \t]+\|)/;
my $attributes = $column_span == 1 ? '' : qq{colspan="$column_span"};
if ($is_left_justified and
@@ -623,8 +623,8 @@ sub CreoleRuleRecursive {
elsif (m/\G\s+/cg) {
$html .= ' ';
}
elsif ( m/\G([A-Za-z\x80-\xff]+([ \t]+[a-z\x80-\xff]+)*[ \t]+)/cg
or m/\G([A-Za-z\x80-\xff]+)/cg
elsif ( m/\G([A-Za-z\x{0080}-\x{fffd}]+([ \t]+[a-z\x{0080}-\x{fffd}]+)*[ \t]+)/cg
or m/\G([A-Za-z\x{0080}-\x{fffd}]+)/cg
or m/\G(\S)/cg) {
$html .= $1; # multiple words but do not match http://foo
}

0
modules/crossbar.pl Executable file → Normal file
View File

View File

@@ -1,20 +1,16 @@
# Copyright (C) 2006 Alex Schroeder <alex@emacswiki.org>
# Copyright (C) 2006-2013 Alex Schroeder <alex@gnu.org>
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/delete-all.pl">delete-all.pl</a></p>';
@@ -27,6 +23,7 @@ $DeleteAge = 172800; # 2*24*60*60
# All pages will be deleted after two days of inactivity!
sub NewDelPageDeletable {
return 1 if $Now - $Page{ts} > $DeleteAge;
return 1 if $Now - $Page{ts} > $DeleteAge
and not $LockOnCreation{$OpenPageName};
return OldDelPageDeletable(@_);
}

View File

@@ -91,14 +91,14 @@ sub DespamBannedContent {
foreach my $url (@urls) {
if ($url =~ /($regexp)/i) {
return Tss('Rule "%1" matched "%2" on this page.',
QuoteHtml($regexp), $url);
QuoteHtml($regexp), QuoteHtml($url));
}
}
}
# depends on strange-spam.pl!
foreach (@DespamStrangeRules) {
my $regexp = $_;
if ($str =~ /($regexp)/) {
if ($str =~ /($regexp)/i) {
my $match = $1;
$match =~ s/\n/ /g;
return Tss('Rule "%1" matched "%2" on this page.',

View File

@@ -1,21 +1,18 @@
# Copyright (C) 2006 Alex Schroeder <alex@emacswiki.org>
# Copyright (C) 2006, 2012 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
use File::Glob ':glob';
use vars qw($DraftDir);
$DraftDir = $DataDir."/draft"; # directory for drafts
@@ -70,15 +67,23 @@ sub DraftNewGetEditForm {
push(@MyMaintenance, \&DraftCleanup);
sub DraftFiles {
return map {
$_ = substr($_, length($DraftDir) + 1);
utf8::decode($_);
$_;
} bsd_glob("$DraftDir/*"), bsd_glob("$DraftDir/.*");
}
sub DraftCleanup {
print '<p>' . T('Draft Cleanup');
foreach my $draft (glob("$DraftDir/* $DraftDir/.*")) {
next if $draft =~ m!/\.\.?$!;
my $ts = (stat($draft))[9];
foreach my $draft (DraftFiles()) {
next if $draft eq '.' or $draft eq '..';
my $ts = (stat("$DraftDir/$draft"))[9];
if ($Now - $ts < 1209600) { # 14*24*60*60
print $q->br(), Tss("%1 was last modified %2 and was kept",
$draft, CalcTimeSince($Now - $ts));
} elsif (unlink($draft)) {
} elsif (unlink("$DraftDir/$draft")) {
print $q->br(), Tss("%1 was last modified %2 and was deleted",
$draft, CalcTimeSince($Now - $ts));
} else {

View File

@@ -0,0 +1,49 @@
# Copyright (C) 20072013 Alex Schroeder <alex@gnu.org>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/duckduckgo-search.pl">duckduckgo-search.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Use_DuckDuckGo_For_Searches">Use DuckDuckGo For Searches</a></p>';
use vars qw($DuckDuckGoSearchDomain);
$DuckDuckGoSearchDomain = undef;
$Action{search} = \&DoDuckDuckGoSearch;
push(@MyInitVariables, \&DuckDuckGoSearchInit);
sub DuckDuckGoSearchInit {
# If $ScriptName does not contain a hostname, this extension will
# have no effect. Domain regexp based on RFC 2396 section 3.2.2.
if (!$DuckDuckGoSearchDomain) {
my $alpha = '[a-zA-Z]';
my $alphanum = '[a-zA-Z0-9]';
my $alphanumdash = '[-a-zA-Z0-9]';
my $domainlabel = "$alphanum($alphanumdash*$alphanum)?";
my $toplabel = "$alpha($alphanumdash*$alphanum)?";
if ($ScriptName =~ m!^(https?://)?([^/]+\.)?($domainlabel\.$toplabel)\.?(:|/|\z)!) {
$DuckDuckGoSearchDomain = $3;
}
}
if ($DuckDuckGoSearchDomain
and GetParam('search', undef)
and not GetParam('action', undef)
and not GetParam('old', 0)) {
SetParam('action', 'search');
}
}
sub DoDuckDuckGoSearch {
my $search = UrlEncode(GetParam('search', undef));
print $q->redirect({-uri=>"https://www.duckduckgo.com/?q=$search+site%3A$DuckDuckGoSearchDomain"});
}

View File

@@ -1,20 +1,16 @@
# Copyright (C) 2005 Alex Schroeder <alex@emacswiki.org>
# Copyright (C) 2005-2013 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/dynamic-comments.pl">dynamic-comments.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Dynamic_Comments_Extension">Dynamic Comments Extension</a></p>';
@@ -36,29 +32,7 @@ function togglecomments (id) {
} unless $HtmlHeaders =~ /commenthidden/; # mod_perl?
}
sub SafeId {
my $id = shift;
my $regexp = "";
$regexp = "|\xc3[\x80-\x96\x98-\xb6\xb8-\xff]|[\xc4-\xca].|\xcb[\x00-\xbf]"
. "|\xcd[\xb0-\xbd\xbf-\xff]|[\xce-\xDF].|\xe0..|\xe1[\x00-\xbe]."
. "|\xe1\xbf[\x00-\xbf]|\xe2\x80[\x8c\x8d]"
if $HttpCharset eq 'UTF-8';
# Unicode Codepoint UTF-8 encoding
# [#xC0-#xD6] c3 80 - c3 96
# [#xD8-#xF6] c3 98 - c3 b6
# [#xF8-#x2FF] c3 b8 - cb bf
# [#x370-#x37D] cd b0 - cd bd
# [#x37F-#x1FFF] cd bf - e1 bf bf
# [#x200C-#x200D] e2 80 8c - e2 80 8d
# [#x2070-#x218F] e2 81 b0 - e2 86 8f -- FIXME \
# [#x2C00-#x2FEF] e2 b0 80 - e2 bf af -- FIXME |
# [#x3001-#xD7FF] e3 80 81 - ed 9f bf -- FIXME | these are missing
# [#xF900-#xFDCF] ef a4 80 - ef b7 8f -- FIXME | in the regexp above
# [#xFDF0-#xFFFD] ef b7 b0 - ef bf bd -- FIXME |
# [#x10000-#xEFFFF] f0 90 80 80 - f3 af bf bf -- FIXME /
$id = ":$id" unless $id =~ /^[:_A-Za-z]$regexp/;
return join('', $id =~ m/([-.:_A-Za-z0-9]$regexp)/g);
}
my $num = 0;
*DynamicCommentsOldGetPageLink = *GetPageLink;
*GetPageLink = *DynamicCommentsNewGetPageLink;
@@ -70,10 +44,10 @@ sub DynamicCommentsNewGetPageLink {
$title =~ s/_/ /g;
my $page = PageHtml($id);
if ($page) {
my $safe = SafeId($id);
return qq{<a href="javascript:togglecomments('$safe')">$title</a>}
my $anchor = "id" . $num++;
return qq{<a href="javascript:togglecomments('$anchor')">$title</a>}
. '</p>' # close p before opening div
. $q->div({-class=>commenthidden, -id=>$safe},
. $q->div({-class=>'commenthidden', -id=>$anchor},
$page,
$q->p(DynamicCommentsOldGetPageLink($id, T('Add Comment'))))
. '<p>'; # open an empty p that will be closed in PrintAllPages

57
modules/fix-encoding.pl Normal file
View File

@@ -0,0 +1,57 @@
# Copyright (C) 2012 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/fix-encoding.pl">fix-encoding.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Fix_Encoding">Fix Encoding</a></p>';
$Action{'fix-encoding'} = \&FixEncoding;
sub FixEncoding {
my $id = shift;
ValidIdOrDie($id);
RequestLockOrError();
OpenPage($id);
my $text = $Page{text};
utf8::decode($text);
Save($id, $text, T('Fix character encoding'), 1) if $text ne $Page{text};
ReleaseLock();
ReBrowsePage($id);
}
$Action{'fix-escaping'} = \&FixEscaping;
sub FixEscaping {
my $id = shift;
ValidIdOrDie($id);
RequestLockOrError();
OpenPage($id);
my $text = UnquoteHtml($Page{text});
Save($id, $text, T('Fix HTML escapes'), 1) if $text ne $Page{text};
ReleaseLock();
ReBrowsePage($id);
}
push(@MyAdminCode, \&FixEncodingMenu);
sub FixEncodingMenu {
my ($id, $menuref, $restref) = @_;
if ($id && GetParam('username')) {
push(@$menuref,
ScriptLink('action=fix-encoding;id=' . UrlEncode($id),
T('Fix character encoding')));
push(@$menuref,
ScriptLink('action=fix-escaping;id=' . UrlEncode($id),
T('Fix HTML escapes')));
}
}

106
modules/form_timeout.pl Normal file
View File

@@ -0,0 +1,106 @@
# form_timeout.pl - a form timeout based anti-spam module for Oddmuse
#
# Copyright (C) 2014 Aki Goto <tyatsumi@gmail.com>
#
# Original code is in PHP from http://textcaptcha.com/really
# by Rob Tuley <hello@rob.cx>. Used with permission.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p>form_timeout_token.pl</p>';
=head1 DESCRIPTION
This is an anti-spam module for Oddmuse using form timeout method.
Edit permission is timed out in specified duration (default is 30 minutes)
after viewing the edit form. When edit content is posted directly by a spam bot
without viewing the edit form, edit will be denied.
=head1 CONFIGURATION
$FormTimeoutSalt
Mandatory. Token hash salt. Specify arbitrary string.
Default = undef.
$FormTimeoutTimeout
The form timeout in seconds.
Default = 60 * 30 (30 minutes).
=cut
use vars qw($FormTimeoutSalt $FormTimeoutTimeout);
use Digest::MD5 qw(md5_hex);
$FormTimeoutSalt = undef;
$FormTimeoutTimeout = 60 * 30; # 30 minutes
push(@MyInitVariables, \&FormTimeoutInitVariables);
sub FormTimeoutInitVariables {
if (!defined($FormTimeoutSalt)) {
ReportError(T('Set $FormTimeoutSalt.'), '500 INTERNAL SERVER ERROR');
}
}
sub FormTimeoutGetHash {
my ($when) = @_;
return md5_hex($FormTimeoutSalt . $when);
}
sub FormTimeoutGetToken {
return $Now . '#' . FormTimeoutGetHash($Now);
}
sub FormTimeoutGetTime {
my ($token) = @_;
my ($when, $hash) = split /#/, $token;
my $valid_hash = FormTimeoutGetHash($when);
if ($hash ne $valid_hash) {
return '';
}
return $when;
}
sub FormTimeoutCheck {
my $token = GetParam('form_timeout_token', '');
my $when = FormTimeoutGetTime($token);
if ($when eq '' || $when < $Now - $FormTimeoutTimeout) {
return 0;
}
return 1;
}
*OldFormTimeoutGetFormStart = *GetFormStart;
*GetFormStart = *NewFormTimeoutGetFormStart;
sub NewFormTimeoutGetFormStart {
my ($ignore, $method, $class) = @_;
my $form = OldFormTimeoutGetFormStart($ignore, $method, $class);
my $token = FormTimeoutGetToken();
$form .= $q->input({-type=>'hidden', -name=>'form_timeout_token',
-value=>$token});
return $form;
}
*OldFormTimeoutDoEdit = *DoEdit;
*DoEdit = *NewFormTimeoutDoEdit;
sub NewFormTimeoutDoEdit {
my ($id, $newText, $preview) = @_;
if (!FormTimeoutCheck()) {
ReportError(T('Form Timeout'), '403 FORBIDDEN', undef,
$q->p(Ts('Editing not allowed: %s is read-only.', NormalToFree($id))));
}
OldFormTimeoutDoEdit($id, $newText, $preview);
}

60
modules/fractions.pl Normal file
View File

@@ -0,0 +1,60 @@
# Copyright (C) 2013 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/fractions.pl">fractions.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Fractions">Fractions</a></p>';
push(@MyRules, \&FractionsRule);
# usage: ^1/32
sub FractionsRule {
if (/\G\^([0-9]+)\/([0-9]+)/cg) {
if ($1 == 1 and $2 == 4) { return "\&#x00bc;"; }
elsif ($1 == 1 and $2 == 2) { return "\&#x00bd;"; }
elsif ($1 == 3 and $2 == 4) { return "\&#x00be;"; }
elsif ($1 == 1 and $2 == 7) { return "\&#x2150;"; }
elsif ($1 == 1 and $2 == 9) { return "\&#x2151;"; }
elsif ($1 == 1 and $2 == 10) { return "\&#x2152;"; }
elsif ($1 == 1 and $2 == 3) { return "\&#x2153;"; }
elsif ($1 == 2 and $2 == 3) { return "\&#x2154;"; }
elsif ($1 == 1 and $2 == 5) { return "\&#x2155;"; }
elsif ($1 == 2 and $2 == 5) { return "\&#x2156;"; }
elsif ($1 == 3 and $2 == 5) { return "\&#x2157;"; }
elsif ($1 == 4 and $2 == 5) { return "\&#x2158;"; }
elsif ($1 == 1 and $2 == 6) { return "\&#x2159;"; }
elsif ($1 == 5 and $2 == 6) { return "\&#x215a;"; }
elsif ($1 == 1 and $2 == 8) { return "\&#x215b;"; }
elsif ($1 == 3 and $2 == 8) { return "\&#x215c;"; }
elsif ($1 == 5 and $2 == 8) { return "\&#x215d;"; }
elsif ($1 == 7 and $2 == 8) { return "\&#x215e;"; }
else {
my $html;
# superscripts
for my $char (split(//, $1)) {
if ($char eq '1') { $html .= "\&#x00b9;"; }
elsif ($char eq '2') { $html .= "\&#x00b2;"; }
elsif ($char eq '3') { $html .= "\&#x00b3;"; }
else { $html .= "\&#x207$char;"; }
}
# fraction slash
$html .= '&#x2044;';
# subscripts
for my $char (split(//, $2)) {
$html .= "\&#x208$char;";
}
return $html;
}
}
return undef;
}

View File

@@ -133,23 +133,50 @@ sub GitNewDeletePage {
push(@MyMaintenance, \&GitCleanup);
$Action{git} = \&DoGitCleanup;
sub DoGitCleanup {
UserIsAdminOrError();
print GetHeader('', 'Git', '');
print $q->start_div({-class=>'content git'});
RequestLockOrError();
print $q->p(T('Main lock obtained.')), '<p>',
T('Cleaning up git repository');
GitCleanup();
ReleaseLock();
print $q->p(T('Main lock released.')), $q->end_div();
PrintFooter();
}
sub GitCleanup {
if (-d $GitRepo) {
print $q->p("Git cleanup starting");
AllPagesList();
# delete all the files including all the files starting with a dot
opendir(DIR, $GitRepo) or ReportError("cannot open directory $GitRepo: $!");
foreach my $file (readdir(DIR)) {
next if $file eq '.git' or $file eq '.' or $file eq '..';
unlink "$GitRepo/$file" or ReportError("cannot delete $GitRepo/$file: $!");
my $name = $file;
utf8::decode($name); # filenames are bytes
next if $file eq '.git' or $file eq '.' or $file eq '..' or $IndexHash{$name};
print $q->p("Deleting left over file $name");
unlink "$GitRepo/$file" or ReportError("cannot delete $GitRepo/$name: $!");
}
closedir DIR;
# write all the files again
foreach my $id (AllPagesList()) {
# write all the files again, just to be sure
print $q->p("Rewriting all the files, just to be sure");
foreach my $id (@IndexList) {
OpenPage($id);
WriteStringToFile("$GitRepo/$id", $Page{text});
}
# commit the new state
# run git!
chdir($GitRepo); # important for all the git commands that follow!
GitRun('commit', '--quiet', '-a', '-m', 'maintenance job',
"--author=Oddmuse <$GitMail>");
# add any new files
print $q->p("Adding new files, if any");
GitRun('add', '.');
# commit the new state
print $q->p("Committing changes, if any");
# try to protect against mysterious crashes
print $q->pre(`$GitBinary commit --quiet -a -m 'maintenance job' --author=Oddmuse <$GitMail>` . ' ');
print $q->p("Git done");
}
}

View File

@@ -50,7 +50,7 @@ sub NewGoogleCustomGetSearchLink {
sub NewGoogleCustomGetHeader {
my $html = OldGoogleCustomGetHeader(@_);
$form .= qq {
my $form = qq {
<!-- Google CSE Search Box Begins -->
<form class="tiny" action="http://www.google.com/cse" id="searchbox_004774160799092323420:6-ff2s0o6yi"><p>
<input type="hidden" name="cx" value="004774160799092323420:6-ff2s0o6yi" />

0
modules/hibernal.pl Executable file → Normal file
View File

0
modules/htmllinks.pl Executable file → Normal file
View File

View File

@@ -24,7 +24,7 @@ sub DoPrintableIndex {
print GetHeader('', T('Index'), '');
my @pages = PrintableIndexPages();
my %hash;
map { push(@{$hash{GetPageDirectory($_)}}, $_); } @pages;
map { push(@{$hash{substr($_,0,1)}}, $_); } @pages;
print '<div class="content printable index">';
print $q->p($q->a({-name=>"top"}),
map { $q->a({-href=>"#$_"}, $_); } sort keys %hash);

1131
modules/joiner.pl Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,7 @@
# img.InlineMath
# img.DisplayMath
use File::Glob ':glob';
use vars qw($LatexDir $LatexLinkDir $LatexExtendPath $LatexSingleDollars);
# One of the following options must be set correctly to the full path of
@@ -172,7 +173,7 @@ sub MakeLaTeX {
#setup rendering directory
my $dir = "$LatexDir/$hash";
if (-d $dir) {
unlink (glob('$dir/*'));
unlink (bsd_glob('$dir/*'));
} else {
mkdir($dir) or return "[Unable to create $dir]";
}
@@ -220,5 +221,3 @@ sub MakeLaTeX {
rmdir ($dir);
return $result;
}

View File

@@ -22,7 +22,7 @@ push(@MyRules, \&LinkAllRule);
$RuleOrder{\&LinkAllRule} = 1000;
sub LinkAllRule {
if (/\G([A-Za-z\x80-\xff]+)/gc) {
if (/\G([A-Za-z\x{0080}-\x{fffd}]+)/gc) {
my $oldpos = pos;
Dirty($1);
# print the word, or the link to the word

View File

@@ -0,0 +1,63 @@
# Copyright (C) 2012 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/list-banned-content.pl">list-banned-content.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/BannedContent">Index Extension</a></p>';
$Action{'list-banned-content'} = \&DoListBannedContent;
sub DoListBannedContent {
print GetHeader('', T('Banned Content'), '');
my @pages = AllPagesList();
my %url_regexps;
my %text_regexps;
foreach (split(/\n/, GetPageContent($BannedContent))) {
next unless m/^\s*([^#]+?)\s*(#\s*(\d\d\d\d-\d\d-\d\d\s*)?(.*))?$/;
$url_regexps{qr($1)} = $4;
}
foreach (split(/\n/, GetPageContent($BannedRegexps))) {
next unless m/^\s*([^#]+?)\s*(#\s*(\d\d\d\d-\d\d-\d\d\s*)?(.*))?$/;
$text_regexps{qr($1)} = $4;
}
print '<div class="content banned"><p>';
print $BannedContent . ': ' . scalar(keys(%url_regexps)) . $q->br() . "\n";
print $BannedRegexps . ': ' . scalar(keys(%text_regexps)) . $q->br() . "\n";
PAGE: foreach my $id (@pages) {
OpenPage($id);
my @urls = $str =~ /$FullUrlPattern/go;
foreach my $url (@urls) {
foreach my $re (keys %url_regexps) {
if ($url =~ $re) {
print GetPageLink($id) . ': '
. Tss('Rule "%1" matched "%2" on this page.', $re, $url) . ' '
. ($url_regexps{$re}
? Ts('Reason: %s.', $url_regexps{$re})
: T('Reason unknown.')) . $q->br() . "\n";
next PAGE;
}
}
}
foreach my $re (keys %text_regexps) {
if ($Page{text} =~ $re) {
print GetPageLink($id) . ': '
. Tss('Rule "%1" matched on this page.', $re) . ' '
. ($text_regexps{$re}
? Ts('Reason: %s.', $text_regexps{$re})
: T('Reason unknown.')) . $q->br() . "\n";
next PAGE;
}
}
}
print '</p></div>';
PrintFooter();
}

View File

@@ -17,7 +17,7 @@ $ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git
$CookieParameters{interface} = '';
use vars qw($CurrentLanguage);
use vars qw($CurrentLanguage $LoadLanguageDir);
my %library= ('bg' => 'bulgarian-utf8.pl',
'de' => 'german-utf8.pl',
@@ -60,6 +60,7 @@ sub LoadLanguage {
foreach $_ (@prefs) {
last if $Lang{$_} eq 'en'; # the default
my $file = $library{$Lang{$_}};
$file = "$LoadLanguageDir/$file" if defined $LoadLanguageDir;
if (-r $file) {
do $file;
do "$ConfigFile-$Lang{$_}" if -r "$ConfigFile-$Lang{$_}";

View File

@@ -54,7 +54,7 @@ You can change this expiry time by setting C<$LnCacheHours>.
=cut
push (MyMaintenance, \&LnMaintenance);
push (@MyMaintenance, \&LnMaintenance);
sub LnMaintenance {
if (opendir(DIR, $RssDir)) { # cleanup if they should expire anyway

42
modules/logbannedcontent.pl Executable file → Normal file
View File

@@ -20,25 +20,31 @@ use vars qw($BannedFile);
$BannedFile = "$DataDir/spammer.log" unless defined $BannedFile;
*OldBannedContent = *BannedContent;
*BannedContent = *LogBannedContent;
$BannedContent = $OldBannedContent; # copy variable
*LogOldBannedContent = *BannedContent;
*BannedContent = *LogNewBannedContent;
$BannedContent = $LogOldBannedContent; # copy variable
sub LogBannedContent {
sub LogNewBannedContent {
my $str = shift;
my $rule = OldBannedContent($str);
if ($rule) {
my $visitor = $ENV{'REMOTE_ADDR'};
($sec, $min, $hr, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
$year=$year+1900;
$mon += 1;
# Fix for 0's
$mon = sprintf("%02d", $mon);
$mday = sprintf("%02d", $mday);
$sec = sprintf("%02d", $sec);
$min = sprintf("%02d", $min);
$hr = sprintf("%02d", $hr);
AppendStringToFile($BannedFile, "$year/$mon/$mday\t$hr:$min:$sec\t$visitor: $OpenPageName - $rule\n");
}
my $rule = LogOldBannedContent($str);
LogWrite($rule) if $rule;
return $rule;
}
*LogOldUserIsBanned = *UserIsBanned;
*UserIsBanned = *LogNewUserIsBanned;
sub LogNewUserIsBanned {
my $str = shift;
my $rule = LogOldUserIsBanned($str);
LogWrite(Ts('Host or IP matched %s', $rule)) if $rule;
return $rule;
}
sub LogWrite {
my $rule = shift;
my $id = $OpenPageName || GetId();
AppendStringToFile($BannedFile,
join("\t", TimeToW3($Now), GetRemoteAddress(), $id, $rule)
. "\n");
}

View File

@@ -18,24 +18,81 @@
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/mac.pl">mac.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Mac">Mac</a></p>';
use Encode;
use Unicode::Normalize;
*OldAllPagesList = *AllPagesList;
*AllPagesList = *NewAllPagesList;
*OldMacAllPagesList = *AllPagesList;
*AllPagesList = *NewMacAllPagesList;
sub NewAllPagesList {
sub NewMacAllPagesList {
$refresh = GetParam('refresh', 0);
if ($IndexInit && !$refresh) {
return @IndexList;
}
OldAllPagesList(@_);
OldMacAllPagesList(@_);
my @new = ();
%IndexHash = ();
foreach my $id (@IndexList) {
$id = encode_utf8(NFC(decode_utf8($id)));
$id = NFC($id);
push(@new, $id);
$IndexHash{$id} = 1;
}
@IndexList = @new;
return @new;
}
*OldMacGrepFiltered = *GrepFiltered;
*GrepFiltered = *NewMacGrepFiltered;
sub NewMacGrepFiltered {
my @pages = OldMacGrepFiltered(@_);
foreach my $id (@pages) {
$id = NFC($id);
}
return @pages;
}
push(@MyInitVariables, \&MacFixEncoding);
sub MacFixEncoding {
# disable grep if searching for non-ascii stuff:
# $ mkdir /tmp/dir
# $ echo schroeder > /tmp/dir/schroeder
# $ echo schröder > /tmp/dir/schröder
# $ echo SCHRÖDER > /tmp/dir/SCHRÖDER-UP # don't use SCHRÖDER because of HFS
# $ grep -rli schröder /tmp/dir
# /tmp/dir/schröder
# $ grep -rli SCHRÖDER /tmp/dir
# /tmp/dir/schröder
#
# Why is grep not finding the upper case variant in the SCHRÖDER-UP
# file?
$UseGrep = 0 if GetParam('search', '') =~ /[x{0080}-\x{fffd}]/;
# the rest is only necessary if using namespaces.pl
return unless %Namespaces;
my %hash = ();
for my $key (keys %Namespaces) {
utf8::decode($key);
$key = NFC($key);
$hash{$key} = $NamespaceRoot . '/' . $key . '/';
}
%Namespaces = %hash;
%hash = ();
for my $key (keys %InterSite) {
utf8::decode($key);
$key = NFC($key);
$hash{$key} = $Namespaces{$key} if $Namespaces{$key};
}
%InterSite = %hash;
}
# for drafts.pl
*OldMacDraftFiles = *DraftFiles;
*DraftFiles = *NewMacDraftFiles;
sub NewMacDraftFiles {
return map { NFC($_) } OldMacDraftFiles(@_);
}

View File

@@ -102,7 +102,7 @@ sub MailIsSubscribed {
# open the DB file
require DB_File;
tie %h, "DB_File", $MailFile;
my %subscribers = map {$_=>1} split(/$FS/, $h{$id});
my %subscribers = map {$_=>1} split(/$FS/, UrlDecode($h{UrlEncode($id)}));
untie %h;
return $subscribers{$mail};
}
@@ -179,13 +179,13 @@ sub MailDeletePage {
my $id = shift;
require DB_File;
tie %h, "DB_File", $MailFile;
foreach my $mail (split(/$FS/, delete $h{$id})) {
my %subscriptions = map {$_=>1} split(/$FS/, $h{$mail});
foreach my $mail (split(/$FS/, UrlDecode(delete $h{UrlEncode($id)}))) {
my %subscriptions = map {$_=>1} split(/$FS/, UrlDecode($h{UrlEncode($mail)}));
delete $subscriptions{$id};
if (%subscriptions) {
$h{$mail} = join($FS, keys %subscriptions);
$h{UrlEncode($mail)} = UrlEncode(join($FS, keys %subscriptions));
} else {
delete $h{$mail};
delete $h{UrlEncode($mail)};
}
}
untie %h;
@@ -256,7 +256,7 @@ sub MailSubscription {
return unless $mail;
require DB_File;
tie %h, "DB_File", $MailFile;
my @result = split(/$FS/, $h{$mail});
my @result = split(/$FS/, UrlDecode($h{UrlEncode($mail)}));
untie %h;
return sort @result;
}
@@ -283,15 +283,16 @@ sub DoMailSubscriptionList {
'<ul>';
}
require DB_File;
tie %h, "DB_File", $MailFile;
foreach my $key (sort keys %h) {
my @values = sort split(/$FS/, $h{$key});
foreach my $encodedkey (sort keys %h) {
my @values = sort split(/$FS/, UrlDecode($h{$encodedkey}));
my $key = UrlDecode($encodedkey);
if ($raw) {
print join(' ', $key, @values) . "\n";
} else {
print $q->li(Ts('%s: ', MailLink($key, @values)),
join(' ', map { MailLink($_, $key) }
sort split(/$FS/, $h{$key})));
join(' ', map { MailLink($_, $key) } @values));
}
}
print '</ul></div>' unless $raw;
@@ -363,16 +364,16 @@ sub MailSubscribe {
require DB_File;
tie %h, "DB_File", $MailFile;
# add to the mail entry
my %subscriptions = map {$_=>1} split(/$FS/, $h{$mail});
my %subscriptions = map {$_=>1} split(/$FS/, UrlDecode($h{UrlEncode($mail)}));
for my $id (@pages) {
$subscriptions{$id} = 1;
}
$h{$mail} = join($FS, keys %subscriptions);
$h{UrlEncode($mail)} = UrlEncode(join($FS, keys %subscriptions));
# add to the page entries
for my $id (@pages) {
my %subscribers = map {$_=>1} split(/$FS/, $h{$id});
my %subscribers = map {$_=>1} split(/$FS/, UrlDecode($h{UrlEncode($id)}));
$subscribers{$mail} = 1;
$h{$id} = join($FS, keys %subscribers);
$h{UrlEncode($id)} = UrlEncode(join($FS, keys %subscribers));
}
untie %h;
# changes made will affect how pages look
@@ -420,53 +421,67 @@ sub MailUnsubscribe {
return unless $mail and @pages;
require DB_File;
tie %h, "DB_File", $MailFile;
my %subscriptions = map {$_=>1} split(/$FS/, $h{$mail});
my %subscriptions = map {$_=>1} split(/$FS/, UrlDecode($h{UrlEncode($mail)}));
foreach my $id (@pages) {
delete $subscriptions{$id};
# take care of reverse lookup
my %subscribers = map {$_=>1} split(/$FS/, $h{$id});
my %subscribers = map {$_=>1} split(/$FS/, UrlDecode($h{UrlEncode($id)}));
delete $subscribers{$mail};
if (%subscribers) {
$h{$id} = join($FS, keys %subscribers);
$h{UrlEncode($id)} = UrlEncode(join($FS, keys %subscribers));
} else {
delete $h{$id};
delete $h{UrlEncode($id)};
}
}
if (%subscriptions) {
$h{$mail} = join($FS, keys %subscriptions);
$h{UrlEncode($mail)} = UrlEncode(join($FS, keys %subscriptions));
} else {
delete $h{$mail} unless %subscriptions;
delete $h{UrlEncode($mail)} unless %subscriptions;
}
untie %h;
# changes made will affect how pages look
SetParam('sub', GetParam('sub', 0) + 1);
}
=head1 Sending Mail
=head1 Migrate
The actual sending of emails depends on setting the appropriate
options.
C<$MailServer>: This defaults to localhost. If you have Oddmuse
installed on a full server that includes an SMTP server such as
sendmail or postfix, you might get away with not setting any of the
variables.
C<$MailUser>: Chances are you will need to authenticate before you can
send an email via your mail server. Specify the name here.
C<$MailPassword>: Specify the password here.
C<$MailFrom>: Often mail servers know which email addresses they
serve. If somebody else tries to use them, they'll return an error
saying that "relaying is not allowed". If you are allowed to use the
mail server, use this option to set the appropriate sender address.
Example setup:
$MailServer = 'smtp.google.com';
$MailUser = 'kensanata';
$MailPassword = '*secret*';
$MailFrom = 'kensanata@gmail.com';
The mailmigrate action will migrate your subscription list from the
old format to the new format. This is necessary because these days
because the keys and values of the DB_File are URL encoded.
=cut
$Action{'migrate-subscriptions'} = \&DoMailMigration;
sub DoMailMigration {
UserIsAdminOrError();
print GetHeader('', T('Migrating Subscriptions')),
$q->start_div({-class=>'content mailmigrate'});
require DB_File;
tie %h, "DB_File", $MailFile;
my $found = 0;
foreach my $key (keys %h) {
if (index($key, '@') != -1) {
$found = 1;
last;
}
}
if (not $found) {
print $q->p(T('No non-migrated email addresses found, migration not necessary.'));
} else {
my %n;
foreach my $key (sort keys %h) {
my $value = $h{$key};
my @values = sort split(/$FS/, $value);
$n{UrlEncode($key)} = join($FS, map { UrlEncode($_) } @values);
}
%h = %n;
print $q->p(Ts('Migrated %s rows.', scalar(keys %n)));
}
print '</div>';
untie %h;
PrintFooter();
}

138
modules/markdown-rule.pl Normal file
View File

@@ -0,0 +1,138 @@
#! /usr/bin/perl
# Copyright (C) 2014 Alex Schroeder <alex@gnu.org>
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/markdown-rule.pl">markdown-rule.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Markdown_Rule_Extension">Markdown Rule Extension</a></p>';
push(@MyRules, \&MarkdownRule);
# Since we want this package to be a simple add-on, we try and avoid
# all conflicts by going *last*. The use of # for numbered lists by
# Usemod conflicts with the use of # for headings, for example.
$RuleOrder{\&MarkdownRule} = 200;
# http://daringfireball.net/projects/markdown/syntax
# https://help.github.com/articles/markdown-basics
# https://help.github.com/articles/github-flavored-markdown
sub MarkdownRule {
# atx headers
if ($bol and m~\G(\s*\n)*(#{1,6})[ \t]*~cg) {
my $header_depth = length($2);
return CloseHtmlEnvironments()
. AddHtmlEnvironment("h" . $header_depth);
}
# end atx header at a newline
elsif ((InElement('h1') or InElement('h2') or InElement('h3') or
InElement('h4') or InElement('h5') or InElement('h6'))
and m/\G\n/cg) {
return CloseHtmlEnvironments()
. AddHtmlEnvironment("p");
}
# setext headers
elsif ($bol and m/\G((\s*\n)*(.+?)[ \t]*\n(-+|=+)[ \t]*\n)/gc) {
return CloseHtmlEnvironments()
. (substr($4,0,1) eq '=' ? $q->h2($3) : $q->h3($3))
. AddHtmlEnvironment('p');
}
# > blockquote
# with continuation
elsif ($bol and m/\G&gt;/gc) {
return CloseHtmlEnvironments()
. AddHtmlEnvironment('blockquote');
}
# ***bold and italic***
elsif (not InElement('strong') and not InElement('em') and m/\G\*\*\*/cg) {
return AddHtmlEnvironment('em') . AddHtmlEnvironment('strong');
}
# **bold**
elsif (m/\G\*\*/cg) {
return AddOrCloseHtmlEnvironment('strong');
}
# *italic*
elsif (m/\G\*/cg) {
return AddOrCloseHtmlEnvironment('em');
}
# ~~strikethrough~~ (deleted)
elsif (m/\G~~/cg) {
return AddOrCloseHtmlEnvironment('del');
}
# - bullet list
elsif ($bol and m/\G(\s*\n)*-[ \t]*/cg
or InElement('li') and m/\G(\s*\n)+-[ \t]*/cg) {
return CloseHtmlEnvironment('li')
. OpenHtmlEnvironment('ul',1) . AddHtmlEnvironment('li');
}
# 1. numbered list
elsif ($bol and m/\G(\s*\n)*\d+\.[ \t]*/cg
or InElement('li') and m/\G(\s*\n)+\d+\.[ \t]*/cg) {
return CloseHtmlEnvironment('li')
. OpenHtmlEnvironment('ol',1) . AddHtmlEnvironment('li');
}
# beginning of a table
elsif ($bol and !InElement('table') and m/\G\|/cg) {
# warn pos . " beginning of a table";
return OpenHtmlEnvironment('table',1)
. AddHtmlEnvironment('tr')
. AddHtmlEnvironment('th');
}
# end of a row and beginning of a new row
elsif (InElement('table') and m/\G\|?\n\|/cg) {
# warn pos . " end of a row and beginning of a new row";
return CloseHtmlEnvironment('tr')
. AddHtmlEnvironment('tr')
. AddHtmlEnvironment('td');
}
# otherwise the table ends
elsif (InElement('table') and m/\G\|?(\n|$)/cg) {
# warn pos . " otherwise the table ends";
return CloseHtmlEnvironment('table')
. AddHtmlEnvironment('p');
}
# continuation of the first row
elsif (InElement('th') and m/\G\|/cg) {
# warn pos . " continuation of the first row";
return CloseHtmlEnvironment('th')
. AddHtmlEnvironment('th');
}
# continuation of other rows
elsif (InElement('td') and m/\G\|/cg) {
# warn pos . " continuation of other rows";
return CloseHtmlEnvironment('td')
. AddHtmlEnvironment('td');
}
# whitespace indentation = code
elsif ($bol and m/\G(\s*\n)*( .+)\n?/gc) {
my $str = substr($2, 4);
while (m/\G( .*)\n?/gc) {
$str .= "\n" . substr($1, 4);
}
return OpenHtmlEnvironment('pre',1) . $str; # always level 1
}
# ``` = code
elsif ($bol and m/\G```[ \t]*\n(.*?)\n```[ \t]*(\n|$)/gcs) {
return CloseHtmlEnvironments() . $q->pre($1)
. AddHtmlEnvironment("p");
}
# [an example](http://example.com/ "Title")
elsif (m/\G\[(.+?)\]\($FullUrlPattern(\s+"(.+?)")?\)/goc) {
my ($text, $url, $title) = ($1, $2, $4);
$url =~ /^($UrlProtocols)/;
my %params;
$params{-href} = $url;
$params{-class} = "url $1";
$params{-title} = $title if $title;
return $q->a(\%params, $text);
}
return undef;
}

View File

@@ -152,7 +152,7 @@ sub MarkdownQuoteHtml {
$html =~ s/&/&amp;/g;
$html =~ s/</&lt;/g;
# $html =~ s/>/&gt;/g;
$html =~ s/[\x00-\x08\x0b\x0c\x0e-\x1f]/ /g; # legal xml: #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
$html =~ s/[\x00-\x08\x0b\x0c\x0e-\x1f]/ /g; # legal xml: #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFD]
return $html;
}
@@ -198,8 +198,8 @@ sub MarkdownNearInit {
sub DoWikiWords {
my $text = shift;
my $WikiWord = '[A-Z]+[a-z\x80-\xff]+[A-Z][A-Za-z\x80-\xff]*';
my $FreeLinkPattern = "([-,.()' _0-9A-Za-z\x80-\xff]+)";
my $WikiWord = '[A-Z]+[a-z\x{0080}-\x{fffd}]+[A-Z][A-Za-z\x{0080}-\x{fffd}]*';
my $FreeLinkPattern = "([-,.()' _0-9A-Za-z\x{0080}-\x{fffd}]+)";
if ($FreeLinks) {
# FreeLinks
@@ -299,7 +299,7 @@ sub CreateWikiLink {
sub UnescapeWikiWords {
my $text = shift;
my $WikiWord = '[A-Z]+[a-z\x80-\xff]+[A-Z][A-Za-z\x80-\xff]*';
my $WikiWord = '[A-Z]+[a-z\x{0080}-\x{fffd}]+[A-Z][A-Za-z\x{0080}-\x{fffd}]*';
# Unescape escaped WikiWords
$text =~ s/\\($WikiWord)/$1/g;
@@ -379,7 +379,7 @@ sub NewEncodeCode {
$text = OldEncodeCode($text);
# Protect Wiki Words
my $WikiWord = '[A-Z]+[a-z\x80-\xff]+[A-Z][A-Za-z\x80-\xff]*';
my $WikiWord = '[A-Z]+[a-z\x{0080}-\x{fffd}]+[A-Z][A-Za-z\x{0080}-\x{fffd}]*';
$text =~ s!($WikiWord)!\\$1!gx;
return $text;
@@ -471,7 +471,7 @@ sub MarkdownAddComment {
sub NewDoAnchors {
my $text = shift;
my $WikiWord = '[A-Z]+[a-z\x80-\xff]+[A-Z][A-Za-z\x80-\xff]*';
my $WikiWord = '[A-Z]+[a-z\x{0080}-\x{fffd}]+[A-Z][A-Za-z\x{0080}-\x{fffd}]*';
return Markdown::_DoAnchors($text);
}

View File

@@ -80,9 +80,9 @@ $RuleOrder{\&MarkupRule} = 150;
%MarkupLines = ('>' => 'pre',
);
my $words = '([A-Za-z\x80-\xff][-%.,:;\'"!?0-9 A-Za-z\x80-\xff]*?)';
my $words = '([A-Za-z\x{0080}-\x{fffd}][-%.,:;\'"!?0-9 A-Za-z\x{0080}-\x{fffd}]*?)';
# zero-width look-ahead assertion to prevent km/h from counting
my $noword = '(?=[^-0-9A-Za-z\x80-\xff]|$)';
my $noword = '(?=[^-0-9A-Za-z\x{0080}-\x{fffd}]|$)';
my $markup_pairs_re = '';
my $markup_forced_pairs_re = '';
@@ -144,6 +144,8 @@ sub MarkupRule {
return CloseHtmlEnvironments()
. MarkupTag($MarkupLines{UnquoteHtml($tag)}, $str)
. AddHtmlEnvironment('p');
} elsif (%MarkupSingles and m/$markup_singles_re/gc) {
return $MarkupSingles{UnquoteHtml($1)};
} elsif (%MarkupForcedPairs and m/$markup_forced_pairs_re/gc) {
my $tag = $1;
my $start = $tag;
@@ -170,11 +172,9 @@ sub MarkupRule {
}
} elsif (%MarkupPairs and m/$markup_pairs_re/gc) {
return MarkupTag($MarkupPairs{UnquoteHtml($1)}, $2);
} elsif (%MarkupSingles and m/$markup_singles_re/gc) {
return $MarkupSingles{UnquoteHtml($1)};
} elsif ($MarkupPairs{'/'} and m|\G~/|gc) {
return '~/'; # fix ~/elisp/ example
} elsif ($MarkupPairs{'/'} and m|\G(/[-A-Za-z0-9\x80-\xff/]+/$words/)|gc) {
} elsif ($MarkupPairs{'/'} and m|\G(/[-A-Za-z0-9\x{0080}-\x{fffd}/]+/$words/)|gc) {
return $1; # fix /usr/share/lib/! example
}
# "foo

View File

@@ -1,17 +1,16 @@
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2012 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
=head1 Namespaces Extension
@@ -38,6 +37,7 @@ be changed using the C<$NamespacesSelf> option.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/namespaces.pl">namespaces.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Namespaces_Extension">Namespaces Extension</a></p>';
use File::Glob ':glob';
use vars qw($NamespacesMain $NamespacesSelf $NamespaceCurrent
$NamespaceRoot $NamespaceSlashing @NamespaceParameters
%Namespaces);
@@ -80,7 +80,8 @@ sub NamespacesInitVariables {
# Do this before changing the $DataDir and $ScriptName
if (!$Monolithic and $UsePathInfo) {
$Namespaces{$NamespacesMain} = $ScriptName . '/';
foreach my $name (glob("$DataDir/*")) {
foreach my $name (bsd_glob("$DataDir/*")) {
utf8::decode($name);
if (-d $name
and $name =~ m|/($InterSitePattern)$|
and $name ne $NamespacesMain
@@ -92,19 +93,21 @@ sub NamespacesInitVariables {
$NamespaceRoot = $ScriptName; # $ScriptName may be changed below
$NamespaceCurrent = '';
my $ns = GetParam('ns', '');
if (not $ns and $UsePathInfo) {
my $path_info = $q->path_info();
utf8::decode($path_info);
# make sure ordinary page names are not matched!
if ($path_info =~ m|^/($InterSitePattern)(/.*)?|
and ($2 or $q->keywords or NamespaceRequiredByParameter())) {
$ns = $1;
}
}
ReportError(Ts('%s is not a legal name for a namespace', $ns))
if $ns and $ns !~ m/^($InterSitePattern)$/;
if (($UsePathInfo
# make sure ordinary page names are not matched!
and $q->path_info() =~ m|^/($InterSitePattern)(/.*)?|
and ($1 ne $NamespacesMain)
and ($1 ne $NamespacesSelf)
and ($2 or $q->keywords or NamespaceRequiredByParameter()))
or
($ns =~ m/^($InterSitePattern)$/
and ($1 ne $NamespacesMain)
and ($1 ne $NamespacesSelf))) {
$NamespaceCurrent = $1;
if ($ns
and $ns ne $NamespacesMain
and $ns ne $NamespacesSelf) {
$NamespaceCurrent = $ns;
# Change some stuff from the original InitVariables call:
$SiteName .= ' ' . $NamespaceCurrent;
$InterWikiMoniker = $NamespaceCurrent;
@@ -115,7 +118,7 @@ sub NamespacesInitVariables {
$TempDir = "$DataDir/temp";
$LockDir = "$TempDir/lock";
$NoEditFile = "$DataDir/noedit";
$RcFile = "$DataDir/rc.log";
$RcFile = "$DataDir/rc.log";
$RcOldFile = "$DataDir/oldrc.log";
$IndexFile = "$DataDir/pageidx";
$VisitorFile = "$DataDir/visitors.log";
@@ -133,8 +136,8 @@ sub NamespacesInitVariables {
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks)
= stat($IndexFile);
$LastUpdate = $mtime;
CreateDir($DataDir); # Create directory if it doesn't exist
ReportError(Ts('Could not create %s', $DataDir) . ": $!", '500 INTERNAL SERVER ERROR')
CreateDir($DataDir); # Create directory if it doesn't exist
ReportError(Ts('Cannot create %s', $DataDir) . ": $!", '500 INTERNAL SERVER ERROR')
unless -d $DataDir;
}
$Namespaces{$NamespacesSelf} = $ScriptName . '?';
@@ -203,8 +206,8 @@ sub NewNamespaceGetRcLines { # starttime, hash of seen pages to use as a second
# directory. This reduces the chances of getting different
# results.
foreach my $site (keys %InterSite) {
if ($InterSite{$site} =~ m|^$ScriptName/([^/]*)|) {
my $ns = $1 or next;
if (substr($InterSite{$site}, 0, length($ScriptName)) eq $ScriptName) {
my $ns = $site;
my $file = "$DataDir/$ns/rc.log";
push(@rcfiles, $file);
$namespaces{$file} = $ns;
@@ -217,7 +220,7 @@ sub NewNamespaceGetRcLines { # starttime, hash of seen pages to use as a second
# starttime. If any rcfile exists with no timestamp before the
# starttime, we need to open its rcoldfile.
foreach my $file (@rcfiles) {
open(F, $file);
open(F, '<:encoding(UTF-8)', $file);
my $line = <F>;
my ($ts) = split(/$FS/o, $line); # the first timestamp in the regular rc file
my @new;
@@ -249,7 +252,7 @@ sub NewNamespaceGetRcLines { # starttime, hash of seen pages to use as a second
return LatestChanges(@result);
}
=head RSS feed
=head2 RSS feed
When retrieving the RSS feed with the parameter full=1, one would
expect the various items to contain the fully rendered HTML.
@@ -373,7 +376,7 @@ sub NewNamespaceBrowsePage {
#REDIRECT into different namespaces
my ($id, $raw, $comment, $status) = @_;
OpenPage($id);
my ($text, $revision) = GetTextRevision(GetParam('revision', ''));
my ($text, $revision) = GetTextRevision(GetParam('revision', ''), 1);
my $oldId = GetParam('oldid', '');
if (not $oldId and not $revision and (substr($text, 0, 10) eq '#REDIRECT ')
and (($WikiLinks and $text =~ /^\#REDIRECT\s+(($InterSitePattern:)?$InterLinkPattern)/)

View File

@@ -24,6 +24,8 @@
# If you are running a multilingual site, then you should explicitly
# load this file from your language-specific config file.
use utf8;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/national-days-de.pl">national-days-de.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Special_Days">Special Days</a></p>';
%SpecialDays = (
@@ -62,6 +64,7 @@ $ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git
'4-17' => 'Syrien: Abzug der letzten französischen Mandatstruppen 1946',
'4-18' => 'Simbabwe: Erlangung der Unabhängigkeit',
'4-19' => 'Jahrestag der Papstwahl (Benedikt XVI.)',
'4-25' => 'Italien: Tag der Befreiung 1945',
'4-26' => 'Tansania: Jahrestag der Vereinigung von Tanganjika und Sansibar 1964',
'4-27' => 'Afghanistan: Tag der Revolution, Sierra Leone: Erlangung der Unabhängigkeit 1961, Südafrika: Tag der ersten freien Wahlen 1994, Togo: Erlangung der Unabhängigkeit 1960',
'4-30' => 'Niederlande: Königinnentag',

View File

@@ -16,6 +16,8 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
use utf8;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/national-days.pl">national-days.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Special_Days">Special Days</a></p>';
%SpecialDays = (
@@ -49,6 +51,7 @@ $ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git
'4-17' => 'Syria, National Day',
'4-18' => 'Zimbabwe, National Day',
'4-19' => 'Sierra Leone, Republic Day',
'4-25' => 'Italy, Liberation Day',
'4-26' => 'Tanzania, Union Day, Israel, Independence Day',
'4-27' => 'Federal Republic of Yugoslavia, National Day, Togo, Togolais National Day, South Africa, Freedom Day',
'4-30' => 'The Netherlands, Official Birthday of Her Majesty Queen Beatrix',
@@ -64,7 +67,7 @@ $ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git
'5-26' => 'Georgia, National Day',
'5-28' => 'Ethiopia, National Day, Azerbaijan, National Day',
'6-1' => 'Samoa, Independence Day',
'6-2' => 'Italy, Foundation of the Republic',
'6-2' => 'Italy, Republic Day',
'6-4' => 'Tonga, Emancipation Day',
'6-6' => 'Sweden, National Day',
'6-10' => 'Portugal, Portugal Day, Camões Day and Day of Portuguese Communities',

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Alex Schroeder <alex@gnu.org>
# Copyright (C) 20032013 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -303,8 +303,12 @@ resolved to the same target (the local page), which is unexpected.
=cut
push(@IndexOptions, ['near', T('Include near pages'), 0,
\&ListNearPages]);
# IndexOptions must be set in MyInitVariables for translations to
# work.
push(@MyInitVariables, sub {
push(@IndexOptions, ['near', T('Include near pages'), 0,
\&ListNearPages]);
});
sub ListNearPages {
my %pages = %NearSource;

View File

@@ -18,6 +18,7 @@
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/not-found-handler.pl">not-found-handler.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/404_Handler_Extension">404 Handler Extension</a></p>';
use File::Glob ':glob';
use vars qw($NotFoundHandlerDir, $LinkFile, %LinkDb, $LinkDbInit);
$NotFoundHandlerDir = '/tmp/oddmuse/cache';
@@ -29,7 +30,7 @@ $Action{clearcache} = \&DoClearCache;
sub DoClearCache {
print GetHeader('', QuoteHtml(T('Clearing Cache')), '');
unlink(glob("$NotFoundHandlerDir/*"));
unlink(bsd_glob("$NotFoundHandlerDir/*"));
print $q->p(T('Done.'));
PrintFooter();
}
@@ -103,7 +104,7 @@ sub NewNotFoundHandlerSave {
NotFoundHandlerCacheUpdate($id);
} else {
# unlink PageName, PageName.en, PageName.de, etc.
unlink("$NotFoundHandlerDir/$id", glob("$NotFoundHandlerDir/$id.[a-z][a-z]"));
unlink("$NotFoundHandlerDir/$id", bsd_glob("$NotFoundHandlerDir/$id.[a-z][a-z]"));
}
}
@@ -128,7 +129,7 @@ sub NotFoundHandlerCacheUpdate {
foreach my $source (keys %LinkDb) {
warn "Examining $source\n";
if (grep(/$target/, @{$LinkDb{$source}})) {
unlink("$NotFoundHandlerDir/$source", glob("$NotFoundHandlerDir/$source.[a-z][a-z]"));
unlink("$NotFoundHandlerDir/$source", bsd_glob("$NotFoundHandlerDir/$source.[a-z][a-z]"));
warn "Unlinking $source\n";
}
}

View File

@@ -33,10 +33,10 @@ $Action{$SelfBan} = \&DoSelfBan;
sub DoSelfBan {
my $date = &TimeToText($Now);
my $str = '^' . quotemeta($ENV{REMOTE_ADDR});
my $str = '^' . quotemeta(GetRemoteAddress());
OpenPage($BannedHosts);
Save ($BannedHosts, $Page{text} . "\n\nself-ban on $date\n $str",
Ts("Self-ban by %s", $ENV{REMOTE_ADDR}), 1); # minor edit
Ts("Self-ban by %s", GetRemoteAddress()), 1); # minor edit
ReportError(T("You have banned your own IP."));
}
@@ -52,7 +52,7 @@ sub OpenProxyNewDoEdit {
sub BanOpenProxy {
my ($force) = @_;
my $ip = $ENV{REMOTE_ADDR};
my $ip = GetRemoteAddress();
my $limit = 60*60*24*30; # rescan after 30 days
# Only check each IP address once a month
my %proxy = split(/\s+/, ReadFile($OpenProxies));

0
modules/poetry.pl Executable file → Normal file
View File

158
modules/private-pages.pl Normal file
View File

@@ -0,0 +1,158 @@
# Copyright (C) 20122013 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
=head1 Private Pages Extension
This module allows you to hide the content of particular pages in Oddmuse.
Unlike the I<Hidden Pages Extension>, this is not based on the user's role of
editor or administrator. Instead, every page can have a different password by
beginning it with #PASSWORD XYZZY where XYZZY is the password required to read
it. Multiple passwords can be supplied, separated by spaces.
Note that all the meta information of the private page remains public: The
I<name> of the page, the fact that is has been edited, the author, the
revision, the content of past revisions that have not been protected by a
password all remain visible to other users.
Notes:
=over
=item * This extension might not work in a mod_perl environment because it
sets C<$NewText> without ever resetting it.
=item * If you're protecting a comment page, people can still leave comments
-- they just can't read the resulting page.
=back
=cut
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/private-pages.pl">private-pages.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Private_Pages_Extension">Private Pages Extension</a></p>';
sub PrivatePageLocked {
my $text = shift;
my ($line) = split(/\n/, $text, 1);
my @token = split(/\s+/, $line);
my $lock = 0;
if (shift(@token) eq '#PASSWORD') {
my $pwd = GetParam('pwd', '');
$lock = 1;
foreach (@token) {
if ($pwd eq $_) {
$lock = 0;
break;
}
}
}
return $lock;
}
*OldPrivatePagesUserCanEdit = *UserCanEdit;
*UserCanEdit = *NewPrivatePagesUserCanEdit;
sub NewPrivatePagesUserCanEdit {
my ($id, $editing, @rest) = @_;
my $result = OldPrivatePagesUserCanEdit($id, $editing, @rest);
# bypass OpenPage and GetPageContent (these are redefined below)
if ($result > 0 and $editing and $IndexHash{$id}) {
my %data = ParseData(ReadFileOrDie(GetPageFile($id)));
if (PrivatePageLocked($data{text})) {
return 0;
}
}
return $result;
}
sub PrivatePageMessage {
return Ts('This page is password protected. If you know the password, you can %s. Once you have done that, return and reload this page.',
'[' . ScriptUrl('action=password') . ' '
. T('supply the password now') . ']');
}
# prevent unauthorized reading
# If we leave $Page{revision}, PrintWikiToHTML will save the new
# PrivatePageMessage as the new page content. If we delete
# $Page{revision}, the text shown will be based on $NewText. If we
# have no $Page{ts} and no $Page{text}, PageDeletable will return 1.
# As a workaround, we set a timestamp. Aging of the page doesn't
# matter since the text starts with #PASSWORD and therefore cannot be
# the empty string or $DeletedPage.
*OldPrivatePagesOpenPage = *OpenPage;
*OpenPage = *NewPrivatePagesOpenPage;
sub NewPrivatePagesOpenPage {
OldPrivatePagesOpenPage(@_);
if (PrivatePageLocked($Page{text})) {
%Page = (); # reset everything
$Page{ts} = $Now;
$NewText = PrivatePageMessage();
}
return $OpenPageName;
}
# prevent reading of page content by other code
*OldPrivatePagesGetPageContent = *GetPageContent;
*GetPageContent = *NewPrivatePagesGetPageContent;
sub NewPrivatePagesGetPageContent {
my $text = OldPrivatePagesGetPageContent(@_);
if (PrivatePageLocked($text)) {
return PrivatePageMessage();
}
return $text;
}
# prevent reading of old revisions
*OldPrivatePagesGetTextRevision = *GetTextRevision;
*GetTextRevision = *NewPrivatePagesGetTextRevision;
sub NewPrivatePagesGetTextRevision {
my ($text, $revision) = OldPrivatePagesGetTextRevision(@_);
if (PrivatePageLocked($text)) {
return (PrivatePageMessage(), $revision);
}
return ($text, $revision);
}
# hide #PASSWORD
push(@MyRules, \&PrivatePageRule);
sub PrivatePageRule {
if (pos == 0 && m/\G#PASSWORD.*\n/gc) {
return '';
}
return undef;
}
# prevent leaking of edit summary
*OldPrivatePagesGetSummary = *GetSummary;
*GetSummary = *NewPrivatePagesGetSummary;
sub NewPrivatePagesGetSummary {
my $text = GetParam('text', '');
if ($text and $text =~ /^#PASSWORD\b/
# no text means aftertext is set (leaving a comment)
or $Page{text} =~ /^#PASSWORD\b/) {
# if no summary was set, set something in order to avoid the default
return '';
}
return OldPrivatePagesGetSummary();
}

View File

@@ -77,8 +77,9 @@ sub NewQuestionaskerDoPost {
or QuestionaskerException($id)) {
print GetHeader('', T('Edit Denied'), undef, undef, '403 FORBIDDEN');
print $q->p(T('You did not answer correctly.'));
print $q->start_form, QuestionaskerGetQuestion(1),
(map { $q->hidden($_, '') }
print GetFormStart(), QuestionaskerGetQuestion(1),
(map { $q->input({-type=>'hidden', -name=>$_,
-value=>UnquoteHtml(GetParam($_))}) }
qw(title text oldtime summary recent_edit aftertext)), $q->end_form;
PrintFooter();
# logging to the error log file of the server

View File

@@ -230,8 +230,9 @@ sub NewReCaptchaDoPost {
print GetHeader('', T('Edit Denied'), undef, undef, '403 FORBIDDEN');
print $q->start_div({-class=>'error'});
print $q->p(T('You did not answer correctly.'));
print $q->start_form, ReCaptchaGetQuestion(1),
(map { $q->hidden($_, '') }
print GetFormStart(), ReCaptchaGetQuestion(1),
(map { $q->input({-type=>'hidden', -name=>$_,
-value=>UnquoteHtml(GetParam($_))}) }
qw(title text oldtime summary recent_edit aftertext)), $q->end_form;
print $q->end_div();
PrintFooter();
@@ -251,7 +252,7 @@ sub ReCaptchaCheckAnswer {
eval "use Captcha::reCAPTCHA";
my $result = Captcha::reCAPTCHA->new()->check_answer(
$ReCaptchaPrivateKey,
$ENV{'REMOTE_ADDR'},
GetRemoteAddress(),
GetParam('recaptcha_challenge_field'),
GetParam('recaptcha_response_field')
);

View File

@@ -80,7 +80,7 @@ sub RefererNewDeletePage {
sub GetRefererFile {
my $id = shift;
return $RefererDir . '/' . GetPageDirectory($id) . "/$id.rf";
return "$RefererDir/$id.rf";
}
sub ReadReferers {
@@ -178,8 +178,8 @@ sub UpdateReferers {
}
my $ua = LWP::UserAgent->new;
my $response = $ua->get($referer);
return unless $response->is_success and $response->content =~ /$self/;
my $title = PageContentToTitle($response->content);
return unless $response->is_success and $response->decoded_content =~ /$self/;
my $title = PageContentToTitle($response->decoded_content);
# starting with a timestamp makes sure that numerical comparisons still work!
$Referers{$referer} = "$Now $title";
return 1;

0
modules/sabifoo.pl Executable file → Normal file
View File

View File

@@ -33,7 +33,7 @@ package OddMuse::Tokenize;
use vars qw($regexp);
$regexp = qr'[A-Za-z0-9_\x80-\xff]+';
$regexp = qr'[A-Za-z0-9_\x{0080}-\x{fffd}]+';
sub new {
my ($classname, @args) = @_;

View File

@@ -33,7 +33,7 @@ push(@MyRules, \&SeTextRule);
# If the length does not match, pos is reset and zero is returned so
# that the remaining rules will be tested instead.
my $word = '([-A-Za-z\x80-\xff]+)';
my $word = '([-A-Za-z\x{0080}-\x{fffd}]+)';
sub SeTextRule {
my $oldpos = pos;
if ($bol && ((m/\G((.+?)[ \t]*\n(-+|=+)[ \t]*\n)/gc

View File

@@ -5,7 +5,7 @@ use vars qw($FS $FreeLinkPattern $UrlProtocols $UrlChars $EndChars
$UrlPattern $q);
$FS = "\x1e";
$FreeLinkPattern = "([-,.()' _0-9A-Za-z\x80-\xff]+)";
$FreeLinkPattern = "([-,.()' _0-9A-Za-z\x{0080}-\x{fffd}]+)";
$UrlProtocols = 'http|https|ftp|afs|news|nntp|mid|cid|mailto|wais|prospero|telnet|gopher|irc';
$UrlChars = '[-a-zA-Z0-9/@=+$_~*.,;:?!\'"()&#%]'; # see RFC 2396
$EndChars = '[-a-zA-Z0-9/@=+$_~*]'; # no punctuation at the end of the url.

0
modules/slideshow.pl Executable file → Normal file
View File

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/smiles.pl">smiles.pl</a></p>';
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/smiles.pl">smiles.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Logo_And_Icons#Smilies">Logo And Icons</a></p>';
%Smilies = (
':-?D' => 'http://www.emacswiki.org/pics/grin.png',

View File

@@ -1,20 +1,16 @@
# Copyright (C) 2004, 2005, 2006 Alex Schroeder <alex@emacswiki.org>
# Copyright (C) 2004-2014 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/static-copy.pl">static-copy.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Static_Copy_Extension">Static Copy Extension</a></p>';
@@ -39,6 +35,7 @@ sub DoStatic {
}
CreateDir($StaticDir);
%StaticFiles = ();
print '<p>' unless $raw;
StaticWriteFiles();
print '</p>' unless $raw;
PrintFooter() unless $raw;
@@ -60,10 +57,20 @@ sub StaticMimeTypes {
sub StaticWriteFiles {
my $raw = GetParam('raw', 0);
my $html = GetParam('html', 0);
local *ScriptLink = *StaticScriptLink;
local *GetDownloadLink = *StaticGetDownloadLink;
# get rid of subscribe link in the footer by mail.pl
local *GetCommentForm = *MailOldGetCommentForm if defined &MailNewGetCommentForm;
foreach my $id (AllPagesList()) {
StaticWriteFile($id);
if ($StaticAlways > 1
or $html
or PageIsUploadedFile($id)) {
StaticWriteFile($id, $html);
}
}
if ($StaticAlways > 1 or $html) {
StaticWriteCss();
}
}
@@ -120,18 +127,22 @@ sub StaticFileName {
}
sub StaticWriteFile {
my $id = shift;
my ($id, $html) = @_;
my $raw = GetParam('raw', 0);
my $html = GetParam('html', 1);
my $filename = StaticFileName($id);
OpenPage($id);
my ($mimetype, $encoding, $data) = $Page{text} =~ /^\#FILE ([^ \n]+) ?([^ \n]*)\n(.*)/s;
return unless $html or $data;
open(F,"> $StaticDir/$filename") or ReportError(Ts('Cannot write %s', $filename));
my ($mimetype, $encoding, $data) =
$Page{text} =~ /^\#FILE ([^ \n]+) ?([^ \n]*)\n(.*)/s;
open(F,"> $StaticDir/$filename")
or ReportError(Ts('Cannot write %s', $filename));
if ($data) {
binmode(F);
StaticFile($id, $mimetype, $data);
} elsif ($html) {
binmode(F, ':utf8');
StaticHtml($id);
} else {
print "no data for ";
}
close(F);
chmod 0644,"$StaticDir/$filename";
@@ -141,7 +152,6 @@ sub StaticWriteFile {
sub StaticFile {
my ($id, $type, $data) = @_;
require MIME::Base64;
binmode(F);
print F MIME::Base64::decode($data);
}
@@ -158,7 +168,7 @@ sub StaticHtml {
<title>$SiteName: $id</title>
<link type="text/css" rel="stylesheet" href="static.css" />
<meta http-equiv="refresh" content="0; url=$target">
<meta http-equiv="content-type" content="text/html; charset=$HttpCharset">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<p>Redirected to <a href="$target">$1</a>.</p>
@@ -173,7 +183,7 @@ EOT
<head>
<title>$SiteName: $id</title>
<link type="text/css" rel="stylesheet" href="static.css" />
<meta http-equiv="content-type" content="text/html; charset=$HttpCharset">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
EOT
@@ -200,7 +210,8 @@ EOT
print F $q->div({-class=>'content'}, PageHtml($id)); # this reopens the page currently open
# footer
my $links = '';
if ($OpenPageName !~ /^$CommentsPrefix/) { # fails if $CommentsPrefix is empty!
if ($OpenPageName !~ /^$CommentsPrefix/ # fails if $CommentsPrefix is empty!
and $IndexHash{$CommentsPrefix . $OpenPageName}) {
$links .= ScriptLink(UrlEncode($CommentsPrefix . $OpenPageName),
T('Comments on this page'));
}
@@ -216,6 +227,21 @@ EOT
print F '</body></html>';
}
sub StaticWriteCss {
my $css;
if ($StyleSheet) {
$css = GetRaw($StyleSheet);
}
if (not $css and $IndexHash{$StyleSheetPage}) {
$css = GetPageContent($StyleSheetPage);
}
if (not $css) {
$css = GetRaw('http://www.oddmuse.org/default.css');
}
WriteStringToFile("$StaticDir/static.css", $css) if $css;
chmod 0644,"$StaticDir/static.css";
}
*StaticFilesOldSave = *Save;
*Save = *StaticFilesNewSave;

View File

@@ -173,7 +173,7 @@ sub StaticHtml {
# Process the page
local $Message = "";
# encoding is left off, so fix it:
print qq!<?xml version="1.0" encoding="$HttpCharset" ?>!;
print qq!<?xml version="1.0" encoding="UTF-8" ?>!;
print GetHeader($id, QuoteHtml($id), undef, "");
print $q->start_div({-class=> 'content browse'});
print PageHtml($id);
@@ -422,7 +422,7 @@ sub StaticNewDoRollback {
} elsif (!UserCanEdit($id, 1)) {
print Ts('Editing not allowed for %s.', $id), $q->br();
} else {
Save($id, $text, Ts('Rollback to %s', TimeToText($to)), $minor, ($Page{ip} ne $ENV{REMOTE_ADDR}));
Save($id, $text, Ts('Rollback to %s', TimeToText($to)), $minor, ($Page{ip} ne GetRemoteAddress()));
StaticDeleteFile($id);
print Ts('%s rolled back', GetPageLink($id)), ($ts ? ' ' . Ts('to %s', TimeToText($to)) : ''), $q->br();
}

View File

@@ -33,7 +33,7 @@ sub TablesLongRule {
# a new row is started when a cell is repeated
# if cells are missing, column spans are created (the first row
# could use row spans...)
if ($bol && m|\G\s*\n*\&lt;table(/[A-Za-z\x80-\xff/]+)? +([A-Za-z\x80-\xff,;\/ ]+)\&gt; *\n|cg) {
if ($bol && m|\G\s*\n*\&lt;table(/[A-Za-z\x{0080}-\x{fffd}/]+)? +([A-Za-z\x{0080}-\x{fffd},;\/ ]+)\&gt; *\n|cg) {
my $class = join(' ', split(m|/|, $1)); # leading / in $1 will make sure we have leading space
Clean(CloseHtmlEnvironments() . "<table class=\"user long$class\">");
# labels and their default class
@@ -60,7 +60,7 @@ sub TablesLongRule {
my $rowspan = '';
my $first = 1;
for my $line (@lines) {
if ($line =~ m|^($regexp)/?([0-9]+)?/?([A-Za-z\x80-\xff/]+)?[:=] *(.*)|) { # regexp changes for other tables
if ($line =~ m|^($regexp)/?([0-9]+)?/?([A-Za-z\x{0080}-\x{fffd}/]+)?[:=] *(.*)|) { # regexp changes for other tables
$label = $1;
$rowspan = $2;
$class = join(' ', split(m|/|, $3)); # no leading / therefore no leading space

View File

@@ -127,10 +127,10 @@ sub NewTagSave { # called within a lock!
# an encoded string; the alternative would be to use a form of
# freeze and thaw.
foreach my $tag (keys %tag) {
my %file = map {$_=>1} split(/$FS/, $h{$tag});
my %file = map {$_=>1} split(/$FS/, UrlDecode($h{UrlEncode($tag)}));
if (not $file{$id}) {
$file{$id} = 1;
$h{$tag} = join($FS, keys %file);
$h{UrlEncode($tag)} = UrlEncode(join($FS, keys %file));
}
}
@@ -138,16 +138,16 @@ sub NewTagSave { # called within a lock!
# tags used. This allows us to delete the references that no longer
# show up without looping through them all. The files are indexed
# with a starting underscore because this is an illegal tag name.
foreach my $tag (split (/$FS/, $h{"_$id"})) {
foreach my $tag (split (/$FS/, UrlDecode($h{UrlEncode("_$id")}))) {
# If the tag we're looking at is no longer listed, we have work to
# do.
if (!$tag{$tag}) {
my %file = map {$_=>1} split(/$FS/, $h{$tag});
my %file = map {$_=>1} split(/$FS/, UrlDecode($h{UrlEncode($tag)}));
delete $file{$id};
if (%file) {
$h{$tag} = join($FS, keys %file);
$h{UrlEncode($tag)} = UrlEncode(join($FS, keys %file));
} else {
delete $h{$tag};
delete $h{UrlEncode($tag)};
}
}
}
@@ -155,9 +155,9 @@ sub NewTagSave { # called within a lock!
# Store the new reverse lookup of all the tags used on the current
# page. If no more tags appear on this page, delete the entry.
if (%tag) {
$h{"_$id"} = join($FS, keys %tag);
$h{UrlEncode("_$id")} = UrlEncode(join($FS, keys %tag));
} else {
delete $h{"_$id"};
delete $h{UrlEncode("_$id")};
}
untie %h;
@@ -183,18 +183,18 @@ sub NewTagDeletePage { # called within a lock!
# For each file in our hash, we have a reverse lookup of all the
# tags used. This allows us to delete the references that no longer
# show up without looping through them all.
foreach my $tag (split (/$FS/, $h{"_$id"})) {
my %file = map {$_=>1} split(/$FS/, $h{$tag});
foreach my $tag (split (/$FS/, UrlDecode($h{UrlEncode("_$id")}))) {
my %file = map {$_=>1} split(/$FS/, UrlDecode($h{UrlEncode($tag)}));
delete $file{$id};
if (%file) {
$h{$tag} = join($FS, keys %file);
$h{UrlEncode($tag)} = UrlEncode(join($FS, keys %file));
} else {
delete $h{$tag};
delete $h{UrlEncode($tag)};
}
}
# Delete reverse lookup entry.
delete $h{"_$id"};
delete $h{UrlEncode("_$id")};
untie %h;
# Return any error codes?
@@ -217,7 +217,7 @@ sub TagFind {
tie %h, "DB_File", $TagFile;
my %page;
foreach my $tag (@tags) {
foreach my $id (split(/$FS/, $h{lc($tag)})) {
foreach my $id (split(/$FS/, UrlDecode($h{UrlEncode(lc($tag))}))) {
$page{$id} = 1;
}
}
@@ -248,9 +248,7 @@ sub NewTagGrepFiltered { # called within a lock!
}
# filter out the tags from the search string
$string = join(' ', grep(!/^-?tag:/, $string =~ /\"([^\"]+)\"|(\S+)/g));
# if no query terms remain, just return the pages we found
# return sort keys %page if $string eq '';
# otherwise run grep
# run the old code for any remaining search terms
return OldTagGrepFiltered($string, sort keys %page);
}
@@ -293,20 +291,20 @@ sub TagCloud {
my $max = 0;
my $min = 0;
my %count = ();
foreach my $tag (grep !/^_/, keys %h) {
$count{$tag} = split(/$FS/, $h{$tag});
$max = $count{$tag} if $count{$tag} > $max;
$min = $count{$tag} if not $min or $count{$tag} < $min;
foreach my $encoded_tag (grep !/^_/, keys %h) {
$count{$encoded_tag} = split(/$FS/, UrlDecode($h{$encoded_tag}));
$max = $count{$encoded_tag} if $count{$encoded_tag} > $max;
$min = $count{$encoded_tag} if not $min or $count{$encoded_tag} < $min;
}
untie %h;
foreach my $tag (sort keys %count) {
my $n = $count{$tag};
print $q->a({-href => "$ScriptName?search=tag:" . UrlEncode($tag),
foreach my $encoded_tag (sort keys %count) {
my $n = $count{$encoded_tag};
print $q->a({-href => "$ScriptName?search=tag:" . $encoded_tag,
-title => $n,
-style => 'font-size: '
. int(80+120*($max == $min ? 1 : ($n-$min)/($max-$min)))
. '%;',
}, NormalToFree($tag)), T(' ... ');
}, NormalToFree(UrlDecode($encoded_tag))), T(' ... ');
}
print '</p></div>';
PrintFooter();
@@ -356,12 +354,15 @@ sub DoTagsReindex {
# For each tag we list the files tagged. Add the current file for
# all tags.
foreach my $tag (keys %tag) {
$h{$tag} = $h{$tag} ? $h{$tag} . $FS . $id : $id;
my $encoded_tag = UrlEncode($tag);
$h{$encoded_tag} = $h{$encoded_tag}
? $h{$encoded_tag} . UrlEncode($FS . $id)
: UrlEncode($id);
}
# Store the reverse lookup of all the tags used on the current
# page.
$h{"_$id"} = join($FS, keys %tag);
$h{UrlEncode("_$id")} = UrlEncode(join($FS, keys %tag));
}
untie %h;
@@ -386,8 +387,8 @@ sub TagList {
# open the DB file
require DB_File;
tie %h, "DB_File", $TagFile;
foreach my $id (sort keys %h) {
print "$id: " . join(', ', split(/$FS/, $h{$id})) . "\n";
foreach my $id (sort map { UrlDecode($_) } keys %h) {
print "$id: " . join(', ', split(/$FS/, UrlDecode($h{UrlEncode($id)}))) . "\n";
}
untie %h;
}
@@ -411,7 +412,7 @@ sub TagsMenu {
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2005, 2009 Alex Schroeder <alex@gnu.org>
Copyright (C) 2005, 2009, 2013 Alex Schroeder <alex@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,8 +1,8 @@
# Copyright (C) 2006 Alex Schroeder <alex@emacswiki.org>
# Copyright (C) 2006, 2012 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
@@ -11,16 +11,14 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
# along with this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/tex.pl">tex.pl</a></p>';
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/tex.pl">tex.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/TeX_Extension">TeX Extension</a></p>';
use vars qw($TeXInit);
use vars qw($TeXInit %Tex);
use utf8;
my %h = qw( !` ¡ {\pounds} £ \pounds £ {\S} § \S § \"{} ¨ {\copyright} ©
%Tex = qw( !` ¡ {\pounds} £ \pounds £ {\S} § \S § \"{} ¨ {\copyright} ©
\copyright © $^a$ ª \={} ¯ $\pm$ ± \pm ± $^2$ ² $^3$ ³ \'{} ´ {\P} ¶
\P ¶ $\cdot$ · \cdot · \c{} ¸ $^1$ ¹ $^o$ º ?` ¿ \`{A} À \`A À \'{A} Á
\'A Á \^{A} Â \^A Â \~{A} Ã \~A Ã \"{A} Ä \"A Ä \k{A} Ą {\AA} Å \AA Å
@@ -154,17 +152,31 @@ _0 ₀ _1 ₁ _2 ₂ _3 ₃ _4 ₄ _5 ₅ _6 ₆ _7 ₇ _8 ₈ _9 ₉ _= ₌ \~
\varpropto ∝ \varrho ϱ \varsigma ς \vartheta ϑ \vartriangleleft ⊲
\vartriangleright ⊳ \vdash ⊢ \vdots ⋮ \vee \veebar ⊻ \vert | \wedge
∧ \wp ℘ \wr ≀ \xi ξ \zeta ζ \Bbb{N} \Bbb{P} \Bbb{R} \Bbb{Z} --
--- — ~ \mu μ \rho ρ \mathscr{I} \Smiley ☺ \blacksmiley ☻
--- — \mu μ \rho ρ \mathscr{I} \Smiley ☺ \blacksmiley ☻
\Frowny ☹ \Letter ✉ \permil ‰ \registered ® \currency ¤ \dh ð \DH Ð
\th þ \TH Þ \micro µ \lnot ¬ \ordfeminine ª \ordmasculine º \lambdabar
ƛ \celsius ℃ \ldq “ \rdq ” \minus \defs ≙ \llbracket 〚 \rrbracket 〛
\ldata 《\rdata 》\glq \grq \glqq „ \"` „ \grqq “ \"' “ \flq
\ldata 《 \rdata 》 \glq \grq \glqq „ \"` „ \grqq “ \"' “ \flq
\frq \flqq « \"< « \frqq » \"> » \- ­ \textmu µ \textfractionsolidus
\textbigcircle ⃝ \textmusicalnote ♪ \textdied ✝ \textcolonmonetary ₡
\textwon ₩ \textnaira ₦ \textpeso ₱ \textlira ₤ \textrecipe ℞
\textinterrobang ‽ \textpertenthousand ‱ \textbaht ฿ \textnumero №
\textdiscount ⁒ \textestimated \textopenbullet ◦ \textlquill ⁅
\textrquill ⁆ \textcircledP ℗ \textreferencemark ※ );
$Tex{'~'} = ' ';
my $re = '(' . join('|', map {quotemeta} keys %h) . ')(\s|\b)';
push(@MyMacros, sub {s/$re/$h{$1}/go});
my $TexRe = '(' . join('|', map {quotemeta} sort { $b cmp $a } keys %Tex) . ')';
$TexRe = qr{$TexRe};
push(@MyRules, \&TexRule);
# use of -- conflicts with MarkupRules such as the following:
# $MarkupForcedPairs{'--'} = 'del';
$RuleOrder{\&TexRule} = 160;
sub TexRule {
if (m/\G$TexRe/goc) {
return $Tex{$1};
}
return undef;
}

View File

@@ -23,6 +23,7 @@
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/throttle.pl">throttle.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Limit_Number_Of_Instances_Running">Limit Number Of Instances Running</a></p>';
use File::Glob ':glob';
use vars qw($InstanceThrottleDir $InstanceThrottleLimit);
$InstanceThrottleDir = $DataDir."/pids"; # directory for pid files
@@ -47,7 +48,7 @@ sub NewDoBrowseRequest {
# limit the script to a maximum of $InstanceThrottleLimit instances
sub DoInstanceThrottle {
my @pids = glob($InstanceThrottleDir."/*");
my @pids = bsd_glob($InstanceThrottleDir."/*");
# Go over all pids: validate each pid by sending signal 0, unlink
# pidfile if pid does not exist and return 0. Count the number of
# zeros (= removed files = zombies) with grep.

256
modules/thumbs.pl Normal file
View File

@@ -0,0 +1,256 @@
# Copyright (C) 2004, 2012 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2005 Rob Neild
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
# Thumbnail (and improved image handling) module for OddMuse wiki
# Conflicts with the "Image extension module"
require MIME::Base64;
use File::Path;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/thumbs.pl">thumbs.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Image_Thumbnails">Image Thumbnails</a></p>';
# Tempoary directory to create thumbnails in
$ThumbnailTempDir = '/tmp';
# Path and name of external program to use to create thumbnails. Only
# ImageMagick 'convert' can be used. You may have to set the MAGICK_HOME
# environment variable in your config file if you set it to
# /usr/local/bin/convert and get the following error:
# convert: no decode delegate for this image format
# For your config file:
# $ENV{MAGICK_HOME} = '/usr/local';
$ThumbnailConvert = '/usr/bin/convert';
# Max size for a thumbnail. If larger size is specified just shows
# regular image
$ThumbnailMaxSize = 500;
# Default thumbnail size if non is specified
$ThumbnailDefaultSize = 100;
# MIME types to create thumbnail for, all allowed if empty list
@ThumbnailTypes = @UploadTypes;
# As well as using ALT, use TITLE. This enables comments to popup when
# hovering mouse over thumbnail
$ThumbnailImageUseTitle = 0;
$ThumbnailCacheDir = "oddmuse_thumbnail_cache";
$ThumbnailCacheUrl = "/oddmuse_thumbnail_cache";
# Define new formatting rule "thumb" that inserts an auto generated thumbnail
# Syntax is [[thumb:page name | etc. ]]
push(@MyRules, \&ThumbNailSupportRule);
sub ThumbNailSupportRule {
my $result;
my $RawMatch;
if (m!\G(\[\[thumb:$FreeLinkPattern(\|.*?)?\]\])!gc)
{
$RawMatch = $1;
# Try and extract out all the options. They can be in any order, apart from comment at end
my $name = $2;
my $size="$ThumbnailDefaultSize"; # default size for thumbnail
my $frame;
my $comment; # default alignment for a non framed picture
my $alignment_framed = 'tright'; # default alignment for a framed picture
my $alignment;
my $params = $3 . '|';
if($params =~ s/\|([0-9]+)px\|/\|/) { $size = $1; }
if($params =~ s/\|thumb\|/\|/) { $frame = 'yes' ;}
if($params =~ s/\|frame\|/\|/) { $frame = 'yes'; }
if ($params =~ s/\|none\|/\|/) { $alignment_framed= 'tnone'; }
if ($params =~ s/\|right\|/\|/) { $alignment_framed= 'tright'; $alignment='floatright';}
if ($params =~ s/\|left\|/\|/) { $alignment_framed= 'tleft'; $alignment='floatleft'; }
if ($params =~ m/\|(.+)\|$/) { $comment = $1; }
my $id = FreeToNormal($name);
AllPagesList();
# if the page does exists
if ($IndexHash{$id})
{
if (! -e "$ThumbnailCacheDir/$id/$size")
{
GenerateThumbNail ($id, $size);
}
my %img_attribs;
my $action = "$ThumbnailCacheUrl/" . UrlEncode($id) . "/$size";
$img_attribs{'-src'} = $action;
if (defined $comment) {
$img_attribs{'-alt'} ="$comment";
$img_attribs{'-title'} = "$comment" if $ThumbnailImageUseTitle==1;
}
else { $img_attribs{'-alt'} = "$name"; }
$img_attribs{'-class'} = 'upload';
$result = $q->img(\%img_attribs);
$result = ScriptLink(UrlEncode($id) , $result, 'image');
if (defined $frame) {
if (defined $comment) { $result = $result . $q->div({-class=>'thumbcaption'}, "$comment"); }
if ($size>0) {
$result = $q->div({-style=>"width:" . ($size+2) . "px"}, $result);
$result = $q->div({-class=>"thumb " . $alignment_framed}, $result);
}
}
else
{
if (defined $alignment) { $result = $q->div({-class=>"$alignment" }, $result); }
}
}
else
{
# if the image does not exist
$result = '[' . T('thumb') . ':' . $name . GetEditLink($id, '?', 1) . ']';
}
}
if (defined $result)
{
Dirty($RawMatch);
print $result;
$result = '';
}
return $result;
}
# define new action "thumbnail" that actually does the on fly generation of the image
# thumbnails are put into the file so they only need be generated once
# we also store the size of thumbnail so that can be used in the markup
# if we get passed a size of zero then all we need to do is check whether we have the image size stored in thumbnail_0
# this enbles markup for non-thumbnail images better
sub GenerateThumbNail {
my ($id, $size) = (@_);
ValidIdOrDie($id);
AllPagesList();
if (not $IndexHash{$id}) { ReportError(Ts('Error creating thumbnail from non existant page %s.' , $id), '500 INTERNAL SERVER ERROR'); } # Page Doesn't exist,
my $openpage = $OpenPageName; # remember the current page we are on
RequestLockOrError();
OpenPage($id);
# Parse out some data
# Check MIME type supported
# Check is a file
my ($text, $revision) = GetTextRevision(GetParam('revision', '')); # maybe revision reset!
my ($type) = TextIsFile($text); # MIME type if an uploaded file
my $data = substr($text, index($text, "\n") + 1);
if ($type)
{
my $regexp = quotemeta($type);
if (@ThumbnailTypes and not grep(/^$regexp$/, @ThumbnailTypes)) {
ReportError(Ts('Can not create thumbnail for file type %s.' , $type), '415 UNSUPPORTED MEDIA TYPE');
}
}
else
{
ReportError(T('Can not create thumbnail for a text document'), '500 INTERNAL SERVER ERROR');
}
my $filename = $ThumbnailTempDir . "/odd" . $id . "_" . $size;
# Decode the original image to a temp file
open(FD, "> $filename") or ReportError(Ts("Could not open %s for writing whilst trying to save image before creating thumbnail. Check write permissions.",$filename), '500 INTERNAL SERVER ERROR');
binmode(FD);
print FD MIME::Base64::decode($data);
close(FD);
eval { mkpath("$ThumbnailCacheDir/$id") };
if ($@) {
ReportError(Ts('Can not create path for thumbnail - %s', $@), '500 INTERNAL SERVER ERROR');
}
# create the thumbnail
my $command = "$ThumbnailConvert '$filename' -verbose -resize ${size}x '$ThumbnailCacheDir/$id/$size' 2>&1";
open (MESSAGE, '-|', $command)
or ReportError(Tss("Failed to run %1 to create thumbnail: %2", $ThumbnailConvert, $!),
'500 INTERNAL SERVER ERROR');
my $convert = <MESSAGE>;
close(MESSAGE);
my $scaled_size_x;
my $scaled_size_y;
my $thumbnail_data= '';
if($?) {
ReportError(Ts("%s ran into an error", $ThumbnailConvert), '500 INTERNAL SERVER ERROR', undef,
$q->pre($command . "\n" . $convert));
} elsif($convert =~ m/=>(\d+)x(\d+)/) {
$scaled_size_x = $1;
$scaled_size_y = $2;
} elsif (!$convert) {
ReportError(Ts("%s produced no output", $ThumbnailConvert), '500 INTERNAL SERVER ERROR');
} else {
ReportError(Ts("Failed to parse %s.", $convert), '500 INTERNAL SERVER ERROR');
}
unlink($filename);
# save tag to page
#$Page{'thumbnail_' . $size} = '#FILE ' . $type . ' created=' . $Now . ' revision=' . $Page{'revision'} . ' size=' . $scaled_size_x . 'x' . $scaled_size_y . "\n" . $thumbnail_data;
#SavePage();
ReleaseLock();
OpenPage($openpage); # restore original open page
}

View File

@@ -25,7 +25,9 @@ $defaultTZ = 'UTC';
$CookieParameters{time} = '';
sub TZget {
my $dt = DateTime->from_epoch(epoch=>shift);
my $ts = shift;
$ts = 0 if not defined($ts);
my $dt = DateTime->from_epoch(epoch=>$ts);
my $tz = GetParam('time', '');
# setting time= will use the (defined) empty string, so avoid that
$tz = $defaultTZ unless $tz;

98
modules/toc-js.pl Normal file
View File

@@ -0,0 +1,98 @@
# Copyright (C) 2013 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
package OddMuse;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/toc-js.pl">toc-js.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Javascript_Table_of_Contents_Extension">Javascript Table of Contents Extension</a></p>';
use vars qw($TocOutlineLibrary);
$TocOutlineLibrary = 'http://h5o.googlecode.com/files/outliner.0.5.0.62.js';
# Add the dojo script to edit pages.
push (@MyInitVariables, \&TocScript);
sub TocScript {
# cookie is not initialized yet so we cannot use GetParam
# Cross browser compatibility: http://www.tek-tips.com/faqs.cfm?fid=4862
# HTML5 Outlines: http://blog.tremily.us/posts/HTML5_outlines/
# Required library: http://code.google.com/p/h5o/
if (GetParam('action', 'browse') eq 'browse') {
$HtmlHeaders .= qq{
<script type="text/javascript" src="$TocOutlineLibrary"></script>
<script type="text/javascript">
function addOnloadEvent(fnc) {
if ( typeof window.addEventListener != "undefined" )
window.addEventListener( "load", fnc, false );
else if ( typeof window.attachEvent != "undefined" ) {
window.attachEvent( "onload", fnc );
}
else {
if ( window.onload != null ) {
var oldOnload = window.onload;
window.onload = function ( e ) {
oldOnload( e );
window[fnc]();
};
}
else
window.onload = fnc;
}
}
var initToc=function() {
var outline = HTML5Outline(document.body);
if (outline.sections.length == 1) {
outline.sections = outline.sections[0].sections;
}
if (outline.sections.length > 1
|| outline.sections.length == 1
&& outline.sections[0].sections.length > 0) {
var toc = document.getElementById('toc');
if (!toc) {
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
if (divs[i].getAttribute('class') == 'toc') {
toc = divs[i];
break;
}
}
}
if (!toc) {
var h2 = document.getElementsByTagName('h2')[0];
if (h2) {
toc = document.createElement('div');
toc.setAttribute('class', 'toc');
h2.parentNode.insertBefore(toc, h2);
}
}
if (toc) {
var html = outline.asHTML(true);
toc.innerHTML = html;
}
}
}
addOnloadEvent(initToc);
</script>
};
}
}

View File

@@ -25,7 +25,6 @@ use vars qw($TocHeaderText
$TocClass
$TocAutomatic
$TocAnchorPrefix
$TocIsApplyingAutomaticRules);
=head2 $TocHeaderText
@@ -140,7 +139,7 @@ that table. This is optional. If not specified, it defaults to "toc".
sub TocRule {
# <toc...> markup. This explicitly displays a table of contents at this point.
if ($bol and
m~\G&lt;toc(/([A-Za-z\x80-\xff/]+))? # $1
m~\G&lt;toc(/([A-Za-z\x{0080}-\x{fffd}/]+))? # $1
(\s+(?:header_text\s*=\s*)?"(.+?)")? # $3
(\s+(?:class\s*=\s*)?"(.+?)")? # $5
&gt;[ \t]*(\n|$)~cgx) { # $7
@@ -229,8 +228,11 @@ sub NewTocApplyRules {
{
local *STDOUT;
open( STDOUT, '>', \$html) or die "Can't open memory file: $!";
binmode STDOUT, ":utf8";
($blocks, $flags) = OldTocApplyRules(@_);
close STDOUT;
utf8::decode($blocks);
utf8::decode($html);
}
# If there are at least two HTML headers on this page, insert a table of
# contents.

View File

@@ -1,17 +1,19 @@
# Copyright (C) 2008 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2008, 2012 Alex Schroeder <alex@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/translation-links.pl">translation-links.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Translation_Links">Translation Links</a></p>';
=head1 Translation Links
@@ -76,7 +78,6 @@ sub TranslationLinkInit {
$TranslationLinkPattern .= '|' if $FreeLinks or $WikiLinks;
$TranslationLinkPattern .= $LinkPattern if $WikiLinks;
$TranslationLinkPattern .= ')\]\]';
my $text = GetPageContent(FreeToNormal(GetId()));
%TranslationLinkData = ();
}
@@ -199,9 +200,13 @@ sub DoTranslationLink {
}
print $q->p($q->label({-for=>'target'}, T('Translated page: ')),
$q->textfield('target', '', 40),
$q->hidden('action', 'translate'),
$q->hidden('id', $source),
$q->hidden('missing', GetParam('missing', '')),
# don't use $q->hidden or you'll get encoding errors
$q->input({-type=>'hidden', -name=>'id',
-value=>$source}),
$q->input({-type=>'hidden', -name=>'action',
-value=>'translate'}),
$q->input({-type=>'hidden', -name=>'missing',
-value=>GetParam('missing', '')}),
$q->submit('dotranslate', T('Go!')));
print $q->endform, $q->end_div();
PrintFooter();

View File

@@ -1 +0,0 @@
*.wiki

View File

@@ -1,24 +1,3 @@
# UTF-8 encoded Brazilian Portuguese language file for use with Oddmuse
#
# Copyright (c) 2003 Marcelo Toledo <rw@locked.org>.
# Copyright (c) 2006, 2007 Hélio Nunes <dedalu@dedalu.art.br>.
#
# Permission is granted to copy, distribute and/or modify this
# document under the terms of the GNU Free Documentation License,
# Version 1.2 or any later version published by the Free Software
# Foundation; with no Invariant Sections, no Front-Cover Texts, and no
# Back-Cover Texts. A copy of the license could be found at:
# http://www.gnu.org/licenses/fdl.txt.
#
# Installation:
# =============
#
# Create a modules subdirectory in your data directory, and put the
# file in there. It will be loaded automatically.
#
# This translation was last checked for Oddmuse version 1.753.
#
$ModulesDescription .= '<p>$Id: brazilian-portuguese-utf8.pl,v 1.14 2009/06/07 19:30:37 as Exp $</p>';
%Translate = split(/\n/,<<END_OF_TRANSLATION);
Include normal pages
Incluir páginas normais
@@ -92,6 +71,8 @@ Please go on to %s.
Por favor, para %s.
Updates since %s
Atualizações desde %s
up to %s
Updates in the last %s days
Atualizações nos últimos %s dias
Updates in the last %s day
@@ -176,6 +157,8 @@ The two revisions are the same.
As duas versões são idênticas.
Editing not allowed for %s.
Edição não permitida para %s.
Rollback of %s would restore banned content.
Rollback to %s
Desfazer para %s
%s rolled back
@@ -196,8 +179,6 @@ Unlock site
Desbloquear site
Lock site
Bloquear site
Install CSS
Instalar CSS
Unlock %s
Desbloquear %s
Lock %s
@@ -320,6 +301,8 @@ Could not get %s lock
Não foi possível conseguir o bloqueio %s
The lock was created %s.
O bloqueio foi criado %s.
Maybe the user running this script is no longer allowed to remove the lock directory?
This operation may take several seconds...
Essa operação pode demorar vários segundos...
Forced unlock of %s lock.
@@ -410,6 +393,8 @@ Filtro:
(para %s)
%s pages found.
%s páginas encontradas.
Malformed regular expression in %s
Replaced: %s
Substituído: %s
Search for: %s
@@ -492,16 +477,12 @@ Displaying Wiki Version
Mostrando a versão do Wiki
Debugging Information
Inter links:
Links inter-:
Too many connections by %s
Muitas conexões de %s
Please do not fetch more than %1 pages in %2 seconds.
Por favor, abra mais do que %1 páginas em %2 segundos.
Check whether the web server can create the directory %s and whether it can create files in it.
Verifique se o servidor web pode criar o diretório %s e se pode criar arquivos nele.
Copy one of the following stylesheets to %s:
Copie uma das seguintes folhas de estilo para %s:
Deleting %s
Excluindo %s
Deleted %s
@@ -618,6 +599,20 @@ Compilation for %s
Compilação para %s
Compilation tag is missing a regular expression.
Falta expressão regular na etiqueta de compilação.
Install CSS
Instalar CSS
Copy one of the following stylesheets to %s:
Copie uma das seguintes folhas de estilo para %s:
Reset
Extract all dates from the database
Dates
No dates found.
Inter links:
Links inter-:
List spammed pages
Listar páginas com spam
Despamming pages
@@ -658,6 +653,14 @@ ordinary changes
alterações normais
Matching page names:
Coincidindo com os nomes de página:
no summary available
page was marked for deletion
Oddmuse
Email:
Could not find %1.html template in %2
Não foi possível encontrar o modelo %1.html em %2
Only Editors are allowed to see this hidden page.
@@ -686,6 +689,14 @@ O modelo %s ou está vazio ou não existe.
-- definido em %s
Local names defined on %1: %2
Nomes locais definidos em %1: %2
Name:
URL:
Define Local Names
Define external redirect:
Locked Pages
Register for %s
@@ -788,8 +799,6 @@ unsubscribe
subscribe
Email:
%s appears to be an invalid mail address
Your mail subscriptions
@@ -826,6 +835,8 @@ You linked more than %s times to the same domain. It would seem that only a spam
%s não é um nome legal para um espaço de nomes
Namespaces
(create locally)
(criar localmente)
Getting page index file for %s.
Obtendo arquivo de índice de página para %s.
Near links:
@@ -842,8 +853,6 @@ EditNearLinks
EditarLinksPróximos
The same page on other sites:
A mesma página em outros sites:
(create locally)
(criar localmente)
image
imagem
download
@@ -858,6 +867,12 @@ Generating Link Database
Gerando Banco de Dados de Link
The 404 handler extension requires the link data extension (links.pl).
A extensão 404 handler requer a extensão link data (links.pl)
Make available offline
Offline
You are currently offline and what you requested is not part of the offline application. You need to be online to do this.
LocalMap
MapaLocal
No page id for action localmap
@@ -872,20 +887,6 @@ Self-ban by %s
Auto-banimento por %s
You have banned your own IP.
Você baniu seu próprio IP.
OpenID Login
Your identity is saved in a cookie, if you have cookies enabled. Cookies may get lost if you connect from another machine, from another account, or using another software.
Your homepage is set to %s.
You have no homepage set.
Homepage:
Homepage is missing
OpenID error %s
Orphan List
Lista de Órfãs
Trail:
@@ -918,6 +919,8 @@ No target wiki was specified in the config file.
Não foi especificado um wiki alvo no arquivo de configuração.
The target wiki was misconfigured.
O wiki alvo está mal configurado.
Upload is limited to %s bytes
You did not answer correctly.
Você não respondeu corretamente à pergunta.
To save this page you must answer this question:
@@ -970,6 +973,10 @@ Static Copy
Cópia Estática
Back to %s
Voltar para %s
Edit image in the browser
Summary of your changes:
Copy to %1 succeeded: %2.
Sucesso na cópia de %1: %2.
Copy to %1 failed: %2.
@@ -1008,12 +1015,40 @@ Too many instances. Only %s allowed.
Muitas instâncias. Apenas %s permitidas.
Please try again later. Perhaps somebody is running maintenance or doing a long search. Unfortunately the site has limited resources, and so we must ask you for a bit of patience.
Por favor, tente novamente mais tarde. Talvez alguém esteja executando manutenção ou uma longa busca. Infelizmente o site tem recursos limitados e, por isso, pedimos um pouco de paciência.
thumb
Error creating thumbnail from non existant page %s.
Can not create thumbnail for file type %s.
Can not create thumbnail for a text document
Could not open %s for writing whilst trying to save image before creating thumbnail. Check write permissions.
Can not create path for thumbnail - %s
Failed to run %1 to create thumbnail: %2
%s ran into an error
%s produced no output
Failed to parse %s.
Timezone
Pick your timezone:
Set
Contents
Conteúdo
Create a new page for today
Add Translation
Please provide a different page name for the translation.
Added translation: %1 (%2)
Translate %s
@@ -1056,6 +1091,8 @@ Páginas Procuradas
%s páginas
%s, referenced from:
%s, referenciada por:
Web application for offline browsing
Upload of %s file
Envio de arquivos %s
Blog

View File

@@ -18,7 +18,8 @@
#
# This translation was updated for Oddmuse 1.354.
#
$ModulesDescription .= '<p>$Id: bulgarian-utf8.pl,v 1.11 2009/06/07 19:30:37 as Exp $</p>';
use utf8;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/translations/bulgarian-utf8.pl">bulgarian-utf8.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Bulgarian">Bulgarian</a></p>';
%Translate = split(/\n/,<<END_OF_TRANSLATION);
Include normal pages
@@ -92,6 +93,8 @@ Please go on to %s.
Моля продължи на %s.
Updates since %s
Промени от %s насам
up to %s
Updates in the last %s days
Промени през последните %s дни
Updates in the last %s day
@@ -176,6 +179,8 @@ The two revisions are the same.
Editing not allowed for %s.
Редакция на %s не е разрешена.
Rollback of %s would restore banned content.
Rollback to %s
Връщане до %s
%s rolled back
@@ -196,8 +201,6 @@ Unlock site
Lock site
Install CSS
Unlock %s
Lock %s
@@ -320,6 +323,8 @@ Could not get %s lock
Не може да се резервират изключителни права върху %s.
The lock was created %s.
Maybe the user running this script is no longer allowed to remove the lock directory?
This operation may take several seconds...
Тази операция може да потрае малко...
Forced unlock of %s lock.
@@ -410,6 +415,8 @@ Filter:
(за %s)
%s pages found.
%s намерени страници.
Malformed regular expression in %s
Replaced: %s
Заместено: %s
Search for: %s
@@ -492,16 +499,12 @@ Displaying Wiki Version
Debugging Information
Inter links:
Интер-линкове:
Too many connections by %s
Прекалено много връзки с %s
Please do not fetch more than %1 pages in %2 seconds.
Check whether the web server can create the directory %s and whether it can create files in it.
Copy one of the following stylesheets to %s:
Deleting %s
Deleted %s
@@ -618,6 +621,20 @@ Compilation for %s
Compilation tag is missing a regular expression.
Install CSS
Copy one of the following stylesheets to %s:
Reset
Extract all dates from the database
Dates
No dates found.
Inter links:
Интер-линкове:
List spammed pages
Despamming pages
@@ -658,6 +675,14 @@ ordinary changes
Matching page names:
no summary available
page was marked for deletion
Oddmuse
Email:
Could not find %1.html template in %2
Only Editors are allowed to see this hidden page.
@@ -686,6 +711,14 @@ The template %s is either empty or does not exist.
Local names defined on %1: %2
Name:
URL:
Define Local Names
Define external redirect:
Locked Pages
Register for %s
@@ -788,8 +821,6 @@ unsubscribe
subscribe
Email:
%s appears to be an invalid mail address
Your mail subscriptions
@@ -826,6 +857,8 @@ You linked more than %s times to the same domain. It would seem that only a spam
Namespaces
(create locally)
Getting page index file for %s.
Получаване на индекс за %s.
Near links:
@@ -842,8 +875,6 @@ EditNearLinks
Редакция на близки линкове
The same page on other sites:
Същата страница на други места:
(create locally)
image
download
@@ -858,6 +889,12 @@ Generating Link Database
The 404 handler extension requires the link data extension (links.pl).
Make available offline
Offline
You are currently offline and what you requested is not part of the offline application. You need to be online to do this.
LocalMap
No page id for action localmap
@@ -872,20 +909,6 @@ Self-ban by %s
You have banned your own IP.
OpenID Login
Your identity is saved in a cookie, if you have cookies enabled. Cookies may get lost if you connect from another machine, from another account, or using another software.
Your homepage is set to %s.
You have no homepage set.
Homepage:
Homepage is missing
OpenID error %s
Orphan List
Trail:
@@ -918,6 +941,8 @@ No target wiki was specified in the config file.
The target wiki was misconfigured.
Upload is limited to %s bytes
You did not answer correctly.
To save this page you must answer this question:
@@ -970,6 +995,10 @@ Static Copy
Back to %s
Обратно към %s
Edit image in the browser
Summary of your changes:
Copy to %1 succeeded: %2.
Copy to %1 failed: %2.
@@ -1008,12 +1037,40 @@ Too many instances. Only %s allowed.
Please try again later. Perhaps somebody is running maintenance or doing a long search. Unfortunately the site has limited resources, and so we must ask you for a bit of patience.
thumb
Error creating thumbnail from non existant page %s.
Can not create thumbnail for file type %s.
Can not create thumbnail for a text document
Could not open %s for writing whilst trying to save image before creating thumbnail. Check write permissions.
Can not create path for thumbnail - %s
Failed to run %1 to create thumbnail: %2
%s ran into an error
%s produced no output
Failed to parse %s.
Timezone
Pick your timezone:
Set
Contents
Create a new page for today
Add Translation
Please provide a different page name for the translation.
Added translation: %1 (%2)
Translate %s
@@ -1056,6 +1113,8 @@ Wanted Pages
%s, referenced from:
Web application for offline browsing
Upload of %s file
Blog

View File

@@ -18,7 +18,8 @@
#
# This translation was last checked for Oddmuse version 1.504.
#
$ModulesDescription .= '<p>$Id: chinese-utf8.pl,v 1.12 2009/06/07 19:30:37 as Exp $</p>';
use utf8;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/translations/chinese-utf8.pl">chinese-utf8.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Chinese">Chinese</a></p>';
%Translate = split(/\n/,<<END_OF_TRANSLATION);
Include normal pages
包含正常頁面
@@ -92,6 +93,8 @@ Please go on to %s.
請繼續前住 %s
Updates since %s
%s 以來的修改
up to %s
Updates in the last %s days
%s 天之內的更動
Updates in the last %s day
@@ -139,7 +142,7 @@ Go!
(minor)
(次要的)
rollback
new
新增
All changes for %s
@@ -165,21 +168,23 @@ Revision %s
Contributors to %s
編寫 %s 的作者
Missing target for rollback.
找不到要回的目標
找不到要回的目標
Target for rollback is too far back.
要回的目標已太久以前了
要回的目標已太久以前了
A username is required for ordinary users.
需使用普通用戶名稱
Rolling back changes
修改
修改
The two revisions are the same.
二個版本相同
Editing not allowed for %s.
不允許編輯 %s
Rollback of %s would restore banned content.
Rollback to %s
%s
%s
%s rolled back
%s 已回
%s 已回
to %s
%s
Index of all pages
@@ -196,8 +201,6 @@ Unlock site
網站解鎖
Lock site
網站鎖定
Install CSS
安裝 CSS
Unlock %s
解鎖 %s
Lock %s
@@ -320,6 +323,8 @@ Could not get %s lock
無法取得 %s 鎖定
The lock was created %s.
建立鎖定 %s
Maybe the user running this script is no longer allowed to remove the lock directory?
This operation may take several seconds...
這個動作可能要花幾秒
Forced unlock of %s lock.
@@ -410,6 +415,8 @@ Filter:
(列出 %s )
%s pages found.
找到 %s 個頁面
Malformed regular expression in %s
Replaced: %s
取代%s
Search for: %s
@@ -492,16 +499,12 @@ Displaying Wiki Version
顯示 Wiki 主機相關套件版本
Debugging Information
Inter links:
內部連結
Too many connections by %s
太多來自 %s 的連線
Please do not fetch more than %1 pages in %2 seconds.
請不要在 %2 秒內抓取超過 %1 頁的資料
Check whether the web server can create the directory %s and whether it can create files in it.
請確認網站伺服器是否可建立 %s 目錄並且在其中建立檔案
Copy one of the following stylesheets to %s:
複製以下 CSS 模版至 %s
Deleting %s
正在刪除 %s
Deleted %s
@@ -618,6 +621,20 @@ Compilation for %s
%s 的彙整
Compilation tag is missing a regular expression.
匯編的標記缺少一個正規表示式
Install CSS
安裝 CSS
Copy one of the following stylesheets to %s:
複製以下 CSS 模版至 %s
Reset
Extract all dates from the database
Dates
No dates found.
Inter links:
內部連結
List spammed pages
列出 SPAM 頁面
Despamming pages
@@ -627,7 +644,7 @@ SPAM 廣告頁面
Cannot find revision %s.
無法取得版本 %s
Revert to revision %1: %2
至版本 %1: %2
至版本 %1: %2
Marked as %s.
標記為 %s
Cannot find unspammed revision.
@@ -658,6 +675,14 @@ ordinary changes
普通變更
Matching page names:
匹配頁面的名稱:
no summary available
page was marked for deletion
Oddmuse
Email:
Could not find %1.html template in %2
無法在 %2 找到 %1.html 的範本
Only Editors are allowed to see this hidden page.
@@ -686,6 +711,14 @@ The template %s is either empty or does not exist.
-- %s 中定義
Local names defined on %1: %2
定義本地名稱在 %1: %2
Name:
URL:
Define Local Names
Define external redirect:
Locked Pages
Register for %s
@@ -788,8 +821,6 @@ unsubscribe
subscribe
Email:
%s appears to be an invalid mail address
Your mail subscriptions
@@ -826,6 +857,8 @@ You linked more than %s times to the same domain. It would seem that only a spam
%s 不是一個正常的命名空間
Namespaces
(create locally)
(本地建立)
Getting page index file for %s.
%s 取得頁面索引資料
Near links:
@@ -842,8 +875,6 @@ EditNearLinks
編輯接近連結
The same page on other sites:
其他網站的相同頁面
(create locally)
(本地建立)
image
圖像
download
@@ -858,6 +889,12 @@ Generating Link Database
產生連結資料庫
The 404 handler extension requires the link data extension (links.pl).
404 訊息您需要安裝 (links.pl) 擴充模組
Make available offline
Offline
You are currently offline and what you requested is not part of the offline application. You need to be online to do this.
LocalMap
本地地圖
No page id for action localmap
@@ -872,20 +909,6 @@ Self-ban by %s
%s 禁止
You have banned your own IP.
您禁止了自已的 IP Address
OpenID Login
Your identity is saved in a cookie, if you have cookies enabled. Cookies may get lost if you connect from another machine, from another account, or using another software.
Your homepage is set to %s.
You have no homepage set.
Homepage:
Homepage is missing
OpenID error %s
Orphan List
孤立頁面列表
Trail:
@@ -918,6 +941,8 @@ No target wiki was specified in the config file.
設定檔案中沒有設定目標(Target) Wiki
The target wiki was misconfigured.
目標(Target) Wiki 設定錯誤
Upload is limited to %s bytes
You did not answer correctly.
您沒有回答正確的答案
To save this page you must answer this question:
@@ -970,6 +995,10 @@ Static Copy
靜態頁面備份
Back to %s
返回 %s
Edit image in the browser
Summary of your changes:
Copy to %1 succeeded: %2.
%2 複製到 %1 成功
Copy to %1 failed: %2.
@@ -1008,12 +1037,40 @@ Too many instances. Only %s allowed.
太多請求只允許 %s
Please try again later. Perhaps somebody is running maintenance or doing a long search. Unfortunately the site has limited resources, and so we must ask you for a bit of patience.
系統忙碌中請稍後在試一次可能有人正在執行維護動作或長期搜尋
thumb
Error creating thumbnail from non existant page %s.
Can not create thumbnail for file type %s.
Can not create thumbnail for a text document
Could not open %s for writing whilst trying to save image before creating thumbnail. Check write permissions.
Can not create path for thumbnail - %s
Failed to run %1 to create thumbnail: %2
%s ran into an error
%s produced no output
Failed to parse %s.
Timezone
Pick your timezone:
Set
Contents
內容
Create a new page for today
建立今日頁面
Add Translation
Please provide a different page name for the translation.
Added translation: %1 (%2)
Translate %s
@@ -1056,6 +1113,8 @@ Wanted Pages
%s 頁面
%s, referenced from:
%s 引用自:
Web application for offline browsing
Upload of %s file
上傳 %s 檔案
Blog

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,8 @@
#
# This translation was last checked for Oddmuse version 1.215.
#
$ModulesDescription .= '<p>$Id: dutch-utf8.pl,v 1.12 2011/05/17 13:24:13 as Exp $</p>';
use utf8;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/translations/dutch-utf8.pl">dutch-utf8.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Dutch">Dutch</a></p>';
%Translate = split(/\n/,<<END_OF_TRANSLATION);
Include normal pages

View File

@@ -16,7 +16,8 @@
# Create a modules subdirectory in your data directory, and put the
# file in there. It will be loaded automatically.
#
$ModulesDescription .= '<p>$Id: finnish-utf8.pl,v 1.11 2009/06/07 19:30:37 as Exp $</p>';
use utf8;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/translations/finnish-utf8.pl">finnish-utf8.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Finnish">Finnish</a></p>';
%Translate = split(/\n/,<<END_OF_TRANSLATION);
Include normal pages

View File

@@ -3,6 +3,8 @@
# Copyright (c) 2003, 2005 Pierre Gaston
# Copyright (c) 2004, 2005 Christophe Ducamp
# Copyright (c) 2010 Alex Schroeder
# Copyright (c) 2012 Aurélien Desbrières
# Copyright (c) 2012 Hervé Robin
#
# Permission is granted to copy, distribute and/or modify this
# document under the terms of the GNU Free Documentation License,
@@ -17,9 +19,12 @@
# Create a modules subdirectory in your data directory, and put the
# file in there. It will be loaded automatically.
#
# This translation was last checked for Oddmuse version 1.296.
#
$ModulesDescription .= '<p>$Id: french-utf8.pl,v 1.20 2011/02/05 12:29:07 as Exp $</p>';
# This translation was last checked for Oddmuse 2.2.
use utf8;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/translations/french-utf8.pl">french-utf8.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/French">French</a></p>';
%Translate = split(/\n/,<<END_OF_TRANSLATION);
Include normal pages
Comprend les pages normales
@@ -30,9 +35,9 @@ Se connecter
Error
Erreur
%s calls
%s appel
Could not create %s
Création impossible de %s
Création de %s impossible
Invalid UserName %s: not saved.
Nom dutilisateur non valide %s : non sauvegardé.
UserName must be 50 characters or less: not saved
@@ -86,13 +91,13 @@ Page non valide %s
Too many redirections
Trop de redirections
No redirection for old revisions
Pas de redirection pour les versions ancienne
Pas de redirection pour les versions anciennes
Invalid link pattern for #REDIRECT
Mise en forme invalide pour le lien de redirection (#REDIRECT)
Syntaxe invalide pour le lien de redirection (#REDIRECT)
Please go on to %s.
SVP aller a %s.
SVP allez à %s.
Updates since %s
Mises à hour depuis %s
Mises à jour depuis %s
up to %s
jusquà
Updates in the last %s days
@@ -108,7 +113,7 @@ Lister toutes les modifications
Skip rollbacks
Sans les retours en arrière
Include rollbacks
Incluant les retours en arrière
Inclure les retours en arrière
List only major changes
Lister seulement les modifications majeures
Include minor changes
@@ -116,7 +121,7 @@ Inclure les modifications mineures
%s days
%s jours
List later changes
Lister les modifications les plus récentes
Lister les modifications plus récentes
RSS
RSS
RSS with pages
@@ -150,15 +155,15 @@ Tous les changements pour %s
from %s
depuis %s
This page is too big to send over RSS.
Cette page est trop grosse pour être envoyée sur RSS
Cette page est trop grande pour être envoyée sur RSS
History of %s
Historique de %s
Compare
Comparer
Deleted
Suprimé
Supprimé(e)
Mark this page for deletion
Marquer cette page à suprimer
Marquer cette page comme étant à supprimer
No other revisions available
Il ny a pas dautre version
current
@@ -172,15 +177,15 @@ Cible manquante pour le retour en arrière.
Target for rollback is too far back.
La cible du retour en arrière est trop ancienne.
A username is required for ordinary users.
Un nom dutilisateur est nécessaire pour les utilisateurs communs
Un nom dutilisateur est nécessaire pour les utilisateurs normaux
Rolling back changes
Réinitialisation en cours
The two revisions are the same.
Les deux révisions sont les mêmes.
Les deux versions sont identiques.
Editing not allowed for %s.
Edition non autorisée pour %s.
Modification non autorisée pour %s.
Rollback of %s would restore banned content.
Un retour à %s restaurara du texte interdit.
Un retour à %s restaurera du contenu interdit.
Rollback to %s
Retour à %s
%s rolled back
@@ -192,13 +197,13 @@ Index de toutes les pages
Wiki Version
Affiche la version du wiki
Unlock Wiki
Supression du verrou
Suppression du verrou
Password
Mot de passe
Run maintenance
Lancer la maintenance
Unlock site
Déverouiller le site
Déverrouiller le site
Lock site
Verouiller le site
Install CSS
@@ -214,11 +219,11 @@ Actions :
Important pages:
Pages importantes :
To mark a page for deletion, put <strong>%s</strong> on the first line.
Pour marquer une page devant être supprimée, ajoutez <strong>%s</strong> à la première ligne
Pour marquer une page comme étant à supprimer, ajoutez <strong>%s</strong> à la première ligne
[Home]
[Accueil]
redirected from %s
redirigée à partir de %s
redirigé(e) à partir de %s
%s:
%s :
Click to search for references to this page
@@ -240,7 +245,7 @@ La base de données est stockée dans le répertoire temporaire %s
Last edited
Dernière modification
Edited
Modifié
Modifié(e)
by %s
par %s
(diff)
@@ -258,9 +263,9 @@ Voir la version actuelle
View all changes
Voir toutes les modifications
View contributors
Vour les contributeurs
Voir les contributeurs
Homepage URL:
Adresse(URL) du site perso
Adresse(URL) du site personnel
s
s
Save
@@ -276,7 +281,7 @@ f
Replace:
Remplacer :
Delete
Suprimer
Supprimer
Validate HTML
Valider HTML
Validate CSS
@@ -284,11 +289,11 @@ Valider CSS
Last edit
Dernière modification
Difference between revision %1 and %2
Différence (de la révision %1 à %2)
Différence entre les versions %1 et %2
revision %s
révision %s
version %s
current revision
révision actuelle
version actuelle
Last major edit (%s)
Dernière modification majeure (%s)
later minor edits
@@ -298,17 +303,17 @@ Pas de diff disponible.
Old revision:
Ancienne révision :
Changed:
Modifiée :
Modifié(e) :
Deleted:
Suprimé :
Supprimé(e) :
Added:
Ajoutée :
Ajouté(e) :
to
à
Revision %s not available
La version %s nest pas disponible
showing current revision instead
présentation à la place de la version en cours.
présentation à la place de la version en cours
Showing revision %s
Présentation de la version %s
Cannot save a nameless page.
@@ -326,11 +331,11 @@ Ne peut obtenir un verrouillage %s
The lock was created %s.
Le verrouillage a été créé %s.
Maybe the user running this script is no longer allowed to remove the lock directory?
Peut-être lutilisateur éxecutant le logiciel nest plus autorisé à effacer le répertoire utilisé pour le verrouillage ?
Peut-être lutilisateur exécutant le logiciel nest-il plus autorisé à effacer le répertoire utilisé pour le verrouillage ?
This operation may take several seconds...
Cette opération peut prendre quelques secondes...
Forced unlock of %s lock.
Supression forcée du verrou %s.
Suppression forcée du verrou %s.
No unlock required.
La suppression du verrou nest pas nécessaire.
%s hours ago
@@ -350,11 +355,11 @@ just now
Edit Denied
Modification interdite
Editing not allowed: user, ip, or network is blocked.
Modification interdite : lutilisateur, ladresse ip, ou le reseau est bloqué.
Modification interdite : lutilisateur, ladresse ip, ou le réseau est bloqué.
Contact the wiki administrator for more information.
Contactez ladministrateur du wiki pour plus dinformation.
The rule %s matched for you.
La règle %s a fonctionné pour vous.
La règle %s a été appliquée pour vous.
See %s for more information.
Voir %s pour plus dinformation.
Editing not allowed: %s is read-only.
@@ -374,7 +379,7 @@ Résumé :
This change is a minor edit.
Cette modification est une édition mineure.
Cancel
Anuler
Annuler
Replace this file with text
Remplacer ce fichier par un texte
Replace this text with a file
@@ -392,7 +397,7 @@ Vous êtes actuellement éditeur de ce site.
You are a normal user on this site.
Vous êtes un utilisateur normal de ce site.
Your password does not match any of the administrator or editor passwords.
Vote mot de passe ne corespond à aucun de ceux des mots de passe administrateurs ou éditeurs.
Vote mot de passe ne correspond ni au mot de passe administrateur ni au mot de passe éditeur.
Password:
Mot de passe :
This site does not use admin or editor passwords.
@@ -410,7 +415,7 @@ La règle "%1" correspondait à "%2" sur cette page.
Reason: %s.
Raison : %s.
Reason unknown.
Raison inconnu.
Raison inconnue.
Filter:
Filtre :
(for %s)
@@ -418,9 +423,9 @@ Filtre :
%s pages found.
%s pages trouvées.
Malformed regular expression in %s
Expression régulière malformé dans %s
Expression rationnelle mal formulée dans %s
Replaced: %s
Remplacé : %s
Remplacé(e) : %s
Search for: %s
Rechercher : %s
View changes for these pages
@@ -432,9 +437,9 @@ par
Transfer Error: %s
Erreur de Transfert : %s
Browser reports no file info.
Le navigateur signale pas dinformation sur le fichier.
Le navigateur ne signale pas dinformation sur le fichier.
Browser reports no file type.
Le navigateur signale pas de format de fichier.
Le navigateur ne signale pas de type de fichier.
The page contains banned text.
Cette page contient un texte interdit.
No changes to be saved.
@@ -448,7 +453,7 @@ SVP vérifiez si vous avez écrasé ces modifications.
Anonymous
Anonyme
Cannot delete the index file %s.
Impossible de supprimer le fichier index %s.
Impossible de supprimer le fichier index %s.
Please check the directory permissions.
Veuillez vérifier les permissions des répertoires.
Your changes were not saved.
@@ -472,11 +477,11 @@ Enlevez le fichier "maintain" ou patientez.
Expiring keep files and deleting pages marked for deletion
Expiration des fichiers de cache et suppression des pages marquées pour la suppression
not deleted:
non supprimée :
non supprimé(e) :
deleted
supprimé
supprimé(e)
Moving part of the %s log file.
Deplace une partie du fichier de log %s.
Déplace une partie du fichier de log %s.
Could not open %s log file
Impossible douvrir le fichier de log %
Error was
@@ -506,15 +511,15 @@ Trop de connexions par %s
Please do not fetch more than %1 pages in %2 seconds.
Veuillez ne pas télécharger plus de %1 pages toutes les %2 secondes
Check whether the web server can create the directory %s and whether it can create files in it.
Verifiez si le serveur web peut créer le répertoire %s et sil peut créer des fichiers dedans.
Vérifiez si le serveur web peut créer le répertoire %s et sil peut créer des fichiers dedans.
Copy one of the following stylesheets to %s:
Copier une des feuilles de style suivantes sur %s.
Deleting %s
Supression de %s
Suppression de %s
Deleted %s
%s supprimée
%s supprimé(e)
Renaming %1 to %2.
Change %1 en %2.
Renomme %1 en %2.
The page %s does not exist
La page %s n'existe pas
The page %s already exists
@@ -522,15 +527,15 @@ La page %s existe déjà
Cannot rename %1 to %2
Impossible de renommer %1 en %2
Renamed to %s
Renommé en %s
Renommé(e) en %s
Renamed from %s
Renommé à partir de %s
Renommé(e) à partir de %s
Renamed %1 to %2.
%1 a été renommée en %2.
%1 a été renommé(e) en %2.
Immediately delete %s
Supprimer immédiatement %s
Rename %s to:
Renommer %s en :
Renommer %s en :
Learn more...
En savoir plus...
Complete Content
@@ -538,17 +543,17 @@ Contenu Complet
The main page is %s.
La page principale est %s.
Archive:
Archive :
Rebuild BackLink database
Rebâtir les liens de la base de données
Internal Page:
Page Interne :
Pages that link to this page
Pages liées à cette page
The search parameter is missing.
Le paramètre de recherche est manquant
Pages link to %s
Pages liées à %s
Cannot highlight the language %s.
Impossible de surligner la langue %s.
Recent Visitors
@@ -586,33 +591,33 @@ Ve
Sa
Sa
January
Janvier
janvier
February
Février
février
March
Mars
mars
April
Avril
avril
May
Mai
mai
June
Juin
juin
July
Juillet
juillet
August
Août
août
September
Septembre
septembre
October
Octobre
octobre
November
Novembre
novembre
December
Décembre
décembre
set %s
paramétrer %s
unset %s
dé-paramétrer %s
Clustermap
Carte du Faisceau
Pages without a Cluster
@@ -626,85 +631,85 @@ Compilation pour %s
Compilation tag is missing a regular expression.
Une expression régulière manque au tag de compilation.
Extract all dates from the database
Extraire toutes les dates depuis la base de données
Dates
Dates
No dates found.
Aucune date trouvée
Inter links:
InterLiens :
InterLiens :
List spammed pages
Lister les pages spammées
Despamming pages
Suppression des textes indésirables sur les pages.
Spammed pages
Pages spammées
Cannot find revision %s.
Impossible de trouver la version %s.
Revert to revision %1: %2
Retour à la version %1 : %2
Retour à la version %1 : %2
Marked as %s.
Marqué comme %s.
Marqué(e) comme %s.
Cannot find unspammed revision.
Impossible de trouver une version sans texte indésirable.
Recover Draft
Récupérer le brouillon
No text to save
Aucun texte à sauvegarder
Draft saved
Brouillon sauvegardé
Draft recovered
Brouillon récupéré
No draft available to recover
Aucun brouillon à récupérer
Save Draft
Sauvegarder le Brouillon
Draft Cleanup
Nettoyer le Brouillon
%1 was last modified %2 and was kept
%1 a été modifié(e) en dernier et %2 a été conservé(e)
%1 was last modified %2 and was deleted
%1 a été modifié(e) en dernier et %2 a été effacé(e)
Unable to delete draft %s
Impossible d'effacer le brouillon %s
Add Comment
Ajouter Commentaire
Ajouter un commentaire
ordinary changes
modifications ordinaires
Matching page names:
Pages correspondant aux noms :
Email:
Email :
E-mail :
Could not find %1.html template in %2
Impossible de trouver le modèle %1.html dans %2
Only Editors are allowed to see this hidden page.
Seuls les Editeurs ont l'autorisation de voir cette page cachée.
Seuls les Éditeurs ont l'autorisation de voir cette page cachée.
Only Admins are allowed to see this hidden page.
Seuls les Administrateurs ont l'autorisation de voir cette page cachée.
Index
Index
Languages:
Langues :
Langues :
Show!
Voir !
Voir !
Define
Définir
Full Link List
Liste Complète des Liens
List of locked pages
Liste des pages verrouillées
Pages tagged with %s
Pages taguées avec %s
Template without parameters
Gabarit sans paramètres
Modèle sans paramètres
The template %s is either empty or does not exist.
Le gabarit %s est soit vide soit n'existe pas.
Le modèle %s est soit vide soit n'existe pas.
-- defined on %s
-- défini sur %s
-- défini(e) sur %s
Local names defined on %1: %2
Noms locaux définis sur %1 : %2
Locked Pages
Pages Verrouillées
Register for %s
Enregistrer pour %s
Please choose a username of the form "FirstLast" using your real name.
@@ -722,7 +727,7 @@ Votre enregistrement pour %s a été soumis.
Please allow time for the webmaster to approve your request.
SVP accordez un peu de temps au webmestre pour valider votre demande.
An email has been sent to "%s" with further instructions.
Un email a été envoyé à "%s" pour de plus amples instructions.
Un e-mail a été envoyé à "%s" pour de plus amples instructions.
There was an error saving your registration.
Il y a eu une erreur au moment de sauvegarder votre enregistrement.
An account was created for %s.
@@ -732,23 +737,23 @@ Se connecter sur %s
Username and/or password are incorrect.
Le nom d'utilisateur et/ou le mot de passe sont incorrects.
Logged in as %s.
Connecté sous %s.
Connecté(e) sous %s.
Logout of %s
Déconnexion de %s
Logout of %s?
Déconnexion de %s ?
Déconnexion de %s ?
Logged out of %s
Déconnecté de %s
Déconnecté(e) de %s
You are now logged out.
Vous êtes maintenant déconnecté.
Vous êtes maintenant déconnecté(e).
Register a new account
Enregistrer un nouveau compte.
Logout
Se déconnecter
Who am I?
Qui suis-je ?
Qui suis-je ?
Forgot your password?
Mot de passe oublié ?
Mot de passe oublié ?
Change your password
Changer votre mot de passe
Approve pending registrations
@@ -758,17 +763,17 @@ Confirmation d'Enregistrement pour %s
%s, your registration has been approved. You can now use your password to login and edit this wiki.
%s, votre enregistrement a été accepté. Vous pouvez désormais utiliser votre mot de passe pour vous connecter et éditer ce wiki.
Confirmation failed. Please email %s for help.
Echec sur la confirmation. SVP envoyez un email à %s pour de l'aide.
Échec sur la confirmation. SVP envoyez un e-mail à %s pour obtenir de l'aide.
Who Am I?
Qui suis-je ?
Qui suis-je ?
You are logged in as %s.
Vous êtes connecté en tant que %s.
Vous êtes connecté(e) en tant que %s.
You are not logged in.
Vous n'êtes pas connecté.
Vous n'êtes pas connecté(e).
Reset Password
Réinitialiser le mot de passe.
The password for %s was reset. It has been emailed to the address on file.
Le mot de passe pour %s a été réinitialisé. Il a été envoyé à l'adresse sur le fichier.
Le mot de passe pour %s a été réinitialisé. Il a été envoyé à l'adresse spécifiée sur le fichier.
There was an error resetting the password for %s.
Il y a eu une erreur de réinitialisation du mot de passe pour %s.
The username "%s" does not exist.
@@ -776,11 +781,11 @@ Le nom d'utilisateur "%s" n'existe pas.
Reset Password for %s
Réinitialiser le mot de passe pour %s
Reset Password?
Réinitialisation Mot de Passe ?
Réinitialisation du Mot de Passe ?
Change Password for %s
Modification Mot de Passe pour %s
Modification du Mot de Passe pour %s
Change Password?
Modification Mot de Passe ?
Modification du Mot de Passe ?
Your current password is incorrect.
Votre Mot de Passe est incorrect.
Your password has been changed.
@@ -788,9 +793,9 @@ Votre mot de passe a été modifié.
Approve Pending Registrations for %s
Accepter les Enregistrements en Attente pour %s
%s has been approved.
%s a été accepté.
%s a été accepté(e).
There was an error approving %s.
Il y a eu une erreur à accepter %s.
Il y a eu une erreur en acceptant %s.
<ul>
<ul>
<li>%1 - %2</li>
@@ -802,15 +807,15 @@ Il n'y a pas d'enregistrements en attente.
Invalid Mail %s: not saved.
Ladresse e-mail %s nest pas valide
unsubscribe
désabonner
se désabonner
subscribe
abonner
s'abonner
%s appears to be an invalid mail address
Ladresse e-mail %s nest pas valide
Your mail subscriptions
Vôtre abonnements
Votre abonnements
All mail subscriptions
Tous les abonnements
Tous les abonnements e-mail
Subscriptions
Abonnements
Show
@@ -818,7 +823,7 @@ Voir
Subscriptions for %s:
Abonnements pour %s :
Unsubscribe
Désabonner
Se désabonner
There are no subscriptions for %s.
Il ny a pas dabonnements pour %s.
Change email address
@@ -826,45 +831,45 @@ Changer ladresse e-mail
Mail addresses are linked to unsubscription links.
Les adresses e-mail sont liées au désabonnement.
Subscribe to %s.
Abonner %s.
S'abonner %s.
Subscribe
Abonner
S'abonner
Subscribed %s to the following pages:
%s est abonné aux pages suivantes :
The remaining pages do not exist.
Les pages restantes nexistent pas (ou plus).
Unsubscribed %s from the following pages:
%s a désabonné les pages suivantes :
%s est désabonné aux pages suivantes :
You linked more than %s times to the same domain. It would seem that only a spammer would do this. Your edit is refused.
Vous avez créé plus de %s liens vers le même domaine. Il semble que seuls les spammeurs font cela. Votre édition est donc refusée.
%s is not a legal name for a namespace
%s nest pas un nom valide pour un espace de noms
Namespaces
Espace de noms
Espaces de noms
Getting page index file for %s.
Récupération du fichier d'index de %s.
Near links:
Liens de proximité :
Liens de proximité :
Search sites on the %s as well
Rechercher aussi les sites présents sur %s
Fetching results from %s:
Récupération des résultats à partir de %s :
Récupération des résultats à partir de %s :
Near pages:
Pages à proximité :
Pages à proximité :
Include near pages
Inclure les pages de proximité
EditNearLinks
EditerLiensDeProximité
ÉditerLiensDeProximité
The same page on other sites:
La même page sur d'autres sites :
La même page sur d'autres sites :
(create locally)
(créer localement)
image
image
download
télécharger
Backlinks
Liens en retour
Clearing Cache
Nettoyage du cache.
Done.
@@ -880,7 +885,7 @@ Aucune page id pour actionner la carte locale
Requested page %s does not exist
La page demandée %s n'existe pas
Local Map for %s
CarteLocale pour %s
Carte Locale pour %s
view
voir
Self-ban by %s
@@ -888,23 +893,23 @@ Auto-bannissement par %s
You have banned your own IP.
Vous avez banni votre propre IP.
OpenID Login
Identification OpenID
Your identity is saved in a cookie, if you have cookies enabled. Cookies may get lost if you connect from another machine, from another account, or using another software.
Votre identité est sauvegardée dans un cookie, si vous avez activé les cookies. Vos cookies seront perdus si vous vous connectez depuis une autre machine, sur un autre compte ou si vous utilisez un autre navigateur.
Your homepage is set to %s.
Votre page d'accueil est établie sur %s.
You have no homepage set.
Votre page d'acceuil n'est pas établie.
Homepage:
Page d'accueil :
Homepage is missing
La page d'accueil est manquante
OpenID error %s
Erreur OpenID %s
Orphan List
Liste Orpheline
Trail:
Trace :
Trace :
None
Aucune
Type
@@ -914,9 +919,9 @@ Lien permanent vers "%s"
anchor first defined here: %s
première ancre définie ici : %s
the page %s also exists
la page %s existe aussi
la page %s existe également
There was an error generating the pdf for %s. Please report this to webmaster, but do not try to download again as it will not work.
Il y a eu une erreur en générant le pdf pour %s. SVP, rendez-compte de cela au webmestre, mais n'essayez pas de télécharger à nouveau, car cela ne fonctionnera pas.
Il y a eu une erreur en générant le pdf pour %s. SVP, rendez compte de cela au webmestre, mais n'essayez pas de télécharger à nouveau, car cela ne fonctionnera pas.
Someone else is generating a pdf for %s. Please wait a minute and then try again.
Quelqu'un d'autre est en train de générer un pdf pour %S. SVP, attendez une minute puis essayez de nouveau.
Download this page as PDF
@@ -930,23 +935,23 @@ Portrait
Publish %s
Publier %s
No target wiki was specified in the config file.
La cible du wiki n'est pas spécifiée dans le fichier de configuration.
The target wiki was misconfigured.
La cible du wiki a été mal configurée.
Upload is limited to %s bytes
Le téléversement est limité à %s bytes
You did not answer correctly.
Vous navez pas répondu correctement.
To save this page you must answer this question:
Il faut réponder a cette question pour sauvegarder la page :
Vous devez répondre à cette question pour sauvegarder la page :
Please type the following two words:
Tapez s'il vous plaît les deux mots suivants :
Please answer this captcha:
Répondez à ce captcha s'il vous plaît :
Referrers
Introducteurs
Référants
All Referrers
Tous les Introducteurs
Tous les Référants
Tag
Tag
Rebuild index for searching
@@ -956,55 +961,55 @@ Nuage de Tags
Search::FreeText is not available on this system.
Search::FreeText n'est pas disponible sur ce système.
Rebuilding index not done.
Reconstruction index non effectuée.
Reconstruction de l'index non effectuée.
(Rebuilding the index can only be done once every 12 hours.)
(La reconstruction de l'index ne peut être faite qu'une fois toutes les 12 heures.)
(La reconstruction de l'index ne peut être effectuée qu'une fois toutes les 12 heures.)
New Pages for Indexed Search
Nouvelle pages pour indexer la recherche
List changes since %s
Changement depuis %s
Changements dans la liste depuis %s
...
...
Search term missing.
Terme de la recherche manquant.
Result pages:
Pages de résultats :
Pages de résultats :
(%s results)
(%s résultats)
Tags:
Tags :
Tags: %s.
Tags : %s
No tags
Pas de tags
Page list for %s
Liste des pages pour %s
Slideshow:%s
Diaporama : %s
Diaporama : %s
Index of all small pages
Index de toutes les pages de petite taille
Static Copy
Copie Statique
Back to %s
Retour à %s
Edit image in the browser
Éditer l'image dans le navigateur
Summary of your changes:
Résumé de tous vos changements :
Copy to %1 succeeded: %2.
Copie vers %1 réussie : %2.
Copie vers %1 réussie : %2.
Copy to %1 failed: %2.
Copie vers %1 échouée : %2.
Copie vers %1 échouée : %2.
Feed for this tag
Flux pour ce tag
Rebuild tag index
Rebâtir votre index de tags
list tags
liste de tags
tag cloud
nuage de tags
Alternatively, use one of the following templates:
Alternativement, utilisez un des modèles suivants :
Alternativement, utilisez un des modèles suivants :
Thread: %s
Fil: %s
ID parameter is missing.
@@ -1012,7 +1017,7 @@ Le paramètre ID est manquant.
Thread %s does not exist.
Le fil %s n'existe pas.
Page %s does not contain a thread.
La page %s ne contient pas de fil.
La page %s ne contient aucun fil.
Add
Ajouter
URL parameter is missing.
@@ -1020,53 +1025,53 @@ Le paramètre URL est manquant.
Add to %s thread
Ajouter %s au fil
Below:
En-dessous :
En-dessous :
URL:
URL :
URL :
Name:
Nom :
Nom :
Too many instances. Only %s allowed.
Trop d'instances. %s seulement est autorisée
Please try again later. Perhaps somebody is running maintenance or doing a long search. Unfortunately the site has limited resources, and so we must ask you for a bit of patience.
Essayez plus tard s'il vous plaît. Peut-être que quelqu'un effectue une maintenance ou une recherche volumineuse. Malheureusement le site a des ressources limitées, nous vous demandons de faire preuve d'un peu de patience.
Timezone
Fuseau horaire
Pick your timezone:
Sélectionnez votre fuseau horaire
Set
Ajusté
Contents
Contenus
Create a new page for today
Ajouter une page nouvelle pour aujourdhui
Add Translation
Àjouter une traduction
Ajouter une traduction
Please provide a different page name for the translation.
Donnez s'il vous plait un nom différent à votre traduction
Added translation: %1 (%2)
Traduction ajoutée : %1 (%2)
Translate %s
Traduire %s
Thank you for writing a translation of %s.
Merci pour traduir %s.
Merci pour la traduction de %s.
Please indicate what language you will be using.
Merci d'indiquer quelle langue vous allez utiliser.
Language is missing
La langue est manquante
Suggested languages:
Langues suggérées
Please indicate a page name for the translation of %s.
Indiquez s'il vous plaît un nom de page pour la traduction de %s.
More help may be available here: %s.
Plus d'aide disponible ici : %s.
Translated page:
Page traduite :
This page is a translation of %s.
Cette page est une traduction de %s.
The translation is up to date.
La traduction est à jour.
The translation is outdated.
La traduction n'est pas à jour.
La traduction n'est plus à jour.
The page does not exist.
La page n'existe pas.
http://search.barnesandnoble.com/booksearch/isbninquiry.asp?ISBN=%s
@@ -1080,23 +1085,23 @@ http://www.pricescan.com/books/BookDetail.asp?isbn=%s
search
chercher
Wanted Pages
Pages recherchées
%s pages
%s pages
%s, referenced from:
%s, référencé(e) depuis :
Upload of %s file
Téléversement du fichier %s
Blog
Blog
Matching pages:
Pages correspondantes :
Pages correspondantes :
New
Nouveau
Nouveau
Edit %s.
Editer %s.
Éditer %s.
Title:
Titre :
Tags:
Tags :
END_OF_TRANSLATION

View File

@@ -1,7 +1,7 @@
# UTF-8 encoded German translation file for use with Oddmuse
#
# Copyright (c) 2003 Karl Loncarek <karl@loncarek.de>
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2009, 2010 Alex Schröder <alex@gnu.org>
# Copyright (c) 2003-2012 Alex Schröder <alex@gnu.org>
#
# Permission is granted to copy, distribute and/or modify this document under
# the terms of the GNU Free Documentation License, Version 1.2 or any later
@@ -15,7 +15,10 @@
# Create a modules subdirectory in your data directory, and put the file in
# there. It will be loaded automatically.
#
$ModulesDescription .= '<p>$Id: german-utf8.pl,v 1.30 2011/02/05 12:40:38 as Exp $</p>';
use utf8;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/translations/german-utf8.pl">german-utf8.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/German">German</a></p>';
%Translate = split(/\n/,<<END_OF_TRANSLATION);
Include normal pages
Mit normalen Seiten
@@ -27,8 +30,8 @@ Error
Fehler
%s calls
%s Aufrufe
Could not create %s
Konnte %s nicht erzeugen
Cannot create %s
%s kann nicht erstellt werden
Invalid UserName %s: not saved.
Ungültiger Benutzername %s: nicht gespeichert.
UserName must be 50 characters or less: not saved
@@ -197,8 +200,6 @@ Unlock site
Wiki entsperren
Lock site
Wiki sperren
Install CSS
CSS installieren
Unlock %s
%s entsperren
Lock %s
@@ -315,8 +316,6 @@ Cannot open %s
%s kann nicht geöffnet werden
Cannot write %s
%s kann nicht geschrieben werden
Cannot create %s
%s kann nicht erstellt werden
Could not get %s lock
Die %s Sperre konnte nicht gesetzt werden
The lock was created %s.
@@ -503,8 +502,6 @@ Please do not fetch more than %1 pages in %2 seconds.
Bitte rufen sie nicht mehr als %1 Seiten in %2 Sekunden auf.
Check whether the web server can create the directory %s and whether it can create files in it.
Vielleicht kann der Webserver das Verzeichnis %s nicht anlegen oder es wurde schon angelegt, aber der Webserver kann darin keine neuen Dateien anlegen.
Copy one of the following stylesheets to %s:
Eines der folgenden Style Sheets kann auf die %s Seite kopiert werden:
Deleting %s
%s löschen
Deleted %s
@@ -621,6 +618,12 @@ Compilation for %s
Zusammenstellung für %s
Compilation tag is missing a regular expression.
Der tag für die Zusammenstellung benötigt noch ein Suchmuster.
Install CSS
CSS installieren
Copy one of the following stylesheets to %s:
Eines der folgenden Style Sheets kann auf die %s Seite kopiert werden:
Reset
Zurück setzen
Extract all dates from the database
Alle Daten aus der Datenbank extrahieren
Dates
@@ -669,6 +672,14 @@ ordinary changes
normale Änderungen
Matching page names:
Übereinstimmende Seitennamen:
Fix character encoding
Zeichenkodierung korrigieren
no summary available
keine Zusammenfassug vorhanden
page was marked for deletion
die Seite war zum Löschen freigegeben
Oddmuse
Oddmuse
Email:
Email:
Could not find %1.html template in %2
@@ -683,6 +694,22 @@ Languages:
Sprachen:
Show!
Zeigen!
LaTeX export
LaTeX Export
An uploaded file cannot be rendered as LaTeX.
Ein hochgeladene Datei kann nicht mit LaTeX dargestellt werden.
Exporting of journal pages to LaTeX is not supported.
Journalseiten können nicht für LaTeX exportiert werden.
Exporting of RSS feeds to LaTeX is not supported.
RSS Feeds können nicht für LaTeX exportiert werden.
Exporting of search results to LaTeX is not supported.
Suchresultate können nicht für LaTeX exportiert werden.
Exporting of redirections to LaTeX is not supported.
Umleitungen können nicht für LaTeX exportiert werden.
Exporting of named entity reference to LaTeX is not supported.
Benannte Zeichen können nicht für LaTeX exportiert werden.
Exporting of images to LaTeX is not supported.
Bilder können nicht für LaTeX exportiert werden.
Define
Definieren
Full Link List
@@ -699,6 +726,14 @@ Die %s Vorlage ist entweder leer oder existiert gar nicht.
-- definiert auf der Seite %s
Local names defined on %1: %2
Der lokale Namen %2 wurde auf der Seite %1 definiert
Name:
Name:
URL:
URL:
Define Local Names
Lokalen Namen definieren
Define external redirect:
Umleitung auf eine externe Seite definieren:
Locked Pages
Gesperrte Seiten
Register for %s
@@ -869,6 +904,12 @@ Generating Link Database
Verweis Datenbank wird angelegt
The 404 handler extension requires the link data extension (links.pl).
Die 404 handler Erweiterung benötigt die Link Data Erweiterung (links.pl).
Make available offline
Offline zur Verfügung stellen
Offline
Offline
You are currently offline and what you requested is not part of the offline application. You need to be online to do this.
Sie sind im Moment offline und was sie verlangt haben, ist nicht Teil der Offline Applikation. Hierfür müssen sie online sein.
LocalMap
LocalMap
No page id for action localmap
@@ -883,20 +924,6 @@ Self-ban by %s
%s hat sich selber verbannt.
You have banned your own IP.
Sie haben ihre eigene IP Nummer verbannt.
OpenID Login
OpenID Login
Your identity is saved in a cookie, if you have cookies enabled. Cookies may get lost if you connect from another machine, from another account, or using another software.
Die Identität wird in einem Cookie gespeichert, falls diese erlaubt sind. Cookies gehen verloren, wenn ein anderer Rechner, eine anderes Konto, oder ein anderer Browser verwendet wird.
Your homepage is set to %s.
Homepage wurde auf %s gesetzt.
You have no homepage set.
Keine Homepage gesetzt.
Homepage:
Homepage:
Homepage is missing
Homepage fehlt
OpenID error %s
OpenID Fehler %s
Orphan List
Liste der Waisen
Trail:
@@ -1025,6 +1052,26 @@ Too many instances. Only %s allowed.
Es laufen schon %s Wiki Prozesse gleichzeitig auf diesem Server. Mehr sind leider nicht erlaubt.
Please try again later. Perhaps somebody is running maintenance or doing a long search. Unfortunately the site has limited resources, and so we must ask you for a bit of patience.
Versuchen Sie es später nocheinmal. Vielleicht werden gerade Wartungsarbeiten durchgeführt, oder ein Suchbefehl nimmt gerade viel Zeit in Anspruch. Leider sind die Resourcen des Rechners limitiert; wir bitten Sie deshalb um etwas Geduld.
thumb
Error creating thumbnail from non existant page %s.
Can not create thumbnail for file type %s.
Can not create thumbnail for a text document
Could not open %s for writing whilst trying to save image before creating thumbnail. Check write permissions.
Can not create path for thumbnail - %s
Failed to run %1 to create thumbnail: %2
%s ran into an error
%s hat einen Fehler festgestellt
%s produced no output
%s hat nichts ausgegeben
Failed to parse %s.
Die Ausgabe von %s wurde nicht verstanden
Timezone
Zeitzone
Pick your timezone:
@@ -1081,6 +1128,8 @@ Gewünschte Seiten
%s Seiten
%s, referenced from:
%s, referenziert von:
Web application for offline browsing
Offline Webapplikation
Upload of %s file
Hochladen der %s Datei
Blog

View File

@@ -15,7 +15,8 @@
# Create a modules subdirectory in your data directory, and put the
# file in there. It will be loaded automatically.
#
$ModulesDescription .= '<p>$Id: greek-utf8.pl,v 1.2 2009/06/07 19:30:37 as Exp $</p>';
use utf8;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/translations/greek-utf8.pl">greek-utf8.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Greek">Greek</a></p>';
%Translate = split(/\n/,<<END_OF_TRANSLATION);
Include normal pages
Με τις κανονικές σελίδες.

View File

@@ -17,7 +17,8 @@
#
# This translation was last checked for Oddmuse version 1.195.
#
$ModulesDescription .= '<p>$Id: hebrew-utf8.pl,v 1.11 2009/06/07 19:30:37 as Exp $</p>';
use utf8;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/translations/hebrew-utf8.pl">hebrew-utf8.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Hebrew">Hebrew</a></p>';
%Translate = split(/\n/,<<END_OF_TRANSLATION);
Include normal pages

View File

@@ -15,7 +15,8 @@
# Create a modules subdirectory in your data directory, and put the
# file in there. It will be loaded automatically.
#
$ModulesDescription .= '<p>$Id: italian-utf8.pl,v 1.11 2009/06/07 19:30:37 as Exp $</p>';
use utf8;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/translations/italian-utf8.pl">italian-utf8.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Italian">Italian</a></p>';
%Translate = split(/\n/,<<END_OF_TRANSLATION);
Include normal pages
Includi le pagine normali

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More