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

Contents of /suikawiki/script/wiki.cgi

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.27 - (show annotations) (download)
Mon Oct 7 12:50:51 2002 UTC (21 years, 7 months ago) by wakaba
Branch: MAIN
Changes since 1.26: +122 -31 lines
2002-10-07  Wakaba <w@suika.fam.cx>

	* wiki.cgi:
	- Output Last-Modified:.
	- Record and output referer information.

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24