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

Diff of /suikawiki/script/wiki.cgi

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.44 by w, Wed Jan 1 12:30:24 2003 UTC revision 1.48 by w, Fri Jan 3 08:25:31 2003 UTC
# Line 7  Line 7 
7  use strict;  use strict;
8  use lib qw(./lib);  use lib qw(./lib);
9  use CGI::Carp qw(fatalsToBrowser);  use CGI::Carp qw(fatalsToBrowser);
10    our $VERSION = do{my @r=(q$Revision$=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
11    
12  require 'wikidata/suikawiki-config.ph';  require 'wikidata/suikawiki-config.ph';
 use Yuki::DiffText qw(difftext);  
13  use Fcntl;  use Fcntl;
14  ##############################  ##############################
15  my %fmt;        ## formatter objects  my %fmt;        ## formatter objects
# Line 18  my %embed_command = ( Line 18  my %embed_command = (
18          form    => qr/\[\[\#form(?:\(([A-Za-z0-9-]+)\))?:'((?:[^'\\]|\\.)*)':'((?:[^'\\]|\\.)*)'(?::'((?:[^'\\]|\\.)*)')?\]\]/,          form    => qr/\[\[\#form(?:\(([A-Za-z0-9-]+)\))?:'((?:[^'\\]|\\.)*)':'((?:[^'\\]|\\.)*)'(?::'((?:[^'\\]|\\.)*)')?\]\]/,
19  );  );
20  our ($modifier_dbtype,$url_cgi,%uri,%PathTo,$use_exists);  our ($modifier_dbtype,$url_cgi,%uri,%PathTo,$use_exists);
21  our (%PageName,$kanjicode,$lang,%fixedpage);  our (%PageName,$kanjicode,$lang,%ViewDefinition);
22    
23  ##############################  ##############################
 my $info_LastModified = 'LastModified';  
 my $info_IsFrozen = 'IsFrozen';  
 ##############################  
24  my %form;  my %form;
25  my %database;  our %database;
26  my %infobase;  our $database = bless {}, 'wiki::dummy';
 my %diffbase;  
27  my %interwiki;  my %interwiki;
28  ##############################  ##############################
29  my %page_command = (  my %page_command = (
     $PageName{IndexPage} => 'index',  
30      $PageName{RssPage} => 'rss',      $PageName{RssPage} => 'rss',
     AdminChangePassword => 'adminchangepasswordform',  
31  );  );
32  my %command_do = (  my %command_do = (
33      read => \&do_read,      read => \&do_read,
34      TEXT_CSS => \&do_output_css,      TEXT_CSS => \&do_output_css,
35      edit => \&do_edit,      edit => \&do_view,
     adminedit => \&do_adminedit,  
     adminchangepasswordform => \&do_adminchangepasswordform,  
36      adminchangepassword => \&do_adminchangepassword,      adminchangepassword => \&do_adminchangepassword,
37      write => \&do_write,      write => \&do_write,
     index => \&do_index,  
38      searchform => \&do_searchform,      searchform => \&do_searchform,
39      comment => \&do_comment,      comment => \&do_comment,
40      RandomJump  => \&do_random_jump,      RandomJump  => \&do_random_jump,
41      rss => \&do_rss,      rss => \&do_rss,
42      diff => \&do_diff,      diff => \&do_diff,
43      wikiform    => \&do_wikiform,      wikiform    => \&do_wikiform,
44      map => \&do_map,      map => \&do_view,
45  );  );
46  my $UA = '';  ## User agent name  my $UA = '';  ## User agent name
47  $| = 1;  $| = 1;
# Line 70  sub main { Line 61  sub main {
61    
62  sub do_read {  sub do_read {
63    my $content = $database{$form{mypage}};    my $content = $database{$form{mypage}};
64    #print "content-type:text/plain;charset=euc-jp\n\n".gmtime."Get Lastmodified\n";    my $lm = $database->mtime ($form{mypage});
   my $lm = &get_info($form{mypage}, $info_LastModified);  
65    wiki::referer::add ($form{mypage}, $ENV{HTTP_REFERER});    wiki::referer::add ($form{mypage}, $ENV{HTTP_REFERER});
66    wiki::useragent::add ($ENV{HTTP_USER_AGENT});    wiki::useragent::add ($ENV{HTTP_USER_AGENT});
   #print gmtime."Search...\n";  
   my ($r, $c) = get_search_result ($form{mypage});  
   my $rl = wiki::referer::list_html ($form{mypage});  
67    my @toc;    my @toc;
   push @toc, qq(-<a href="#wikipage-see-also">@{[&Resource('SeeAlso',escape=>1)]}</a>) if $c;  
   push @toc, qq(-<a href="#wikipage-referer">@{[&Resource('Referers',escape=>1)]}</a>) if $rl;  
68      my $cf = 'SuikaWiki/0.9';      my $cf = 'SuikaWiki/0.9';
69      ## Should be support at least:      ## Should be support at least:
70      ## - 'SuikaWiki/0.9' CRLF      ## - 'SuikaWiki/0.9' CRLF
# Line 87  sub do_read { Line 72  sub do_read {
72      ## - "/*" WSP* 'W3C-CSS/' ("1.0" / "2.0") "*/" CRLF      ## - "/*" WSP* 'W3C-CSS/' ("1.0" / "2.0") "*/" CRLF
73      $cf = $1 if $content =~ s#^(?:/\*\s*|[\#<]\?)?([A-Z][A-Za-z0-9-]+/[0-9.]+(?:[^0-9.\x0D\x0A][^\x0D\x0A]*)?)[\x0D\x0A]+##s;      $cf = $1 if $content =~ s#^(?:/\*\s*|[\#<]\?)?([A-Z][A-Za-z0-9-]+/[0-9.]+(?:[^0-9.\x0D\x0A][^\x0D\x0A]*)?)[\x0D\x0A]+##s;
74      if ($cf =~ m!^(?:\#\?)?SuikaWiki/0.9(?:$|\s)!) {      if ($cf =~ m!^(?:\#\?)?SuikaWiki/0.9(?:$|\s)!) {
75      #print gmtime."Header...\n";        my $expires = time;
76        &print_header ($form{mypage}, -last_modified => $lm, -expires => time + 120,        if ($cf =~ /interactive="yes"/) {
77            $lm = $expires;
78          } else {
79            $expires += 120;
80          }
81          &print_header ($form{mypage}, -last_modified => $lm, -expires => $expires,
82          -content_format => $cf, -noindex => ($cf =~ /obsoleted="yes"/ ? 1 : 0));          -content_format => $cf, -noindex => ($cf =~ /obsoleted="yes"/ ? 1 : 0));
         #print "\n". gmtime."Body...\n";  
83        &print_content ($content, content_format => $cf, last_modified => $lm,        &print_content ($content, content_format => $cf, last_modified => $lm,
84          -toc => \@toc);          -toc => \@toc);
85        print &text_to_html (q([[#comment]])) if $cf !~ /obsoleted="yes"/ && !$fixedpage{$form{mypage}};        print &text_to_html (q([[#comment]])) if $cf !~ /obsoleted="yes"/ && !$database->meta (IsFrozen => $form{mypage});
86      } else {      } else {
87        &print_header($form{mypage}, -expires => time + 120, -last_modified => $lm);        &print_header($form{mypage}, -expires => time + 120, -last_modified => $lm);
88        print "<pre>@{[&escape($content)]}</pre>";        print "<pre>@{[&escape($content)]}</pre>";
89      }      }
90      if ($c) {      &load_formatter ('view');
91        print qq{<h2 @{[&id_and_name('wikipage-see-also')]}>@{[&Resource('SeeAlso',escape=>1)]}</h2>};      print $fmt{view}->replace ($ViewDefinition{read} => bless {param => \%form, page => $form{mypage}, toc => \@toc, formatter => $fmt{view}, &_compatible_options ()}, 'SuikaWiki::Plugin');
92        print $r;      &print_footer ($form{mypage}, $lm);
     }  
     if ($rl) {  
       print qq(<div @{[&id_and_name('wikipage-referer')]}><h2>@{[&Resource('Referers',escape=>1)]}</h2>\n$rl</div>\n);  
     }  
         #print "\n". gmtime."Footer...\n";  
   &print_footer($form{mypage}, $lm);  
         #print "\n". gmtime."Fin...\n";  
93  }  }
94    
95  sub do_output_css {  sub do_output_css {
# Line 115  sub do_output_css { Line 97  sub do_output_css {
97    wiki::useragent::add ($ENV{HTTP_USER_AGENT});    wiki::useragent::add ($ENV{HTTP_USER_AGENT});
98    my $content = $database{$form{mypage}};    my $content = $database{$form{mypage}};
99    if ($content =~ m#^\s*/\*\s*W3C-CSS#) {    if ($content =~ m#^\s*/\*\s*W3C-CSS#) {
100      my $lm = gmtime &get_info($form{mypage}, $info_LastModified);      my $lm = gmtime $database->mtime ($form{mypage});
101      print "Content-Type: text/css; charset=@{[&get_charset_name($kanjicode)]}\n";      print "Content-Type: text/css; charset=@{[&get_charset_name($kanjicode)]}\n";
102      print "Last-Modified: $lm\n";      print "Last-Modified: $lm\n";
103      print "Expires: @{[scalar gmtime time+3600]}\n";    ## TODO: don't use asctime      print "Expires: @{[scalar gmtime time+3600]}\n";    ## TODO: don't use asctime
# Line 138  sub id_and_name ($) { Line 120  sub id_and_name ($) {
120      }      }
121  }  }
122    
123  sub do_edit {  sub do_view {
     my ($page) = &unarmor_name(&armor_name($form{mypage}));  
     if (not &is_editable($page)) {  
         &print_header($page, -noindex => 1);  
         &print_message(&Resource('Error:ThisPageIsUneditable'));  
     } elsif (&is_frozen($page)) {  
         &print_header($page, -noindex => 1);  
         &print_message(&Resource('Error:ThisPageIsUneditable'));  
     } else {  
         &print_header($page, -noindex => 1, -expires => time+60);  
         &print_editform($database{$page}, &get_info($page, $info_LastModified), admin=>0);  
     }  
124      wiki::referer::add ($form{mypage}, $ENV{HTTP_REFERER});      wiki::referer::add ($form{mypage}, $ENV{HTTP_REFERER});
125      wiki::useragent::add ($ENV{HTTP_USER_AGENT});      wiki::useragent::add ($ENV{HTTP_USER_AGENT});
126      my ($r, $c) = get_search_result ($form{mypage});      &print_header($form{mypage}, -noindex => 1, -expires => time+60);
127      my $rl = wiki::referer::list_html ($form{mypage});      &load_formatter ('view');
128      if ($c) {      my $view = $form{mycmd};
129        print qq{<h2 id="wikipage-see-also">@{[&Resource('SeeAlso',escape=>1)]}</h2>};      if ($view eq 'edit') {
130        print $r;        $view = 'adminedit' if $form{admin};
131      }      } elsif ($view =~ /[^0-9A-Za-z]/) {
132      if ($rl) {        $view = 'view'
       print qq(<div id="wikipage-referer"><h2>@{[&Resource('Referers',escape=>1)]}</h2>\n$rl</div>\n);  
     }  
     &print_footer($page);  
 }  
   
 sub do_adminedit {  
     my ($page) = &unarmor_name(&armor_name($form{mypage}));  
     &print_header($page, -noindex => 1);  
     if (not &is_editable($page)) {  
         &print_message(&Resource('Error:ThisPageIsUneditable'));  
     } else {  
         &print_message(&Resource('Error:PasswordIsNotSpecified'));  
         &print_editform($database{$page}, &get_info($page, $info_LastModified), admin=>1);  
133      }      }
134      &print_footer($page);      print $fmt{view}->replace ($ViewDefinition{$view} => bless {param => \%form, page => $form{mypage}, toc => [], formatter => $fmt{view}, &_compatible_options ()}, 'SuikaWiki::Plugin');
135  }      &print_footer($form{mypage});
   
 sub do_adminchangepasswordform {  
     &print_header('AdminChangePassword', -noindex => 1);  
     &print_passwordform;  
     &print_footer('AdminChangePassword');  
136  }  }
137    
138  sub do_adminchangepassword {  sub do_adminchangepassword {
139      if ($form{mynewpassword} ne $form{mynewpassword2}) {      if ($form{mynewpassword} ne $form{mynewpassword2}) {
140          &print_error(&Resource('Error:PasswordMismatch'));          &print_error(&Resource('Error:PasswordMismatch'));
141      }      }
142      my ($validpassword_crypt) = &get_info($PageName{AdminSpecialPage}, 'AdminPassword');      my ($validpassword_crypt) = $database->meta (AdminPassword => $PageName{AdminSpecialPage});
143      if ($validpassword_crypt) {      if ($validpassword_crypt) {
144          if (not &valid_password($form{myoldpassword})) {          if (not &valid_password($form{myoldpassword})) {
 #            &send_mail_to_admin(<<"EOD", "AdminChangePassword");  
 #myoldpassword=$form{myoldpassword}  
 #mynewpassword=$form{mynewpassword}  
 #mynewpassword2=$form{mynewpassword2}  
 #EOD  
145              &print_error(&Resource('Error:PasswordIsIncorrect'));              &print_error(&Resource('Error:PasswordIsIncorrect'));
146          }          }
147      }      }
# Line 202  sub do_adminchangepassword { Line 150  sub do_adminchangepassword {
150      my $salt1 = $token[(time | $$) % scalar(@token)];      my $salt1 = $token[(time | $$) % scalar(@token)];
151      my $salt2 = $token[($sec + $min*60 + $hour*60*60) % scalar(@token)];      my $salt2 = $token[($sec + $min*60 + $hour*60*60) % scalar(@token)];
152      my $crypted = crypt($form{mynewpassword}, "$salt1$salt2");      my $crypted = crypt($form{mynewpassword}, "$salt1$salt2");
153      &set_info($PageName{AdminSpecialPage}, 'AdminPassword', $crypted);      $database->meta (AdminPassword => $PageName{AdminSpecialPage} => $crypted);
154    
155      &print_header('CompletedSuccessfully', -noindex => 1);      &print_header('CompletedSuccessfully', -noindex => 1);
156      &print_message(&Resource('Error:PasswordIsChanged'));      &print_message(&Resource('Error:PasswordIsChanged'));
157      &print_footer('CompletedSuccessfully');      &print_footer('CompletedSuccessfully');
158  }  }
159    
160  sub do_index {  sub valid_password ($) {
161    wiki::referer::add ($form{mypage}, $ENV{HTTP_REFERER});      my ($validpassword_crypt) = $database->meta (AdminPassword => $PageName{AdminSpecialPage});
162    wiki::useragent::add ($ENV{HTTP_USER_AGENT});      return crypt (shift, $validpassword_crypt) eq $validpassword_crypt ? 1 : 0;
     &print_header($PageName{IndexPage});  
     print qq(<ul>);  
     foreach my $page (sort keys %database) {  
         if (&is_editable($page)) {  
             print qq(<li><a href="$url_cgi?@{[&encode($page)]}">@{[&escape($page)]}</a>@{[&escape(&get_subjectline($page))]}</li>);  
         }  
     }  
     print qq(</ul>);  
     my ($r, $c) = get_search_result ($form{mypage});  
     if ($c) {  
       print qq{<h2 @{[&id_and_name('wikipage-see-also')]}>@{[&Resource('SeeAlso',escape=>1)]}</h2>};  
       print $r;  
     }  
     my $rl = wiki::referer::list_html ($form{mypage});  
     if ($rl) {  
         print qq(<div @{[&id_and_name('wikipage-referer')]}><h2>@{[&Resource('Referers',escape=>1)]}</h2>\n$rl</div>\n);  
     }  
     &print_footer($PageName{IndexPage});  
163  }  }
164    
165  sub do_write {  sub do_write {
# Line 244  sub do_write { Line 174  sub do_write {
174          return;          return;
175      }      }
176    
177      if (&conflict($form{mypage}, $form{mymsg})) {      ## Check confliction
178          return;      if ($form{myLastModified} ne $database->mtime ($page)) {
179      }        &print_header($page, -noindex => 1);
180          &load_formatter ('view');
181      # Making diff        print $fmt{view}->replace ($ViewDefinition{-conflict} => bless {param => \%form, page => $form{mypage}, toc => [], formatter => $fmt{view}, &_compatible_options ()}, 'SuikaWiki::Plugin');
182      {        &print_footer($page);
183          &open_diff;        return;
         my @msg1 = split(/\n/, $database{$form{mypage}});  
         my @msg2 = split(/\n/, $form{mymsg});  
         $diffbase{$form{mypage}} = &difftext(\@msg1, \@msg2);  
         &close_diff;  
184      }      }
185    
186      if ($form{mymsg}) {      if ($form{mymsg}) {
187          $database{$form{mypage}} = $form{mymsg};          if ($form{mytouch} || !ref $database) {
188          #&send_mail_to_admin($form{mypage}, "Modify");            $database{$form{mypage}} = $form{mymsg};
189          if ($form{mytouch}) {          } else {
190              &set_info($form{mypage}, $info_LastModified, time);            $database->STORE ($form{mypage} => $form{mymsg}, -touch => 0);
             &update_recent_changes;  
191          }          }
192          &set_info($form{mypage}, $info_IsFrozen, 0 + $form{myfrozen});          $database->meta (IsFrozen => $form{mypage} => 0 + $form{myfrozen});
193          my $fragment = '';          my $fragment = '';
194          $fragment .= qq(;after_edit_cmd=@{[&encode($form{after_edit_cmd})]}) if $form{after_edit_cmd};          $fragment .= qq(;after_edit_cmd=@{[&encode($form{after_edit_cmd})]}) if $form{after_edit_cmd};
195          if ($form{__comment_anchor_index}) {          if ($form{__comment_anchor_index}) {
# Line 277  sub do_write { Line 202  sub do_write {
202          &print_content(&Resource('Error:ContinueReading')." @{[&armor_name($form{mypage})]}");          &print_content(&Resource('Error:ContinueReading')." @{[&armor_name($form{mypage})]}");
203          &print_footer('CompletedSuccessfully');          &print_footer('CompletedSuccessfully');
204      } else {      } else {
         #&send_mail_to_admin($form{mypage}, "Delete");  
205          delete $database{$form{mypage}};          delete $database{$form{mypage}};
         delete $infobase{$form{mypage}};  
         if ($form{mytouch}) {  
             &update_recent_changes;  
         }  
206          &print_header($form{mypage}, -noindex => 1);          &print_header($form{mypage}, -noindex => 1);
207          &print_message(&Resource('Error:PageIsDeletedSuccessfully'));          &print_message(&Resource('Error:PageIsDeletedSuccessfully'));
208          &print_footer($form{mypage});          &print_footer($form{mypage});
209      }      }
210  }  }
211    
212    sub _compatible_options () {
213      (use_anchor_name => ($UA =~ m#Mozilla/[12]\.|Microsoft Internet Explorer# ? 1 : 0));
214    }
215    
216  sub get_search_result ($;%) {  sub get_search_result ($;%) {
217    my $word = lc shift;    my $word = lc shift;
218    my %option = @_;    my %option = @_;
# Line 362  sub print_header ($;%) { Line 286  sub print_header ($;%) {
286      }      }
287      push @head, qq(<title>@{[&escape($page)]}</title>);      push @head, qq(<title>@{[&escape($page)]}</title>);
288      if ($UA !~ m#Mozilla/[1-4]\.# || $UA =~ m#MSIE (?:[4-9]\.|\d\d)#) {      if ($UA !~ m#Mozilla/[1-4]\.# || $UA =~ m#MSIE (?:[4-9]\.|\d\d)#) {
289        push @head, qq(<link rel="stylesheet" type="text/css" href="@{[&escape($uri{wiki}.'?mycmd=TEXT_CSS;mypage='.&encode($PageName{DefaultStyleForHTML}).';x-lm='.&get_info($PageName{DefaultStyleForHTML}, $info_LastModified))]}");        push @head, qq(<link rel="stylesheet" type="text/css").
290                      qq( href="@{[&escape($uri{wiki}.'?mycmd=TEXT_CSS;mypage='.&encode($PageName{DefaultStyleForHTML}).';x-lm='.$database->mtime ($PageName{DefaultStyleForHTML}))]}");
291      }      }
292      push @head, q(<meta name="ROBOTS" content="NOINDEX">) if $option{-noindex};      push @head, q(<meta name="ROBOTS" content="NOINDEX">) if $option{-noindex};
293      my ($Links, $links) = &make_navigate_links ($page);      my ($Links, $links) = &make_navigate_links ($page);
# Line 415  sub print_navigate_links (@) { Line 340  sub print_navigate_links (@) {
340      <a href="$url_cgi?$PageName{FrontPage}" class="wiki" title="@{[&Resource('GoToHomePageLong',escape=>1)]}">@{[&Resource('GoToHomePage',escape=>1)]}</a> |      <a href="$url_cgi?$PageName{FrontPage}" class="wiki" title="@{[&Resource('GoToHomePageLong',escape=>1)]}">@{[&Resource('GoToHomePage',escape=>1)]}</a> |
341      <a href="$url_cgi?$PageName{SearchPage}" class="wiki" title="@{[&Resource('GoToSearchPageLong',escape=>1)]}">@{[&Resource('GoToSearchPage',escape=>1)]}</a> |      <a href="$url_cgi?$PageName{SearchPage}" class="wiki" title="@{[&Resource('GoToSearchPageLong',escape=>1)]}">@{[&Resource('GoToSearchPage',escape=>1)]}</a> |
342      <a href="$url_cgi?mycmd=RandomJump;x-param=@{[time.[0..9]->[rand 10]]}" class="wiki randomlink" title="@{[&Resource('GoSomewhereLong',escape=>1)]}">@{[&Resource('GoSomewhere',escape=>1)]}</a> |      <a href="$url_cgi?mycmd=RandomJump;x-param=@{[time.[0..9]->[rand 10]]}" class="wiki randomlink" title="@{[&Resource('GoSomewhereLong',escape=>1)]}">@{[&Resource('GoSomewhere',escape=>1)]}</a> |
343      <a href="$url_cgi?RecentChanges" class="wiki" title="@{[&Resource('GoToRecentChangesLong',escape=>1)]}">@{[&Resource('GoToRecentChanges',escape=>1)]}</a>      <a href="$url_cgi?$PageName{RecentChanges}" class="wiki" title="@{[&Resource('GoToRecentChangesLong',escape=>1)]}">@{[&Resource('GoToRecentChanges',escape=>1)]}</a>
344  </div>  </div>
345  EOH  EOH
346  }  }
# Line 424  sub make_navigate_links ($) { Line 349  sub make_navigate_links ($) {
349      my $page = shift;      my $page = shift;
350      my @link;      my @link;
351      push @link, {rel=>'edit', href=>"$url_cgi?mycmd=edit;mypage=@{[&encode($page)]}", class=>"wiki-command", title=>&Resource('EditThisPageLink')} if &is_editable ($page) && !&is_frozen ($page);      push @link, {rel=>'edit', href=>"$url_cgi?mycmd=edit;mypage=@{[&encode($page)]}", class=>"wiki-command", title=>&Resource('EditThisPageLink')} if &is_editable ($page) && !&is_frozen ($page);
352      push @link, {rel=>'edit', href=>"$url_cgi?mycmd=adminedit;mypage=@{[&encode($page)]}", class=>"wiki-command", title=>&Resource('AdminEditThisPageLink')} if &is_editable ($page) || &is_frozen ($page);      push @link, {rel=>'edit', href=>"$url_cgi?mycmd=edit;admin=1;mypage=@{[&encode($page)]}", class=>"wiki-command", title=>&Resource('AdminEditThisPageLink')} if &is_editable ($page) || &is_frozen ($page);
353      push @link, {rel=>'view', href=>"$url_cgi?mycmd=read;mypage=@{[&encode($page)]};x-p=@{[time.[0..9]->[rand 10]]}", class=>'wiki-command', title=>&Resource('ViewThisPageLink')};      push @link, {rel=>'view', href=>"$url_cgi?mycmd=read;mypage=@{[&encode($page)]};x-p=@{[time.[0..9]->[rand 10]]}", class=>'wiki-command', title=>&Resource('ViewThisPageLink')};
354      push @link, {rel=>'myself', href=>"$url_cgi?@{[&encode($page)]}", class=>'wiki', title=>&Resource('GoToMyselfLink')};      push @link, {rel=>'myself', href=>"$url_cgi?@{[&encode($page)]}", class=>'wiki', title=>&Resource('GoToMyselfLink')};
355      push @link, {rel=>'index', href=>"$url_cgi?$PageName{IndexPage}", class=>'wiki', title=>&Resource('GoToIndexPageLink')};      push @link, {rel=>'index', href=>"$url_cgi?$PageName{IndexPage}", class=>'wiki', title=>&Resource('GoToIndexPageLink')};
356      push @link, {rel=>'home', href=>"$url_cgi?$PageName{FrontPage}", class=>'wiki', title=>&Resource('GoToHomePageLink')};      push @link, {rel=>'home', href=>"$url_cgi?$PageName{FrontPage}", class=>'wiki', title=>&Resource('GoToHomePageLink')};
357      push @link, {rel=>'News', href=>"$url_cgi?WikiNews", class=>'wiki', title=>&Resource('GoToWikiNewsLink')};      push @link, {rel=>'News', href=>"$url_cgi?WikiNews", class=>'wiki', title=>&Resource('GoToWikiNewsLink')};
358      push @link, {rel=>'News', href=>"$url_cgi?RecentChanges", class=>"wiki", title=>&Resource('GoToRecentChangesLink')};      push @link, {rel=>'News', href=>"$url_cgi?$PageName{RecentChanges}", class=>"wiki", title=>&Resource('GoToRecentChangesLink')};
359      push @link, {rel=>'News', href=>"$url_cgi?$PageName{RssPage}", class=>"wiki", title=>&Resource('GoToRssPageLink'), type=>'application/xml'};      push @link, {rel=>'News', href=>"$url_cgi?$PageName{RssPage}", class=>"wiki", title=>&Resource('GoToRssPageLink'), type=>'application/xml'};
360      push @link, {rel=>'search', href=>"$url_cgi?$PageName{SearchPage}", class=>'wiki', title=>&Resource('GoToSearchPageLink')};      push @link, {rel=>'search', href=>"$url_cgi?$PageName{SearchPage}", class=>'wiki', title=>&Resource('GoToSearchPageLink')};
361      push @link, {rel=>'help', href=>"$url_cgi?WikiHelp", class=>'wiki', title=>&Resource('GoToWikiHelpLink')};      push @link, {rel=>'help', href=>"$url_cgi?WikiHelp", class=>'wiki', title=>&Resource('GoToWikiHelpLink')};
# Line 439  sub make_navigate_links ($) { Line 364  sub make_navigate_links ($) {
364      push @link, {rel=>'jump', href=>qq(javascript:var%20WikiName=prompt('Please%20input%20the%20WikiName:','','Jump%20to%20SuikaWiki');if(WikiName)%7B_content.location.href='$url_cgi%3Fmycmd=edit;mypage='+encodeURIComponent(WikiName)%7D), class=>'wiki-cmd', title=>&Resource('JumpToEditLink')};      push @link, {rel=>'jump', href=>qq(javascript:var%20WikiName=prompt('Please%20input%20the%20WikiName:','','Jump%20to%20SuikaWiki');if(WikiName)%7B_content.location.href='$url_cgi%3Fmycmd=edit;mypage='+encodeURIComponent(WikiName)%7D), class=>'wiki-cmd', title=>&Resource('JumpToEditLink')};
365      push @link, {rel=>'lucky', href=>"$url_cgi?mycmd=RandomJump;x-param=@{[time.[0..9]->[rand 10]]}", class=>'wiki randomlink', title=>&Resource('GoSomewhereLink')};      push @link, {rel=>'lucky', href=>"$url_cgi?mycmd=RandomJump;x-param=@{[time.[0..9]->[rand 10]]}", class=>'wiki randomlink', title=>&Resource('GoSomewhereLink')};
366      push @link, {rel=>'history', href=>$uri{cvs_wikipage}.do{my $s=$page;$s=~s/(.)/sprintf '%02X', ord $1/ges;$s}.'.txt', title=>&Resource('ViewHistoryOfThisPageLink'),hreflang=>'en'} if $uri{cvs_wikipage};      push @link, {rel=>'history', href=>$uri{cvs_wikipage}.do{my $s=$page;$s=~s/(.)/sprintf '%02X', ord $1/ges;$s}.'.txt', title=>&Resource('ViewHistoryOfThisPageLink'),hreflang=>'en'} if $uri{cvs_wikipage};
367      push @link, {rel=>'history', href=>"$url_cgi?mycmd=diff;mypage=@{[&encode($page)]}", title=>&Resource('ViewDiffOfThisPageLink'), class=>'wiki-command'};      push @link, {rel=>'history', href=>"$url_cgi?mycmd=diff;mypage=@{[&encode($page)]}", title=>&Resource('ViewDiffOfThisPageLink'), class=>'wiki-command'} if $wiki::diff::UseDiff;
368      push @link, {rel=>'contents', href=>"$url_cgi?mycmd=map;mypage=@{[&encode($page)]}", title=>&Resource('ShowMapOfThisPageLink'), class=>'wiki-command'};      push @link, {rel=>'contents', href=>"$url_cgi?mycmd=map;mypage=@{[&encode($page)]}", title=>&Resource('ShowMapOfThisPageLink'), class=>'wiki-command'};
369      my ($Links, $links) = ('', '');      my ($Links, $links) = ('', '');
370      for my $e (@link) {      for my $e (@link) {
# Line 476  EOD Line 401  EOD
401    
402  sub escape {  sub escape {
403      my $s = shift;      my $s = shift;
404      $s =~ s|\r\n|\n|g;      $s =~ s|\x0D\x0A|\x0A|g;
405      $s =~ s|&|&amp;|g;      $s =~ s|&|&amp;|g;
406      $s =~ s|<|&lt;|g;      $s =~ s|<|&lt;|g;
407      $s =~ s|>|&gt;|g;      $s =~ s|>|&gt;|g;
# Line 501  sub print_content ($;$) { Line 426  sub print_content ($;$) {
426    
427  sub text_to_html {  sub text_to_html {
428      my ($txt, %option) = @_;      my ($txt, %option) = @_;
429      my @toc;      my $toc = $option{-toc} || [];
     my @toc2 = @{$option{-toc}||[]};  
430      my $tocnum = 0;      my $tocnum = 0;
431            
432      ## Load constants      ## Load constants
# Line 524  sub text_to_html { Line 448  sub text_to_html {
448      foreach (@txt) {      foreach (@txt) {
449          chomp;          chomp;
450          if (/^\*\*\*\*\*([^\x0D\x0A]*)/) {          if (/^\*\*\*\*\*([^\x0D\x0A]*)/) {
451              push(@toc, qq(----- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));              push @$toc, [5, "i$tocnum" => ($1 || $tocnum)];
452              push(@result, splice(@saved), qq(<h6 @{[&id_and_name("i$tocnum")]}>) . &inline($1, const => \%const) . '</h6>');              push(@result, splice(@saved), qq(<h6 @{[&id_and_name("i$tocnum")]}>) . &inline($1, const => \%const) . '</h6>');
453              $tocnum++;              $tocnum++;
454          } elsif (/^\*\*\*\*([^\x0D\x0A]*)/) {          } elsif (/^\*\*\*\*([^\x0D\x0A]*)/) {
455              push(@toc, qq(---- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));              push @$toc, [4, "i$tocnum" => ($1 || $tocnum)];
456              push(@result, splice(@saved), qq(<h5 @{[&id_and_name("i$tocnum")]}>) . &inline($1, const => \%const) . '</h5>');              push(@result, splice(@saved), qq(<h5 @{[&id_and_name("i$tocnum")]}>) . &inline($1, const => \%const) . '</h5>');
457              $tocnum++;              $tocnum++;
458          } elsif (/^\*\*\*([^\x0D\x0A]*)/) {          } elsif (/^\*\*\*([^\x0D\x0A]*)/) {
459              push(@toc, qq(--- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));              push @$toc, [3, "i$tocnum" => ($1 || $tocnum)];
460              push(@result, splice(@saved), qq(<h4 @{[&id_and_name("i$tocnum")]}>) . &inline($1, const => \%const) . '</h4>');              push(@result, splice(@saved), qq(<h4 @{[&id_and_name("i$tocnum")]}>) . &inline($1, const => \%const) . '</h4>');
461              $tocnum++;              $tocnum++;
462          } elsif (/^\*\*([^\x0D\x0A]*)/) {          } elsif (/^\*\*([^\x0D\x0A]*)/) {
463          # if (/^\*\*(.*)/) {          # if (/^\*\*(.*)/) {
464          # Walrus mod (6) end          # Walrus mod (6) end
465              push(@toc, qq(-- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));              push @$toc, [2, "i$tocnum" => ($1 || $tocnum)];
466              push(@result, splice(@saved), qq(<h3 @{[&id_and_name("i$tocnum")]}>) . &inline($1, const => \%const) . '</h3>');              push(@result, splice(@saved), qq(<h3 @{[&id_and_name("i$tocnum")]}>) . &inline($1, const => \%const) . '</h3>');
467              $tocnum++;              $tocnum++;
468          } elsif (/^\*([^\x0D\x0A]*)/) {          } elsif (/^\*([^\x0D\x0A]*)/) {
469              push(@toc, qq(- <a href="#i$tocnum">@{[&escape($1)||$tocnum]}</a>\n));              push @$toc, [1, "i$tocnum" => ($1 || $tocnum)];
470              push(@result, splice(@saved), qq(<h2 @{[&id_and_name("i$tocnum")]}>) . &inline($1, const => \%const) . '</h2>');              push(@result, splice(@saved), qq(<h2 @{[&id_and_name("i$tocnum")]}>) . &inline($1, const => \%const) . '</h2>');
471              $tocnum++;              $tocnum++;
472          } elsif (/^(={1,6})(.*)/) {          } elsif (/^(={1,6})(.*)/) {
# Line 610  sub text_to_html { Line 534  sub text_to_html {
534      }      }
535      push(@result, splice(@saved));      push(@result, splice(@saved));
536            
537      my $toc = '';      my $r = join("\n", @result);
538      if ($option{toc}) {      $r =~ s#<p>\x0D?\x0A</p>##g;
539          # Convert @toc (table of contents) to HTML.      $r =~ s#[\x0D\x0A]+</#</#g;
540          # This part is taken from Makio Tsukamoto's WalWiki.      $r =~ s#<pre>\x0D?\x0A#<pre>#g;
541          my (@tocsaved, @tocresult);      $r;
         foreach (@toc,@toc2) {  
             if (/^(-{1,6})(.*)$/) {  
                 &back_push('ul', length($1), \@tocsaved, \@tocresult);  
                 push(@tocresult, '<li>' . $2 . '</li>');  
             }  
         }  
         push(@tocresult, splice(@tocsaved));  
         $toc = join("\n", @tocresult);  
         $toc = $toc ? qq(<div id="wikipage-toc">$toc</div>) : '';  
     }  
     $toc .= join("\n", @result);  
     $toc =~ s#<p>\n</p>##g;  
     $toc =~ s#[\x0D\x0A]+</#</#g;  
     $toc =~ s#<pre>\n#<pre>#g;  
     $toc;  
542  }  }
543    
544  sub back_push {  sub back_push {
# Line 656  sub inline ($;%) { Line 565  sub inline ($;%) {
565      $line =~ s:\[RUBYB\[([^]]+)\] \[([^]]+)\] \[([^]]+)\]\]:<span class="ruby"><ruby class="rb"><rb>$1</rb><rp>(</rp><rt>$2</rt><rp>)</rp></ruby><span class="rp"> (</span><span class="rt-below">$3</span><span class="rp">) </span></span>:g;      $line =~ s:\[RUBYB\[([^]]+)\] \[([^]]+)\] \[([^]]+)\]\]:<span class="ruby"><ruby class="rb"><rb>$1</rb><rp>(</rp><rt>$2</rt><rp>)</rp></ruby><span class="rp"> (</span><span class="rt-below">$3</span><span class="rp">) </span></span>:g;
566      $line =~ s:\[RUBY\[([^]]+)\] \[([^]]+)\]\]:<ruby><rb>$1</rb><rp>(</rp><rt>$2</rt><rp>)</rp></ruby>:g;      $line =~ s:\[RUBY\[([^]]+)\] \[([^]]+)\]\]:<ruby><rb>$1</rb><rp>(</rp><rt>$2</rt><rp>)</rp></ruby>:g;
567      $line =~ s:\[RUBYB\[([^]]+)\] \[([^]]+)\]\]:<span class="ruby"><span class="rb">$1</span><span class="rp"> (</span><span class="rt-below">$2</span><span class="rp">) </span></span>:g;      $line =~ s:\[RUBYB\[([^]]+)\] \[([^]]+)\]\]:<span class="ruby"><span class="rb">$1</span><span class="rp"> (</span><span class="rt-below">$2</span><span class="rp">) </span></span>:g;
     $line =~ s%\[Q\[([^]]+)\](?: \[&lt;([\x21-\x5A\x5E-\x7E]+)&gt;\])?\]%¡Ö<q@{[$2?qq( cite="$2"):'']}>$1</q>¡×%g;  
568      $line =~ s|'''([^']+)'''|<strong>$1</strong>|g;      $line =~ s|'''([^']+)'''|<strong>$1</strong>|g;
569      $line =~ s|''([^']+)''|<em>$1</em>|g;      $line =~ s|''([^']+)''|<em>$1</em>|g;
570      $line =~ s{      $line =~ s{
# Line 667  sub inline ($;%) { Line 575  sub inline ($;%) {
575      }{      }{
576        my ($l, $page,$anchor, $anum, $uri) = ($1, $3,$4, 0+$5, $6);        my ($l, $page,$anchor, $anum, $uri) = ($1, $3,$4, 0+$5, $6);
577        if ($l) {        if ($l) {
578          return &embedded_to_html($1);          &embedded_to_html($1);
579        } elsif (defined $page) {        } elsif (defined $page) {
580          &make_wikilink ($page, anchor => 0+$anchor);          &make_wikilink ($page, anchor => 0+$anchor);
581        } elsif ($anum) {        } elsif ($anum) {
# Line 741  sub make_custom_form ($$$$) { Line 649  sub make_custom_form ($$$$) {
649          $FormIndex++;          $FormIndex++;
650          if (length $definition) {          if (length $definition) {
651              my $param = bless {}, 'SuikaWiki::Plugin';              my $param = bless {}, 'SuikaWiki::Plugin';
652              my $lastmodified = &get_info($form{mypage}, $info_LastModified);              my $lastmodified = $database->mtime ($form{mypage});
653              &load_formatter (qw/form_input form_option/);              &load_formatter (qw/form_input form_option/);
654              $definition = &unescape ($definition);              $definition = &unescape ($definition);
655              $definition =~ s/\\(.)/$1/g;              $definition =~ s/\\(.)/$1/g;
# Line 751  sub make_custom_form ($$$$) { Line 659  sub make_custom_form ($$$$) {
659              $param->{output}->{form} = 1 unless defined $param->{output}->{form};              $param->{output}->{form} = 1 unless defined $param->{output}->{form};
660              $definition .= ' %submit;' if $definition !~ /%submit/ && !$param->{output}->{nosubmit} && $param->{output}->{form};              $definition .= ' %submit;' if $definition !~ /%submit/ && !$param->{output}->{nosubmit} && $param->{output}->{form};
661              my $target_page = $param->{output}->{page} || $form{mypage};              my $target_page = $param->{output}->{page} || $form{mypage};
662              $param->{form_disabled} = 1 if $fixedpage{$target_page};              $param->{form_disabled} = 1 if $database->meta (IsFrozen => $form{mypage});
663              my $target_form = $param->{output}->{id};              my $target_form = $param->{output}->{id};
664              my $r = '';              my $r = '';
665              $r = <<EOH if $param->{output}->{form};              $r = <<EOH if $param->{output}->{form};
# Line 813  sub init_form { Line 721  sub init_form {
721        }        }
722      }      }
723      $form{mypage} ||= 'HomePage';      $form{mypage} ||= 'HomePage';
724        $form{mypage} =~ tr/\x00-\x1F\x7F//d;
725      $form{mycmd} ||= 'read';      $form{mycmd} ||= 'read';
726    
727      # mypreview_edit        -> do_edit, with preview.      # mypreview_edit        -> do_edit, with preview.
# Line 836  sub init_form { Line 745  sub init_form {
745      $form{myname} = &code_convert(\$form{myname}, $kanjicode);      $form{myname} = &code_convert(\$form{myname}, $kanjicode);
746  }  }
747    
 sub update_recent_changes {  
     my $update = "- @{[&get_now]} [[$form{mypage}]] @{[&get_subjectline($form{mypage})]}";  
     my @oldupdates = split(/\x0D?\x0A/, $database{RecentChanges});  
     shift @oldupdates; ## '#?' magic line  
     my @updates;  
     foreach (@oldupdates) {  
         /^\- \d\d\d\d\-\d\d\-\d\d \d\d:\d\d \[\[([^]]+)\]\]/;  
         my $name = $1;  
         if ($name ne $form{mypage}) {  
             push @updates, $_;  
         }  
     }  
     if (&is_exist_page($form{mypage})) {  
       unshift @updates, $update;  
     }  
     splice @updates, (&Resource ('RecentChanges:Max') || 50) + 1;  
     $database{RecentChanges} = "#?SuikaWiki/0.9\n" . join("\n", @updates);  
     if ($PathTo{TouchFile}) {  
         open(FILE, "> ".$PathTo{TouchFile});  
         print FILE localtime() . "\n";  
         close(FILE);  
     }  
 }  
   
748  {my %SubjectLine;  {my %SubjectLine;
749  sub get_subjectline {  sub get_subjectline {
750      my ($page, %option) = @_;      my ($page, %option) = @_;
# Line 883  sub get_subjectline { Line 768  sub get_subjectline {
768  sub open_db {  sub open_db {
769      if ($modifier_dbtype eq 'dbmopen') {      if ($modifier_dbtype eq 'dbmopen') {
770          dbmopen(%database, $PathTo{WikiDataBase}, 0666) or &print_error("(dbmopen) $PathTo{WikiDataBase}");          dbmopen(%database, $PathTo{WikiDataBase}, 0666) or &print_error("(dbmopen) $PathTo{WikiDataBase}");
         dbmopen(%infobase, $PathTo{WikiInfoBase}, 0666) or &print_error("(dbmopen) $PathTo{WikiInfoBase}");  
771      } elsif ($modifier_dbtype eq 'AnyDBM_File') {      } elsif ($modifier_dbtype eq 'AnyDBM_File') {
772          eval q{use AnyDBM_File};          eval q{use AnyDBM_File};
773          tie(%database, "AnyDBM_File", $PathTo{WikiDataBase}, O_RDWR|O_CREAT, 0666) or &print_error("(tie AnyDBM_File) $PathTo{WikiDataBase}");          tie(%database, "AnyDBM_File", $PathTo{WikiDataBase}, O_RDWR|O_CREAT, 0666) or &print_error("(tie AnyDBM_File) $PathTo{WikiDataBase}");
774          tie(%infobase, "AnyDBM_File", $PathTo{WikiInfoBase}, O_RDWR|O_CREAT, 0666) or &print_error("(tie AnyDBM_File) $PathTo{WikiInfoBase}");      } elsif ($modifier_dbtype eq 'Yuki::YukiWikiDB') {
     } else {  
775          eval q{use Yuki::YukiWikiDB};          eval q{use Yuki::YukiWikiDB};
776          tie(%database, "Yuki::YukiWikiDB", $PathTo{WikiDataBase}) or &print_error("(tie Yuki::YukiWikiDB) $PathTo{WikiDataBase}");          tie(%database, "Yuki::YukiWikiDB", $PathTo{WikiDataBase}) or &print_error("(tie Yuki::YukiWikiDB) $PathTo{WikiDataBase}");
777          tie(%infobase, "Yuki::YukiWikiDB", $PathTo{WikiInfoBase}) or &print_error("(tie Yuki::YukiWikiDB) $PathTo{WikiInfoBase}");      } else {    ## Yuki::YukiWikiDB || Yuki::YukiWikiDBMeta
778            eval qq{use $modifier_dbtype};
779            $database = tie(%database, $modifier_dbtype => $PathTo{WikiDataBase}, -lock => 2, -backup => $wiki::diff::UseDiff) or &print_error("(tie $modifier_dbtype) $PathTo{WikiDataBase}");
780      }      }
781  }  }
782    
783  sub close_db {  sub close_db {
784      if ($modifier_dbtype eq 'dbmopen') {      if ($modifier_dbtype eq 'dbmopen') {
785          dbmclose(%database);          dbmclose(%database);
         dbmclose(%infobase);  
     } elsif ($modifier_dbtype eq 'AnyDBM_File') {  
         untie(%database);  
         untie(%infobase);  
786      } else {      } else {
787          untie(%database);          untie(%database);
         untie(%infobase);  
788      }      }
789  }  }
790    
791  sub open_diff {  sub editform (@) {
792      if ($modifier_dbtype eq 'dbmopen') {    my %option = @_;
793          dbmopen(%diffbase, $PathTo{WikiDiffBase}, 0666) or &print_error("(dbmopen) $PathTo{WikiDiffBase}");    my $frozen = &is_frozen ($option{page});
794      } elsif ($modifier_dbtype eq 'AnyDBM_File') {    $option{content} = $database{$option{page}} unless defined $option{content};
795          tie(%diffbase, "AnyDBM_File", $PathTo{WikiDiffBase}, O_RDWR|O_CREAT, 0666) or &print_error("(tie AnyDBM_File) $PathTo{WikiDiffBase}");    $option{content} = $database{NewPageTemplate} unless length $option{content};
796      } else {    $option{last_modified} = $database->mtime ($option{page}) unless defined $option{last_modified};
797          tie(%diffbase, "Yuki::YukiWikiDB", $PathTo{WikiDiffBase}) or &print_error("(tie Yuki::YukiWikiDB) $PathTo{WikiDiffBase}");    my $f = '';
798      }    my $magic = '';
799  }    $magic = $1 if $option{content} =~ m/^([^\x0A\x0D]+)/s;
800      
801  sub close_diff {    my $selected = 'read';
802      if ($modifier_dbtype eq 'dbmopen') {    if ($form{after_edit_cmd}) {
803          dbmclose(%diffbase);      $selected = $form{after_edit_cmd};
804      } elsif ($modifier_dbtype eq 'AnyDBM_File') {    } elsif ($magic =~ /Const|Config|CSS/) {
805          untie(%diffbase);      $selected = 'edit';
806      } else {    }
807          untie(%diffbase);    my $afteredit = <<EOH;
     }  
 }  
   
 sub print_editform {  
     my ($mymsg, $lastmodified, %mode) = @_;  
     my $frozen = &is_frozen($form{mypage});  
   
     if ($form{mypreview}) {  
         if ($form{mymsg}) {  
             unless ($mode{conflict}) {  
                 print qq(<h3>@{[&Resource('Preview:Title',escape=>1)]}</h3>\n);  
                 print qq(<p>@{[&Resource('Preview:Notice',escape=>1)]}</p>\n);  
                 print qq(<div class="preview">\n);  
                 &print_content($form{mymsg});  
                 print qq(</div>\n);  
             }  
         } else {  
             print @{[&Resource('Preview:Empty',escape=>1)]};  
         }  
         $mymsg = &escape($form{mymsg});  
     } else {  
         $mymsg = &escape($mymsg || $database{NewPageTemplate});  
     }  
     my $magic = '';  
     $magic = $1 if $mymsg =~ m/^([^\x0A\x0D]+)/s;  
   
     my $edit = $mode{admin} ? 'adminedit' : 'edit';  
     my $escapedmypage = &escape($form{mypage});  
     my $escapedmypassword = &escape($form{mypassword});  
     my $selected = 'read';  
     if ($form{after_edit_cmd}) {  
         $selected = $form{after_edit_cmd};  
     } elsif ($magic =~ /Const|Config|CSS/) {  
         $selected = 'edit';  
     }  
     my $afteredit = <<EOH;  
808  <select name="after_edit_cmd">  <select name="after_edit_cmd">
809  <option value="read" label="@{[&Resource('Edit:SaveAndView',escape=>1)]}"@{[$selected eq 'read' ? ' selected="selected"':'']}>@{[&Resource('Edit:SaveAndView',escape=>1)]}</option>  <option value="read" label="@{[&Resource('Edit:SaveAndView',escape=>1)]}"@{[$selected eq 'read' ? ' selected="selected"':'']}>@{[&Resource('Edit:SaveAndView',escape=>1)]}</option>
810  <option value="edit" label="@{[&Resource('Edit:SaveAndEdit',escape=>1)]}"@{[$selected eq 'edit' ? ' selected="selected"':'']}>@{[&Resource('Edit:SaveAndEdit',escape=>1)]}</option>  <option value="edit" label="@{[&Resource('Edit:SaveAndEdit',escape=>1)]}"@{[$selected eq 'edit' ? ' selected="selected"':'']}>@{[&Resource('Edit:SaveAndEdit',escape=>1)]}</option>
811  </select>  </select>
812  EOH  EOH
813      $f .= <<"EOD";
814      print <<"EOD";  <form action="$uri{wiki}" method="post">
815  <form action="$url_cgi" method="post">      @{[ $option{conflict} ? '' : qq(<label><input type="submit" name="mypreview_write" value="@{[&Resource('Edit:Save',escape=>1)]}"><kbd>S</kbd></label>) ]}
816  <h2>@{[&Resource('Edit:Title',escape=>1)]}</h2>      @{[ $option{admin} ? qq(<label>@{[&Resource('Edit:Password=',escape=>1)]}<input type="password" name="mypassword" value="" size="10"></label>) : "" ]} [@{[&get_new_anchor_index($option{content})]}]<br>
817      @{[ $mode{conflict} ? '' : qq(<input type="submit" name="mypreview_write" value="@{[&Resource('Edit:Save',escape=>1)]}"><kbd>S</kbd>) ]}      <input type="hidden" name="myLastModified" value="$option{last_modified}">
818      @{[ $mode{admin} ? qq(<label>@{[&Resource('Edit:Password=',escape=>1)]}<input type="password" name="mypassword" value="$escapedmypassword" size="10"></label>) : "" ]} [@{[do {my $n = 0;      <input type="hidden" name="mypage" value="@{[&escape($form{mypage})]}">
819                 $mymsg =~ s/(?:-+\s)?\[([0-9]+)\]/$n = $1 if $1 > $n; $&/mge;      <textarea cols="@{[&Resource('Edit:Form:Cols')+0||80]}" rows="@{[&Resource('Edit:Form:Rows')+0||20]}" name="mymsg" tabindex="1">@{[&escape($option{content})]}</textarea><br>
                ++$n}]}]<br>  
     <input type="hidden" name="myLastModified" value="$lastmodified">  
     <input type="hidden" name="mypage" value="$escapedmypage">  
     <textarea cols="@{[&Resource('Edit:Form:Cols')+0||80]}" rows="@{[&Resource('Edit:Form:Rows')+0||20]}" name="mymsg" tabindex="1">$mymsg</textarea><br>  
820  @{[  @{[
821      $mode{admin} ?      $option{admin} ?
822      qq(      qq(
823      <label><input type="radio" name="myfrozen" value="1" @{[$frozen ? qq(checked="checked") : ""]}>@{[&Resource('Edit:Freeze',escape=>1)]}</label>      <label><input type="radio" name="myfrozen" value="1" @{[$frozen ? qq(checked="checked") : ""]}>@{[&Resource('Edit:Freeze',escape=>1)]}</label>
824      <label><input type="radio" name="myfrozen" value="0" @{[$frozen ? "" : qq(checked="checked")]}>@{[&Resource('Edit:DontFreeze',escape=>1)]}</label><br>)      <label><input type="radio" name="myfrozen" value="0" @{[$frozen ? "" : qq(checked="checked")]}>@{[&Resource('Edit:DontFreeze',escape=>1)]}</label><br>)
825      : ""      : ""
826  ]}  ]}
827  @{[  @{[
828      $mode{conflict} ? "" :      $option{conflict} ? "" :
829      qq(      qq(
830          <input type="checkbox" name="mytouch" value="on" checked="checked">@{[&Resource('Edit:UpdateTimeStamp',escape=>1)]}<br>          <label><input type="checkbox" name="mytouch" value="on" checked="checked">@{[&Resource('Edit:UpdateTimeStamp',escape=>1)]}</label><br>
831          <input type="submit" name="mypreview_$edit" value="@{[&Resource('Edit:Preview',escape=>1)]}">          <label><input type="submit" name="mypreview_write" value="@{[&Resource('Edit:Save',escape=>1)]}" accesskey="S"><kbd>S</kbd></label>
         <input type="submit" name="mypreview_write" value="@{[&Resource('Edit:Save',escape=>1)]}" accesskey="S"><kbd>S</kbd>  
832         $afteredit         $afteredit
        <br>  
833      )      )
834  ]}  ]}
835  </form>  </form>
836  EOD  EOD
837      unless ($mode{conflict}) {      unless ($option{conflict}) {
838          ## Show help text          ## Show help text
839          my $help = $database{WikiEditHelp};          my $help = $database{WikiEditHelp};
840          $help =~ s!^\#\?([A-Z][A-Za-z0-9-]+/[0-9.]+(?:[^0-9.\x0D\x0A][^\x0D\x0A]*)?)[\x0D\x0A]+!!s;          $help =~ s!^\#\?([A-Z][A-Za-z0-9-]+/[0-9.]+(?:[^0-9.\x0D\x0A][^\x0D\x0A]*)?)[\x0D\x0A]+!!s;
841          print &text_to_html ($help, toc => 0);          $f .= &text_to_html ($help, toc => 0);
842      }      }
843  }      $f;
   
 sub print_passwordform {  
         print <<"EOD";  
 <form action="$url_cgi" method="post">  
     <input type="hidden" name="mycmd" value="adminchangepassword">  
     <label>@{[&Resource('Password:Old=',escape=>1)]}<input type="password" name="myoldpassword" size="10"></label><br>  
     <label>@{[&Resource('Password:New1=',escape=>1)]}<input type="password" name="mynewpassword" size="10"></label><br>  
     <label>@{[&Resource('Password:New2=',escape=>1)]}<input type="password" name="mynewpassword2" size="10"></label><br>  
     <input type="submit" value="@{[&Resource('WikiForm:Change',escape=>1)]}"><br>  
 </form>  
 EOD  
844  }  }
845    
846  sub is_editable {  sub is_editable {
847      my ($page) = @_;      my ($page) = @_;
848      if ($fixedpage{$page} || $page =~ /\s/ || $page =~ /^\#/) {      $page =~ /[\x00-\x1F\x7F]/ ? 0 : 1;
         return 0;  
     } else {  
         return 1;  
     }  
849  }  }
850    
851  # armor_name:  # armor_name:
# Line 1062  sub encode { Line 885  sub encode {
885      return $encoded;      return $encoded;
886  }  }
887    
 sub conflict {  
     my ($page, $rawmsg) = @_;  
     if ($form{myLastModified} eq &get_info($page, $info_LastModified)) {  
         return 0;  
     }  
     &print_header($page, -noindex => 1);  
     &print_content(&Resource('Error:Conflict'));  
     &print_editform($rawmsg, $form{myLastModified}, frozen=>0, conflict=>1);  
     &print_footer($page);  
     return 1;  
 }  
   
888  sub get_now {  sub get_now {
889      my ($sec, $min, $hour, $day, $mon, $year) = localtime(time);      my ($sec, $min, $hour, $day, $mon, $year) = localtime(time);
890      $year += 1900;      $year += 1900;
# Line 1096  sub init_InterWikiName { Line 907  sub init_InterWikiName {
907    $interwiki{'[[]]'} = 1;       ## dummy    $interwiki{'[[]]'} = 1;       ## dummy
908  }  }
909    
   
 sub get_info {  
     my ($page, $key) = @_;  
     my %info = map { split(/=/, $_, 2) } split(/\n/, $infobase{$page});  
     return $info{$key};  
 }  
   
 sub set_info {  
     my ($page, $key, $value) = @_;  
     my %info = map { split(/=/, $_, 2) } split(/\n/, $infobase{$page});  
     $info{$key} = $value;  
     my $s = '';  
     for (keys %info) {  
         $s .= "$_=$info{$_}\n";  
     }  
     $infobase{$page} = $s;  
 }  
   
910  sub frozen_reject {  sub frozen_reject {
911      my ($isfrozen) = &get_info($form{mypage}, $info_IsFrozen);      my ($isfrozen) = $database->meta (IsFrozen => $form{mypage});
912      my ($willbefrozen) = $form{myfrozen};      my ($willbefrozen) = $form{myfrozen};
913      if (not $isfrozen and not $willbefrozen) {      if (not $isfrozen and not $willbefrozen) {
914          # You need no check.          # You need no check.
# Line 1129  sub frozen_reject { Line 922  sub frozen_reject {
922      }      }
923  }  }
924    
925  sub valid_password {  sub is_frozen ($) { $database->meta (IsFrozen => $_[0]) ? 1 : 0 }
     my ($givenpassword) = @_;  
     my ($validpassword_crypt) = &get_info($PageName{AdminSpecialPage}, 'AdminPassword');  
     if (crypt($givenpassword, $validpassword_crypt) eq $validpassword_crypt) {  
         return 1;  
     } else {  
         return 0;  
     }  
 }  
   
 sub is_frozen {  
     my ($page) = @_;  
     if (&get_info($page, $info_IsFrozen)) {  
         return 1;  
     } else {  
         return 0;  
     }  
 }  
926    
927  sub do_comment {  sub do_comment {
928      my ($content) = $database{$form{mypage}};      my ($content) = $database{$form{mypage}};
# Line 1201  sub embedded_to_html { Line 977  sub embedded_to_html {
977      my ($embedded) = @_;      my ($embedded) = @_;
978      if ($embedded eq '[[#comment]]' or $embedded eq '[[#rcomment]]') {      if ($embedded eq '[[#comment]]' or $embedded eq '[[#rcomment]]') {
979        unless ($main::_EMBEDED) {        unless ($main::_EMBEDED) {
980          my $lastmodified = &get_info($form{mypage}, $info_LastModified);          my $lastmodified = $database->mtime ($form{mypage});
981          return <<"EOD";          return <<"EOD";
982  <form action="$url_cgi" method="post" id="x-comment-@{[++$CommentIndex]}" class="comment"><p>  <form action="$url_cgi" method="post" id="x-comment-@{[++$CommentIndex]}" class="comment"><p>
983      <input type="hidden" name="mycmd" value="comment">      <input type="hidden" name="mycmd" value="comment">
# Line 1329  sub code_convert { Line 1105  sub code_convert {
1105      $code = 'euc' if $code =~ /euc/;      $code = 'euc' if $code =~ /euc/;
1106      $code = 'sjis' if $code =~ /shift/;      $code = 'sjis' if $code =~ /shift/;
1107      $code = 'utf8' if $code =~ /utf/;      $code = 'utf8' if $code =~ /utf/;
     #&Jcode::convert($contentref, $code);       # for Jcode.pm  
 #    &jcode::convert($contentref, $code);       # for jcode.pl  
     #&Jcode::tr ($contentref, "\xA3\xB0-\xA3\xB9\xA3\xC1-\xA3\xDA\xA3\xE1-\xA3\xFA\xA1\xF5\xA1\xA4\xA1\xA5\xA1\xA7\xA1\xA8\xA1\xA9\xA1\xAA\xA1\xAE\xA1\xB0\xA1\xB2\xA1\xBF\xA1\xC3\xA1\xCA\xA1\xCB\xA1\xCE\xA1\xCF\xA1\xD0\xA1\xD1\xA1\xDC\xA1\xF0\xA1\xF3\xA1\xF4\xA1\xF6\xA1\xF7\xA1\xE1\xA2\xAF\xA2\xB0\xA2\xB2\xA2\xB1\xA1\xE4\xA1\xE3\xA1\xC0\xA1\xA1" => q(0-9A-Za-z&,.:;?!`^_/|()[]{}+$%#*@='"~-><\ )) if $code eq 'euc';  
1108      $$contentref = Jcode->new ($contentref)->tr ("\xA3\xB0-\xA3\xB9\xA3\xC1-\xA3\xDA\xA3\xE1-\xA3\xFA\xA1\xF5\xA1\xA4\xA1\xA5\xA1\xA7\xA1\xA8\xA1\xA9\xA1\xAA\xA1\xAE\xA1\xB0\xA1\xB2\xA1\xBF\xA1\xC3\xA1\xCA\xA1\xCB\xA1\xCE\xA1\xCF\xA1\xD0\xA1\xD1\xA1\xDC\xA1\xF0\xA1\xF3\xA1\xF4\xA1\xF6\xA1\xF7\xA1\xE1\xA2\xAF\xA2\xB0\xA2\xB2\xA2\xB1\xA1\xE4\xA1\xE3\xA1\xC0\xA1\xA1" => q(0-9A-Za-z&,.:;?!`^_/|()[]{}+$%#*@='"~-><\ ))->$code;      $$contentref = Jcode->new ($contentref)->tr ("\xA3\xB0-\xA3\xB9\xA3\xC1-\xA3\xDA\xA3\xE1-\xA3\xFA\xA1\xF5\xA1\xA4\xA1\xA5\xA1\xA7\xA1\xA8\xA1\xA9\xA1\xAA\xA1\xAE\xA1\xB0\xA1\xB2\xA1\xBF\xA1\xC3\xA1\xCA\xA1\xCB\xA1\xCE\xA1\xCF\xA1\xD0\xA1\xD1\xA1\xDC\xA1\xF0\xA1\xF3\xA1\xF4\xA1\xF6\xA1\xF7\xA1\xE1\xA2\xAF\xA2\xB0\xA2\xB2\xA2\xB1\xA1\xE4\xA1\xE3\xA1\xC0\xA1\xA1" => q(0-9A-Za-z&,.:;?!`^_/|()[]{}+$%#*@='"~-><\ ))->$code;
1109      return $$contentref;      return $$contentref;
1110  }  }
1111    
1112  sub do_diff {  sub do_diff {
     if (not &is_editable($form{mypage})) {  
         &do_read;  
         return;  
     }  
     &open_diff;  
1113      my $title = $form{mypage};      my $title = $form{mypage};
1114      &print_header($title, -noindex => 1);      &print_header($title, -noindex => 1);
1115      $_ = &escape($diffbase{$form{mypage}});      print qq(<h2>@{[&Resource('Diff:Title',escape=>1)]}</h2>);
     &close_diff;  
     print qq(<h3>@{[&Resource('Diff:Title',escape=>1)]}</h3>);  
1116      print qq(<p>@{[&Resource('Diff:Notice',escape=>1)]}</p>);      print qq(<p>@{[&Resource('Diff:Notice',escape=>1)]}</p>);
1117      print qq(<pre class="diff">);      print qq(<pre class="diff">);
1118      foreach (split(/\n/, $_)) {      for (split(/\n/, &escape ($database->traverse_diff ($form{mypage})))) {
1119          if (/^\+(.*)/) {          if (/^\+(.*)/) {
1120              print qq(<ins class="added">$1</ins>\n);              print qq(<ins class="added">$1</ins>\n);
1121          } elsif (/^\-(.*)/) {          } elsif (/^\-(.*)/) {
# Line 1393  sub do_rss { Line 1159  sub do_rss {
1159              title       => &escape($title),              title       => &escape($title),
1160              link        => $myuri . '?' . &encode($title),              link        => $myuri . '?' . &encode($title),
1161              description => &escape(&get_subjectline($title,delimiter=>'')),              description => &escape(&get_subjectline($title,delimiter=>'')),
1162              'dc:date'   => &get_info ($title, $info_LastModified),              'dc:date'   => $database->mtime ($title),
1163            );            );
1164            $count++;            $count++;
1165          }          }
# Line 1421  sub is_exist_page { Line 1187  sub is_exist_page {
1187  }  }
1188    
1189  sub __get_database ($) { $database{ $_[0] } }  sub __get_database ($) { $database{ $_[0] } }
 sub __set_database ($$) { $database{ $_[0] } = $_[1] }  
   
 sub do_map {  
     my $page = $form{mypage};  
     &print_header ($page);  
     wiki::referer::add ($form{mypage}, $ENV{HTTP_REFERER});  
     wiki::useragent::add ($ENV{HTTP_USER_AGENT});  
     my ($r, $c) = get_search_result ($form{mypage});  
     my $rl = wiki::referer::list_html ($form{mypage});  
     print "<h2>@{[&Resource('Map:Title',escape=>1)]}</h2>\n<p>@{[&Resource('Map:Description',escape=>1)]}</p>\n";  
     my %option = (level => 0+&Resource('Map:Depth'), weight_list => {}, not_exist => {},  
       map_from_here => &Resource('Map:FromHere'),  
       map_from_here_description => &Resource('Map:FromHereLong'));  
     &wiki::map::make_list ($page, %option);  
     print &wiki::map::list_to_html ($page, $option{weight_list}, %option);  
     if ($c) {  
       print qq{<h2 id="wikipage-see-also">@{[&Resource('SeeAlso',escape=>1)]}</h2>};  
       print $r;  
     }  
     if ($rl) {  
       print qq(<div id="wikipage-referer"><h2>@{[&Resource('Referers',escape=>1)]}</h2>\n$rl</div>\n);  
     }  
     &print_footer ($page);  
 }  
1190    
1191  my %_Resource;  my %_Resource;
1192  sub Resource ($;%) {  sub Resource ($;%) {
# Line 1475  sub add ($$) { Line 1217  sub add ($$) {
1217    $list{ $uri }++;    $list{ $uri }++;
1218    set ($page, \%list);    set ($page, \%list);
1219  }  }
1220  sub get ($) {  sub get ($) { split /"/, $main::database->meta (Referer => $_[0]) }
   my $page = shift;  
   split /"/, main::get_info ($page, 'Referer');  
 }  
1221  sub set ($%) {  sub set ($%) {
1222    my $page = shift;    my $page = shift;
1223    my $list = shift;    my $list = shift;
1224    main::set_info ($page, Referer => join '"', %$list);    $main::database->meta (Referer => $page => join '"', %$list);
1225  }  }
1226    
1227  sub get_dont_record () {  sub get_dont_record () {
# Line 1536  sub __decode ($) { Line 1275  sub __decode ($) {
1275  }  }
1276    
1277  package wiki::useragent;  package wiki::useragent;
1278    our $UseLog;
1279    
1280  sub add ($) {  sub add ($) {
1281    my $s = shift;    my $s = shift;
1282    return unless length $s;    return unless length $s;
1283      return unless $UseLog;
1284    $s =~ s/([\x00-\x08\x0A-\x1F\x25\x7F-\xFF])/sprintf '%%%02X', unpack 'C', $1/ge;    $s =~ s/([\x00-\x08\x0A-\x1F\x25\x7F-\xFF])/sprintf '%%%02X', unpack 'C', $1/ge;
1285    my %ua;    my %ua;
1286    for (split /\n/, &main::__get_database('WikiUserAgentList')) {    for (split /\n/, &main::__get_database($main::PageName{UserAgentList})) {
1287      if (/^-\[(\d+)\] (.+)$/) {      if (/^-\[(\d+)\] (.+)$/) {
1288        my ($t, $n) = ($1, $2);        my ($t, $n) = ($1, $2);
1289        $n =~ tr/\x0A\x0D//d;        $n =~ tr/\x0A\x0D//d;
# Line 1554  sub add ($) { Line 1295  sub add ($) {
1295    for (sort {$ua{$a} <=> $ua{$b}} keys %ua) {    for (sort {$ua{$a} <=> $ua{$b}} keys %ua) {
1296      $s .= sprintf qq(-[%d] %s\n), $ua{$_}, $_;      $s .= sprintf qq(-[%d] %s\n), $ua{$_}, $_;
1297    }    }
1298    &main::__set_database ('WikiUserAgentList' => $s);    $main::database->STORE ($main::PageName{UserAgentList} => $s, -touch => 0);
1299  }  }
1300    
1301  package wiki::suikawikiconst;  package wiki::suikawikiconst;
# Line 1574  sub to_hash ($;$) { Line 1315  sub to_hash ($;$) {
1315    $h;    $h;
1316  }  }
1317    
1318    package wiki::dummy;
1319    sub mtime (@) {undef}
1320    sub meta (@) {undef}
1321    sub Yuki::YukiWikiDB2::meta (@) {undef}
1322    
1323  package SuikaWiki::Plugin;  package SuikaWiki::Plugin;
1324    our $plugin_directory;  # defined in top of this file.    our $plugin_directory;  # defined in top of this file.
1325    our %List;    our %List;
1326      our %Index;
1327    
1328  sub escape ($$) { main::escape ($_[1]) }  sub escape ($$) { main::escape ($_[1]) }
1329  sub unescape ($$) { main::unescape ($_[1]) }  sub unescape ($$) { main::unescape ($_[1]) }
# Line 1585  sub decode ($$) { main::decode ($_[1]) } Line 1332  sub decode ($$) { main::decode ($_[1]) }
1332  sub __get_datetime ($) { main::get_now () }  sub __get_datetime ($) { main::get_now () }
1333  sub resource ($$;%) { shift; &main::Resource (@_) }  sub resource ($$;%) { shift; &main::Resource (@_) }
1334  sub uri ($$) { $main::uri{$_[1]} }  sub uri ($$) { $main::uri{$_[1]} }
1335    sub new_index ($$) { ++$Index{$_[1]} }
1336    
1337  sub regist ($@) {  sub regist ($@) {
1338      my $pack = shift;      my $pack = shift;
# Line 1645  sub get ($;\%) { Line 1393  sub get ($;\%) {
1393    defined $v ? $v : $resname;    defined $v ? $v : $resname;
1394  }  }
1395    
 package wiki::map;  
   
 sub make_list ($;%) {  
   my ($page, %option) = @_;  
   $option{level} ||= 3;  
   my %weight;  
   my $content = &main::__get_database ($page);  
   $content =~ s{^\#\?([^\x0A\x0D]+)}{  
     if ($1 =~ /import="([^"]+)"/) {  
       for (split /\s*,\s*/, $1) {  
         $weight{$_} += 2;  
       }  
     }  
     $&;  
   }ges;  
   ## Bug: this code does not support content type.  
   $content =~ s{\[\[((?!\#)[^]]+)\](?:>>\d+)?\]}{  
     $weight{$1}++; $&;  
   }ge;  
   delete $weight{$page};        ## Delete myself  
   for my $page (keys %weight) {  
     my $w = ($content =~ s/\Q$page\E/$&/g);  
     $weight{$page} += $w + $weight{$page}; ## Weight of [[name]] is x2.  
     ($weight{$page} *= 0.1, $option{not_exist}->{$page} = 1) unless &main::is_exist_page ($page);  
   }  
   $option{weight_list}->{$page} = \%weight;  
   if (--$option{level}) {  
     for my $page (keys %weight) {  
       &make_list ($page, %option) unless $option{weight_list}->{$page};  
     }  
   }  
   $option{weight_list};  
 }  
   
 sub list_to_html ($$;%) {  
   my ($Page, $wlist, %option) = @_;  
   my $r = '';  
   $option{outputed}->{$Page} = 1;  
   for my $page (sort {$wlist->{$Page}->{$b} <=> $wlist->{$Page}->{$a}} keys %{$wlist->{$Page}}) {  
     $r .= qq(<li><span class="weight">[@{[0+$wlist->{$Page}->{$page}]}]</span> <a href="$main::url_cgi?@{[&main::encode($page)]}" class="wiki@{[$option{not_exist}->{$page}?' not-exist':'']}">@{[&main::escape ($page).($option{not_exist}->{$page}?qq(<span class="mark">@{[&main::Resource('JumpAndEditWikiPageMark',escape=>1)]}</span>):'')]}</a> <a href="$main::url_cgi?mycmd=map;mypage=@{[&main::encode($page)]}" class="wiki-cmd map-from-here" title="@{[&main::escape($option{map_from_here_description})]}">@{[&main::escape($option{map_from_here})]}</a> <span class="summary">@{[&main::escape(&main::get_subjectline($page))]}</span>);  
     unless ($option{outputed}->{$page}) {  
       $r .= &list_to_html ($page, $wlist, %option);  
     }  
     $r .= "</li>\n";  
   }  
   $r ? qq(<ul class="map">$r</ul>) : '';  
 }  
   
1396  package main;  package main;
1397  &main;  &main;
1398  exit 0;  exit 0;
# Line 1701  exit 0; Line 1401  exit 0;
1401  __END__  __END__
1402  =head1 NAME  =head1 NAME
1403    
1404  wiki.cgi - This is YukiWiki, yet another Wiki clone.  wiki.cgi --- SuikaWiki: Yet yet another Wiki engine
 walwiki.cgi based on yukiwiki.cgi - Yet another WikiWikiWeb clone.  
   
 =head1 DESCRIPTION  
   
 YukiWiki is yet another Wiki clone.  
1405    
1406  YukiWiki can treat Japanese WikiNames (enclosed with [[ and ]]).  =head1 AUTHORS
 YukiWiki provides 'InterWiki' feature, RDF Site Summary (RSS),  
 and some embedded commands (such as [[#comment]] to add comments).  
1407    
1408  Read F<readme_en.txt> (English) or F<readme_ja.txt> (Japanese) in more detail.  Hiroshi Yuki <hyuki@hyuki.com> <http://www.hyuki.com/yukiwiki/>
1409    
1410  =head1 AUTHOR  Makio Tsukamoto <http://digit.que.ne.jp/>
1411    
1412  Hiroshi Yuki <hyuki@hyuki.com> http://www.hyuki.com/yukiwiki/  Wakaba <w@suika.fam.cx>
1413    
1414  =head1 LICENSE  =head1 LICENSE
1415    
1416  Copyright (C) 2000-2002 by Hiroshi Yuki.  Copyright (C) 2000-2003 AUTHORS
1417    
1418  This program is free software; you can redistribute it and/or  This program is free software; you can redistribute it and/or
1419  modify it under the same terms as Perl itself.  modify it under the same terms as Perl itself.

Legend:
Removed from v.1.44  
changed lines
  Added in v.1.48

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24