Compare commits

..

41 Commits
2.2.5 ... 2.2.6

Author SHA1 Message Date
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 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
19 changed files with 2341 additions and 1167 deletions

View File

@@ -1,12 +1,12 @@
;;; oddmuse-curl.el -- edit pages on an Oddmuse wiki using curl
;;
;; Copyright (C) 20062013 Alex Schroeder <alex@gnu.org>
;; 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/cgi-bin/wiki/OddmuseMode
;; 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
@@ -45,22 +45,16 @@
(require 'goto-addr)
(require 'info)
(defcustom oddmuse-directory "~/emacs/oddmuse"
(defcustom oddmuse-directory "~/.emacs.d/oddmuse"
"Directory to store oddmuse pages."
:type '(string)
:group 'oddmuse)
(defcustom oddmuse-wikis
'(("TestWiki" "http://www.emacswiki.org/cgi-bin/test"
utf-8 "question" nil)
("EmacsWiki" "http://www.emacswiki.org/cgi-bin/emacs"
'(("EmacsWiki" "http://www.emacswiki.org/cgi-bin/emacs"
utf-8 "uihnscuskc" nil)
("CommunityWiki" "http://www.communitywiki.org/cw"
utf-8 "question" nil)
("OddmuseWiki" "http://www.oddmuse.org/cgi-bin/oddmuse"
utf-8 "question" nil)
("CampaignWiki" "http://www.campaignwiki.org/wiki/NameOfYourWiki"
utf-8 "ts" nil))
utf-8 "question" nil))
"Alist mapping wiki names to URLs.
The elements in this list are:
@@ -160,15 +154,15 @@ It must print the RSS 3.0 text format to stdout.
(defvar oddmuse-post-command
(concat "curl --silent --write-out '%{http_code}'"
" --form title=%t"
" --form summary=%s"
" --form username=%u"
" --form password=%p"
" --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")
" --form text='<-'"
" '%w'")
"Command to use for publishing pages.
It must accept the page on stdin.
@@ -397,11 +391,11 @@ Font-locking is controlled by `oddmuse-markup-functions'.
("%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)
(shell-quote-argument
(symbol-value (cdr pair)))
(symbol-value (cdr pair))
command t t))))
command))
@@ -450,13 +444,14 @@ Use a prefix argument to force a reload of the page."
(pop-to-buffer (get-buffer name))
(let* ((wiki-data (assoc wiki oddmuse-wikis))
(url (nth 1 wiki-data))
(oddmuse-page-name pagename)
(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)
@@ -474,8 +469,9 @@ Use a prefix argument to force a reload of the page."
"Figure out what page we need to visit
and call `oddmuse-edit' on it."
(interactive "P")
(let ((pagename (if arg (oddmuse-read-pagename oddmuse-wiki)
(oddmuse-pagename-at-point))))
(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)))
@@ -494,17 +490,17 @@ and call `oddmuse-edit' on it."
(defun oddmuse-pagename-at-point ()
"Page name at point."
(let ((pagename (word-at-point)))
(cond ((oddmuse-current-free-link-contents))
((oddmuse-wikiname-p pagename)
pagename)
(t
(error "No link found at point")))))
(or (oddmuse-current-free-link-contents)
(oddmuse-wikiname-p pagename))))
(defun oddmuse-wikiname-p (pagename)
"Whether PAGENAME is WikiName or not."
(let (case-fold-search)
(string-match (concat "^" oddmuse-link-pattern "$") pagename)))
(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")
@@ -519,7 +515,7 @@ 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."
(message "%s..." mesg)
(message "%s using %s..." mesg command)
;; If ON-REGION, the resulting HTTP CODE is found in BUF, so check
;; that, too.
(if (and (= 0 (if on-region

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

@@ -237,9 +237,6 @@ a.near:link {
a.near:visited {
color:#550;
}
a.tag:before {
content:"\2601\ ";
}
ol, ul, dl {
padding-top:0.5em;
}

View File

@@ -0,0 +1,169 @@
# 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
By default, Oddmuse disperses page data files into 27 directories
based on the first character of the page name. The directories are "A"
to "Z", and "other". If you use your wiki as a blog, all the pages
starting with a date end up in "other". If your page names start with
letters other than "A" to "Z", all the pages end up in "other". If you
are using comment pages, all your comment pages end in "C". This can
turn into a problem if you reach ten thousand pages and more in a
single directory.
=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();
}

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

@@ -44,6 +44,6 @@ sub DuckDuckGoSearchInit {
}
sub DoDuckDuckGoSearch {
my $search = GetParam('search', undef);
my $search = UrlEncode(GetParam('search', undef));
print $q->redirect({-uri=>"https://www.duckduckgo.com/?q=$search+site%3A$DuckDuckGoSearchDomain"});
}

1131
modules/joiner.pl Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -78,7 +78,8 @@ sub NewQuestionaskerDoPost {
print GetHeader('', T('Edit Denied'), undef, undef, '403 FORBIDDEN');
print $q->p(T('You did not answer correctly.'));
print GetFormStart(), QuestionaskerGetQuestion(1),
(map { $q->hidden($_, '') }
(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

@@ -1,4 +1,4 @@
# Copyright (C) 2004-2013 Alex Schroeder <alex@gnu.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
@@ -35,6 +35,7 @@ sub DoStatic {
}
CreateDir($StaticDir);
%StaticFiles = ();
print '<p>' unless $raw;
StaticWriteFiles();
print '</p>' unless $raw;
PrintFooter() unless $raw;
@@ -56,15 +57,21 @@ 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()) {
if ($StaticAlways > 1
or GetParam('html', 0)
or $html
or PageIsUploadedFile($id)) {
StaticWriteFile($id);
StaticWriteFile($id, $html);
}
}
if ($StaticAlways > 1 or $html) {
StaticWriteCss();
}
}
sub StaticScriptLink {
@@ -120,15 +127,19 @@ sub StaticFileName {
}
sub StaticWriteFile {
my $id = shift;
my ($id, $html) = @_;
my $raw = GetParam('raw', 0);
my $filename = StaticFileName($id);
OpenPage($id);
my ($mimetype, $encoding, $data) = $Page{text} =~ /^\#FILE ([^ \n]+) ?([^ \n]*)\n(.*)/s;
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 ";
@@ -141,7 +152,6 @@ sub StaticWriteFile {
sub StaticFile {
my ($id, $type, $data) = @_;
require MIME::Base64;
binmode(F);
print F MIME::Base64::decode($data);
}
@@ -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

@@ -142,7 +142,7 @@ Go!
(minor)
(次要的)
rollback
new
新增
All changes for %s
@@ -168,13 +168,13 @@ 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.
@@ -182,9 +182,9 @@ Editing not allowed for %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
@@ -644,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.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
# 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/>.
require 't/test.pl';
package OddMuse;
use Test::More tests => 10;
use utf8; # tests contain UTF-8 characters and it matters
clear_pages();
update_page('HomePage', 'Das ist ein Ei.');
ok(-f GetPageFile('HomePage'), 'page file');
update_page('HomePage', 'This is an egg.');
ok(-f GetKeepFile('HomePage', 1), 'keep file');
update_page('ホームページ', 'これが卵です。');
ok(-f GetPageFile('ホームページ'), 'Japanese page file');
update_page($StyleSheetPage, '/* nothing to see */', '', 0, 1);
ok(-f GetPageFile($StyleSheetPage), 'locked page file');
ok(-f GetLockedPageFile($StyleSheetPage), 'page lock');
add_module('balanced-page-directories.pl');
test_page(get_page('HomePage'), 'This is an egg.');
ok(-f GetKeepFile('HomePage', 1), 'keep file');
test_page(get_page('ホームページ'), 'これが卵です。');
ok(-f GetLockedPageFile($StyleSheetPage), 'page lock');
# create a new page
test_page(update_page('サイトマップ', '日本語ユーザーに向けて'),
'日本語ユーザーに向けて');

View File

@@ -1,24 +1,20 @@
# Copyright (C) 2006 Alex Schroeder <alex@emacswiki.org>
# Copyright (C) 20062014 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/>.
require 't/test.pl';
package OddMuse;
use Test::More tests => 35;
use Test::More tests => 36;
clear_pages();
AppendStringToFile($ConfigFile, "\$CommentsPrefix = 'Comments on ';\n");
@@ -89,11 +85,17 @@ test_page(get_page('Comments_on_Yadda'), 'This is my comment\.', '-- Alex');
test_page(get_page('action=rc raw=1'), 'title: Comments on Yadda',
'description: This is my comment.', 'generator: Alex');
# homepage
get_page('title=Comments_on_Yadda', 'aftertext=This%20is%20another%20comment.',
'username=Alex', 'homepage=http%3a%2f%2fwww%2eoddmuse%2eorg%2f');
xpath_test(get_page('Comments_on_Yadda'),
'//p[contains(text(),"This is my comment.")]',
'//a[@class="url http outside"][@href="http://www.oddmuse.org/"][text()="Alex"]');
# variant without protocol
get_page('title=Comments_on_Yadda', 'aftertext=This%20is%20another%20comment.',
'username=Berta', 'homepage=alexschroeder%2ech');
xpath_test(get_page('Comments_on_Yadda'),
'//a[@class="url http outside"][@href="http://alexschroeder.ch"][text()="Berta"]');
my $textarea = '//textarea[@name="aftertext"][@id="aftertext"]';
xpath_test(get_page('Comments_on_Yadda'), $textarea);

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2011 Alex Schroeder <alex@gnu.org>
# Copyright (C) 20112014 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
@@ -14,7 +14,7 @@
require 't/test.pl';
package OddMuse;
use Test::More tests => 34;
use Test::More tests => 35;
clear_pages();
@@ -38,7 +38,7 @@ test_page($page, '2011-12-17', '2011-12-16', '2011-12-15',
test_page_negative($page, '2011-12-12', '2011-12-11', '2011-12-10',
'2011-12-09', '2011-12-08');
xpath_test($page, '//a[@href="http://localhost/wiki.pl?action=more;num=5;regexp=^\d\d\d\d-\d\d-\d\d;search=;mode=;offset=5"][text()="More..."]');
xpath_test($page, '//a[@href="http://localhost/wiki.pl?action=more;num=5;regexp=%5e%5cd%5cd%5cd%5cd-%5cd%5cd-%5cd%5cd;search=;mode=;offset=5"][text()="More..."]');
# check that the link for more actually works
@@ -60,7 +60,12 @@ test_page($page, '2011-12-13', '2011-12-12', '2011-12-11',
'2011-12-10', '2011-12-09');
xpath_test($page, '//a[text()="More..."]');
# one las check
# one last check
xpath_test_negative(get_page("action=more num=5 offset=6 "),
'//a[text()="More..."]');
# check for unescaped URL
$page = update_page('Plus', "Using a plus:\n\n<journal 5 \"^.+\">");
xpath_test($page, '//a[text()="More..."][@href="http://localhost/wiki.pl?action=more;num=5;regexp=%5e.%2b;search=;mode=;offset=5"]');

View File

@@ -55,3 +55,7 @@ test_page(update_page('test', 'answer new question', undef, undef, undef,
test_page(get_page('Comments_on_test'),
'label for="username"',
'say hi');
# test for corruption of Unicode text
update_page('Umlaute', '<Schröder>');
test_page($redirect, '&lt;Schröder&gt;')

View File

@@ -1,21 +1,22 @@
# Copyright (C) 2007, 2008, 2009 Alex Schroeder <alex@gnu.org>
# Copyright (C) 20072014 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/>.
require 't/test.pl';
package OddMuse;
use Test::More tests => 29;
use utf8;
use Test::More tests => 36;
clear_pages();
add_module('static-copy.pl');
@@ -114,16 +115,37 @@ xpath_test(update_page('HomePage', "Static: [[image:Trogs]]"),
# delete the static pages and regenerate it
ok(unlink("$DataDir/static/Trogs.svgz"), "Deleted $DataDir/static/Trogs.svgz");
ok(unlink("$DataDir/static/Logo.png"), "Deleted $DataDir/static/Logo.png");
test_page(get_page('action=static raw=1 pwd=foo'), "Trogs", "Logo");
ok(-f "$DataDir/static/Trogs.svgz", "$DataDir/static/Trogs.svgz exists");
ok(-f "$DataDir/static/Logo.png", "$DataDir/static/Logo.png exists");
ok(! -f "$DataDir/static/HomePage.html", "$DataDir/static/HomePage.html does not exist");
test_page(get_page('action=static raw=1 pwd=foo html=1'), "Trogs", "Logo", "HomePage");
ok(-f "$DataDir/static/Trogs.svgz", "$DataDir/static/Trogs.svgz exists");
ok(-f "$DataDir/static/Logo.png", "$DataDir/static/Logo.png exists");
ok(-f "$DataDir/static/HomePage.html", "$DataDir/static/HomePage.html exists");
# Make sure spaces are translated to underscores (fixed in image.pl)
# StaticWriteFiles must write uploaded files only (since $StaticAlways = 1)
$page = get_page('action=static raw=1 pwd=foo');
test_page($page, "Trogs", "Logo"); # Remember, a rollback has restored Logo.png
test_page_negative($page, "HomePage"); # since it an ordinary page
ok(-s "$DataDir/static/Trogs.svgz", "$DataDir/static/Trogs.svgz has nonzero size");
ok(-s "$DataDir/static/Logo.png", "$DataDir/static/Logo.png has nonzero size");
ok(! -e "$DataDir/static/HomePage.html", "$DataDir/static/HomePage.html does not exist");
# force generation of HomePage using html=1
$page = get_page('action=static raw=1 pwd=foo html=1');
test_page($page, "Trogs", "Logo", "HomePage");
test_page_negative($page, "no data"); # must not skip HomePage!
ok(-s "$DataDir/static/Trogs.svgz", "$DataDir/static/Trogs.svgz has nonzero size");
ok(-s "$DataDir/static/Logo.png", "$DataDir/static/Logo.png has nonzero size");
ok(-s "$DataDir/static/HomePage.html", "$DataDir/static/HomePage.html has nonzero size");
# check that links between pages work as expected
xpath_test(update_page("Test", "Link to HomePage. Testing Ümlaute."),
'//a[text()="HomePage"][@href="http://localhost/wiki.pl/HomePage"]');
test_page(get_page('action=static raw=1 pwd=foo html=1'), 'Test');
xpath_test_file("$DataDir/static/Test.html",
'//a[text()="HomePage"][@href="HomePage.html"]');
test_file("$DataDir/static/Test.html",
"Ümlaute");
test_file("$DataDir/static/static.css",
"body { background-color:#FFF; color:#000; margin:1em 2em; }");
# make sure spaces are translated to underscores (fixed in image.pl)
add_module('image.pl');
# Now, create real pages. First, we'll use the ordinary image link to

View File

@@ -158,6 +158,18 @@ sub test_page {
}
}
# one file, many tests
sub test_file {
my ($file, @tests) = @_;
if (open(F, '< :utf8', $file)) {
local $/ = undef;
test_page(<F>, @tests);
close(F);
} else {
warn "cannot open $file\n";
}
}
# one string, many negative tests
sub test_page_negative {
my $page = shift;
@@ -208,6 +220,17 @@ sub xpath_test {
xpath_do(sub { shift > 0; }, "No Matches\n", @_);
}
sub xpath_test_file {
my ($file, @tests) = @_;
if (open(F, '< :utf8', $file)) {
local $/ = undef;
xpath_test(<F>, @tests);
close(F);
} else {
warn "cannot open $file\n";
}
}
sub negative_xpath_test {
xpath_do(sub { shift == 0; }, "Unexpected Matches\n", @_);
}

89
wiki.pl
View File

@@ -39,7 +39,8 @@ use vars qw($RssLicense $RssCacheHours @RcDays $TempDir $LockDir $DataDir
$KeepDir $PageDir $RcOldFile $IndexFile $BannedContent $NoEditFile $BannedHosts
$ConfigFile $FullUrl $SiteName $HomePage $LogoUrl $RcDefault $RssDir
$IndentLimit $RecentTop $RecentLink $EditAllowed $UseDiff $KeepDays $KeepMajor
$EmbedWiki $BracketText $UseConfig $UseLookup $AdminPass $EditPass $NetworkFile
$EmbedWiki $BracketText $UseConfig $UseLookup $AdminPass $EditPass
$PassHashFunction $PassSalt $NetworkFile
$BracketWiki $FreeLinks $WikiLinks $SummaryHours $FreeLinkPattern $RCName
$RunCGI $ShowEdits $LinkPattern $RssExclude $InterLinkPattern $MaxPost $UseGrep
$UrlPattern $UrlProtocols $ImageExtensions $InterSitePattern $FS $CookieName
@@ -49,7 +50,7 @@ $RssImageUrl $ReadMe $RssRights $BannedCanRead $SurgeProtection $TopLinkBar
$LanguageLimit $SurgeProtectionTime $SurgeProtectionViews $DeletedPage
%Languages $InterMap $ValidatorLink %LockOnCreation $RssStyleSheet
%CookieParameters @UserGotoBarPages $NewComment $HtmlHeaders $StyleSheetPage
$ConfigPage $ScriptName $CommentsPrefix @UploadTypes $AllNetworkFiles
$ConfigPage $ScriptName $CommentsPrefix $CommentsPattern @UploadTypes $AllNetworkFiles
$UsePathInfo $UploadAllowed $LastUpdate $PageCluster %PlainTextPages
$RssInterwikiTranslate $UseCache $Counter $ModuleDir $FullUrlPattern
$SummaryDefaultLength $FreeInterLinkPattern %InvisibleCookieParameters
@@ -95,12 +96,14 @@ $StyleSheetPage = 'css'; # Page for CSS sheet
$LogoUrl = ''; # URL for site logo ('' for no logo)
$NotFoundPg = ''; # Page for not-found links ('' for blank pg)
$NewText = "This page is empty.\n"; # New page text
$NewComment = "Add your comment here.\n"; # New comment text
$NewText = T('This page is empty.') . "\n"; # New page text
$NewComment = T('Add your comment here.') . "\n"; # New comment text
$EditAllowed = 1; # 0 = no, 1 = yes, 2 = comments pages only, 3 = comments only
$AdminPass = '' unless defined $AdminPass; # Whitespace separated passwords.
$EditPass = '' unless defined $EditPass; # Whitespace separated passwords.
$PassHashFunction = '' unless defined $PassHashFunction; # Name of the function to create hashes
$PassSalt = '' unless defined $PassSalt; # Salt will be added to any password before hashing
$BannedHosts = 'BannedHosts'; # Page for banned hosts
$BannedCanRead = 1; # 1 = banned cannot edit, 0 = banned cannot read
@@ -151,6 +154,7 @@ $TopLinkBar = 1; # 1 = add a goto bar at the top of the page
$UserGotoBar = ''; # HTML added to end of goto bar
$ValidatorLink = 0; # 1 = Link to the W3C HTML validator service
$CommentsPrefix = ''; # prefix for comment pages, eg. 'Comments_on_' to enable
$CommentsPattern = undef; # regex used to match comment pages
$HtmlHeaders = ''; # Additional stuff to put in the HTML <head> section
$IndentLimit = 20; # Maximum depth of nested lists
$LanguageLimit = 3; # Number of matches req. for each language
@@ -289,6 +293,8 @@ sub InitVariables { # Init global session variables for mod_perl!
(\$HomePage, \$RCName, \$BannedHosts, \$InterMap, \$StyleSheetPage, \$CommentsPrefix,
\$ConfigPage, \$NotFoundPg, \$RssInterwikiTranslate, \$BannedContent, \$RssExclude, );
$CommentsPrefix .= '_' if $add_space;
$CommentsPattern = "^$CommentsPrefix(.*)"
unless defined $CommentsPattern or not $CommentsPrefix;
@UserGotoBarPages = ($HomePage, $RCName) unless @UserGotoBarPages;
my @pages = sort($BannedHosts, $StyleSheetPage, $ConfigPage, $InterMap,
$RssInterwikiTranslate, $BannedContent);
@@ -465,12 +471,12 @@ sub ApplyRules {
}
Clean(AddHtmlEnvironment('p')); # if dirty block is looked at later, this will disappear
($_, pos) = ($old_, $oldpos); # restore \G (assignment order matters!)
} elsif ($bol && m/\G(\&lt;journal(\s+(\d*))?(\s+"(.*?)")?(\s+(reverse|past|future))?(\s+search\s+(.*))?\&gt;[ \t]*\n?)/cgi) {
} elsif ($bol && m/\G(\&lt;journal(\s+(\d*)(,(\d*))?)?(\s+"(.*?)")?(\s+(reverse|past|future))?(\s+search\s+(.*))?\&gt;[ \t]*\n?)/cgi) {
# <journal 10 "regexp"> includes 10 pages matching regexp
Clean(CloseHtmlEnvironments());
Dirty($1);
my ($oldpos, $old_) = (pos, $_); # remember these because of the call to PrintJournal()
PrintJournal($3, $5, $7, 0, $9); # no offset
PrintJournal($3, $5, $7, $9, 0, $11); # no offset
Clean(AddHtmlEnvironment('p')); # if dirty block is looked at later, this will disappear
($_, pos) = ($old_, $oldpos); # restore \G (assignment order matters!)
} elsif ($bol && m/\G(\&lt;rss(\s+(\d*))?\s+(.*?)\&gt;[ \t]*\n?)/cgis) {
@@ -819,7 +825,7 @@ sub GetRaw {
sub DoJournal {
print GetHeader(undef, T('Journal'));
print $q->start_div({-class=>'content'});
PrintJournal(map { GetParam($_, ''); } qw(num regexp mode offset search));
PrintJournal(map { GetParam($_, ''); } qw(num num regexp mode offset search));
print $q->end_div();
PrintFooter();
}
@@ -829,9 +835,10 @@ sub JournalSort { $b cmp $a }
sub PrintJournal {
return if $CollectingJournal; # avoid infinite loops
local $CollectingJournal = 1;
my ($num, $regexp, $mode, $offset, $search) = @_;
my ($num, $numMore, $regexp, $mode, $offset, $search) = @_;
$regexp = '^\d\d\d\d-\d\d-\d\d' unless $regexp;
$num = 10 unless $num;
$numMore = $num unless $numMore;
$offset = 0 unless $offset;
# FIXME: Should pass filtered list of pages to SearchTitleAndBody to save time?
my @pages = sort JournalSort (grep(/$regexp/, $search ? SearchTitleAndBody($search) : AllPagesList()));
@@ -860,7 +867,9 @@ sub PrintJournal {
print $q->start_div({-class=>'journal'});
my $next = $offset + PrintAllPages(1, 1, $num, @pages[$offset .. $#pages]);
print $q->end_div();
print $q->p({-class=>'more'}, ScriptLink("action=more;num=$num;regexp=$regexp;search=$search;mode=$mode;offset=$next", T('More...'), 'more')) if $pages[$next];
$regexp = UrlEncode($regexp);
$search = UrlEncode($search);
print $q->p({-class=>'more'}, ScriptLink("action=more;num=$numMore;regexp=$regexp;search=$search;mode=$mode;offset=$next", T('More...'), 'more')) if $pages[$next];
}
sub PrintAllPages {
@@ -880,17 +889,21 @@ sub PrintAllPages {
$q->h1($links ? GetPageLink($id)
: $q->a({-name=>$id}, UrlEncode(FreeToNormal($id))));
PrintPageHtml();
if ($comments and $id !~ /^$CommentsPrefix/o) {
print $q->p({-class=>'comment'},
GetPageLink($CommentsPrefix . $id,
T('Comments on this page')));
}
PrintPageCommentsLink($id, $comments);
print $q->end_div();
$n++; # pages actually printed
}
return $i;
}
sub PrintPageCommentsLink {
my ($id, $comments) = @_;
if ($comments and $CommentsPattern and $id !~ /$CommentsPattern/o) {
print $q->p({-class=>'comment'},
GetPageLink($CommentsPrefix . $id, T('Comments on this page')));
}
}
sub RSS {
return if $CollectingJournal; # avoid infinite loops when using full=1
local $CollectingJournal = 1;
@@ -1380,7 +1393,7 @@ sub BrowseResolvedPage {
print $q->redirect({-uri=>$resolved});
} elsif ($class && $class eq 'alias') { # an anchor was found instead of a page
ReBrowsePage($resolved);
} elsif (not $resolved and $NotFoundPg and $id !~ /^$CommentsPrefix/o) { # custom page-not-found message
} elsif (not $resolved and $NotFoundPg and $id !~ /$CommentsPattern/o) { # custom page-not-found message
BrowsePage($NotFoundPg);
} elsif ($resolved) { # an existing page was found
BrowsePage($resolved, GetParam('raw', 0));
@@ -1942,7 +1955,7 @@ sub RssItem {
$rss .= "<description>" . QuoteHtml($summary) . "</description>\n" if $summary;
$rss .= "<pubDate>" . $date . "</pubDate>\n";
$rss .= "<comments>" . ScriptUrl($CommentsPrefix . UrlEncode($id))
. "</comments>\n" if $CommentsPrefix and $id !~ /^$CommentsPrefix/o;
. "</comments>\n" if $CommentsPattern and $id !~ /$CommentsPattern/o;
$rss .= "<dc:contributor>" . $username . "</dc:contributor>\n" if $username;
$rss .= "<wiki:status>" . (1 == $revision ? 'new' : 'updated')
. "</wiki:status>\n";
@@ -2428,8 +2441,8 @@ sub GetFooterLinks {
my ($id, $rev) = @_;
my @elements;
if ($id and $rev ne 'history' and $rev ne 'edit') {
if ($CommentsPrefix) {
if ($id =~ /^$CommentsPrefix(.*)/o) {
if ($CommentsPattern) {
if ($id =~ /$CommentsPattern/o) {
push(@elements, GetPageLink($1, undef, 'original', T('a')));
} else {
push(@elements, GetPageLink($CommentsPrefix . $id, undef, 'comment', T('c')));
@@ -2460,8 +2473,8 @@ sub GetFooterLinks {
sub GetCommentForm {
my ($id, $rev, $comment) = @_;
if ($CommentsPrefix ne '' and $id and $rev ne 'history' and $rev ne 'edit'
and $id =~ /^$CommentsPrefix/o and UserCanEdit($id, 0, 1)) {
if ($CommentsPattern ne '' and $id and $rev ne 'history' and $rev ne 'edit'
and $id =~ /$CommentsPattern/o and UserCanEdit($id, 0, 1)) {
return $q->div({-class=>'comment'}, GetFormStart(undef, undef, 'comment'), # protected by questionasker
$q->p(GetHiddenValue('title', $id),
GetTextArea('aftertext', $comment ? $comment : $NewComment, 10)), $EditNote,
@@ -2706,7 +2719,6 @@ sub OpenPage { # Sets global variables
local $/ = undef;
$Page{text} = <F>;
close F;
} elsif ($CommentsPrefix and $id =~ /^$CommentsPrefix(.*)/o) { # do nothing
}
}
$OpenPageName = $id;
@@ -3032,11 +3044,9 @@ sub FreeToNormal { # trim all spaces and convert them to underlines
my $id = shift;
return '' unless $id;
$id =~ s/ /_/g;
if (index($id, '_') > -1) { # Quick check for any space/underscores
$id =~ s/__+/_/g;
$id =~ s/^_//;
$id =~ s/_$//;
}
$id =~ s/__+/_/g;
$id =~ s/^_//;
$id =~ s/_$//;
return UnquoteHtml($id);
}
@@ -3221,7 +3231,7 @@ sub UserCanEdit {
return 1 if UserIsEditor();
return 0 if !$EditAllowed or -f $NoEditFile;
return 0 if $editing and UserIsBanned(); # this call is more expensive
return 0 if $EditAllowed >= 2 and (not $CommentsPrefix or $id !~ /^$CommentsPrefix/o);
return 0 if $EditAllowed >= 2 and (not $CommentsPattern or $id !~ /$CommentsPattern/o);
return 1 if $EditAllowed >= 3 and ($comment or (GetParam('aftertext', '') and not GetParam('text', '')));
return 0 if $EditAllowed >= 3;
return 1;
@@ -3243,19 +3253,22 @@ sub UserIsBanned {
}
sub UserIsAdmin {
return 0 if $AdminPass eq '';
my $pwd = GetParam('pwd', '');
foreach (split(/\s+/, $AdminPass)) {
return 1 if $pwd eq $_;
}
return 0;
return UserHasPassword(GetParam('pwd', ''), $AdminPass);
}
sub UserIsEditor {
return 1 if UserIsAdmin(); # Admin includes editor
return 0 if $EditPass eq '';
my $pwd = GetParam('pwd', ''); # Used for both passwords
foreach (split(/\s+/, $EditPass)) {
return UserHasPassword(GetParam('pwd', ''), $EditPass);
}
sub UserHasPassword {
my ($pwd, $pass) = @_;
return 0 if not $pass;
if ($PassHashFunction ne '') {
no strict 'refs';
$pwd = &$PassHashFunction($pwd . $PassSalt);
}
foreach (split(/\s+/, $pass)) {
return 1 if $pwd eq $_;
}
return 0;
@@ -3338,7 +3351,7 @@ sub AllPagesList {
if (not $refresh and -f $IndexFile) {
my ($status, $rawIndex) = ReadFile($IndexFile); # not fatal
if ($status) {
%IndexHash = split(/\s+/, $rawIndex);
%IndexHash = split(/ /, $rawIndex);
@IndexList = sort(keys %IndexHash);
return @IndexList;
}
@@ -3711,7 +3724,7 @@ sub AddComment {
my $author = GetParam('username', T('Anonymous'));
my $homepage = GetParam('homepage', '');
$homepage = 'http://' . $homepage
if $homepage and not substr($homepage,0,7) eq 'http://';
if $homepage and $homepage !~ /^($UrlProtocols):/;
$author = "[$homepage $author]" if $homepage;
$string .= "\n----\n\n" if $string and $string ne "\n";
$string .= $comment . "\n\n"