Compare commits

...

3 Commits

Author SHA1 Message Date
Markus Lude
4a8bc551e2 (InitVariables): Fixed warning if $LastUpdate is undefined
(ResolveId): Return list with empty values as fallback to avoid warnings
in functions which call ResolveId()
(DoRc): Initialize $ts to 0 to avoid warnings
(GetRc): restored part of comment which got lost
(EncodePage): Initialize $result to avoid warning when adding strings
2005-12-11 20:09:12 +00:00
Markus Lude
07d17a83e1 (ValidId): Return when $id is undefined before doing a
replacement in order to not get a warning.
(InitVariables): Set $LastUpdate on every request and
reinitialize some variables in case the server runs several
mod_perl processes.
2005-12-11 18:41:00 +00:00
Alex Schroeder
c444ee65dd unfinished move to get -wT working 2005-12-04 10:31:47 +00:00
12 changed files with 172 additions and 140 deletions

View File

@@ -56,7 +56,7 @@ install:
dpkg -i oddmuse*.deb
test:
perl test.pl
perl -T test.pl
package-upload: debian-$(VERSION).tar.gz debian-$(VERSION).tar.gz.sig
curl -T "{debian-$(VERSION).tar.gz,debian-$(VERSION).tar.gz.sig}" \

View File

@@ -18,7 +18,7 @@
package OddMuse;
$ModulesDescription .= '<p>$Id: big-brother.pl,v 1.6 2005/10/07 13:09:29 as Exp $</p>';
$ModulesDescription .= '<p>$Id: big-brother.pl,v 1.6.2.1 2005/12/04 10:31:48 as Exp $</p>';
use vars qw($VisitorTime);
@@ -112,7 +112,7 @@ sub DoBigBrother { # no caching of this page!
}
foreach my $name (sort {$latest{$b} <=> $latest{$a}} keys %latest) {
my $when = CalcTimeSince($Now - $latest{$name});
my $error = ValidId($name);
my ($error) = ValidId($name);
my $who = $name && !$error && $name !~ /\./ ? GetPageLink($name) : T('Anonymous');
my %entries = %{$BigBrotherData{$name}};
my %reverse = (); # reverse hash to filter out duplicate targets

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p>$Id: calendar.pl,v 1.37 2005/10/07 23:23:30 as Exp $</p>';
$ModulesDescription .= '<p>$Id: calendar.pl,v 1.37.2.1 2005/12/04 10:31:48 as Exp $</p>';
use vars qw($CalendarOnEveryPage $CalendarUseCal);
@@ -146,7 +146,7 @@ sub CalendarRule {
sub PrintYearCalendar {
my $year = shift;
my @pages = AllPagesList();
print $q->p({-class=>nav},
print $q->p({-class=>'nav'},
ScriptLink('action=calendar;year=' . ($year-1), T('Previous')),
'|',
ScriptLink('action=calendar;year=' . ($year+1), T('Next')));

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p>$Id: crumbs.pl,v 1.5 2005/10/07 23:23:30 as Exp $</p>';
$ModulesDescription .= '<p>$Id: crumbs.pl,v 1.5.2.1 2005/12/04 10:31:48 as Exp $</p>';
push(@MyRules, \&CrumbsRule);
$RuleOrder{\&CrumbsRule} = -10; # run before default rules!
@@ -29,7 +29,6 @@ sub CrumbsRule {
my $cluster = FreeToNormal($2);
my %seen = ($cluster => 1);
my @links = ($cluster);
AllPagesList(); # set IndexHash
while ($cluster) {
my $text = GetPageContent($cluster); # opening n files is slow!
if (($WikiLinks && $text =~ /^$LinkPattern\n/)

View File

@@ -16,13 +16,14 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p>$Id: image.pl,v 1.15 2005/03/01 16:48:01 sblatt Exp $</p>';
$ModulesDescription .= '<p>$Id: image.pl,v 1.15.2.1 2005/12/04 10:31:48 as Exp $</p>';
use vars qw($ImageUrlPath);
$ImageUrlPath = '/images'; # URL where the images are to be found
push(@MyRules, \&ImageSupportRule);
$RuleOrder{\&ImageSupportRule} = -1; # run this rule before the default image rule for consistency
# [[image/class:page name|alt text|target]]
@@ -34,9 +35,12 @@ sub ImageSupportRule {
$class .= ' ' . substr($1, 1) if $1;
my $external = $2;
my $name = $3;
my $alt = $6 ? substr($6, 1) : T("image: %s", $name);
my $alt = $6 ? substr($6, 1) : Ts("image: %s", $name); # use name if no alt text is specified
my $link = $7 ? substr($7, 1) : '';
my $id = FreeToNormal($name);
# short-cut if the page does not exist
return '[' . ($image ? T('image') : T('download')) . ':' . $name
. ']' . GetEditLink($id, '?', 1) unless $external or $IndexHash{$id};
# link to the image if no link was given
if (not $link) {
if ($external) {

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p>$Id: irc.pl,v 1.4 2005/10/07 23:23:30 as Exp $</p>';
$ModulesDescription .= '<p>$Id: irc.pl,v 1.4.2.1 2005/12/04 10:31:48 as Exp $</p>';
use vars qw($IrcNickRegexp $IrcLinkNick);
@@ -29,18 +29,19 @@ $IrcLinkNick = 0;
# This adds an extra <br> at the beginning. Alternatively, add it to
# the last line, or only add it when required.
sub IrcRule {
if ($bol && m/\G&lt;($IrcNickRegexp)&gt;/gc) {
my $str = $1;
my $error = ValidId($str);
if ($bol && m/\G(\d\d?:\d\d)?\s*&lt;($IrcNickRegexp)&gt;/gc) {
my ($time, $nick) = ($1, $2);
my ($error) = ValidId($nick);
# if we're in a dl, close the open dd but not the dl. (if we're
# not in a dl, that closes all environments.) then open a dl
# unless we're already in a dl. put the nick in a dt.
my $html = CloseHtmlEnvironmentUntil('dd') . OpenHtmlEnvironment('dl', 1, 'irc')
. AddHtmlEnvironment('dt');
$html .= $q->span({-class=>'time'}, $time, ' ') if $time;
if ($error or not $IrcLinkNick) {
$html .= $q->b($str);
$html .= $q->b($nick);
} else {
$html .= GetPageOrEditLink($str);
$html .= GetPageOrEditLink($nick);
}
$html .= CloseHtmlEnvironment('dt') . AddHtmlEnvironment('dd');
return $html;

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p>$Id: link-all.pl,v 1.6 2004/11/15 00:12:20 as Exp $</p>';
$ModulesDescription .= '<p>$Id: link-all.pl,v 1.6.2.1 2005/12/04 10:31:48 as Exp $</p>';
push(@MyRules, \&LinkAllRule);
$RuleOrder{\&LinkAllRule} = 1000;
@@ -36,7 +36,6 @@ sub LinkAllRule {
sub LinkAllGetPageLinkIfItExists {
my $id = shift;
AllPagesList() unless $IndexInit;
if ($IndexHash{$id}) {
return GetPageLink($id);
} elsif (GetParam('define', 0)) {

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p>$Id: links.pl,v 1.1 2004/06/20 19:15:41 as Exp $</p>';
$ModulesDescription .= '<p>$Id: links.pl,v 1.1.2.1 2005/12/04 10:31:48 as Exp $</p>';
$Action{links} = \&DoLinks;
@@ -63,6 +63,7 @@ sub GetFullLinkList { # opens all pages!
sub GetLinkList { # for the currently open page
my ($raw, $url, $inter, $link) = @_;
return () unless $Page{blocks};
my @blocks = split($FS, $Page{blocks});
my @flags = split($FS, $Page{flags});
my %links;

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p>$Id: tables-long.pl,v 1.13 2005/10/09 11:58:34 as Exp $</p>';
$ModulesDescription .= '<p>$Id: tables-long.pl,v 1.13.2.1 2005/12/04 10:31:48 as Exp $</p>';
push(@MyRules, \&TablesLongRule);
@@ -34,7 +34,8 @@ sub TablesLongRule {
# 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) {
my $class = join(' ', split(m|/|, $1)); # leading / in $1 will make sure we have leading space
my $class = '';
$class = join(' ', split(m|/|, $1)) if $1; # leading / in $1 will make sure we have leading space
Clean(CloseHtmlEnvironments() . "<table class=\"user long$class\">");
# labels and their default class
my %default_class = ();
@@ -60,7 +61,7 @@ sub TablesLongRule {
for my $line (@lines) {
if ($line =~ m|^($regexp)/?([A-Za-z\x80-\xff/]+)?[:=] *(.*)|) { # regexp changes for other tables
$label = $1;
$class = join(' ', split(m|/|, $2)); # no leading / therefore no leading space
$class = join(' ', split(m|/|, $2)) if $2; # no leading / therefore no leading space
$line = $3;
if ($row{$label}) { # repetition of label, we must start a new row
TablesLongRow(\@labels, \%row, \%class, $first);

View File

@@ -1,2 +1,5 @@
@list = (1,2,3,4,5);
print join(', ', @list[1 .. -1]), "\n";
%h = ('a' => 'b', \['1', '2'] => 'c');
foreach (keys %h) {
print "$_ -> $h{$_}\n";
print "@{$_}\n";
}

77
test.pl
View File

@@ -1,4 +1,4 @@
#!/usr/bin/perl
#!/usr/bin/perl -wT
# Copyright (C) 2004, 2005 Alex Schroeder <alex@emacswiki.org>
#
@@ -20,13 +20,15 @@
use XML::LibXML;
use Encode;
no warnings 'once';
# Import the functions
package OddMuse;
$RunCGI = 0; # don't print HTML on stdout
$UseConfig = 0; # don't read module files
do 'wiki.pl';
push (@INC, '.');
require 'wiki.pl';
Init();
my ($passed, $failed) = (0, 0);
@@ -35,6 +37,12 @@ my $redirect;
undef $/;
$| = 1; # no output buffering
sub untaint {
my $str = shift;
$str =~ /(.*)/s; # match newlines
return $1;
}
sub url_encode {
my $str = shift;
return '' unless $str;
@@ -51,7 +59,7 @@ sub url_encode {
print "* means that a page is being updated\n";
sub update_page {
my ($id, $text, $summary, $minor, $admin, @rest) = @_;
my ($id, $text, $summary, $minor, $admin, @rest) = map { untaint($_) } @_;
print '*';
my $pwd = $admin ? 'foo' : 'wrong';
$id = url_encode($id);
@@ -59,8 +67,8 @@ sub update_page {
$summary = url_encode($summary);
$minor = $minor ? 'on' : 'off';
my $rest = join(' ', @rest);
$redirect = `perl wiki.pl Save=1 title=$id summary=$summary recent_edit=$minor text=$text pwd=$pwd $rest`;
$output = `perl wiki.pl action=browse id=$id`;
$redirect = `perl -wT wiki.pl Save=1 title=$id summary=$summary recent_edit=$minor text=$text pwd=$pwd $rest`;
$output = `perl -wT wiki.pl action=browse id=$id`;
# just in case a new page got created or NearMap or InterMap
$IndexInit = 0;
$NearInit = 0;
@@ -73,7 +81,7 @@ sub update_page {
print "+ means that a page is being retrieved\n";
sub get_page {
print '+';
open(F,"perl wiki.pl @_ |");
open(F,"perl -wT wiki.pl @_ |");
my $output = <F>;
close F;
return $output;
@@ -274,7 +282,7 @@ sub remove_rule {
sub add_module {
my $mod = shift;
mkdir $ModuleDir unless -d $ModuleDir;
my $dir = `/bin/pwd`;
my $dir = untaint(`/bin/pwd`);
chop($dir);
symlink("$dir/modules/$mod", "$ModuleDir/$mod") or die "Cannot symlink $mod: $!"
unless -l "$ModuleDir/$mod";
@@ -663,6 +671,8 @@ test_page(get_page('RSS'), @Test);
redirection:
print '[redirection]';
clear_pages();
update_page('Miles_Davis', 'Featuring [[John Coltrane]]'); # plain link
update_page('John_Coltrane', '#REDIRECT Coltrane'); # no redirect
update_page('Sonny_Stitt', '#REDIRECT [[Stitt]]'); # redirect
@@ -834,6 +844,8 @@ test_page_negative($page, @Negatives);
conflicts:
print '[conflicts]';
clear_pages();
# Using the example files from the diff3 manual
my $lao_file = q{The Way that can be told of is not the eternal Way;
@@ -932,7 +944,7 @@ sleep(2);
update_page('ConflictTest', $lao_file);
$_ = `perl wiki.pl action=edit id=ConflictTest`;
$_ = `perl -wT wiki.pl action=edit id=ConflictTest`;
/name="oldtime" value="([0-9]+)"/;
my $oldtime = $1;
@@ -957,7 +969,7 @@ sleep(2);
update_page('ConflictTest', $tzu_file);
$_ = `perl wiki.pl action=edit id=ConflictTest`;
$_ = `perl -wT wiki.pl action=edit id=ConflictTest`;
/name="oldtime" value="([0-9]+)"/;
$oldtime = $1;
@@ -1003,9 +1015,10 @@ sleep(2);
update_page('ConflictTest', $lao_file);
$_ = `perl wiki.pl action=edit id=ConflictTest`;
$_ = `perl -wT wiki.pl action=edit id=ConflictTest`;
/name="oldtime" value="([0-9]+)"/;
$oldtime = $1;
test_page($oldtime, '^\d+$');
sleep(2);
@@ -1792,7 +1805,7 @@ print '[usemod module]';
clear_pages();
do 'modules/usemod.pl';
add_module('usemod.pl');
InitVariables();
%Test = split('\n',<<'EOT');
@@ -1892,7 +1905,7 @@ usemod_options:
print '[usemod options]';
# some patterns use options in regular expressions with /o and need to be recompiled
do 'modules/usemod.pl';
add_module('usemod.pl');
$UseModSpaceRequired = 0;
$UseModMarkupInTitles = 1;
InitVariables();
@@ -1931,8 +1944,8 @@ remove_rule(\&UsemodRule);
markup_module:
print '[markup module]';
do 'modules/usemod.pl';
do 'modules/markup.pl';
add_module('usemod.pl');
add_module('markup.pl');
InitVariables();
%Test = split('\n',<<'EOT');
@@ -2023,8 +2036,8 @@ setext_module:
print '[setext module]';
clear_pages(); # link-all will confuse us
do 'modules/setext.pl';
do 'modules/link-all.pl';
add_module('setext.pl');
add_module('link-all.pl');
%Test = split('\n',<<'EOT');
foo
@@ -2064,8 +2077,8 @@ remove_rule(\&LinkAllRule);
anchors_module:
print '[anchors module]';
do 'modules/anchors.pl';
do 'modules/link-all.pl'; # check compatibility
add_module('anchors.pl');
add_module('link-all.pl'); # check compatibility
%Test = split('\n',<<'EOT');
This is a [:day for fun and laughter].
@@ -2134,19 +2147,23 @@ remove_module('link-all.pl');
image_module:
print '[image module]';
do "modules/image.pl";
clear_pages();
add_module('image.pl');
update_page('bar', 'foo');
%Test = split('\n',<<'EOT');
[[image:foo]]
//a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=foo;upload=1"][text()="?"]
[[image:foo|text|http://www.oddmuse.org/]]
//a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=foo;upload=1"][text()="?"]
[[image:bar]]
//a[@class="image"][@href="http://localhost/test.pl/bar"]/img[@class="upload"][@src="http://localhost/test.pl/download/bar"][@alt="bar"]
//a[@class="image"][@href="http://localhost/test.pl/bar"]/img[@class="upload"][@src="http://localhost/test.pl/download/bar"][@alt="image: bar"]
[[image:bar|alternative text]]
//a[@class="image"][@href="http://localhost/test.pl/bar"]/img[@class="upload"][@src="http://localhost/test.pl/download/bar"][@alt="alternative text"]
[[image:bar|alternative > text]]
//a[@class="image"][@href="http://localhost/test.pl/bar"]/img[@class="upload"][@src="http://localhost/test.pl/download/bar"][@alt="alternative &gt; text"]
[[image/left:bar|alternative text]]
//a[@class="image left"][@href="http://localhost/test.pl/bar"]/img[@class="upload"][@title="alternative text"][@src="http://localhost/test.pl/download/bar"][@alt="alternative text"]
[[image:bar|alternative text|foo]]
@@ -2160,6 +2177,7 @@ EOT
xpath_run_tests();
remove_rule(\&ImageSupportRule);
remove_module('image.pl');
# --------------------
@@ -2182,6 +2200,7 @@ EOT
run_tests();
remove_rule(\&SubscribedRecentChangesRule);
remove_module('subscriberc.pl');
# --------------------
@@ -2245,6 +2264,8 @@ test_page(get_page('toc_test'),
remove_rule(\&UsemodRule);
remove_rule(\&TocRule);
*GetHeader = *OldTocGetHeader;
remove_module('toc.pl');
remove_module('usemod.pl');
# --------------------
@@ -2285,6 +2306,7 @@ add_module('usemod.pl');
update_page('headers', "== is header ==\n\ntext\n");
test_page(get_page('headers'), '<h2>is header</h2>');
remove_rule(\&UsemodRule);
remove_module('usemod.pl');
# toc only
add_module('toc.pl');
@@ -2295,12 +2317,14 @@ test_page(get_page('headers'),
'<h2><a id="toc0">one</a></h2>',
'<h2><a id="toc1">two</a></h2>', );
remove_rule(\&TocRule);
remove_module('toc.pl');
# headers only
add_module('headers.pl');
update_page('headers', "is header\n=========\n\ntext\n");
test_page(get_page('headers'), '<h2>is header</h2>');
remove_rule(\&HeadersRule);
remove_module('headers.pl');
# --------------------
@@ -2355,6 +2379,7 @@ remove_rule(\&TocRule);
*GetHeader = *OldTocGetHeader;
remove_rule(\&PortraitSupportRule);
*ApplyRules = *OldPortraitSupportApplyRules;
remove_module('portrait-support.pl');
# --------------------
@@ -2374,6 +2399,7 @@ add_module('usemod.pl');
update_page('hr', "one\n----\nthree\n");
test_page(get_page('hr'), '<div class="content browse"><p>one </p><hr /><p>three</p></div>');
remove_rule(\&UsemodRule);
remove_module('usemod.pl');
# headers only
add_module('headers.pl');
@@ -2383,6 +2409,7 @@ test_page(get_page('hr'), '<div class="content browse"><h3>one</h3><p>two</p></d
update_page('hr', "one\n\n----\nthree\n");
test_page(get_page('hr'), '<div class="content browse"><p>one</p><hr /><p>three</p></div>');
remove_rule(\&HeadersRule);
remove_module('headers.pl');
# --------------------
@@ -2400,8 +2427,8 @@ test_page(get_page('hr'), '<div class="content browse"><div class="color one"><p
add_module('usemod.pl');
update_page('hr', "one\n----\nthree\n");
test_page(get_page('hr'), '<div class="content browse"><p>one </p><hr /><p>three</p></div>');
unlink('/tmp/oddmuse/modules/usemod.pl') or die "Cannot unlink: $!";
remove_rule(\&UsemodRule);
remove_module('usemod.pl');
# headers and portrait-support
add_module('headers.pl');
@@ -2410,11 +2437,12 @@ test_page(get_page('hr'), '<div class="content browse"><h3>one</h3><p>two</p></d
update_page('hr', "one\n\n----\nthree\n");
test_page(get_page('hr'), '<div class="content browse"><p>one</p><hr /><p>three</p></div>');
unlink('/tmp/oddmuse/modules/headers.pl') or die "Cannot unlink: $!";
remove_rule(\&HeadersRule);
remove_module('headers.pl');
remove_rule(\&PortraitSupportRule);
*ApplyRules = *OldPortraitSupportApplyRules;
remove_module('portrait-support.pl');
# --------------------
@@ -2460,6 +2488,7 @@ xpath_test(get_page('action=calendar'),
remove_rule(\&CalendarRule);
*GetHeader = *OldCalendarGetHeader;
remove_module('calendar.pl');
# --------------------
@@ -2467,7 +2496,6 @@ crumbs:
print '[crumbs]';
clear_pages();
AppendStringToFile($ConfigFile, "\$PageCluster = 'Cluster';\n");
add_module('crumbs.pl');
@@ -2478,6 +2506,7 @@ xpath_test(get_page('Games'),
'//p/span[@class="crumbs"]/a[@class="local"][@href="http://localhost/wiki.pl/HomePage"][text()="HomePage"]/following-sibling::text()[string()=" "]/following-sibling::a[@class="local"][@href="http://localhost/wiki.pl/Software"][text()="Software"]');
remove_rule(\&CrumbsRule);
remove_module('crumbs.pl');
# --------------------

181
wiki.pl
View File

@@ -114,8 +114,8 @@ $InterMap = 'InterMap'; # name of the intermap page
$NearMap = 'NearMap'; # name of the nearmap page
$RssInterwikiTranslate = 'RssInterwikiTranslate'; # name of RSS interwiki translation page
@MyRules = (\&LinkRules); # default rules that can be overridden
$RuleOrder{\&LinkRules} = 0;
$ENV{PATH} = '/usr/bin/'; # Path used to find 'diff'
%RuleOrder = (\&LinkRules => 0);
$ENV{PATH} = '/usr/bin'; # Path used to find 'diff'
$UseDiff = 1; # 1 = use diff
$SurgeProtection = 1; # 1 = protect against leeches
$SurgeProtectionTime = 20; # Size of the protected window in seconds
@@ -258,14 +258,16 @@ sub InitRequest {
sub InitVariables { # Init global session variables for mod_perl!
$WikiDescription = $q->p($q->a({-href=>'http://www.oddmuse.org/'}, 'Oddmuse'))
. $q->p(q{$Id: wiki.pl,v 1.629 2005/10/29 16:46:37 as Exp $});
. $q->p(q{$Id: wiki.pl,v 1.629.2.3 2005/12/11 20:09:12 lude Exp $});
$WikiDescription .= $ModulesDescription if $ModulesDescription;
$PrintedHeader = 0; # Error messages don't print headers unless necessary
$ReplaceForm = 0; # Only admins may search and replace
$ScriptName = $q->url() unless defined $ScriptName; # URL used in links
$FullUrl = $ScriptName unless $FullUrl; # URL used in forms
$Now = time; # Reset in case script is persistent
$LastUpdate = (stat($IndexFile))[9] unless $LastUpdate;
my $ts = (stat($IndexFile))[9]; # always stat for multiple server processes
ReInit() if ($LastUpdate and $LastUpdate != $ts); # reinit if another process changed files
$LastUpdate = $ts;
%Locks = ();
@Blocks = ();
@Flags = ();
@@ -288,7 +290,7 @@ sub InitVariables { # Init global session variables for mod_perl!
PermanentAnchorsInit() if $PermanentAnchors; # reads $PermanentAnchorsFile
%NearLinksUsed = (); # List of links used during this request
unshift(@MyRules, \&MyRules) if defined(&MyRules) && (not @MyRules or $MyRules[0] != \&MyRules);
@MyRules = sort {$RuleOrder{$a} <=> $RuleOrder{$b}} @MyRules; # default is 0
@MyRules = sort {($RuleOrder{$a}||0) <=> ($RuleOrder{$b}||0)} @MyRules; # undefined is 0
ReportError(Ts('Could not create %s', $DataDir) . ": $!", '500 INTERNAL SERVER ERROR')
unless -d $DataDir;
foreach my $sub (@MyInitVariables) {
@@ -669,14 +671,15 @@ sub RunMyRules {
}
sub PrintWikiToHTML {
my ($pageText, $savecache, $revision, $islocked) = @_;
my ($text, $savecache, $revision, $islocked) = @_;
$FootnoteNumber = 0;
$pageText =~ s/$FS//g; # Remove separators (paranoia)
$pageText = QuoteHtml($pageText);
my ($blocks, $flags) = ApplyRules($pageText, 1, $savecache, $revision, 'p'); # p is start tag!
$text =~ s/$FS//g if $text; # Remove separators (paranoia)
$text = QuoteHtml($text);
my ($blocks, $flags) = ApplyRules($text, 1, $savecache, $revision, 'p'); # p is start tag!
# local links, anchors if cache ok
if ($savecache and not $revision and $Page{revision} # don't save revision 0 pages
and $Page{blocks} ne $blocks and $Page{flags} ne $flags) {
and $Page{blocks} and $Page{blocks} ne $blocks
and $Page{flags} and $Page{flags} ne $flags) {
$Page{blocks} = $blocks;
$Page{flags} = $flags;
if ($islocked or RequestLockDir('main')) { # not fatal!
@@ -688,6 +691,7 @@ sub PrintWikiToHTML {
sub QuoteHtml {
my $html = shift;
return '' unless defined $html;
$html =~ s/&/&amp;/g;
$html =~ s/</&lt;/g;
$html =~ s/>/&gt;/g;
@@ -696,6 +700,7 @@ sub QuoteHtml {
sub UnquoteHtml {
my $html = shift;
return '' unless defined $html;
$html =~ s/&lt;/</g;
$html =~ s/&gt;/>/g;
$html =~ s/&amp;/&/g;
@@ -742,7 +747,7 @@ sub PrintJournal {
} else {
@pages = sort {$b cmp $a} @pages;
}
if ($mode eq 'reverse') {
if ($mode and $mode eq 'reverse') {
@pages = reverse @pages;
}
@pages = @pages[0 .. $num - 1] if $#pages >= $num;
@@ -840,9 +845,9 @@ sub RSS {
}
my $contributor = $i->{dc}->{contributor};
$contributor = $i->{$wikins}->{username} unless $contributor;
$contributor =~ s/^\s+//;
$contributor =~ s/\s+$//;
$contributor = $i->{$rdfns}->{value} unless $contributor;
$contributor =~ s/^\s+// if $contributor;
$contributor =~ s/\s+$// if $contributor;
$line .= $q->span({-class=>'contributor'}, $q->span(T(' . . . . ')) . $contributor) if $contributor;
if ($description) {
if ($description =~ /</) {
@@ -861,7 +866,7 @@ sub RSS {
}
my @lines = sort { $b cmp $a } keys %lines;
@lines = @lines[0..$maxitems-1] if $maxitems and $#lines > $maxitems;
my $date;
my $date = '';
foreach my $key (@lines) {
my $line = $lines{$key};
if ($key =~ /(\d\d\d\d(?:-\d?\d)?(?:-\d?\d)?)(?:[T ](\d?\d:\d\d))?/) {
@@ -888,7 +893,8 @@ sub GetRss {
my $str = '';
if (GetParam('cache', $UseCache) > 0) {
foreach my $uri (keys %todo) { # read cached rss files if possible
if ($Now - (stat($todo{$uri}))[9] < $RssCacheHours * 3600) {
my $ts = (stat($todo{$uri}))[9];
if ($ts and $Now - $ts < $RssCacheHours * 3600) {
$data{$uri} = ReadFile($todo{$uri});
delete($todo{$uri}); # no need to fetch them below
}
@@ -1227,7 +1233,7 @@ sub DoBrowseRequest {
eval { local $SIG{__DIE__}; MyActions(); };
} elsif ($action) {
ReportError(Ts('Invalid action parameter %s', $action), '501 NOT IMPLEMENTED');
} elsif (($search ne '') || (GetParam('dosearch', '') ne '')) {
} elsif ($search and $search ne '' || GetParam('dosearch', '') ne '') { # allow search for "0"
DoSearch($search);
} elsif (GetParam('title', '')) {
DoPost(GetParam('title', ''));
@@ -1242,26 +1248,19 @@ sub DoBrowseRequest {
sub ValidId {
my $id = shift;
return T('Page name is missing') unless $id;
return Ts('Page name is too long: %s', $id) if (length($id) > 120);
if ($FreeLinks) {
$id =~ s/ /_/g;
return Ts('Invalid Page %s', $id) if (!($id =~ m|^$FreeLinkPattern$|));
return Ts('Invalid Page %s (must not end with .db)', $id) if ($id =~ m|\.db$|);
return Ts('Invalid Page %s (must not end with .lck)', $id) if ($id =~ m|\.lck$|);
} else {
return Ts('Page name may not contain space characters: %s', $id) if ($id =~ m| |);
return Ts('Invalid Page %s', $id) if (!($id =~ /^$LinkPattern$/));
}
return '';
return (T('Page name is missing')) unless $id;
$id =~ s/ /_/g;
return (Ts('Page name is too long: %s', $id)) if length($id) > 120;
return (Ts('Invalid Page %s (must not end with .db)', $id)) if $id =~ m|\.db$|;
return (Ts('Invalid Page %s (must not end with .lck)', $id)) if $id =~ m|\.lck$|;
return (Ts('Invalid Page %s', $id)) if $FreeLinks ? $id !~ m|^$FreeLinkPattern$| : $id !~ m|^$LinkPattern$|;
return ('', $1);
}
sub ValidIdOrDie {
my $id = shift;
my $error;
$error = ValidId($id);
my ($error, $untainted) = ValidId(shift);
ReportError($error, '400 BAD REQUEST') if $error;
return 1;
return $untainted;
}
sub ResolveId { # return css class, resolved id, title (eg. for popups), exist-or-not
@@ -1278,10 +1277,11 @@ sub ResolveId { # return css class, resolved id, title (eg. for popups), exist-o
my $site = $NearSource{$id}[0];
return ('near', GetInterSiteUrl($site, $id), $site); # return source as title attribute
}
return ('', '', '', '');
}
sub BrowseResolvedPage {
my $id = FreeToNormal(shift);
my $id = ValidIdOrDie(FreeToNormal(shift));
my ($class, $resolved, $title, $exists) = ResolveId($id);
if ($class && $class eq 'near' && not GetParam('rcclusteronly', 0)) { # nearlink (is url)
print $q->redirect({-uri=>$resolved});
@@ -1292,7 +1292,7 @@ sub BrowseResolvedPage {
} elsif ($resolved) { # an existing page was found
BrowsePage($resolved, GetParam('raw', 0));
} else { # new page!
BrowsePage($id, GetParam('raw', 0), undef, '404 NOT FOUND') if ValidIdOrDie($id);
BrowsePage($id, GetParam('raw', 0), undef, '404 NOT FOUND');
}
}
@@ -1304,7 +1304,7 @@ sub BrowsePage {
my ($text, $revision) = GetTextRevision(GetParam('revision', ''));
# handle a single-level redirect
my $oldId = GetParam('oldid', '');
if (not $oldId and not $revision and (substr($text, 0, 10) eq '#REDIRECT ')) {
if (not $oldId and not $revision and $text and substr($text, 0, 10) eq '#REDIRECT ') {
if (($FreeLinks and $text =~ /^\#REDIRECT\s+\[\[$FreeLinkPattern\]\]/)
or ($WikiLinks and $text =~ /^\#REDIRECT\s+$LinkPattern/)) {
ReBrowsePage(FreeToNormal($1), $id); # trim extra whitespace from $1, prevent loops with $id
@@ -1393,7 +1393,7 @@ sub PageFresh { # pages can depend on other pages (ie. last update), admin statu
sub PageEtag {
my ($changed, $visible, %params) = CookieData();
return UrlEncode(join($FS, $LastUpdate, sort(values %params))); # no CTL in field values
return UrlEncode(join($FS, $LastUpdate||'0', sort(values %params))); # no CTL in field values
}
sub FileFresh { # old files are never stale, current files are stale when the page was modified
@@ -1460,6 +1460,7 @@ sub DoRc {
my $i = 0;
while ($i < @fullrc) { # Optimization: skip old entries quickly
my ($ts) = split(/$FS/, $fullrc[$i]); # just look at the first element
$ts = 0 unless $ts;
if ($ts >= $starttime) {
$i -= 1000 if ($i > 0);
last;
@@ -1469,6 +1470,7 @@ sub DoRc {
$i -= 1000 if (($i > 0) && ($i >= @fullrc));
for (; $i < @fullrc ; $i++) {
my ($ts) = split(/$FS/, $fullrc[$i]); # just look at the first element
$ts = 0 unless $ts;
last if ($ts >= $starttime);
}
if ($i == @fullrc && $showHTML) {
@@ -1612,7 +1614,7 @@ sub GetRc {
&$printDailyTear($date);
}
if ($all) {
$revision = undef if ($ts == $changetime{$pagename}); # last one without revision
$revision = undef if ($ts and $changetime{$pagename} and $ts == $changetime{$pagename}); # last one without revision
}
&$printRCLine($pagename, $ts, $host, $username, $summary, $minor, $revision,
\@languages, $cluster);
@@ -1666,7 +1668,7 @@ sub GetRcHtml {
if ($cluster and $PageCluster) {
$diff .= GetPageLink($PageCluster) . ':';
} elsif ($UseDiff and GetParam('diffrclink', 1)) {
if ($revision == 1) {
if ($revision and $revision == 1) {
$diff .= '(' . $q->span({-class=>'new'}, T('new')) . ')';
} elsif ($all) {
$diff .= '(' . ScriptLinkDiff(2, $pagename, $tDiff, '', $revision) . ')';
@@ -1823,8 +1825,7 @@ sub DoRandom {
# == History ==
sub DoHistory {
my $id = shift;
ValidIdOrDie($id);
my $id = ValidIdOrDie(shift);
print GetHeader('',QuoteHtml(Ts('History of %s', $id)));
OpenPage($id);
my $row = 0;
@@ -1893,7 +1894,7 @@ sub DoRollback {
OpenPage($id);
my ($text, $minor) = GetTextAtTime($to);
if ($text and $Page{text} ne $text) {
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, 0);
print Ts('%s rolled back', $id), $q->br();
}
}
@@ -1984,7 +1985,8 @@ sub GetAuthorLink {
$username = FreeToNormal($username);
my $name = $username;
$name =~ s/_/ /g;
if (ValidId($username) ne '') { # Invalid under current rules
my ($error) = ValidId($username);
if ($error) { # Invalid under current rules
$username = ''; # Just pretend it isn't there.
}
if ($username and $RecentLink) {
@@ -2060,7 +2062,7 @@ sub GetHttpHeader {
$headers{-status} = $status if $status;
my $cookie = Cookie();
$headers{-cookie} = $cookie if $cookie;
if ($q->request_method() eq 'HEAD') {
if ($q->request_method()||'' eq 'HEAD') { # no warning on the command line
print $q->header(%headers);
exit; # total shortcut -- HEAD never expects anything other than the header!
}
@@ -2070,8 +2072,8 @@ sub GetHttpHeader {
sub CookieData {
my ($changed, $visible, %params);
foreach my $key (keys %CookieParameters) { # map { UrlEncode($_) }
my $default = $CookieParameters{$key};
my $value = GetParam($key, $default); # values are URL encoded
my $default = $CookieParameters{$key} || '';
my $value = GetParam($key, $default) || ''; # values are URL encoded
$params{$key} = $value if $value ne $default;
# The cookie is considered to have changed under he following
# condition: If the value was already set, and the new value is not
@@ -2193,7 +2195,7 @@ sub GetNearLinksUsed {
sub GetFooterTimestamp {
my ($id, $rev) = @_;
if ($id and $rev ne 'history' and $rev ne 'edit' and $Page{revision}) {
if ($id and (!$rev or $rev ne 'history' and $rev ne 'edit') and $Page{revision}) {
my @elements = ($q->br(), ($rev eq '' ? T('Last edited') : T('Edited')), TimeToText($Page{ts}),
Ts('by %s', GetAuthorLink($Page{host}, $Page{username})));
push(@elements, ScriptLinkDiff(2, $id, T('(diff)'), $rev)) if $UseDiff and $Page{revision} > 1;
@@ -2205,7 +2207,7 @@ sub GetFooterTimestamp {
sub GetFooterLinks {
my ($id, $rev) = @_;
my @elements;
if ($id and $rev ne 'history' and $rev ne 'edit') {
if ($id and (!$rev or $rev ne 'history' and $rev ne 'edit')) {
if ($CommentsPrefix) {
if ($OpenPageName =~ /^$CommentsPrefix(.*)/) {
push(@elements, GetPageLink($1));
@@ -2224,10 +2226,10 @@ sub GetFooterLinks {
push(@elements, ScriptLink('action=password', T('This page is read-only')));
}
}
if ($id and $rev ne 'history') {
if ($id and (!$rev or $rev ne 'history')) {
push(@elements, GetHistoryLink($id, T('View other revisions')));
}
if ($rev ne '') {
if ($rev) {
push(@elements, GetPageLink($id, T('View current revision')),
GetRCLink($id, T('View all changes')));
}
@@ -2253,7 +2255,7 @@ sub GetCommentForm {
$q->textfield(-name=>'homepage', -default=>GetParam('homepage', ''),
-override=>1, -size=>40, -maxlength=>100)),
$q->p($q->submit(-name=>'Save', -accesskey=>T('s'), -value=>T('Save')), ' ',
$q->submit(-name=>'Preview', -accesskey=>T('p'), -value=>T('Preview'))),
$q->submit(-name=>'Preview', -accesskey=>T('p'), -value=>T('Preview'))), # DoPost
$q->endform());
}
return '';
@@ -2317,8 +2319,8 @@ sub PrintHtmlDiff {
sub GetCacheDiff {
my $type = shift;
my $diff = $Page{"diff-$type"};
$diff = $Page{"diff-minor"} if ($diff eq '1'); # if major eq minor diff
my $diff = $Page{"diff-$type"} || '';
$diff = $Page{"diff-minor"} if $diff eq '1'; # if major eq minor diff
return $diff;
}
@@ -2570,14 +2572,14 @@ sub SaveKeepFile {
sub EncodePage {
my @data = @_;
my $result;
my $result = '';
$result .= (shift @data) . ': ' . EscapeNewlines(shift @data) . "\n" while (@data);
return $result;
}
sub EscapeNewlines {
$_[0] =~ s/\n/\n\t/g; # modify original instead of copying
return $_[0];
$_[0] =~ s/\n/\n\t/g if $_[0]; # modify original instead of copying
return $_[0] || '';
}
sub ExpireKeepFiles { # call with opened page
@@ -2791,7 +2793,7 @@ sub FreeToNormal { # trim all spaces and convert them to underlines
sub DoEdit {
my ($id, $newText, $preview) = @_;
ValidIdOrDie($id);
$id = ValidIdOrDie($id);
my $upload = GetParam('upload', undef);
if (!UserCanEdit($id, 1)) {
my $rule = UserIsBanned();
@@ -2861,7 +2863,7 @@ sub DoEdit {
-default=>$username, -override=>1,
-size=>20, -maxlength=>50));
print $q->p($q->submit(-name=>'Save', -accesskey=>T('s'), -value=>T('Save'))
. ($upload ? '' : ' ' . $q->submit(-name=>'Preview', -accesskey=>T('p'), -value=>T('Preview'))));
. ($upload ? '' : ' ' . $q->submit(-name=>'Preview', -accesskey=>T('p'), -value=>T('Preview')))); # DoPost
if ($upload) {
print $q->p(ScriptLink('action=edit;upload=0;id=' . UrlEncode($id), T('Replace this file with text.')));
} elsif ($UploadAllowed or UserIsAdmin()) {
@@ -2881,8 +2883,8 @@ sub GetUpload {
}
sub DoDownload {
my $id = shift;
OpenPage($id) if ValidIdOrDie($id);
my $id = ValidIdOrDie(shift);
OpenPage($id);
print $q->header(-status=>'304 NOT MODIFIED') and return if FileFresh(); # FileFresh needs an OpenPage!
my ($text, $revision) = GetTextRevision(GetParam('revision', '')); # maybe revision reset!
my $ts = $Page{ts};
@@ -2970,12 +2972,12 @@ sub UserIsBanned {
}
sub UserIsAdmin {
return 0 if ($AdminPass eq '');
return 0 if ($AdminPass eq '');
my $pwd = GetParam('pwd', '');
return 0 if ($pwd eq '');
return 0 unless $pwd;
foreach (split(/\s+/, $AdminPass)) {
next if ($_ eq '');
return 1 if ($pwd eq $_);
next if $_ eq '';
return 1 if $pwd eq $_;
}
return 0;
}
@@ -3245,19 +3247,19 @@ sub PrintSearchResult {
my $raw = GetParam('raw', 0);
my $files = ($regex =~ /^\^#FILE/); # usually skip files
OpenPage($name); # should be open already, just making sure!
my $pageText = $Page{text};
my $text = $Page{text};
my %entry;
# get the page, filter it, remove all tags
$pageText =~ s/$FS//g; # Remove separators (paranoia)
$pageText =~ s/[\s]+/ /g; # Shrink whitespace
$pageText =~ s/([-_=\\*\\.]){10,}/$1$1$1$1$1/g ; # e.g. shrink "----------"
$text =~ s/$FS//g; # Remove separators (paranoia)
$text =~ s/[\s]+/ /g; # Shrink whitespace
$text =~ s/([-_=\\*\\.]){10,}/$1$1$1$1$1/g ; # e.g. shrink "----------"
$entry{title} = $name;
if ($files) {
($entry{description}) = TextIsFile($pageText);
($entry{description}) = TextIsFile($text);
} else {
$entry{description} = SearchExtract(QuoteHtml($pageText), $regex);
$entry{description} = SearchExtract(QuoteHtml($text), $regex);
}
$entry{size} = int((length($pageText)/1024)+1) . 'K';
$entry{size} = int((length($text)/1024)+1) . 'K';
$entry{'last-modified'} = TimeToText($Page{ts});
$entry{username} = $Page{username};
$entry{host} = $Page{host};
@@ -3326,7 +3328,7 @@ sub SearchExtract {
}
sub Replace {
my ($from, $to) = @_;
my ($from, $to) = map {/(.*)/;$1;} @_; # untaint
my $lang = GetParam('lang', '');
RequestLockOrError(); # fatal
foreach my $id (AllPagesList()) {
@@ -3337,8 +3339,7 @@ sub Replace {
}
$_ = $Page{text};
if (eval "s{$from}{$to}gi") { # allows use of backreferences
Save($id, $_, $from . ' -> ' . $to, 1,
($Page{ip} ne $ENV{REMOTE_ADDR}));
Save($id, $_, $from . ' -> ' . $to, 1, 0);
}
}
ReleaseLock();
@@ -3381,8 +3382,7 @@ sub PrintAllPages {
# == Posting new pages ==
sub DoPost {
my $id = FreeToNormal(shift);
ValidIdOrDie($id);
my $id = ValidIdOrDie(FreeToNormal(shift));
if (!UserCanEdit($id, 1)) {
ReportError(Ts('Editing not allowed for %s.', $id), '403 FORBIDDEN');
} elsif (($id eq 'SampleUndefinedPage') or ($id eq T('SampleUndefinedPage'))) {
@@ -3442,7 +3442,7 @@ sub DoPost {
my $summary = GetSummary();
# rebrowse if no changes
my $oldrev = $Page{revision};
if (GetParam('Preview', '')) {
if (GetParam('Preview', '')) { # Preview button was used
ReleaseLock();
if ($comment) {
BrowsePage($id, 0, $comment);
@@ -3458,16 +3458,14 @@ sub DoPost {
}
my $newAuthor = 0;
if ($oldrev) { # the first author (no old revision) is not considered to be "new"
if (GetParam('username', '')) { # prefer usernames for potential new author detection
$newAuthor = 1 if GetParam('username', '') ne $Page{username};
} elsif ($ENV{REMOTE_ADDR} ne $Page{ip}) {
$newAuthor = 1;
}
# prefer usernames for potential new author detection
$newAuthor = 1 if not $Page{username} or $Page{username} ne GetParam('username', '');
$newAuthor = 1 if not $ENV{REMOTE_ADDR} or not $Page{ip} or $ENV{REMOTE_ADDR} ne $Page{ip};
}
my $oldtime = $Page{ts};
my $myoldtime = GetParam('oldtime', ''); # maybe empty!
# Handle raw edits with the meta info on the first line
if (GetParam('raw',0) == 2 and $string =~ /^([0-9]+).*\n((.*\n)*.*)/) {
if (GetParam('raw', 0) == 2 and $string =~ /^([0-9]+).*\n((.*\n)*.*)/) {
$myoldtime = $1;
$string = $2;
}
@@ -3622,7 +3620,7 @@ sub MergeRevisions { # merge change from file2 to file3 into file1
# Note: all diff and recent-list operations should be done within locks.
sub WriteRcLog {
my ($id, $summary, $minor, $revision, $username, $host, $languages, $cluster) = @_;
my $rc_line = join($FS, $Now, $id, $minor, $summary, $host,
my $rc_line = join($FS, map { $_||'' } $Now, $id, $minor, $summary, $host,
$username, $revision, $languages, $cluster);
AppendStringToFile($RcFile, $rc_line . "\n");
}
@@ -3630,7 +3628,7 @@ sub WriteRcLog {
sub UpdateDiffs {
my ($old, $new) = @_;
$Page{'diff-minor'} = GetDiff($old, $new);
if ($Page{revision} - 1 == $Page{oldmajor}) {
if ($Page{revision} and $Page{oldmajor} and $Page{revision} - 1 == $Page{oldmajor}) {
$Page{'diff-major'} = 1; # used in GetCacheDiff to indicate it is the same as in diff-minor
} else {
$Page{'diff-major'} = GetKeptDiff($new, $Page{oldmajor});
@@ -3738,8 +3736,8 @@ sub PageDeletable {
sub DeletePage { # Delete must be done inside locks.
my $id = shift;
my $status = ValidId($id);
return $status if $status; # this would be the error message
my ($error) = ValidId($id);
return $error if $error; # this would be the error message
foreach my $fname (GetPageFile($id), GetKeepFiles($id), GetKeepDir($id), GetLockedPageFile($id), $IndexFile) {
unlink($fname) if (-f $fname);
}
@@ -3774,12 +3772,8 @@ sub DoPageLock {
print GetHeader('', T('Set or Remove page edit lock'));
# Consider allowing page lock/unlock at editor level?
return if (!UserIsAdminOrError());
my $id = GetParam('id', '');
if ($id eq '') {
print $q->p(T('Missing page id to lock/unlock...'));
return;
}
my $fname = GetLockedPageFile($id) if ValidIdOrDie($id);
my $id = ValidIdOrDie(GetParam('id', ''));
my $fname = GetLockedPageFile($id);
if (GetParam('set', 1)) {
WriteStringToFile($fname, 'editing locked.');
} else {
@@ -3919,7 +3913,8 @@ sub GetPermanentAnchor {
my $text = $id;
$text =~ s/_/ /g;
my ($class, $resolved, $title, $exists) = ResolveId($id);
if ($class eq 'alias' and $title ne $OpenPageName) {
no warnings 'uninitialized'; # FIXME
if ($class and $class eq 'alias' and $title ne $OpenPageName) {
return '[' . Ts('anchor first defined here: %s',
ScriptLink(UrlEncode($resolved), $text, 'alias')) . ']';
} elsif ($PermanentAnchors{$id} ne $OpenPageName