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

Contents of /suikawiki/script/wiki.cgi

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.27 - (hide 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 wakaba 1.9 #!/usr/bin/perl
2 wakaba 1.16 #!perl
3 wakaba 1.9 #
4 wakaba 1.16 # wiki.cgi - This is YukiWiki, yet another Wiki clone.
5 wakaba 1.9 #
6 wakaba 1.16 # Copyright (C) 2000-2002 by Hiroshi Yuki.
7 wakaba 1.9 # <hyuki@hyuki.com>
8     # http://www.hyuki.com/yukiwiki/
9     #
10 wakaba 1.16 # This program is free software; you can redistribute it and/or
11     # modify it under the same terms as Perl itself.
12 wakaba 1.9 #
13 wakaba 1.16 ##############################
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 wakaba 1.9 #
39 wakaba 1.16 #=======================================
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 wakaba 1.17 my $walversion;
60 wakaba 1.9 ##############################
61 wakaba 1.16 #
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 wakaba 1.17 my $modifier_dir_data = './wikidata'; # Your data directory.
73 wakaba 1.27 my $modifier_rss_title = "SuikaWiki $walversion";
74 wakaba 1.16 my $modifier_rss_link = 'http://suika.fam.cx/~wakaba/-temp/wiki2/wiki'; # Blank is not allowed.
75 wakaba 1.27 my $modifier_rss_description = 'This is SuikaWiki';
76 wakaba 1.9 ##############################
77 wakaba 1.16 #
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 wakaba 1.25 my $url_stylesheet = $url_cgi.'?mycmd=TEXT_CSS;mypage=WikiHTMLStyle';
87 wakaba 1.16 my $icontag = '<img src="/icons/folder" alt="*" width="40" height="40" />';
88     my $maxrecent = 50;
89 wakaba 1.9 my $cols = 80;
90     my $rows = 20;
91     ##############################
92 wakaba 1.16 #
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 wakaba 1.18 my $FrontPage = 'HomePage';
108 wakaba 1.16 my $IndexPage = 'IndexPage';
109     my $SearchPage = 'SearchPage';
110     my $CreatePage = 'CreatePage';
111     my $ErrorPage = 'ErrorPage';
112     my $RssPage = 'RssPage';
113 wakaba 1.26 my $NAME_OF_WikiPageLicense = 'WikiPageLicense';
114 wakaba 1.16 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 wakaba 1.25 my $interwiki_name = 'i:([^:]+):([^:].*)';
122 wakaba 1.16 ##############################
123     my $embed_comment = '[[#comment]]';
124     my $embed_rcomment = '[[#rcomment]]';
125 wakaba 1.25 my $embed_comment_Name_Prompt = '名前:';
126     my $DEFAULT_embed_comment_name = '名無しさん';
127 wakaba 1.16 my $embed_interwiki = '^\[\[#(box|text|password):(\S+)\]\]$'; # Walrus add (5)
128 wakaba 1.22 my %embed_command = (
129     searched => '^\[\[#searched:([^\]]+)\]\]$',
130     );
131 wakaba 1.16 ##############################
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 wakaba 1.18 #$FrontPage => 1,
149 wakaba 1.16 );
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 wakaba 1.18 #$FrontPage => 'FrontPage',
164 wakaba 1.16 );
165     my %command_do = (
166     read => \&do_read,
167 wakaba 1.25 TEXT_CSS => \&do_output_css,
168 wakaba 1.16 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 wakaba 1.9 ##############################
189 wakaba 1.16 # &test_convert;
190 wakaba 1.9 &main;
191     exit(0);
192 wakaba 1.16 ##############################
193 wakaba 1.9
194     sub main {
195 wakaba 1.16 &init_resource;
196     &open_db;
197     &init_form;
198     &init_InterWikiName;
199     if ($command_do{$form{mycmd}}) {
200     &{$command_do{$form{mycmd}}};
201 wakaba 1.9 } else {
202 wakaba 1.16 &do_FrontPage;
203 wakaba 1.9 }
204 wakaba 1.16 &close_db;
205 wakaba 1.9 }
206    
207     sub do_read {
208 wakaba 1.26 my $content = $database{$form{mypage}};
209 wakaba 1.27 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 wakaba 1.26 my $cf = 'SuikaWiki/0.9';
213 wakaba 1.27 ## 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 wakaba 1.26 if ($cf =~ m#^SuikaWiki/0.9(?:$|\s)#) {
219 wakaba 1.27 &print_content($content, content_format => $cf, last_modified => $lm);
220 wakaba 1.26 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 wakaba 1.22 if ($c) {
226 wakaba 1.26 print q{<h2 id="SEE-ALSO">See also</h2>};
227 wakaba 1.22 print $r;
228     }
229 wakaba 1.27 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 wakaba 1.9 }
235    
236 wakaba 1.25 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 wakaba 1.9 sub do_edit {
251 wakaba 1.16 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 wakaba 1.9 }
260 wakaba 1.16 &print_footer($page);
261 wakaba 1.9 }
262    
263 wakaba 1.16 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 wakaba 1.9 } else {
269 wakaba 1.16 &print_message($resource{passwordneeded});
270     &print_editform($database{$page}, &get_info($page, $info_LastModified), admin=>1);
271 wakaba 1.9 }
272 wakaba 1.16 &print_footer($page);
273 wakaba 1.9 }
274    
275 wakaba 1.16 sub do_adminchangepasswordform {
276     &print_header($AdminChangePassword);
277     &print_passwordform;
278     &print_footer($AdminChangePassword);
279     }
280 wakaba 1.9
281 wakaba 1.16 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 wakaba 1.9 EOD
293 wakaba 1.16 &print_error($resource{passworderror});
294 wakaba 1.9 }
295 wakaba 1.16 }
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 wakaba 1.24 print qq(<li><a href="$url_cgi?@{[&encode($page)]}">@{[&escape($page)]}</a>@{[&escape(&get_subjectline($page))]}</li>);
314 wakaba 1.16 # print qq(<li>@{[&get_info($page, $info_IsFrozen)]}</li>);
315     # print qq(<li>@{[0 + &is_frozen($page)]}</li>);
316 wakaba 1.9 }
317     }
318 wakaba 1.16 print qq(</ul>);
319     &print_footer($IndexPage);
320 wakaba 1.9 }
321    
322 wakaba 1.16 sub do_write {
323     if (&frozen_reject()) {
324     return;
325 wakaba 1.9 }
326    
327     if (not &is_editable($form{mypage})) {
328 wakaba 1.16 &print_header($form{mypage});
329     &print_message($resource{cantchange});
330     &print_footer($form{mypage});
331 wakaba 1.9 return;
332     }
333    
334 wakaba 1.16 if (&conflict($form{mypage}, $form{mymsg})) {
335 wakaba 1.9 return;
336     }
337    
338 wakaba 1.16 # Making diff
339 wakaba 1.9 {
340 wakaba 1.16 &open_diff;
341     my @msg1 = split(/\n/, $database{$form{mypage}});
342 wakaba 1.9 my @msg2 = split(/\n/, $form{mymsg});
343 wakaba 1.16 $diffbase{$form{mypage}} = &difftext(\@msg1, \@msg2);
344     &close_diff;
345 wakaba 1.9 }
346    
347     if ($form{mymsg}) {
348 wakaba 1.16 $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 wakaba 1.27 &print_header($CompletedSuccessfully, -goto => $url_cgi.'?'.&encode($form{mypage}).($form{comment_index}?"#x-comment-$form{comment_index}":''));
356 wakaba 1.16 &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 wakaba 1.9 }
370     }
371    
372 wakaba 1.16 sub do_searchform {
373     &print_header($SearchPage);
374     &print_searchform("");
375     &print_footer($SearchPage);
376 wakaba 1.9 }
377    
378 wakaba 1.16 sub do_search {
379 wakaba 1.22 my $word = $form{mymsg};
380 wakaba 1.16 &print_header($SearchPage);
381 wakaba 1.22 &print_searchform(&escape($word));
382 wakaba 1.24 print scalar get_search_result ($word, -output_not_found => 1);
383 wakaba 1.16 &print_footer($SearchPage);
384 wakaba 1.9 }
385    
386 wakaba 1.22 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 wakaba 1.27 $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 wakaba 1.22 $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 wakaba 1.16 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 wakaba 1.9 }
419    
420 wakaba 1.16 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 wakaba 1.9 }
429    
430     sub print_error {
431     my ($msg) = @_;
432 wakaba 1.16 &print_header($ErrorPage);
433     print qq(<p><strong class="error">$msg</strong></p>);
434     &print_footer($ErrorPage);
435 wakaba 1.9 exit(0);
436     }
437    
438 wakaba 1.27 sub print_header ($;%) {
439     my ($page, %option) = @_;
440 wakaba 1.16 my $bodyclass = "normal";
441     if (&is_frozen($page) and $form{mycmd} =~ /^(read|write)$/) {
442     $bodyclass = "frozen";
443 wakaba 1.22 }
444 wakaba 1.27 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 wakaba 1.16 my $cookedpage = &encode($page);
447 wakaba 1.24 my $escapedpage = &escape($page);
448 wakaba 1.9 print <<"EOD";
449 wakaba 1.16 Content-type: text/html; charset=$charset
450 wakaba 1.18 Content-Language: $lang
451     Content-Style-Type: text/css
452 wakaba 1.9
453 wakaba 1.16 <!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 wakaba 1.24 <title>$escapedpage @{[&escape(&get_subjectline($page))]}</title>
459 wakaba 1.16 <link rel="index" href="$url_cgi?$IndexPage">
460 wakaba 1.26 <link rel="copyright" href="$url_cgi?$NAME_OF_WikiPageLicense">
461 wakaba 1.24 <link rev="made" href="mailto:@{[&escape($modifier_mail)]}">
462     <link rel="stylesheet" type="text/css" href="@{[&escape($url_stylesheet)]}">
463 wakaba 1.9 </head>
464 wakaba 1.16 <body class="$bodyclass">
465 wakaba 1.22 EOD
466     &print_navigate_links ($page);
467     print <<EOD;
468 wakaba 1.27 <h1 class="header">@{[&escape($page)]}
469     <span class="wikipage-summary">@{[&escape(&get_subjectline($page))]}</span></h1>
470 wakaba 1.22 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 wakaba 1.16 <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 wakaba 1.22 ? qq(<a title="$resource{editthispage}" href="$url_cgi?mycmd=edit;mypage=$cookedpage" accesskey="E">$resource{editbutton} <kbd>E</kbd></a> | )
495 wakaba 1.16 : 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 wakaba 1.22 EOH
509 wakaba 1.9 }
510    
511 wakaba 1.16 sub print_footer {
512 wakaba 1.27 my ($page, $lm) = @_;
513 wakaba 1.16 $walrus_log = ($walrus_debugging) ? &text_to_html("----\n$walrus_log") : ''; # Walrus add (debug)
514     # Walrus mod (1) start
515 wakaba 1.27 my $cvslog = '$Revision: 1.26 $ $Date: 2002/09/28 10:54:27 $';
516 wakaba 1.22 print_navigate_links ($page);
517     print <<"EOD";
518 wakaba 1.27 @{[ $lm ? qq(<div id="wikipage-last-modified">Last modified: $lm</div>) : '' ]}
519 wakaba 1.16 <div class="footer">
520 wakaba 1.9 <p>
521 wakaba 1.16 <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 wakaba 1.18 <a href="/gate/cvs/wakaba/wiki/" title="CVS Repository">
524 wakaba 1.19 $cvslog
525 wakaba 1.18 </a>
526 wakaba 1.9 </p>
527 wakaba 1.18 <div class="navigation">
528     [<a href="/" title="このサーバーの首頁">/</a>
529     <a href="/map" title="このサーバーの案内">地図</a>
530     <a href="/search/" title="このサーバーの検索">検索</a>]
531     </div>
532 wakaba 1.10 </div>
533 wakaba 1.19 $walrus_log
534 wakaba 1.16 </body>
535     </html>
536 wakaba 1.12 EOD
537 wakaba 1.16 # 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 wakaba 1.9 }
552    
553 wakaba 1.16 sub escape {
554     my $s = shift;
555     $s =~ s|\r\n|\n|g;
556 wakaba 1.23 $s =~ s|&|&amp;|g;
557 wakaba 1.16 $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 wakaba 1.23 $s =~ s|&lt;|<|g;
567     $s =~ s|&gt;|>|g;
568     $s =~ s|&quot;|"|g;
569     $s =~ s|&amp;|&|g;
570 wakaba 1.16 return $s;
571     }
572    
573 wakaba 1.26 sub print_content ($;$) {
574 wakaba 1.27 my ($rawcontent, %option) = @_;
575 wakaba 1.16 print &text_to_html($rawcontent, toc=>1);
576 wakaba 1.9 }
577    
578 wakaba 1.16 sub text_to_html {
579     my ($txt, %option) = @_;
580 wakaba 1.9 my (@txt) = split(/\n/, $txt);
581 wakaba 1.16 my (@toc);
582     my $tocnum = 0;
583     my (@saved, @result);
584     unshift(@saved, "</p>");
585     push(@result, "<p>");
586 wakaba 1.9 foreach (@txt) {
587     chomp;
588 wakaba 1.25 if (/^\*\*\*\*\*([^\x0D\x0A]*)/) {
589     push(@toc, qq(----- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));
590 wakaba 1.18 push(@result, splice(@saved), qq(<h6 id="i$tocnum">) . &inline($1) . '</h6>');
591     $tocnum++;
592 wakaba 1.25 } elsif (/^\*\*\*\*([^\x0D\x0A]*)/) {
593     push(@toc, qq(---- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));
594 wakaba 1.18 push(@result, splice(@saved), qq(<h5 id="i$tocnum">) . &inline($1) . '</h5>');
595     $tocnum++;
596 wakaba 1.25 } elsif (/^\*\*\*([^\x0D\x0A]*)/) {
597     push(@toc, qq(--- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));
598 wakaba 1.18 push(@result, splice(@saved), qq(<h4 id="i$tocnum">) . &inline($1) . '</h4>');
599     $tocnum++;
600 wakaba 1.25 } elsif (/^\*\*([^\x0D\x0A]*)/) {
601 wakaba 1.16 # if (/^\*\*(.*)/) {
602     # Walrus mod (6) end
603 wakaba 1.25 push(@toc, qq(-- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));
604 wakaba 1.16 push(@result, splice(@saved), qq(<h3><a name="i$tocnum"> </a>) . &inline($1) . '</h3>');
605     $tocnum++;
606 wakaba 1.25 } elsif (/^\*([^\x0D\x0A]*)/) {
607     push(@toc, qq(- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));
608 wakaba 1.16 push(@result, splice(@saved), qq(<h2><a name="i$tocnum"> </a>) . &inline($1) . '</h2>');
609     $tocnum++;
610 wakaba 1.25 } elsif (/^(={1,6})(.*)/) {
611 wakaba 1.18 &back_push('ol', length($1), \@saved, \@result);
612     push(@result, '<li>' . &inline($2) . '</li>');
613 wakaba 1.25 } elsif (/^(-{1,6})(.*)/) {
614 wakaba 1.16 &back_push('ul', length($1), \@saved, \@result);
615 wakaba 1.13 push(@result, '<li>' . &inline($2) . '</li>');
616 wakaba 1.9 } elsif (/^:([^:]+):(.*)/) {
617 wakaba 1.16 &back_push('dl', 1, \@saved, \@result);
618 wakaba 1.9 push(@result, '<dt>' . &inline($1) . '</dt>', '<dd>' . &inline($2) . '</dd>');
619 wakaba 1.18 } elsif (/^(>{1,5})(.*)/) {
620 wakaba 1.16 &back_push('blockquote', length($1), \@saved, \@result);
621 wakaba 1.9 push(@result, &inline($2));
622     } elsif (/^\s*$/) {
623     push(@result, splice(@saved));
624     unshift(@saved, "</p>");
625     push(@result, "<p>");
626     } elsif (/^(\s+.*)$/) {
627 wakaba 1.16 &back_push('pre', 1, \@saved, \@result);
628 wakaba 1.18 #push(@result, &escape($1)); # Not &inline, but &escape
629 wakaba 1.26 push(@result, &inline($1));
630 wakaba 1.16 # } 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 wakaba 1.26 } 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 wakaba 1.9 } else {
667     push(@result, &inline($_));
668     }
669     }
670     push(@result, splice(@saved));
671 wakaba 1.27
672     my $toc = '';
673 wakaba 1.16 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 wakaba 1.25 if (/^(-{1,6})(.*)$/) {
679 wakaba 1.16 &back_push('ul', length($1), \@tocsaved, \@tocresult);
680     push(@tocresult, '<li>' . $2 . '</li>');
681     }
682     }
683     push(@tocresult, splice(@tocsaved));
684 wakaba 1.27 $toc = join("\n", @tocresult);
685     $toc = $toc ? qq(<div id="wikipage-toc">$toc</div>) : '';
686 wakaba 1.16 }
687 wakaba 1.27 return $toc . join("\n", @result);
688 wakaba 1.9 }
689    
690     sub back_push {
691 wakaba 1.16 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 wakaba 1.9 }
702     }
703    
704 wakaba 1.16 sub inline {
705     my ($line) = @_;
706     $line = &escape($line);
707 wakaba 1.18 $line =~ s|'''([^']+?)'''|<strong>$1</strong>|g;
708     $line =~ s|''([^']+?)''|<em>$1</em>|g;
709 wakaba 1.16 $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 wakaba 1.18 (
712 wakaba 1.25 (?:&lt;(?:mailto|http|https|ftp|urn|news):[\x21-\x7E]*)&gt;
713 wakaba 1.18 |
714     ($bracket_name) # [[likethis]], [[#comment]], [[Friend:remotelink]]
715     |
716     ($interwiki_definition) # [[Friend http://somewhere/?q=sjis($1)]]
717     #|
718     # ($wiki_name)
719     )
720 wakaba 1.16 !
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 wakaba 1.21 $chunk =~ s/^&lt;(.*)&gt;$/$1/;
730 wakaba 1.16 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 wakaba 1.25 if ($use_autoimg and $name =~ /^(http|https|ftp):.+\.(png|gif|jpe?g)/) {
737 wakaba 1.16 $name = qq(<img src="$name">) ;
738     }
739     $name = &unarmor_name($name);
740     # Walrus add (3) end
741 wakaba 1.25 if ($chunk =~ /^(http|https|ftp|news):/) {
742 wakaba 1.16 # 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 wakaba 1.21 return qq(&lt;<a href="$chunk">$name</a>&gt;);
749 wakaba 1.16 # Walrus mod (3) end
750 wakaba 1.18 } 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 wakaba 1.16 # return qq(<a href="$chunk">$2</a>); # Walrus del (3)
754 wakaba 1.18 return qq(&lt;<a href="$chunk">$name</a>&gt;); # Walrus add (3)
755 wakaba 1.16 } 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 wakaba 1.24 return qq(<a href="$remoteurl">@{[&escape($name)]}</a>); # Walrus add (3)
772 wakaba 1.16 } else {
773     # return $chunk; # Walrus del (3)
774 wakaba 1.24 return &escape($name); # Walrus add (3)
775 wakaba 1.16 }
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 wakaba 1.26 return qq(<a title="$subject" href="$url_cgi?$cookedchunk" class="wiki">@{[&escape($name)]}</a>); # Walrus add (3)
780 wakaba 1.16 } elsif ($page_command{$chunk}) {
781     # return qq(<a title="$chunk" href="$url_cgi?$cookedchunk">$chunk</a>); # Walrus del (3)
782 wakaba 1.24 return qq(<a title="$chunk" href="$url_cgi?$cookedchunk" class="wiki">@{[&escape($name)]}</a>); # Walrus add (3)
783 wakaba 1.16 } else {
784 wakaba 1.24 return qq(<a title="$resource{editthispage}" href="$url_cgi?mycmd=edit;mypage=$cookedchunk" class="wiki">@{[&escape($name)]}<span class="mark">$editchar</span></a>);
785 wakaba 1.9 }
786     }
787     }
788    
789 wakaba 1.16 sub print_message {
790     my ($msg) = @_;
791     print qq(<p><strong>$msg</strong></p>);
792 wakaba 1.9 }
793    
794 wakaba 1.22 sub get_message {
795     my ($msg) = @_;
796     qq(<p><strong>$msg</strong></p>);
797     }
798    
799 wakaba 1.16 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 wakaba 1.9
830 wakaba 1.16 #
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 wakaba 1.9 }
860    
861 wakaba 1.16 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 wakaba 1.9
872 wakaba 1.16 # Get the subject of the page.
873     my $subject = $database{$page};
874 wakaba 1.25 $subject =~ s#^SuikaWiki/0.9[^\x0D\x0A]*[\x0D\x0A]+##s;
875 wakaba 1.16 $subject =~ s/\r?\n.*//s;
876 wakaba 1.27 return "$delim$subject".$option{tail};
877 wakaba 1.16 }
878 wakaba 1.9 }
879    
880 wakaba 1.16 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 wakaba 1.9 }
906    
907 wakaba 1.16 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 wakaba 1.9 }
918     }
919    
920 wakaba 1.16 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 wakaba 1.9
933 wakaba 1.16 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 wakaba 1.9
943 wakaba 1.16 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 wakaba 1.9 }
952    
953 wakaba 1.16 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 wakaba 1.9 }
963    
964 wakaba 1.16 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 wakaba 1.9 } else {
982 wakaba 1.25 $mymsg = &escape($mymsg || $database{NewPageTemplate});
983 wakaba 1.9 }
984    
985 wakaba 1.16 my $edit = $mode{admin} ? 'adminedit' : 'edit';
986 wakaba 1.24 my $escapedmypage = &escape($form{mypage});
987     my $escapedmypassword = &escape($form{mypassword});
988 wakaba 1.16
989     print <<"EOD";
990     <form action="$url_cgi" method="post">
991 wakaba 1.24 @{[ $mode{admin} ? qq($resource{frozenpassword} <input type="password" name="mypassword" value="$escapedmypassword" size="10"><br>) : "" ]}
992 wakaba 1.16 <input type="hidden" name="myLastModified" value="$lastmodified">
993 wakaba 1.24 <input type="hidden" name="mypage" value="$escapedmypage">
994 wakaba 1.25 <textarea cols="$cols" rows="$rows" name="mymsg" tabindex="1">$mymsg</textarea><br>
995 wakaba 1.16 @{[
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 wakaba 1.22 <input type="submit" name="mypreview_write" value="$resource{savebutton}" accesskey="S"><kbd>S</kbd><br>
1008 wakaba 1.16 )
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 wakaba 1.9 close(FILE);
1018 wakaba 1.16 print &text_to_html($content, toc=>0);
1019 wakaba 1.9 }
1020     }
1021    
1022 wakaba 1.16 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 wakaba 1.9 }
1033    
1034 wakaba 1.16 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 wakaba 1.9 }
1050    
1051 wakaba 1.16 # armor_name:
1052     # WikiName -> WikiName
1053     # not_wiki_name -> [[not_wiki_name]]
1054     sub armor_name {
1055     my ($name) = @_;
1056 wakaba 1.25 #if ($name =~ /^$wiki_name$/) {
1057     # return $name;
1058     #} else {
1059 wakaba 1.16 return "[[$name]]";
1060 wakaba 1.25 #}
1061 wakaba 1.9 }
1062    
1063 wakaba 1.16 # 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 wakaba 1.9 }
1074    
1075 wakaba 1.16 sub is_bracket_name {
1076     my ($name) = @_;
1077     if ($name =~ /^$bracket_name$/) {
1078     return 1;
1079     } else {
1080     return 0;
1081 wakaba 1.9 }
1082     }
1083    
1084 wakaba 1.16 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 wakaba 1.9
1091 wakaba 1.16 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 wakaba 1.9
1104 wakaba 1.16 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 wakaba 1.9
1115 wakaba 1.16 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 wakaba 1.9
1154 wakaba 1.16 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 wakaba 1.9
1179 wakaba 1.16 sub get_info {
1180     my ($page, $key) = @_;
1181     my %info = map { split(/=/, $_, 2) } split(/\n/, $infobase{$page});
1182     return $info{$key};
1183     }
1184 wakaba 1.9
1185 wakaba 1.16 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 wakaba 1.9
1196 wakaba 1.16 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 wakaba 1.9
1211 wakaba 1.16 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 wakaba 1.9
1221 wakaba 1.16 sub is_frozen {
1222     my ($page) = @_;
1223     if (&get_info($page, $info_IsFrozen)) {
1224     return 1;
1225     } else {
1226     return 0;
1227     }
1228     }
1229 wakaba 1.9
1230 wakaba 1.16 sub do_comment {
1231     my ($content) = $database{$form{mypage}};
1232     my $datestr = &get_now;
1233 wakaba 1.25 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 wakaba 1.27 my $i = 1; my $o = 0;
1240 wakaba 1.25 $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 wakaba 1.16 }
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 wakaba 1.9
1264 wakaba 1.27 my $CommentIndex = 0;
1265 wakaba 1.16 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 wakaba 1.27 <form action="$url_cgi" method="post" id="x-comment-@{[++$CommentIndex]}">
1271 wakaba 1.16 <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 wakaba 1.27 <input type="hidden" name="comment_index" value="$CommentIndex">
1276 wakaba 1.25 $embed_comment_Name_Prompt
1277 wakaba 1.16 <input type="text" name="myname" value="" size="10">
1278 wakaba 1.26 <input type="text" name="mymsg" value="" size="60">
1279 wakaba 1.16 <input type="submit" value="$resource{commentbutton}">
1280     </form>
1281     EOD
1282 wakaba 1.22 } elsif ($embedded =~ /$embed_command{searched}/) {
1283     return get_search_result ($1);
1284 wakaba 1.16 # 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 wakaba 1.9
1294 wakaba 1.16 # 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 wakaba 1.9
1307 wakaba 1.16 # 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 wakaba 1.9
1329 wakaba 1.16 sub code_convert {
1330 wakaba 1.27 my ($contentref, $code) = (shift, shift || $kanjicode);
1331     # &Jcode::convert($contentref, $code); # for Jcode.pm
1332     &jcode::convert($contentref, $code); # for jcode.pl
1333 wakaba 1.16 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 wakaba 1.9
1363 wakaba 1.16 [[YukiWiki2]]
1364 wakaba 1.9
1365 wakaba 1.16 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 wakaba 1.9
1399 wakaba 1.16 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 wakaba 1.9
1428 wakaba 1.16 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 wakaba 1.9
1458 wakaba 1.16 @{[$rss->as_string]}
1459     EOD
1460     }
1461 wakaba 1.9
1462 wakaba 1.16 sub is_exist_page {
1463     my ($name) = @_;
1464     if ($use_exists) {
1465     return exists($database{$name});
1466     } else {
1467     return $database{$name};
1468     }
1469 wakaba 1.27 }
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 wakaba 1.16 }
1551 wakaba 1.9
1552 wakaba 1.16 1;
1553     __END__
1554     =head1 NAME
1555 wakaba 1.9
1556 wakaba 1.16 wiki.cgi - This is YukiWiki, yet another Wiki clone.
1557 wakaba 1.9
1558 wakaba 1.16 =head1 DESCRIPTION
1559 wakaba 1.9
1560 wakaba 1.16 YukiWiki is yet another Wiki clone.
1561 wakaba 1.9
1562 wakaba 1.16 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 wakaba 1.9
1566 wakaba 1.16 Read F<readme_en.txt> (English) or F<readme_ja.txt> (Japanese) in more detail.
1567 wakaba 1.9
1568 wakaba 1.16 =head1 AUTHOR
1569 wakaba 1.9
1570 wakaba 1.16 Hiroshi Yuki <hyuki@hyuki.com> http://www.hyuki.com/yukiwiki/
1571 wakaba 1.9
1572 wakaba 1.16 =head1 LICENSE
1573 wakaba 1.9
1574 wakaba 1.16 Copyright (C) 2000-2002 by Hiroshi Yuki.
1575 wakaba 1.9
1576 wakaba 1.16 This program is free software; you can redistribute it and/or
1577     modify it under the same terms as Perl itself.
1578 wakaba 1.9
1579     =cut

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24