/[pub]/suikawiki/script/wiki.cgi
Suika

Contents of /suikawiki/script/wiki.cgi

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.32 - (show annotations) (download)
Sun Dec 1 04:32:50 2002 UTC (21 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.31: +92 -25 lines
NN2 & IE3 & Opera6 support

1 #!/usr/bin/perl
2 #
3 # wiki.cgi - This is YukiWiki, yet another Wiki clone.
4 #
5 # Copyright (C) 2000-2002 by Hiroshi Yuki.
6 # <hyuki@hyuki.com>
7 # http://www.hyuki.com/yukiwiki/
8 #
9 # This program is free software; you can redistribute it and/or
10 # modify it under the same terms as Perl itself.
11 #
12 # walwiki.cgi based on yukiwiki.cgi - Yet another WikiWikiWeb clone.
13
14 # Walrus add (debug) start
15 my $walrus_log;
16 my $walrus_debugging = 0;
17 # Walrus add (debug) end
18
19 # Libraries.
20 use strict;
21 use lib qw(./WalWiki/lib);
22 use CGI qw(:standard);
23 use CGI::Carp qw(fatalsToBrowser);
24 use Yuki::RSS;
25 use Yuki::DiffText qw(difftext);
26 use Yuki::YukiWikiDB;
27 use AnyDBM_File;
28 require 'jcode.pl';
29 require Jcode;
30 use Fcntl;
31 my $version = '2.0.beta1.2002-05-29';
32 my $walversion;
33 ##############################
34 #
35 # You MUST modify following '$modifier_...' variables.
36 #
37 my $modifier_mail = 'w@suika.fam.cx'; # Your mail address, like 'walrus@digit.que.ne.jp'.
38 my $modifier_url = 'http://suika.fam.cx/~wakaba/'; # Your web page, like 'http://digit.que.ne.jp/work/'.
39 my $modifier_name = '和'; # Your name, like 'Makio Tsukamoto'.
40 # my $modifier_dbtype = 'AnyDBM_File'; # Fast, not available on some server, page size limited.
41 # my $modifier_dbtype = 'dbmopen'; # Fast, not available on some server, page size limited.
42 my $modifier_dbtype = 'YukiWikiDB'; # Slow, available on all environment.
43 # my $modifier_sendmail = '/usr/sbin/sendmail -t -n'; # Your sendmail.
44 my $modifier_sendmail = ''; # If you don't need mail notification.
45 my $modifier_dir_data = './wikidata'; # Your data directory.
46 my $modifier_rss_title = "SuikaWiki $walversion";
47 my $modifier_rss_link = 'http://suika.fam.cx/~wakaba/-temp/wiki2/wiki'; # Blank is not allowed.
48 my $modifier_rss_description = 'This is SuikaWiki';
49 ##############################
50 #
51 # You MAY modify following variables.
52 #
53 my $file_touch = "$modifier_dir_data/touched.txt";
54 my $file_resource = "$modifier_dir_data/resource.txt";
55 my $file_FrontPage = "$modifier_dir_data/frontpage.txt";
56 my $file_conflict = "$modifier_dir_data/conflict.txt";
57 my $file_format = "$modifier_dir_data/format.txt";
58 my $url_cgi = '/~wakaba/-temp/wiki/wiki'; ## MUST be started from '/'
59 my $url_stylesheet = $url_cgi.'?mycmd=TEXT_CSS;mypage=WikiHTMLStyle';
60 my $icontag = '<img src="/icons/folder" alt="*" width="40" height="40" />';
61 my $maxrecent = 50;
62 my $cols = 80;
63 my $rows = 20;
64 ##############################
65 #
66 # You MAY, but do NOT NEED modify following variables.
67 #
68 my $dataname = "$modifier_dir_data/wiki";
69 my $infoname = "$modifier_dir_data/info";
70 my $diffname = "$modifier_dir_data/diff";
71 my $editchar = '?';
72 my $subject_delimiter = ' - ';
73 my $use_autoimg = 1; # automatically convert image URL into <img> tag.
74 my $use_exists = 0; # If you can use 'exists' method for your DB.
75 ##############################
76 my $InterWikiName = 'InterWikiName';
77 my $RecentChanges = 'RecentChanges';
78 my $AdminChangePassword = 'AdminChangePassword';
79 my $CompletedSuccessfully = 'CompletedSuccessfully';
80 my $FrontPage = 'HomePage';
81 my $IndexPage = 'IndexPage';
82 my $SearchPage = 'SearchPage';
83 my $CreatePage = 'CreatePage';
84 my $ErrorPage = 'ErrorPage';
85 my $RssPage = 'RssPage';
86 my $NAME_OF_WikiPageLicense = 'WikiPageLicense';
87 my $AdminSpecialPage = 'Admin Special Page'; # must include spaces.
88 ##############################
89 my $bracket_name = '\[\[(\S+?)\]\]';
90 my $embedded_name = '\[\[(#\S+?)\]\]';
91 my %fmt; ## formatter objects
92 ##############################
93 my $embed_comment = '[[#comment]]';
94 my $embed_rcomment = '[[#rcomment]]';
95 my $embed_comment_Name_Prompt = '名前:';
96 my $DEFAULT_embed_comment_name = '名無しさん';
97 my $embed_interwiki = '^\[\[#(box|text|password):(\S+)\]\]$'; # Walrus add (5)
98 my %embed_command = (
99 searched => '^\[\[#searched:([^\]]+)\]\]$',
100 );
101 ##############################
102 my $info_LastModified = 'LastModified';
103 my $info_IsFrozen = 'IsFrozen';
104 my $info_AdminPassword = 'AdminPassword';
105 ##############################
106 my $kanjicode = 'euc';
107 my $charset = 'EUC-JP';
108 my $lang = 'ja';
109 my %fixedpage = (
110 $IndexPage => 1,
111 $CreatePage => 1,
112 $ErrorPage => 1,
113 $RssPage => 1,
114 $RecentChanges => 1,
115 $SearchPage => 1,
116 $AdminChangePassword => 1,
117 $CompletedSuccessfully => 1,
118 #$FrontPage => 1,
119 WikiUserAgentList => 1,
120 );
121 my %form;
122 my %database;
123 my %infobase;
124 my %diffbase;
125 my %resource;
126 my %interwiki;
127 ##############################
128 my %page_command = (
129 $IndexPage => 'index',
130 $SearchPage => 'searchform',
131 $CreatePage => 'create',
132 $RssPage => 'rss',
133 $AdminChangePassword => 'adminchangepasswordform',
134 #$FrontPage => 'FrontPage',
135 );
136 my %command_do = (
137 read => \&do_read,
138 TEXT_CSS => \&do_output_css,
139 edit => \&do_edit,
140 adminedit => \&do_adminedit,
141 adminchangepasswordform => \&do_adminchangepasswordform,
142 adminchangepassword => \&do_adminchangepassword,
143 write => \&do_write,
144 index => \&do_index,
145 searchform => \&do_searchform,
146 search => \&do_search,
147 create => \&do_create,
148 createresult => \&do_createresult,
149 FrontPage => \&do_FrontPage,
150 comment => \&do_comment,
151 RandomJump => \&do_random_jump,
152 rss => \&do_rss,
153 diff => \&do_diff,
154 interwikibox => \&do_interwiki_box, # Walrus add (5)
155 );
156 ##############################
157 my @ignore_html_page = ('FrontPage'); # Walrus add (6)
158 my @ignore_html_tags = ('a', 'br', 'img'); # Walrus add (6)
159 my $walversion = '2.0.beta1.wal.1'; # Walrus add (1)
160 ##############################
161 # &test_convert;
162 my $UA = '';
163 &main;
164 exit(0);
165 ##############################
166
167 sub main {
168 $UA = $main::ENV{HTTP_USER_AGENT};
169 &init_resource;
170 &open_db;
171 &init_form;
172 &init_InterWikiName;
173 if ($command_do{$form{mycmd}}) {
174 &{$command_do{$form{mycmd}}};
175 } else {
176 &do_FrontPage;
177 }
178 &close_db;
179 }
180
181 sub do_read {
182 my $content = $database{$form{mypage}};
183 my $lm = &get_info($form{mypage}, $info_LastModified);
184 wiki::referer::add ($form{mypage}, $ENV{HTTP_REFERER});
185 wiki::useragent::add ($ENV{HTTP_USER_AGENT});
186 my ($r, $c) = get_search_result ($form{mypage});
187 my $rl = wiki::referer::list_html ($form{mypage});
188 my @toc;
189 push @toc, qq(-<a href="#wikipage-see-also">See Also</a>) if $c;
190 push @toc, qq(-<a href="#wikipage-referer">参照元</a>) if $rl;
191 my $cf = 'SuikaWiki/0.9';
192 ## Should be support at least:
193 ## - 'SuikaWiki/0.9' CRLF
194 ## - 'H2H/' ("0.9" / "1.0" / "1.1") CRLF
195 ## - "/*" WSP* 'W3C-CSS/' ("1.0" / "2.0") "*/" CRLF
196 $cf = $1 if $content =~ s#^(?:/\*\s*|[\#<]\?)?([A-Z][A-Za-z0-9-]+/[0-9.]+(?:[^0-9.\x0D\x0A][^\x0D\x0A]*)?)[\x0D\x0A]+##s;
197 if ($cf =~ m!^(?:\#\?)?SuikaWiki/0.9(?:$|\s)!) {
198 &print_header ($form{mypage}, -last_modified => $lm,
199 -content_format => $cf, -noindex => $cf =~ /obsoleted="yes"/);
200 &print_content ($content, content_format => $cf, last_modified => $lm,
201 -toc => \@toc);
202 print &text_to_html (q([[#comment]])) if $cf !~ /obsoleted="yes"/ && !$fixedpage{$form{mypage}};
203 } else {
204 &print_header($form{mypage}, -last_modified => $lm);
205 print "<pre>@{[&escape($content)]}</pre>";
206 }
207 if ($c) {
208 print qq{<h2 @{[&id_and_name('wikipage-see-also')]}>See also</h2>};
209 print $r;
210 }
211 if ($rl) {
212 print qq(<div @{[&id_and_name('wikipage-referer')]}><h2>参照元</h2>\n$rl</div>\n);
213 }
214 &print_footer($form{mypage}, $lm);
215 }
216
217 sub do_output_css {
218 my $content = $database{$form{mypage}};
219 if ($content =~ m#^\s*/\*\s*W3C-CSS#) {
220 my $lm = &get_info($form{mypage}, $info_LastModified);
221 print "Content-Type: text/css; charset=$charset\n";
222 print "Last-Modified: $lm\n";
223 print "\n";
224 print $content;
225 } else {
226 print "Status: 406 Unsupported Media Type\n";
227 &print_header('WikiPageIsNotCSS', -noindex => 1);
228 &print_content($database{WikiPageIsNotCSS});
229 &print_footer('WikiPageIsNotCSS');
230 }
231 }
232
233 sub id_and_name ($) {
234 my $name = shift;
235 if ($UA =~ m#Mozilla/2#) {
236 qq{id="$name"><a name="$name"></a};
237 } else {
238 qq{id="$name"};
239 }
240 }
241
242 sub do_edit {
243 my ($page) = &unarmor_name(&armor_name($form{mypage}));
244 &print_header($page, -noindex => 1);
245 if (not &is_editable($page)) {
246 &print_message($resource{cantchange});
247 } elsif (&is_frozen($page)) {
248 &print_message($resource{cantchange});
249 } else {
250 &print_editform($database{$page}, &get_info($page, $info_LastModified), admin=>0);
251 }
252 wiki::referer::add ($form{mypage}, $ENV{HTTP_REFERER});
253 wiki::useragent::add ($ENV{HTTP_USER_AGENT});
254 my ($r, $c) = get_search_result ($form{mypage});
255 my $rl = wiki::referer::list_html ($form{mypage});
256 if ($c) {
257 print q{<h2 id="wikipage-see-also">See also</h2>};
258 print $r;
259 }
260 if ($rl) {
261 print qq(<div id="wikipage-referer"><h2>参照元</h2>\n$rl</div>\n);
262 }
263 &print_footer($page);
264 }
265
266 sub do_adminedit {
267 my ($page) = &unarmor_name(&armor_name($form{mypage}));
268 &print_header($page, -noindex => 1);
269 if (not &is_editable($page)) {
270 &print_message($resource{cantchange});
271 } else {
272 &print_message($resource{passwordneeded});
273 &print_editform($database{$page}, &get_info($page, $info_LastModified), admin=>1);
274 }
275 &print_footer($page);
276 }
277
278 sub do_adminchangepasswordform {
279 &print_header($AdminChangePassword, -noindex => 1);
280 &print_passwordform;
281 &print_footer($AdminChangePassword);
282 }
283
284 sub do_adminchangepassword {
285 if ($form{mynewpassword} ne $form{mynewpassword2}) {
286 &print_error($resource{passwordmismatcherror});
287 }
288 my ($validpassword_crypt) = &get_info($AdminSpecialPage, $info_AdminPassword);
289 if ($validpassword_crypt) {
290 if (not &valid_password($form{myoldpassword})) {
291 &send_mail_to_admin(<<"EOD", "AdminChangePassword");
292 myoldpassword=$form{myoldpassword}
293 mynewpassword=$form{mynewpassword}
294 mynewpassword2=$form{mynewpassword2}
295 EOD
296 &print_error($resource{passworderror});
297 }
298 }
299 my ($sec, $min, $hour, $day, $mon, $year, $weekday) = localtime(time);
300 my (@token) = ('0'..'9', 'A'..'Z', 'a'..'z');
301 my $salt1 = $token[(time | $$) % scalar(@token)];
302 my $salt2 = $token[($sec + $min*60 + $hour*60*60) % scalar(@token)];
303 my $crypted = crypt($form{mynewpassword}, "$salt1$salt2");
304 &set_info($AdminSpecialPage, $info_AdminPassword, $crypted);
305
306 &print_header($CompletedSuccessfully, -noindex => 1);
307 &print_message($resource{passwordchanged});
308 &print_footer($CompletedSuccessfully);
309 }
310
311 sub do_index {
312 &print_header($IndexPage);
313 print qq(<ul>);
314 foreach my $page (sort keys %database) {
315 if (&is_editable($page)) {
316 print qq(<li><a href="$url_cgi?@{[&encode($page)]}">@{[&escape($page)]}</a>@{[&escape(&get_subjectline($page))]}</li>);
317 # print qq(<li>@{[&get_info($page, $info_IsFrozen)]}</li>);
318 # print qq(<li>@{[0 + &is_frozen($page)]}</li>);
319 }
320 }
321 print qq(</ul>);
322 &print_footer($IndexPage);
323 }
324
325 sub do_write {
326 if (&frozen_reject()) {
327 return;
328 }
329
330 if (not &is_editable($form{mypage})) {
331 &print_header($form{mypage}, -noindex => 1);
332 &print_message($resource{cantchange});
333 &print_footer($form{mypage});
334 return;
335 }
336
337 if (&conflict($form{mypage}, $form{mymsg})) {
338 return;
339 }
340
341 # Making diff
342 {
343 &open_diff;
344 my @msg1 = split(/\n/, $database{$form{mypage}});
345 my @msg2 = split(/\n/, $form{mymsg});
346 $diffbase{$form{mypage}} = &difftext(\@msg1, \@msg2);
347 &close_diff;
348 }
349
350 if ($form{mymsg}) {
351 $database{$form{mypage}} = $form{mymsg};
352 &send_mail_to_admin($form{mypage}, "Modify");
353 if ($form{mytouch}) {
354 &set_info($form{mypage}, $info_LastModified, '' . localtime);
355 &update_recent_changes;
356 }
357 &set_info($form{mypage}, $info_IsFrozen, 0 + $form{myfrozen});
358 &print_header($CompletedSuccessfully, -noindex => 1, -goto => $url_cgi.'?mycmd=read;mypage='.&encode($form{mypage}).qq(;x-param=@{[time.[0..9]->[rand 10]]}).($form{__comment_anchor_index}?"#anchor-$form{__comment_anchor_index}":''));
359 &print_message($resource{saved});
360 &print_content("$resource{continuereading} @{[&armor_name($form{mypage})]}");
361 &print_footer($CompletedSuccessfully);
362 } else {
363 &send_mail_to_admin($form{mypage}, "Delete");
364 delete $database{$form{mypage}};
365 delete $infobase{$form{mypage}};
366 if ($form{mytouch}) {
367 &update_recent_changes;
368 }
369 &print_header($form{mypage}, -noindex => 1);
370 &print_message($resource{deleted});
371 &print_footer($form{mypage});
372 }
373 }
374
375 sub do_searchform {
376 &print_header($SearchPage);
377 &print_searchform("");
378 &print_footer($SearchPage);
379 }
380
381 sub do_search {
382 my $word = $form{mymsg};
383 &print_header($SearchPage);
384 &print_searchform(&escape($word));
385 print scalar get_search_result ($word, -output_not_found => 1, -match_myself => 1);
386 &print_footer($SearchPage);
387 }
388
389 sub get_search_result ($;%) {
390 my $word = lc shift;
391 my %option = @_;
392 my @r;
393 foreach my $page (keys %database) {
394 next if $page eq $RecentChanges || ($page eq $word && !$option{-match_myself});
395 my $content = $database{$page};
396 my $cf = 'SuikaWiki/0.9';
397 $cf = $1 if $content =~ s/^\#\?([^\x0A\x0D]+)//s;
398 next if $cf =~ /obsoleted="yes"/;
399 if (index (lc $page, $word) > -1) {
400 my $c = $content =~ s/\Q$word\E//gi;
401 push @r, [$page, $c+20];
402 } elsif (index ($word, lc $page) > -1) {
403 my $c = $content =~ s/\Q$word\E//gi;
404 push @r, [$page, $c+10];
405 } elsif (my $c = $content =~ s/\Q$word\E//gi) {
406 push @r, [$page, $c];
407 }
408 }
409 my $em = sub { my $s = shift; $s =~ s#(\Q$word\E)#<em>$1</em>#gi; $s };
410 my $r = join "\n", map {qq(<li>[$_->[1]] <a href ="$url_cgi?@{[&encode($_->[0])]}" class="wiki">@{[&$em(&escape($_->[0]))]}</a> <span class="wikipage-summary">@{[&$em(&escape(&get_subjectline($_->[0])))]}</span></li>)} sort {$b->[1] <=> $a->[1] || $a->[0] cmp $b->[0]} @r;
411 $r = qq|<ul class="search-result">$r</ul>| if $r;
412 get_message ($resource{notfound}) if @r == 0 && $option{-output_not_found};
413 wantarray? ($r, scalar @r): $r;
414 }
415
416 sub do_create {
417 &print_header($CreatePage);
418 print <<"EOD";
419 <form action="$url_cgi" method="post">
420 <input type="hidden" name="mycmd" value="edit">
421 <strong>$resource{newpagename}</strong><br>
422 <input type="text" name="mypage" value="" size="20">
423 <input type="submit" value="$resource{createbutton}"><br>
424 </form>
425 EOD
426 &print_footer($CreatePage);
427 }
428
429 sub do_random_jump {
430 my @list = keys %database;
431 my $name = &encode ($list[rand @list]);
432 my ($scheme) = 'http';
433 $scheme = $1 if $main::ENV{SERVER_PROTOCOL} =~ m#([A-Za-z0-9+.%-]+)#;
434 print "Location: $scheme://$main::ENV{SERVER_NAME}:$main::ENV{SERVER_PORT}$url_cgi?$name\n";
435 print "\n";
436 }
437
438 sub do_FrontPage {
439 open(FILE, $file_FrontPage) or &print_error("($file_FrontPage)");
440 my $content = join('', <FILE>);
441 &code_convert(\$content, $kanjicode);
442 close(FILE);
443 &print_header($FrontPage);
444 &print_content($content);
445 &print_footer($FrontPage);
446 }
447
448 sub print_error {
449 my ($msg) = @_;
450 &print_header($ErrorPage, -noindex => 1);
451 print qq(<p><strong class="error">$msg</strong></p>);
452 &print_footer($ErrorPage);
453 exit(0);
454 }
455
456 sub print_header ($;%) {
457 my ($page, %option) = @_;
458 my $bodyclass = "normal";
459 if (&is_frozen($page) and $form{mycmd} =~ /^(read|write)$/) {
460 $bodyclass = "frozen";
461 }
462 $bodyclass .= " wiki-page-obsoleted" if $option{-content_format} =~ /obsoleted="yes"/;
463 if ($option{-goto}) {
464 if ($UA =~ m#Mozilla/2|Opera#) {
465 $option{-goto} =~ tr/;/&/;
466 print qq{Refresh: 0; url=$option{-goto}\n};
467 } else {
468 print qq{Refresh: 0; url="$option{-goto}"\n};
469 }
470 }
471 print qq{Last-Modified: $option{-last_modified}\n} if $option{-last_modified};
472 my $meta_ct = '';
473 if ($UA =~ m#Mozilla/2#) {
474 $meta_ct = qq{text/html; charset=@{[&x_charset($charset)]}};
475 print qq{Content-Type: $meta_ct\n};
476 $meta_ct = qq{<meta http-equiv="content-type" content="$meta_ct">};
477 } else {
478 print qq{Content-Type: text/html; charset=$charset\n};
479 }
480 my $cookedpage = &encode($page);
481 my $escapedpage = &escape($page);
482 print <<"EOD";
483 Content-Language: $lang
484 Content-Style-Type: text/css
485
486 <!--
487 <!DOCTYPE html
488 PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
489 "http://www.w3.org/TR/html4/loose.dtd"> + RUBY -->
490 <html lang="$lang">
491 <head>
492 $meta_ct
493 <title>$escapedpage</title>
494 <link rel="index" href="$url_cgi?$IndexPage">
495 <link rel="help" href="$url_cgi?WikiHelp">
496 <link rel="copyright" href="$url_cgi?$NAME_OF_WikiPageLicense">
497 <link rel="stylesheet" type="text/css" href="@{[&escape($url_stylesheet)]}">
498 @{[$option{-noindex} ? q(<meta name="ROBOTS" content="NOINDEX">) : '']}
499 </head>
500 <body class="$bodyclass">
501 EOD
502 &print_navigate_links ($page);
503 print <<EOD;
504 <h1 class="header">@{[&escape($page)]}</h1>
505 EOD
506 }
507
508 sub x_charset ($) {
509 my $charset = lc shift;
510 if ($charset eq 'euc-jp') {
511 $charset = 'x-euc-jp';
512 } elsif ($charset eq 'shift_jis') {
513 $charset = 'x-sjis';
514 }
515 $charset;
516 }
517
518 sub print_navigate_links (@) {
519 my ($page) = @_;
520 my $editable = 0;
521 my $admineditable = 0;
522 if (&is_frozen($page) and $form{mycmd} =~ /^(read|write)$/) {
523 $editable = 0;
524 #$admineditable = 1;
525 } elsif (&is_editable($page) and $form{mycmd} =~ /^(read|write)$/) {
526 #$admineditable = 1;
527 $editable = 1;
528 } else {
529 $editable = 0;
530 }
531 my $cookedpage = &encode($page);
532 print <<EOH;
533 <div class="tools">
534 @{[ $admineditable
535 ? qq(<a title="$resource{admineditthispage}" href="$url_cgi?mycmd=adminedit;mypage=$cookedpage">$resource{admineditbutton}</a> | )
536 : qq()
537 ]}
538 @{[ $editable
539 ? #qq(<a title="$resource{editthispage}" href="$url_cgi?mycmd=edit;mypage=$cookedpage" accesskey="E">$resource{editbutton} <kbd>E</kbd></a> | )
540 qq(<a title="$resource{editthispage}" href="$url_cgi?mycmd=edit;mypage=$cookedpage" accesskey="E">編集</a> | )
541 : qq()
542 ]}
543 <a href="$url_cgi?mycmd=read;mypage=$cookedpage;x-param=@{[time.[0..9]->[rand 10]]}">表示</a> |
544 @{[ $admineditable
545 ? qq(<a href="$url_cgi?mycmd=diff;mypage=$cookedpage">$resource{diffbutton}</a> | )
546 : qq()
547 ]}
548 <a href="$url_cgi?$CreatePage" class="wiki">新規</a> |
549 <a href="$url_cgi?$IndexPage" class="wiki">$resource{indexbutton}</a> |
550 <a href="$url_cgi?$FrontPage" class="wiki">首頁</a> |
551 <a href="$url_cgi?$SearchPage" class="wiki">$resource{searchbutton}</a> |
552 <a href="$url_cgi?mycmd=RandomJump;x-param=@{[time.[0..9]->[rand 10]]}" class="wiki randomlink">どこか</a> |
553 <a href="$url_cgi?$RecentChanges" class="wiki">最新</a>
554 </div>
555 EOH
556 <<EOH; ## temp
557 <a href="$url_cgi?$CreatePage" class="wiki">$resource{createbutton}</a> |
558 <a href="$url_cgi?$IndexPage" class="wiki">$resource{indexbutton}</a> |
559 <!-- <a href="$url_cgi?$RssPage" class="wiki">$resource{rssbutton}</a> | -->
560 <a href="$url_cgi?$FrontPage" class="wiki">$FrontPage</a> |
561 <a href="$url_cgi?$SearchPage" class="wiki">$resource{searchbutton}</a> |
562 <a href="$url_cgi?mycmd=RandomJump;x-param=@{[time.[0..9]->[rand 10]]}" class="wiki randomlink">どこか</a> |
563 <a href="$url_cgi?$RecentChanges" class="wiki">$resource{recentchangesbutton}</a>
564 </div>
565 EOH
566 }
567
568 sub print_footer {
569 my ($page, $lm) = @_;
570 $walrus_log = ($walrus_debugging) ? &text_to_html("----\n$walrus_log") : ''; # Walrus add (debug)
571 # Walrus mod (1) start
572 my $cvslog1 = q$Revision: 1.31 $;
573 my $cvslog2 = q$Date: 2002/11/14 10:22:19 $;
574 print_navigate_links ($page);
575 print <<"EOD";
576 @{[ $lm ? qq(<div id="wikipage-last-modified">Last modified: $lm</div>) : '' ]}
577 <div class="footer">
578 <a href="http://www.hyuki.com/yukiwiki/" title="$version &copy; 2000-2002 by Hiroshi Yuki">YukiWiki</a> <a href="http://digit.que.ne.jp/work/" title="$walversion &copy; 2000-2002 by Makio Tsukamoto">WalWiki</a>
579 <a href="/gate/cvs/wakaba/wiki/" title="CVS Repository of this script ($cvslog2)">SuikaWiki $cvslog1</a>
580 <div class="navigation">
581 [<a href="/" title="このサーバーの首頁">/</a>
582 <a href="/map" title="このサーバーの案内">地図</a>
583 <a href="/search/" title="このサーバーの検索">検索</a>]
584 </div>
585 </div>
586 $walrus_log
587 </body>
588 </html>
589 EOD
590 # print <<"EOD";
591 # <hr>
592 # <address class="footer">
593 # <a href="http://www.hyuki.com/yukiwiki/">YukiWiki</a> $version
594 # &copy; 2000-2002 by <a href="http://www.hyuki.com/">Hiroshi Yuki</a>.<br />
595 # Modified by <a href="$modifier_url">$modifier_name</a>.
596 # </address>
597 # <p class="footer">
598 # <a href="http://www.hyuki.com/yukiwiki/">$icontag</a>
599 # </p>
600 # </body>
601 # </html>
602 # EOD
603 # Walrus mod (1) end
604 }
605
606 sub escape {
607 my $s = shift;
608 $s =~ s|\r\n|\n|g;
609 $s =~ s|&|&amp;|g;
610 $s =~ s|<|&lt;|g;
611 $s =~ s|>|&gt;|g;
612 $s =~ s|"|&quot;|g;
613 return $s;
614 }
615
616 sub unescape {
617 my $s = shift;
618 # $s =~ s|\n|\r\n|g;
619 $s =~ s|&lt;|<|g;
620 $s =~ s|&gt;|>|g;
621 $s =~ s|&quot;|"|g;
622 $s =~ s|&amp;|&|g;
623 return $s;
624 }
625
626 sub print_content ($;$) {
627 my ($rawcontent, %option) = @_;
628 print &text_to_html($rawcontent, toc=>1, %option);
629 }
630
631 sub text_to_html {
632 my ($txt, %option) = @_;
633 my (@txt) = split(/\n/, $txt);
634 my @toc;
635 my @toc2 = @{$option{-toc}||[]};
636 my $tocnum = 0;
637 my (@saved, @result);
638 unshift(@saved, "</p>");
639 push(@result, "<p>");
640 foreach (@txt) {
641 chomp;
642 if (/^\*\*\*\*\*([^\x0D\x0A]*)/) {
643 push(@toc, qq(----- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));
644 push(@result, splice(@saved), qq(<h6 id="i$tocnum">) . &inline($1) . '</h6>');
645 $tocnum++;
646 } elsif (/^\*\*\*\*([^\x0D\x0A]*)/) {
647 push(@toc, qq(---- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));
648 push(@result, splice(@saved), qq(<h5 id="i$tocnum">) . &inline($1) . '</h5>');
649 $tocnum++;
650 } elsif (/^\*\*\*([^\x0D\x0A]*)/) {
651 push(@toc, qq(--- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));
652 push(@result, splice(@saved), qq(<h4 id="i$tocnum">) . &inline($1) . '</h4>');
653 $tocnum++;
654 } elsif (/^\*\*([^\x0D\x0A]*)/) {
655 # if (/^\*\*(.*)/) {
656 # Walrus mod (6) end
657 push(@toc, qq(-- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));
658 push(@result, splice(@saved), qq(<h3><a name="i$tocnum"> </a>) . &inline($1) . '</h3>');
659 $tocnum++;
660 } elsif (/^\*([^\x0D\x0A]*)/) {
661 push(@toc, qq(- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));
662 push(@result, splice(@saved), qq(<h2><a name="i$tocnum"> </a>) . &inline($1) . '</h2>');
663 $tocnum++;
664 } elsif (/^(={1,6})(.*)/) {
665 &back_push('ol', length($1), \@saved, \@result);
666 push(@result, '<li>' . &inline($2) . '</li>');
667 } elsif (/^(-{1,6})(.*)/) {
668 &back_push('ul', length($1), \@saved, \@result);
669 my ($pf, $l) = ('', $2);
670 if (!$main::_EMBEDED && $l =~ s/^\s*\[([0-9]+)\]//) {
671 my $num = 0+$1;
672 $pf = qq(<a name="anchor-$num" id="anchor-$num" class="anchor">[$num]</a>);
673 }
674 push(@result, '<li>' . $pf . &inline ($l) . '</li>');
675 } elsif (/^:([^:]+):(.*)/) {
676 &back_push('dl', 1, \@saved, \@result);
677 push(@result, '<dt>' . &inline($1) . '</dt>', '<dd>' . &inline($2) . '</dd>');
678 } elsif (/^(?!>>\d)(>{1,5})(.*)/) {
679 &back_push('blockquote', length($1), \@saved, \@result);
680 push @result, "<p>";
681 push(@result, &inline($2));
682 unshift @saved, "</p>";
683 } elsif (/^\s*$/) {
684 push(@result, splice(@saved));
685 push(@result, "<p>");
686 unshift(@saved, "</p>");
687 } elsif (/^(\s+.*)$/) {
688 &back_push('pre', 1, \@saved, \@result);
689 #push(@result, &escape($1)); # Not &inline, but &escape
690 push(@result, &inline($1));
691 # } elsif (/^\,(.*)$/) { # Walrus del (BF)
692 } elsif (/^\,(.*?)[\x0D\x0A]*$/) { # Walrus add (BF)
693 &back_push('table', 1, \@saved, \@result, ' border="1"');
694 #######
695 # This part is taken from Mr. Ohzaki's Perl Memo and Makio Tsukamoto's WalWiki.
696 # XXXXX
697 my $tmp = "$1,";
698 my @value = map {/^"(.*)"$/ ? scalar($_ = $1, s/""/"/g, $_) : $_} ($tmp =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g);
699 my @align = map {(s/^\s+//) ? ((s/\s+$//) ? ' align="center"' : ' align="right"') : ''} @value;
700 my @colspan = map {($_ eq '==') ? 0 : 1} @value;
701 for (my $i = 0; $i < @value; $i++) {
702 if ($colspan[$i]) {
703 while ($i + $colspan[$i] < @value and $value[$i + $colspan[$i]] eq '==') {
704 $colspan[$i]++;
705 }
706 $colspan[$i] = ($colspan[$i] > 1) ? sprintf(' colspan="%d"', $colspan[$i]) : '';
707 $value[$i] = sprintf('<td%s%s>%s</td>', $align[$i], $colspan[$i], &inline($value[$i]));
708 } else {
709 $value[$i] = '';
710 }
711 }
712 push(@result, join('', '<tr>', @value, '</tr>'));
713 # XXXXX
714 #######
715 } elsif (/^\[(INS|DEL|PRE)\[\s*$/) {
716 push @result, splice (@saved), '<'.lc($1).'>';
717 unshift @saved, "</p>";
718 push @result, "<p>";
719 } elsif (/^\](INS|DEL|PRE)\]\s*$/) {
720 push @result, splice (@saved), '</'.lc($1).'>';
721 } elsif (/^\[([0-9]+)\](.*)$/ && !$main::_EMBEDED) {
722 my $num = 0+$1;
723 push @result, qq(<a name="anchor-$num" id="anchor-$num" class="anchor">[$num]</a>);
724 push @result, &inline ($2);
725 } else {
726 push(@result, &inline($_));
727 }
728 }
729 push(@result, splice(@saved));
730
731 my $toc = '';
732 if ($option{toc}) {
733 # Convert @toc (table of contents) to HTML.
734 # This part is taken from Makio Tsukamoto's WalWiki.
735 my (@tocsaved, @tocresult);
736 foreach (@toc,@toc2) {
737 if (/^(-{1,6})(.*)$/) {
738 &back_push('ul', length($1), \@tocsaved, \@tocresult);
739 push(@tocresult, '<li>' . $2 . '</li>');
740 }
741 }
742 push(@tocresult, splice(@tocsaved));
743 $toc = join("\n", @tocresult);
744 $toc = $toc ? qq(<div id="wikipage-toc">$toc</div>) : '';
745 }
746 $toc .= join("\n", @result);
747 $toc =~ s#<p>\n</p>##g;
748 $toc =~ s#[\x0D\x0A]+</#</#g;
749 $toc =~ s#<pre>\n#<pre>#g;
750 $toc;
751 }
752
753 sub back_push {
754 my ($tag, $level, $savedref, $resultref, $attr) = @_;
755 while (@$savedref > $level) {
756 push(@$resultref, shift(@$savedref));
757 }
758 if ($savedref->[0] ne "</$tag>") {
759 push(@$resultref, splice(@$savedref));
760 }
761 while (@$savedref < $level) {
762 unshift(@$savedref, "</$tag>");
763 push(@$resultref, "<$tag$attr>");
764 }
765 }
766
767 sub inline {
768 my ($line) = @_;
769 $line = &escape($line);
770 $line =~ s{\[(INS|DEL|SUP|SUB|VAR|CODE|KBD|SAMP|DFN)(?:\(([A-Za-z0-9\x20-]+)\))?\[(.+?)\]\]}{<@{[lc $1]}@{[$2 ? qq( class="$2") : '']}>$3</@{[lc $1]}>}g;
771 $line =~ s:\[(WEAK)\[(.+?)\]\]:<span class="@{[lc $1]}">$2</span>:g;
772 $line =~ s:\[ABBR\[([^]]+)\] \[([^]]+)\]\]:<acronym title="$2">$1</acronym>:g;
773 $line =~ s:\[RUBYB\[([^]]+)\] \[([^]]+)\] \[([^]]+)\]\]:<span class="ruby"><ruby class="rb"><rb>$1</rb><rp>(</rp><rt>$2</rt><rp>)</rp></ruby><span class="rp"> (</span><span class="rt-below">$3</span><span class="rp">) </span></span>:g;
774 $line =~ s:\[RUBY\[([^]]+)\] \[([^]]+)\]\]:<ruby><rb>$1</rb><rp>(</rp><rt>$2</rt><rp>)</rp></ruby>:g;
775 $line =~ s:\[RUBYB\[([^]]+)\] \[([^]]+)\]\]:<span class="ruby"><span class="rb">$1</span><span class="rp"> (</span><span class="rt-below">$2</span><span class="rp">) </span></span>:g;
776 $line =~ s%\[Q\[([^]]+)\](?: \[&lt;([\x21-\x5A\x5E-\x7E]+)&gt;\])?\]%「<q@{[$2?qq( cite="$2"):'']}>$1</q>」%g;
777 $line =~ s|'''([^']+)'''|<strong>$1</strong>|g;
778 $line =~ s|''([^']+)''|<em>$1</em>|g;
779 $line =~ s{
780 ((?:$bracket_name)) # [[likethis]], [[#comment]], [[Friend:remotelink]]
781 |\[\[([^[]+?)]&gt;&gt;([0-9]+)] # [[WikiName]>>1]
782 |&gt;&gt;([0-9]+)
783 |&lt;([A-Za-z0-9%]+:(?:(?!&gt;).)+)&gt;
784 }{
785 my ($l, $page,$anchor, $anum, $uri) = ($1, $3,$4, 0+$5, $6);
786 if ($l) {
787 &make_link($l)
788 } elsif (defined $page) {
789 &make_wikilink ($page, anchor => 0+$anchor);
790 } elsif ($anum) {
791 qq(<a href="#anchor-$anum" class="wiki-anchor">&gt;&gt;$anum</a>);
792 } elsif ($uri) {
793 &make_urilink ($uri);
794 }
795 }gex;
796 return $line;
797 }
798
799 sub make_wikilink ($%) {
800 my ($ename, %option) = @_;
801 my $name = &unescape ($ename);
802 if ($database{$name}) {
803 my $subject = &escape (&get_subjectline ($name, delimiter => ''));
804 if ($option{anchor}) {
805 return qq(<a title="$subject" href="$url_cgi?@{[&encode($name)]}#anchor-$option{anchor}" class="wiki">$ename&gt;&gt;$option{anchor}</a>);
806 } else {
807 return qq(<a title="$subject" href="$url_cgi?@{[&encode($name)]}" class="wiki">$ename</a>);
808 }
809 } else {
810 return qq(<a title="$resource{editthispage}" href="$url_cgi?mycmd=edit;mypage=@{[&escape($name)]}" class="wiki not-exist">$ename<span class="mark">$editchar</span></a>);
811 }
812 }
813
814 sub make_urilink ($;%) {
815 require URI;
816 my $uri = shift;
817 if ($uri =~ s/^IW://) { ## InterWiki (not URI)
818 $uri = &unescape ($uri);
819 if ($uri =~ /^([^\x00-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+|"(?:\\.|[^"\\])+"):([^\x00-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+|"(?:\\.|[^"\\])+")$/) {
820 my ($site, $name) = ($1, $2);
821 for ($site, $name) {
822 if (s/^"//) { s/"$//; s/\\(.)/$1/g }
823 }
824 if ($interwiki{$site}) {
825 my $uri = &escape ($fmt{interwiki}->replace ($interwiki{$site} => {site => $site, name => $name}));
826 $site = &escape ($site); $name = &escape ($name);
827 qq(&lt;<a href="$uri" class="out-of-wiki interwiki" title="$name ($site); URI: &lt;$uri&gt;"><span class="interwiki-site">$site:</span><span class="interwiki-name">$name</span></a>&gt;);
828 } else {
829 qq(&lt;未登録の <a href="$url_cgi?InterWikiName" class="wiki">InterWikiName</a>: @{[&escape ($site)]}>);
830 }
831 } else {
832 qq(&lt;不正な <a href="$url_cgi?InterWikiName" class="wiki">InterWikiName</a>: @{[&escape($uri)]}>);
833 }
834 } elsif ($uri =~ /^urn:/) { ## URN
835 my $uri2 = &escape (URI->new ('/uri-res/N2L?'.&unescape ($uri), 'http')->canonical);
836 qq(&lt;<a href="$uri2" title="URI: &lt;$uri&gt; (via &lt;$uri2&gt;)" class="out-of-wiki urn">$uri</a>&gt;);
837 } elsif ($uri =~ s/^MAIL://) { ## mail address (not URI)
838 my $uri2 = &escape (URI->new ('mailto:'.&unescape ($uri))->canonical);
839 qq(&lt;<a href="$uri2" class="out-of-wiki mail">$uri</a>&gt;);
840 } elsif ($uri =~ s/^IMG(?:\([^)]+\))?://) { ## image (not URI itself)
841 my $uri2 = &escape (URI->new (&unescape ($uri))->canonical);
842 qq(<img src="$uri2" alt="" title="URI: &lt;$uri2&gt;" class="out-of-wiki">);
843 } else { ## misc. URI
844 CGI::Carp::warningsToBrowser (0);
845 my $uri2 = &escape (URI->new (&unescape ($uri))->canonical);
846 CGI::Carp::warningsToBrowser (1);
847 qq(&lt;<a href="$uri2" title="URI: &lt;$uri2&gt;" class="out-of-wiki">$uri</a>&gt;);
848 }
849 }
850
851 ## to be obsoleted
852 sub make_link {
853 my $chunk = shift;
854 # Walrus add (3) start
855 $chunk =~ s/^&lt;(.*)&gt;$/$1/;
856 my $name = $chunk;
857 $name = &unarmor_name($name);
858 # Walrus add (3) end
859 if ($chunk =~ /^$embedded_name$/) {
860 return &embedded_to_html($chunk);
861 } else {
862 $chunk = &unarmor_name($chunk);
863 $chunk = &unescape($chunk); # To treat '&' or '>' or '<' correctly.
864 my $cookedchunk = &encode($chunk);
865 if ($database{$chunk}) {
866 my $subject = &escape(&get_subjectline($chunk, delimiter => ''));
867 # return qq(<a title="$subject" href="$url_cgi?$cookedchunk">$chunk</a>); # Walrus del (3)
868 return qq(<a title="$subject" href="$url_cgi?$cookedchunk" class="wiki">@{[&escape($name)]}</a>); # Walrus add (3)
869 } elsif ($page_command{$chunk}) {
870 # return qq(<a title="$chunk" href="$url_cgi?$cookedchunk">$chunk</a>); # Walrus del (3)
871 return qq(<a title="$chunk" href="$url_cgi?$cookedchunk" class="wiki">@{[&escape($name)]}</a>); # Walrus add (3)
872 } else {
873 return qq(<a title="$resource{editthispage}" href="$url_cgi?mycmd=edit;mypage=$cookedchunk" class="wiki">@{[&escape($name)]}<span class="mark">$editchar</span></a>);
874 }
875 }
876 }
877
878 sub print_message {
879 my ($msg) = @_;
880 print qq(<p><strong>$msg</strong></p>);
881 }
882
883 sub get_message {
884 my ($msg) = @_;
885 qq(<p><strong>$msg</strong></p>);
886 }
887
888 sub init_form {
889 if (param()) {
890 foreach my $var (param()) {
891 $form{$var} = param($var);
892 }
893 }
894 $form{mypage} = &code_convert(\$form{mypage}, $kanjicode);
895 if ($main::ENV{QUERY_STRING} && $main::ENV{QUERY_STRING} !~ /[&;=]/) {
896 my $query = &decode($main::ENV{QUERY_STRING});
897 $query = &code_convert(\$query, $kanjicode);
898 if ($page_command{$query}) {
899 $form{mycmd} = $page_command{$query};
900 $form{mypage} = $query;
901 } else {
902 $form{mypage} = $query;
903 $form{mycmd} = $database{$form{mypage}} ? 'read' : 'edit';
904 }
905 }
906 $form{mypage} ||= 'HomePage';
907 $form{mycmd} ||= 'read';
908
909 # mypreview_edit -> do_edit, with preview.
910 # mypreview_adminedit -> do_adminedit, with preview.
911 # mypreview_write -> do_write, without preview.
912 foreach (keys %form) {
913 if (/^mypreview_(.*)$/) {
914 $form{mycmd} = $1;
915 $form{mypreview} = 1;
916 }
917 }
918
919 #
920 # $form{mycmd} is frozen here.
921 #
922
923 $form{mymsg} = &code_convert(\$form{mymsg}, $kanjicode);
924 $form{myname} = &code_convert(\$form{myname}, $kanjicode);
925 }
926
927 sub update_recent_changes {
928 my $update = "- @{[&get_now]} [[@{[&escape($form{mypage})]}]] @{[&get_subjectline($form{mypage})]}";
929 my @oldupdates = split(/\r?\n/, $database{$RecentChanges});
930 my @updates;
931 foreach (@oldupdates) {
932 /^\- \d\d\d\d\-\d\d\-\d\d \([^)]+\) \d\d:\d\d \[\[(\S+?)\]\]/;
933 my $name = $1;
934 if ($name ne $form{mypage}) {
935 push @updates, $_;
936 }
937 }
938 if (&is_exist_page($form{mypage})) {
939 unshift @updates, $update;
940 }
941 splice(@updates, $maxrecent + 1);
942 $database{$RecentChanges} = "#?SuikaWiki/0.9\n" . join("\n", @updates);
943 if ($file_touch) {
944 open(FILE, "> $file_touch");
945 print FILE localtime() . "\n";
946 close(FILE);
947 }
948 }
949
950 sub get_subjectline {
951 my ($page, %option) = @_;
952 if (not &is_editable($page)) {
953 return "";
954 } else {
955 # Delimiter check.
956 my $delim = $subject_delimiter;
957 if (defined($option{delimiter})) {
958 $delim = $option{delimiter};
959 }
960
961 # Get the subject of the page.
962 my $subject = $database{$page};
963 $subject =~ s#^(?:\#\?)?SuikaWiki/0.9[^\x0D\x0A]*[\x0D\x0A]+##s;
964 $subject =~ s/\r?\n.*//s;
965 return "$delim$subject".$option{tail};
966 }
967 }
968
969 sub send_mail_to_admin {
970 my ($page, $mode) = @_;
971 return unless $modifier_sendmail;
972 my $message = <<"EOD";
973 To: $modifier_mail
974 From: $modifier_mail
975 Subject: [Wiki]
976 MIME-Version: 1.0
977 Content-Type: text/plain; charset=ISO-2022-JP
978 Content-Transfer-Encoding: 7bit
979
980 --------
981 MODE = $mode
982 REMOTE_ADDR = $ENV{REMOTE_ADDR}
983 REMOTE_HOST = $ENV{REMOTE_HOST}
984 --------
985 $page
986 --------
987 $database{$page}
988 --------
989 EOD
990 &code_convert(\$message, 'jis');
991 open(MAIL, "| $modifier_sendmail");
992 print MAIL $message;
993 close(MAIL);
994 }
995
996 sub open_db {
997 if ($modifier_dbtype eq 'dbmopen') {
998 dbmopen(%database, $dataname, 0666) or &print_error("(dbmopen) $dataname");
999 dbmopen(%infobase, $infoname, 0666) or &print_error("(dbmopen) $infoname");
1000 } elsif ($modifier_dbtype eq 'AnyDBM_File') {
1001 tie(%database, "AnyDBM_File", $dataname, O_RDWR|O_CREAT, 0666) or &print_error("(tie AnyDBM_File) $dataname");
1002 tie(%infobase, "AnyDBM_File", $infoname, O_RDWR|O_CREAT, 0666) or &print_error("(tie AnyDBM_File) $infoname");
1003 } else {
1004 tie(%database, "Yuki::YukiWikiDB", $dataname) or &print_error("(tie Yuki::YukiWikiDB) $dataname");
1005 tie(%infobase, "Yuki::YukiWikiDB", $infoname) or &print_error("(tie Yuki::YukiWikiDB) $infoname");
1006 }
1007 }
1008
1009 sub close_db {
1010 if ($modifier_dbtype eq 'dbmopen') {
1011 dbmclose(%database);
1012 dbmclose(%infobase);
1013 } elsif ($modifier_dbtype eq 'AnyDBM_File') {
1014 untie(%database);
1015 untie(%infobase);
1016 } else {
1017 untie(%database);
1018 untie(%infobase);
1019 }
1020 }
1021
1022 sub open_diff {
1023 if ($modifier_dbtype eq 'dbmopen') {
1024 dbmopen(%diffbase, $diffname, 0666) or &print_error("(dbmopen) $diffname");
1025 } elsif ($modifier_dbtype eq 'AnyDBM_File') {
1026 tie(%diffbase, "AnyDBM_File", $diffname, O_RDWR|O_CREAT, 0666) or &print_error("(tie AnyDBM_File) $diffname");
1027 } else {
1028 tie(%diffbase, "Yuki::YukiWikiDB", $diffname) or &print_error("(tie Yuki::YukiWikiDB) $diffname");
1029 }
1030 }
1031
1032 sub close_diff {
1033 if ($modifier_dbtype eq 'dbmopen') {
1034 dbmclose(%diffbase);
1035 } elsif ($modifier_dbtype eq 'AnyDBM_File') {
1036 untie(%diffbase);
1037 } else {
1038 untie(%diffbase);
1039 }
1040 }
1041
1042 sub print_searchform {
1043 my ($word) = @_;
1044 print <<"EOD";
1045 <form action="$url_cgi" method="get">
1046 <input type="hidden" name="mycmd" value="read">
1047 <input type="text" name="mypage" value="$word" size="20">
1048 <input type="submit" value="$resource{searchbutton}">
1049 </form>
1050 EOD
1051 }
1052
1053 sub print_editform {
1054 my ($mymsg, $lastmodified, %mode) = @_;
1055 my $frozen = &is_frozen($form{mypage});
1056
1057 if ($form{mypreview}) {
1058 if ($form{mymsg}) {
1059 unless ($mode{conflict}) {
1060 print qq(<h3>$resource{previewtitle}</h3>\n);
1061 print qq($resource{previewnotice}\n);
1062 print qq(<div class="preview">\n);
1063 &print_content($form{mymsg});
1064 print qq(</div>\n);
1065 }
1066 } else {
1067 print qq($resource{previewempty});
1068 }
1069 $mymsg = &escape($form{mymsg});
1070 } else {
1071 $mymsg = &escape($mymsg || $database{NewPageTemplate});
1072 }
1073
1074 my $edit = $mode{admin} ? 'adminedit' : 'edit';
1075 my $escapedmypage = &escape($form{mypage});
1076 my $escapedmypassword = &escape($form{mypassword});
1077
1078 print <<"EOD";
1079 <form action="$url_cgi" method="post">
1080 <h2>$escapedmypageの編集</h2>
1081 @{[ $mode{admin} ? qq($resource{frozenpassword} <input type="password" name="mypassword" value="$escapedmypassword" size="10"><br>) : "" ]}
1082 <input type="hidden" name="myLastModified" value="$lastmodified">
1083 <input type="hidden" name="mypage" value="$escapedmypage">
1084 <textarea cols="$cols" rows="$rows" name="mymsg" tabindex="1">$mymsg</textarea><br>
1085 @{[
1086 $mode{admin} ?
1087 qq(
1088 <input type="radio" name="myfrozen" value="1" @{[$frozen ? qq(checked="checked") : ""]}>$resource{frozenbutton}
1089 <input type="radio" name="myfrozen" value="0" @{[$frozen ? "" : qq(checked="checked")]}>$resource{notfrozenbutton}<br>)
1090 : ""
1091 ]}
1092 @{[
1093 $mode{conflict} ? "" :
1094 qq(
1095 <input type="checkbox" name="mytouch" value="on" checked="checked">$resource{touch}<br>
1096 <input type="submit" name="mypreview_$edit" value="$resource{previewbutton}">
1097 <input type="submit" name="mypreview_write" value="$resource{savebutton}" accesskey="S"><kbd>S</kbd>
1098 [@{[do {my $n = 0;
1099 $mymsg =~ s/(?:-+\s)?\[([0-9]+)\]/$n = $1 if $1 > $n; $&/mge;
1100 ++$n}]}]<br>
1101 )
1102 ]}
1103 </form>
1104 EOD
1105 unless ($mode{conflict}) {
1106 # Show the format rule.
1107 my $help = $database{'WikiEditHelp'};
1108 $help =~ s!^\#\?([A-Z][A-Za-z0-9-]+/[0-9.]+(?:[^0-9.\x0D\x0A][^\x0D\x0A]*)?)[\x0D\x0A]+!!s;
1109 print &text_to_html ($help, toc => 0);
1110 # open(FILE, $file_format) or &print_error("($file_format)");
1111 # my $content = join('', <FILE>);
1112 # &code_convert(\$content, $kanjicode);
1113 # close(FILE);
1114 # print &text_to_html($content, toc=>0);
1115 }
1116 }
1117
1118 sub print_passwordform {
1119 print <<"EOD";
1120 <form action="$url_cgi" method="post">
1121 <input type="hidden" name="mycmd" value="adminchangepassword">
1122 $resource{oldpassword} <input type="password" name="myoldpassword" size="10"><br>
1123 $resource{newpassword} <input type="password" name="mynewpassword" size="10"><br>
1124 $resource{newpassword2} <input type="password" name="mynewpassword2" size="10"><br>
1125 <input type="submit" value="$resource{changepasswordbutton}"><br>
1126 </form>
1127 EOD
1128 }
1129
1130 sub is_editable {
1131 my ($page) = @_;
1132 if ($fixedpage{$page} || $page =~ /\s/ || $page =~ /^\#/) {
1133 return 0;
1134 } else {
1135 return 1;
1136 }
1137 }
1138
1139 # armor_name:
1140 # WikiName -> WikiName
1141 # not_wiki_name -> [[not_wiki_name]]
1142 sub armor_name { qq([[$_[0]]]) }
1143
1144 # unarmor_name:
1145 # [[bracket_name]] -> bracket_name
1146 # WikiName -> WikiName
1147 sub unarmor_name {
1148 my ($name) = @_;
1149 if ($name =~ /^$bracket_name$/) {
1150 return $1;
1151 } else {
1152 return $name;
1153 }
1154 }
1155
1156 sub decode {
1157 my ($s) = @_;
1158 $s =~ tr/+/ /;
1159 $s =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("C", hex($1))/eg;
1160 return $s;
1161 }
1162
1163 sub encode {
1164 my ($s) = @_;
1165 my $encoded = '';
1166 foreach my $ch (split(//, $s)) {
1167 if ($ch =~ /[A-Za-z0-9_]/) {
1168 $encoded .= $ch;
1169 } else {
1170 $encoded .= '%' . sprintf("%02X", ord($ch));
1171 }
1172 }
1173 return $encoded;
1174 }
1175
1176 sub init_resource {
1177 open(FILE, $file_resource) or &print_error("(resource)");
1178 while (<FILE>) {
1179 chomp;
1180 next if /^#/;
1181 my ($key, $value) = split(/=/, $_, 2);
1182 $resource{$key} = &code_convert(\$value, $kanjicode);
1183 }
1184 close(FILE);
1185 }
1186
1187 sub conflict {
1188 my ($page, $rawmsg) = @_;
1189 if ($form{myLastModified} eq &get_info($page, $info_LastModified)) {
1190 return 0;
1191 }
1192 open(FILE, $file_conflict) or &print_error("(conflict)");
1193 my $content = join('', <FILE>);
1194 &code_convert(\$content, $kanjicode);
1195 close(FILE);
1196 &print_header($page, -noindex => 1);
1197 &print_content($content);
1198 &print_editform($rawmsg, $form{myLastModified}, frozen=>0, conflict=>1);
1199 &print_footer($page);
1200 return 1;
1201 }
1202
1203 sub get_now {
1204 my (@week) = qw(Sun Mon Tue Wed Thu Fri Sat);
1205 my (@week) = qw(日 月 火 水 木 金 土);
1206 my ($sec, $min, $hour, $day, $mon, $year, $weekday) = localtime(time);
1207 $year += 1900;
1208 $mon++;
1209 $mon = "0$mon" if $mon < 10;
1210 $day = "0$day" if $day < 10;
1211 $hour = "0$hour" if $hour < 10;
1212 $min = "0$min" if $min < 10;
1213 #$sec = "0$sec" if $sec < 10;
1214 $weekday = $week[$weekday];
1215 return "$year-$mon-$day ($weekday) $hour:$min";
1216 }
1217
1218 sub init_InterWikiName {
1219 my @content = split /\n/, $database{$InterWikiName};
1220 for (@content) {
1221 if (/^([^#]\S*)\s+(\S[^\x0A\x0D]+)/) {
1222 $interwiki{$1} = $2;
1223 }
1224 }
1225 require Message::Util::Formatter;
1226 $fmt{interwiki} = Message::Util::Formatter->new;
1227 $fmt{interwiki}->{encoded} = sub {
1228 my ($o, $p) = @_;
1229 if ($o->{except}) {
1230 $o->{except} =~ tr/\x00-\x20\x22\x23%\x2D<>^[\x5C]`{|}\x7F-\xFF//d;
1231 }
1232 my $s = &code_convert (\$p->{name}, $o->{charset} || 'iso-2022-7bit');
1233 $s =~ s/([^$o->{except}A-Za-z0-9_-])/sprintf '%%%02X', unpack 'C', $1/ge;
1234 $s;
1235 };
1236 $fmt{interwiki}->{ykwk} = sub { ## YukiWiki1
1237 my ($o, $p) = @_;
1238 my $s = $p->{name};
1239 $s = qq([[$s]]) if $s !~ /^[A-Z][a-z]+(?:[A-Z][a-z]+)+$/;
1240 &encode (&code_convert (\$p->{name}, $o->{charset} || 'shift_jis'));
1241 };
1242 }
1243
1244
1245 sub get_info {
1246 my ($page, $key) = @_;
1247 my %info = map { split(/=/, $_, 2) } split(/\n/, $infobase{$page});
1248 return $info{$key};
1249 }
1250
1251 sub set_info {
1252 my ($page, $key, $value) = @_;
1253 my %info = map { split(/=/, $_, 2) } split(/\n/, $infobase{$page});
1254 $info{$key} = $value;
1255 my $s = '';
1256 for (keys %info) {
1257 $s .= "$_=$info{$_}\n";
1258 }
1259 $infobase{$page} = $s;
1260 }
1261
1262 sub frozen_reject {
1263 my ($isfrozen) = &get_info($form{mypage}, $info_IsFrozen);
1264 my ($willbefrozen) = $form{myfrozen};
1265 if (not $isfrozen and not $willbefrozen) {
1266 # You need no check.
1267 return 0;
1268 } elsif (valid_password($form{mypassword})) {
1269 # You are admin.
1270 return 0;
1271 } else {
1272 &print_error($resource{passworderror});
1273 return 1;
1274 }
1275 }
1276
1277 sub valid_password {
1278 my ($givenpassword) = @_;
1279 my ($validpassword_crypt) = &get_info($AdminSpecialPage, $info_AdminPassword);
1280 if (crypt($givenpassword, $validpassword_crypt) eq $validpassword_crypt) {
1281 return 1;
1282 } else {
1283 return 0;
1284 }
1285 }
1286
1287 sub is_frozen {
1288 my ($page) = @_;
1289 if (&get_info($page, $info_IsFrozen)) {
1290 return 1;
1291 } else {
1292 return 0;
1293 }
1294 }
1295
1296 sub do_comment {
1297 my ($content) = $database{$form{mypage}};
1298 my $default_name; ## this code does not strict.
1299 $default_name = $1 if $content =~ /default-name="([^"]+)"/;
1300 my $datestr = '[WEAK['.&get_now.']]';
1301 my $namestr = $form{myname} || $default_name || $DEFAULT_embed_comment_name;
1302 ($namestr = '', $datestr = '') if $form{myname} eq 'nodate';
1303 if ($namestr =~ /^(?:>>)?[0-9]/) {
1304 $namestr = qq( ''$namestr'': );
1305 } elsif (length $namestr) {
1306 $namestr = qq( ''[[$namestr]]'': );
1307 }
1308 my $anchor = 0;
1309 $content =~ s/(?:-+\s)?\[([0-9]+)\]/$anchor = $1 if $1 > $anchor; $&/mge;
1310 $anchor++;
1311 my $i = 1; my $o = 0;
1312 $content =~ s{(\Q$embed_comment\E|\Q$embed_rcomment\E)}{
1313 my $embed = $1;
1314 if ($i == $form{comment_index}) {
1315 if ($embed eq $embed_comment) {
1316 $embed = "- [$anchor] $datestr$namestr$form{mymsg}\n$embed"; $o = 1;
1317 } else {
1318 $embed .= "\n- [$anchor] $datestr$namestr$form{mymsg}"; $o = 1;
1319 }
1320 }
1321 $i++; $embed;
1322 }ge;
1323 unless ($o) {
1324 $content = "#?SuikaWiki/0.9\n\n" unless $content;
1325 $content .= "\n" unless $content =~ /\n$/s;
1326 $content .= "- [$anchor] $datestr$namestr$form{mymsg}\n";
1327 }
1328 $form{__comment_anchor_index} = $anchor;
1329 if ($form{mymsg} || $form{myname}) {
1330 $form{mymsg} = $content;
1331 $form{mytouch} = 'on';
1332 &do_write;
1333 } else {
1334 $form{mycmd} = 'read';
1335 &do_read;
1336 }
1337 }
1338
1339 my $CommentIndex = 0;
1340 sub embedded_to_html {
1341 my ($embedded) = @_;
1342 if ($embedded eq $embed_comment or $embedded eq $embed_rcomment) {
1343 unless ($main::_EMBEDED) {
1344 my $lastmodified = &get_info($form{mypage}, $info_LastModified);
1345 return <<"EOD";
1346 <form action="$url_cgi" method="post" id="x-comment-@{[++$CommentIndex]}" class="comment"><p>
1347 <input type="hidden" name="mycmd" value="comment">
1348 <input type="hidden" name="mypage" value="$form{mypage}">
1349 <input type="hidden" name="myLastModified" value="$lastmodified">
1350 <input type="hidden" name="mytouch" value="on">
1351 <input type="hidden" name="comment_index" value="$CommentIndex">
1352 $embed_comment_Name_Prompt
1353 <input type="text" name="myname" value="" size="10" class="comment-name">
1354 <input type="text" name="mymsg" value="" size="60" class="comment-msg">
1355 <input type="submit" value="$resource{commentbutton}" class="comment-submit">
1356 </p></form>
1357 EOD
1358 } else {
1359 return <<"EOD";
1360 <del><form action="$url_cgi" method="get">
1361 <input type="hidden" name="mycmd" value="read">
1362 <input type="hidden" name="mypage" value="$form{mypage}">
1363 $embed_comment_Name_Prompt
1364 <input type="text" name="myname" value="" size="10" disabled="disabled">
1365 <input type="text" name="mymsg" value="" size="60" disabled="disabled">
1366 <input type="submit" value="$resource{commentbutton}" disabled="disabled">
1367 </form></del>
1368 EOD
1369 }
1370 } elsif ($embedded =~ /$embed_command{searched}/) {
1371 return get_search_result ($1, -match_myself => 1);
1372 # Walrus add (5) start
1373 } elsif ($embedded =~ /$embed_interwiki/ and my $remoteurl = $interwiki{$2}) {
1374 $_ = &make_interwiki_box($1, $2);
1375 return ($_) ? $_ : $embedded;
1376 # Walrus add (5) end
1377 } elsif ($embedded =~ /^\[\[\#embed:(.+)\]\]$/) {
1378 my ($name, $r) = ($1, '');
1379 if ($main::_EMBEDED != 1) {
1380 my ($content, $cf) = ($database{$name}, 'SuikaWiki/0.9');
1381 $cf = $1 if $content =~ s!^(?:[\#<]\?|/\*\s*)?([A-Z][A-Za-z0-9-]+/[0-9.]+(?:[^0-9.][^\x0D\x0A]*)?)[\x0D\x0A]+!!s;
1382 if ($cf =~ m!^(?:\#\?)?SuikaWiki/0.9(?:$|\s)!) {
1383 $main::_EMBEDED = 1;
1384 $r = &text_to_html ($content, content_format => $cf);
1385 $main::_EMBEDED = 0;
1386 } elsif (length $content) {
1387 $r = "<pre>@{[&escape ($content)]}</pre>";
1388 } else {
1389 $r = &text_to_html ("[INS[\n埋め込まれている [[$name]] はまだ書かれていません。\n]INS]\n", content_format => 'SuikaWiki/0.9');
1390 }
1391 } else { ## nested #EMBED
1392 $r = &text_to_html ("[INS[\n[[$name]] の埋め込みは (入り組んでいるので) 解決されませんでした。\n]INS]\n", content_format => 'SuikaWiki/0.9');
1393 }
1394 return qq(<blockquote title="@{[&escape($name)]}" class="wiki-embed">$r<div class="cite-note">『<cite><a href="$url_cgi?@{[&encode($name)]}" class="wiki">@{[&escape($name)]}</a></cite>』</div></blockquote>);
1395 } elsif ($embedded =~ /^\[\[\#randomlink:(.+)\]\]$/) {
1396 return qq(<a href="$url_cgi?mycmd=RandomJump;x-param=@{[time.[0..9]->[rand 10]]}" class="wiki randomlink">$1</a>);
1397 } else {
1398 return $embedded;
1399 }
1400 }
1401
1402 # Walrus add (5) start
1403 sub do_interwiki_box {
1404 my $remoteurl = $interwiki{$form{'myintername'}};
1405 if ($remoteurl) {
1406 $remoteurl =~ s/\b(euc|sjis|ykwk|asis|isbn)\(\$1\)/&interwiki_convert($1, $form{'mylocalname'})/e;
1407 print "Location: $remoteurl\n\n";
1408 exit(1);
1409 } else {
1410 &do_read;
1411 }
1412 }
1413 # Walrus add (5) end
1414
1415 # Walrus add (5) start
1416 sub make_interwiki_box {
1417 my ($localname, $intername) = @_;
1418 my %ignoretype = (
1419 'box' => 'text',
1420 'text' => 'text',
1421 'pass' => 'password',
1422 'password' => 'password'
1423 );
1424 my $converted = ($ignoretype{$localname}) ? <<EOD : undef;
1425 <form action="$url_cgi" method="post">
1426 <input type="hidden" name="mycmd" value="interwikibox">
1427 <input type="hidden" name="mypage" value="$form{mypage}">
1428 <input type="hidden" name="myintername" value="$intername">
1429 $intername:
1430 <input type="$ignoretype{$localname}" name="mylocalname" value="" size="10">
1431 <input type="submit" value="Submit">
1432 </form>
1433 EOD
1434 }
1435 # Walrus add (5) end
1436
1437 sub code_convert {
1438 my ($contentref, $code) = (shift, shift || $kanjicode);
1439 $code = 'jis' if $code =~ /iso/;
1440 $code = 'euc' if $code =~ /euc/;
1441 $code = 'sjis' if $code =~ /shift/;
1442 $code = 'utf8' if $code =~ /utf/;
1443 &Jcode::convert($contentref, $code); # for Jcode.pm
1444 # &jcode::convert($contentref, $code); # for jcode.pl
1445 &jcode::tr ($contentref, "\xA3\xB0-\xA3\xB9\xA3\xC1-\xA3\xDA\xA3\xE1-\xA3\xFA\xA1\xF5\xA1\xA4\xA1\xA5\xA1\xA7\xA1\xA8\xA1\xA9\xA1\xAA\xA1\xAE\xA1\xB0\xA1\xB2\xA1\xBF\xA1\xC3\xA1\xCA\xA1\xCB\xA1\xCE\xA1\xCF\xA1\xD0\xA1\xD1\xA1\xDC\xA1\xF0\xA1\xF3\xA1\xF4\xA1\xF6\xA1\xF7\xA1\xE1\xA2\xAF\xA2\xB0\xA2\xB2\xA2\xB1\xA1\xE4\xA1\xE3\xA1\xC0\xA1\xA1" => q(0-9A-Za-z&,.:;?!`^_/|()[]{}+$%#*@='"~-><\ )) if $code eq 'euc';
1446 return $$contentref;
1447 }
1448
1449 sub test_convert {
1450 my $txt = &text_to_html(<<"EOD", toc=>1);
1451 *HEADER1
1452 **HEADER1-1
1453 -ITEM1
1454 -ITEM2
1455 -ITEM3
1456 PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1
1457 PAR1PAR1PAR1PAR1PAR1PAR1''BOLD''PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1
1458 PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1
1459
1460 PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2
1461 PAR2PAR2PAR2PAR2PAR2PAR2'''ITALIC'''PAR2PAR2PAR2PAR2PAR2PAR2PAR2
1462 PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2
1463 **HEADER1-2
1464 :TERM1:DESCRIPTION1 AND ''BOLD''
1465 PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1
1466 PAR1PAR1PAR1PAR1PAR1PAR1''BOLD''PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1
1467 PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1
1468 :TERM2:DESCRIPTION2
1469 :TERM3:DESCRIPTION3
1470 ----
1471 *HEADER2
1472 **HEADER2-1
1473 http://www.hyuki.com/
1474 **HEADER2-2
1475
1476 [[YukiWiki2]]
1477
1478 PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1
1479 PAR1PAR1PAR1PAR1PAR1PAR1'''''BOLD ITALIC'''''PAR1PAR1PAR1PAR1PAR1
1480 PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1PAR1
1481 >PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2
1482 >PAR2PAR2PAR2PAR2PAR2PAR2'''ITALIC'''PAR2PAR2PAR2PAR2PAR2PAR2PAR2
1483 >PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2PAR2
1484
1485 LEVEL0LEVEL0LEVEL0LEVEL0LEVEL0LEVEL0LEVEL0
1486
1487 >LEVEL1
1488 >LEVEL1
1489 >LEVEL1
1490 >>LEVEL2
1491 >>LEVEL2
1492 >>LEVEL2
1493 >>>LEVEL3
1494 -HELLO-1
1495 --HELLO-2
1496 (HELLO-2, HELLO-2, HELLO-2)
1497 ---HELLO-3
1498 (HELLO-3, HELLO-3, HELLO-3)
1499 --HELLO-2
1500 ---HELLO-3
1501 --HELLO-2
1502 ---HELLO-3
1503 >>>LEVEL3
1504 >>>LEVEL3
1505 >>>LEVEL3
1506 >>>LEVEL3
1507 EOD
1508 print $txt;
1509 exit;
1510 }
1511
1512 sub do_diff {
1513 if (not &is_editable($form{mypage})) {
1514 &do_read;
1515 return;
1516 }
1517 &open_diff;
1518 my $title = $form{mypage};
1519 &print_header($title, -noindex => 1);
1520 $_ = &escape($diffbase{$form{mypage}});
1521 &close_diff;
1522 print qq(<h3>$resource{difftitle}</h3>);
1523 print qq($resource{diffnotice});
1524 print qq(<pre class="diff">);
1525 foreach (split(/\n/, $_)) {
1526 if (/^\+(.*)/) {
1527 print qq(<b class="added">$1</b>\n);
1528 } elsif (/^\-(.*)/) {
1529 print qq(<s class="deleted">$1</s>\n);
1530 } elsif (/^\=(.*)/) {
1531 print qq(<span class="same">$1</span>\n);
1532 } else {
1533 print qq|??? $_\n|;
1534 }
1535 }
1536 print qq(</pre>);
1537 print qq(<hr>);
1538 &print_footer($title);
1539 }
1540
1541 sub do_rss {
1542 my $rss = new Yuki::RSS(
1543 version => '1.0',
1544 encoding => $charset,
1545 );
1546 $rss->channel(
1547 title => $modifier_rss_title,
1548 link => $modifier_rss_link,
1549 description => $modifier_rss_description,
1550 );
1551 my $recentchanges = $database{$RecentChanges};
1552 my $count = 0;
1553 foreach (split(/\n/, $recentchanges)) {
1554 last if ($count >= 15);
1555 /^\- \d\d\d\d\-\d\d\-\d\d \([^)]+\) \d\d:\d\d:\d\d (\S+)/; # date format.
1556 my $title = &unarmor_name($1);
1557 my $escaped_title = &escape($title);
1558 my $link = $modifier_rss_link . '?' . &encode($title);
1559 my $description = $escaped_title . &escape(&get_subjectline($title));
1560 $rss->add_item(
1561 title => $escaped_title,
1562 link => $link,
1563 description => $description,
1564 );
1565 $count++;
1566 }
1567 # print RSS information (as XML).
1568 print <<"EOD"
1569 Content-type: text/xml
1570
1571 @{[$rss->as_string]}
1572 EOD
1573 }
1574
1575 sub is_exist_page {
1576 my ($name) = @_;
1577 if ($use_exists) {
1578 return exists($database{$name});
1579 } else {
1580 return $database{$name};
1581 }
1582 }
1583
1584 sub __get_database ($) { $database{ $_[0] } }
1585 sub __set_database ($$) { $database{ $_[0] } = $_[1] }
1586
1587 package wiki::referer;
1588 sub add ($$) {
1589 my $page = shift;
1590 my $uri = shift;
1591 unless (ref $uri) {
1592 require URI;
1593 $uri = URI->new ($uri);
1594 ## Some schemes do not have query part.
1595 eval q{ $uri->query (undef) if $uri->query =~ /^[0-9]{6,8}$/ };
1596 $uri->fragment (undef);
1597 }
1598 $uri = $uri->canonical;
1599 return unless $uri;
1600 for my $regex (&get_dont_record) {
1601 return if $uri =~ /$regex/;
1602 }
1603 my %list = get ($page);
1604 $list{ $uri }++;
1605 set ($page, \%list);
1606 }
1607 sub get ($) {
1608 my $page = shift;
1609 split /"/, main::get_info ($page, 'Referer');
1610 }
1611 sub set ($%) {
1612 my $page = shift;
1613 my $list = shift;
1614 main::set_info ($page, Referer => join '"', %$list);
1615 }
1616
1617 sub get_dont_record () {
1618 map {s/\$/\\\$/g; s/\@/\\\@/g; $_}
1619 grep !/^#/,
1620 split /[\x0D\x0A]+/, &main::__get_database ('RefererDontRecord');
1621 }
1622 sub get_site_name () {
1623 my @lines = grep /[^#]/, split /[\x0D\x0A]+/, &main::__get_database('RefererSiteName');
1624 my @item;
1625 for (@lines) {
1626 next if /^#/;
1627 my ($uri, $name) = split /\s+/, $_, 2;
1628 $uri =~ s/\$/\\\$/g; $uri =~ s/\@/\\\@/g; $uri =~ s/\//\\\//g;
1629 $name =~ s!([()/\\])!\\$1!g; $name =~ s/\$([0-9]+)/).__decode (\${$1}).q(/g;
1630 push @item, [$uri, qq(q($name))];
1631 }
1632 @item;
1633 }
1634
1635 sub list_html ($) {
1636 my $page = shift;
1637 my %list = get ($page);
1638 my $r = '';
1639 my @name = get_site_name;
1640 for my $uri (sort keys %list) {
1641 my $title;
1642 for my $item (@name) {
1643 if ($uri =~ /$item->[0]/) {
1644 $title = $uri;
1645 eval qq{\$title =~ s/^.*$item->[0].*\$/$item->[1]/e}
1646 or die $@ ;#. qq{\$title =~ s/^.*$item->[0].*\$/$item->[1]/e};
1647 last;
1648 }
1649 }
1650 my $euri = main::escape ($uri);
1651 if ($title) {
1652 $r .= qq(<li>[$list{$uri}] <a href="$euri" title="URI: &lt;$euri>">@{[main::escape ($title)]}</a></li>\n);
1653 } else {
1654 $r .= qq(<li>[$list{$uri}] &lt;<a href="$euri">$euri</a>&gt;</li>\n);
1655 }
1656 }
1657 $r ? qq(<ul>$r</ul>\n) : '';
1658 }
1659
1660 sub __decode ($) {
1661 my $s = shift;
1662 $s =~ tr/+/ /;
1663 $s =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/chr hex $1/ge;
1664 main::code_convert (\$s);
1665 }
1666
1667 package wiki::useragent;
1668
1669 sub add ($) {
1670 my $s = shift;
1671 return unless length $s;
1672 $s =~ s/([\x00-\x08\x0A-\x1F\x25\x7F-\xFF])/sprintf '%%%02X', unpack 'C', $1/g;
1673 my %ua;
1674 for (split /\n/, &main::__get_database('WikiUserAgentList')) {
1675 if (/^-\[(\d+)\] (.+)$/) {
1676 my ($t, $n) = ($1, $2);
1677 $n =~ tr/\x0A\x0D//d;
1678 $ua{$n} = $t;
1679 }
1680 }
1681 $ua{$s}++;
1682 my $s = qq(#?SuikaWiki/0.9\n);
1683 for (sort {$ua{$a} <=> $ua{$b}} keys %ua) {
1684 $s .= sprintf qq(-[%d] %s\n), $ua{$_}, $_;
1685 }
1686 &main::__set_database ('WikiUserAgentList' => $s);
1687 }
1688
1689 1;
1690 __END__
1691 =head1 NAME
1692
1693 wiki.cgi - This is YukiWiki, yet another Wiki clone.
1694
1695 =head1 DESCRIPTION
1696
1697 YukiWiki is yet another Wiki clone.
1698
1699 YukiWiki can treat Japanese WikiNames (enclosed with [[ and ]]).
1700 YukiWiki provides 'InterWiki' feature, RDF Site Summary (RSS),
1701 and some embedded commands (such as [[#comment]] to add comments).
1702
1703 Read F<readme_en.txt> (English) or F<readme_ja.txt> (Japanese) in more detail.
1704
1705 =head1 AUTHOR
1706
1707 Hiroshi Yuki <hyuki@hyuki.com> http://www.hyuki.com/yukiwiki/
1708
1709 =head1 LICENSE
1710
1711 Copyright (C) 2000-2002 by Hiroshi Yuki.
1712
1713 This program is free software; you can redistribute it and/or
1714 modify it under the same terms as Perl itself.
1715
1716 =cut

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24