/[pub]/suikawiki/script/lib/suikawiki.pl
Suika

Contents of /suikawiki/script/lib/suikawiki.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.12 - (show annotations) (download)
Tue Sep 16 05:16:31 2003 UTC (21 years, 7 months ago) by wakaba
Branch: MAIN
Branch point for: branch-suikawiki-1
Changes since 1.11: +4 -3 lines
File MIME type: text/plain
current practice

1 # -*- perl -*-
2 use strict;
3
4 package wiki;
5 our $VERSION = do{my @r=(q$Revision: 1.11 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
6 package main;
7 binmode STDOUT; binmode STDIN;
8 use Fcntl;
9 require SuikaWiki::Plugin;
10 our %embed_command = (
11 form => qr/\[\[\#form(?:\(([A-Za-z0-9-]+)\))?:'((?:[^'\\]|\\.)*)':'((?:[^'\\]|\\.)*)'(?::'((?:[^'\\]|\\.)*)')?\]\]/,
12 );
13 our ($modifier_dbtype,%uri,%PathTo,%PageName,$kanjicode);
14
15 our %form;
16 our %database;
17 our $database = bless {}, 'wiki::dummy';
18 my %command_do = (
19 default => \&do_view,
20 adminchangepassword => \&do_adminchangepassword,
21 write => \&do_write,
22 comment => \&do_comment,
23 RandomJump => sub {
24 my @list = keys %main::database;
25 &main::_http_see_other (page => $list[rand @list]);
26 },
27 wikiform => \&do_wikiform,
28 );
29 our $UA = ''; ## User agent name
30 $| = 1;
31 require SuikaWiki::Name::Space;
32 my $NS_XHTML1 = 'http://www.w3.org/1999/xhtml';
33
34 sub _wiki_exit () {
35 &close_db;
36 exit;
37 }
38
39 sub do_view {
40 require SuikaWiki::View;
41 my $content = $main::database{$main::form{mypage}};
42 my $lm = SuikaWiki::Plugin->_database->mtime ($main::form{mypage});
43 ## Determine mode
44 my $view = $form{mycmd};
45 if (!$view || $view eq 'default' || $view =~ /[^0-9A-Za-z_]/) {
46 ## BUG: this code is not strict
47 if ($main::ENV{HTTP_COOKIE} =~ /SelectedMode=([0-9A-Za-z_-]+)/) {
48 $view = $1; $view =~ tr/-/_/;
49 } else {
50 $view = 'read';
51 }
52 }
53 ## Get content and its meta info
54 my ($magic, $content) = SuikaWiki::Plugin->magic_and_content ($content);
55 $magic ||= '#?SuikaWiki/0.9';
56 my $o = bless {param => \%main::form, page => $main::form{mypage}, toc => [],
57 magic => $magic, content => $content,
58 &main::_compatible_options ()}, 'SuikaWiki::Plugin';
59 my $view_def = SuikaWiki::View->definition ($view);
60 if (!$view_def->check ($o)) {
61 print "Status: 406 Unsupported Media Type\n";
62 $view = '-UnsupportedMediaType';
63 $view_def = SuikaWiki::View->definition ($view);
64 }
65 my $prop = $view_def->properties;
66 my $media = $prop->{media};
67 if ($prop->{xmedia} && $main::UA =~ /Gecko/) { ## TODO: conneg
68 $media = $prop->{xmedia};
69 $o->{media} = $media;
70 } elsif ($main::UA =~ m#Mozilla/0\..+Windows#) {
71 $main::kanjicode = 'shift_jis';
72 }
73
74 if ($prop->{preprocess}) {
75 _wiki_exit () unless &{$prop->{preprocess}} (o => $o);
76 }
77
78 ## Output CGI/HTTP headers
79 if ($magic =~ m!^\#\?SuikaWiki/0.9!) {
80 &main::print_header ($main::form{mypage},
81 -last_modified => ($magic =~ /interactive="yes"/ ? time : $lm),
82 -expires => ($magic =~ /interactive="yes"/ ? 1 : undef), o => $o,
83 -media => $media, -view => $view_def, -magic => $magic, content => $content);
84 } else {
85 &main::print_header($main::form{mypage}, -media => $media, -view => $view_def,
86 -magic => $magic, -last_modified => $lm, o => $o);
87 }
88 ## Output HTTP message body
89 my $fmt = SuikaWiki::Plugin->formatter ('view');
90 my $s = $fmt->replace ($view_def->as_string => $o, {formatter => $fmt});
91 if ($main::kanjicode eq 'euc') {
92 #require Compress::Zlib;
93 #print scalar Compress::Zlib::memGzip (''.$s);
94 print $s;
95 } else {
96 $s .= '';
97 print &main::code_convert (\$s => $main::kanjicode);
98 }
99 }
100
101 sub _do_view_msg (%) {
102 require SuikaWiki::View;
103 my %option = @_;
104 my $o = $option{-o} || bless {param => \%form, page => $option{-page},
105 &_compatible_options ()}, 'SuikaWiki::Plugin';
106 $o->{toc} = [];
107 $o->{condition} = \%option; ## This parameter really used??
108 my $view_def = SuikaWiki::View->definition ($option{-view});
109 unless ($view_def->check ($o)) {
110 print "Status: 406 Unsupported Media Type\n";
111 $option{-view} = '-UnsupportedMediaType';
112 $view_def = SuikaWiki::View->definition ($option{-view});
113 }
114 my $prop = $view_def->properties;
115 my $media = $prop->{media};
116 if ($prop->{xmedia} && $UA =~ /Gecko/) {
117 $media = $prop->{xmedia};
118 $o->{media} = $media;
119 }
120 &print_header($option{-page}, -media => $media, -view => $view_def, o => $o, -goto => $option{-goto});
121 ## Output HTTP message body
122 my $fmt = SuikaWiki::Plugin->formatter ('view');
123 my $s = $fmt->replace ($view_def->as_string => $o, {formatter => $fmt});
124 if ($main::kanjicode eq 'euc') {
125 print $s;
126 } else {
127 print &main::code_convert (\$s => $main::kanjicode);
128 }
129 }
130
131 # [move to SuikaWiki::Plugin::WikiAdmin]
132 sub do_adminchangepassword {
133 if ($form{mynewpassword} ne $form{mynewpassword2}) {
134 &_do_view_msg (-view => '-error', -page => $form{mypage},
135 error_message => &Resource ('Error:PasswordMismatch'));
136 return;
137 }
138 my ($validpassword_crypt) = $database->meta (AdminPassword => $PageName{AdminSpecialPage});
139 if ($validpassword_crypt) {
140 if (not &valid_password($form{myoldpassword})) {
141 &_do_view_msg (-view => '-error', -page => $form{mypage},
142 error_message => &Resource ('Error:PasswordIsIncorrect'));
143 return;
144 }
145 }
146 my ($sec, $min, $hour, $day, $mon, $year, $weekday) = localtime(time);
147 my (@token) = ('0'..'9', 'A'..'Z', 'a'..'z');
148 my $salt1 = $token[(time | $$) % scalar(@token)];
149 my $salt2 = $token[($sec + $min*60 + $hour*60*60) % scalar(@token)];
150 my $crypted = crypt($form{mynewpassword}, "$salt1$salt2");
151 $database->meta (AdminPassword => $PageName{AdminSpecialPage} => $crypted);
152
153 &_do_view_msg (-view => '-wrote', -page => $form{mypage});
154 }
155
156 # [move to SuikaWiki::WikiDB]
157 sub valid_password ($) {
158 my ($validpassword_crypt) = $database->meta (AdminPassword => $PageName{AdminSpecialPage});
159 return crypt (shift, $validpassword_crypt) eq $validpassword_crypt ? 1 : 0;
160 }
161
162 # [move to SuikaWiki::Plugin::WikiEdit]
163 sub do_write {
164 if (&frozen_reject()) {
165 return;
166 }
167
168 if (not &is_editable($form{mypage})) {
169 &_do_view_msg (-view => '-error', -page => $form{mypage},
170 error_message => &Resource ('Error:ThisPageIsUneditable'));
171 return;
172 }
173
174 ## Check confliction
175 if ($form{myLastModified} ne $database->mtime ($form{mypage})) {
176 &_do_view_msg (-view => '-conflict', -page => $form{mypage});
177 return;
178 }
179
180 if ($form{mymsg}) {
181 if ($form{mytouch} || !ref $database) {
182 $database{$form{mypage}} = $form{mymsg};
183 } else {
184 $database->STORE ($form{mypage} => $form{mymsg}, -touch => 0);
185 }
186 $database->meta (IsFrozen => $form{mypage} => 0 + $form{myfrozen});
187 my $uri = SuikaWiki::Plugin->_uri_wiki_page ($form{mypage}, mode => ($form{after_edit_cmd}||'default'), with_lm => 1, absolute => 1);
188 $uri .= qq(;after_edit_cmd=@{[SuikaWiki::Plugin->encode($form{after_edit_cmd})]}) if $form{after_edit_cmd};
189 if ($form{__comment_anchor_index}) {
190 $uri .= qq(#anchor-$form{__comment_anchor_index});
191 } elsif ($form{__wikiform_anchor_index}) {
192 $uri .= qq(#wikiform-$form{__wikiform_anchor_index});
193 }
194 &_http_see_other (uri => $uri, page => $form{mypage}, alternate_view => '-wrote');
195 } else {
196 delete $database{$form{mypage}};
197 &_do_view_msg (-view => '-deleted', -page => $form{mypage});
198 }
199 }
200
201 sub _http_see_other (%) {
202 my %o = @_;
203 $o{uri} ||= SuikaWiki::Plugin->_uri_wiki_page ($o{page}, absolute => 1);
204 if ($o{alternate_view} && ($main::ENV{SERVER_PROTOCOL} eq 'HTTP/0.9'
205 || $main::ENV{SERVER_PROTOCOL} eq 'HTTP/1.0')
206 && !($main::UA =~ m#Microsoft Internet Explorer|Mozilla#)) {
207 &_do_view_msg (-view => $o{alternate_view}, -page => $o{page}, -goto => $o{uri}, -o => $o{o});
208 } else {
209 my $status = q(303 See Other);
210 if ($main::UA =~ m!Mozilla/[0-4]\.|Microsoft Internet Explorer!) {
211 $status = q(302 See Other);
212 }
213 my $euri = SuikaWiki::Plugin->escape ($o{uri});
214 print qq(Status: $status
215 Location: $o{uri}
216 Content-Type: text/html
217 Content-Language: en
218
219 <!DOCTYPE p SYSTEM>
220 <p>See &lt;<a href="$euri">$euri</a>&gt;.</p>);
221 }
222 _wiki_exit ();
223 }
224
225 sub _compatible_options () {
226 (use_anchor_name => ($main::UA =~ m#Mozilla/[1-4]\.|Microsoft Internet Explorer# ? 1 : 0));
227 }
228
229
230
231 sub print_header ($;%) {
232 my ($page, %option) = @_;
233 if ($main::ENV{HTTP_IF_MODIFIED_SINCE} && $option{-last_modified}) {
234 ## TODO: use Message::Field::Date
235 if ($option{-view}->properties->{if}->{modified_since}
236 && $main::ENV{HTTP_IF_MODIFIED_SINCE} =~ /([0-9]{1,2})\s*([A-Za-z]{3})\s*([0-9]{2,4})\s*([0-9]{2}):([0-9]{2}):([0-9]{2})\s*[Gg][Mm][Tt]/) {
237 require Time::Local;
238 my ($d, $M, $y, $h, $m, $s) = ($1, $2, $3, $4, $5, $6);
239 $M = {jan=>0,feb=>1,mar=>2,apr=>3,may=>4,jun=>5,jul=>6,aug=>7,sep=>8,oct=>9,nov=>10,dec=>11}->{lc $M};
240 #$y += 1900 if $y < 100; ## BUG: don't conform HTTP spec
241 my $t = Time::Local::timegm_nocheck ($s, $m, $h, $d, $M, $y);
242 if ($option{-last_modified} <= $t) {
243 print "Status: 304 Not Modified\n\n";
244 _wiki_exit ();
245 }
246 }
247 }
248 my $UA = SuikaWiki::Plugin->user_agent_names;
249 $option{o}->{-header}->{class}->{frozen} = 1 if &main::is_frozen ($page);
250 $option{o}->{-header}->{class}->{'wiki-page-obsoleted'} = 1 if $option{-magic} =~ /obsoleted="yes"/;
251 $option{o}->{-header}->{additional_html_element} ||= SuikaWiki::Markup::XML->new (type => '#fragment');
252 print "Vary: Negotiate,User-Agent,Accept-Language,Accept\n";
253 if ($option{-goto}) {
254 if ($UA =~ m#Opera|MSIE 2\.#) {
255 ## WARNING: This code may output unsafe HTML document if $option{-goto} is unclean.
256 $option{-goto} =~ tr/;/&/ if $UA =~ m#Opera#;
257 print qq{Refresh: 0; url=$option{-goto}\n};
258 for ($option{o}->{-header}->{additional_html_element}->append_new_node
259 (namespace_uri => $NS_XHTML1, local_name => 'meta')) {
260 $_->set_attribute ('http-equiv' => 'refresh');
261 $_->set_attribute (content => "0; url=$option{-goto}");
262 $_->option (use_EmptyElemTag => 1);
263 }
264 } else {
265 $option{-goto} =~ tr/;/&/ if $UA =~ m#Mozilla/[1-4]\.#;
266 print qq{Refresh: 0; url="$option{-goto}"\n};
267 for ($option{o}->{-header}->{additional_html_element}->append_new_node
268 (namespace_uri => $NS_XHTML1, local_name => 'meta')) {
269 $_->set_attribute ('http-equiv' => 'refresh');
270 $_->set_attribute (content => qq(0; url="$option{-goto}"));
271 $_->option (use_EmptyElemTag => 1);
272 }
273 }
274 }
275 print qq{Last-Modified: @{[scalar gmtime $option{-last_modified}]}\n}
276 if $option{-last_modified};
277 if ($option{-expires} != -1) {
278 if (defined $option{-expires}) { ## TODO: Don't use asctime
279 print qq{Expires: @{[scalar gmtime (time + $option{-expires})]}\n};
280 } elsif ($option{-media}->{expires} != -1) {
281 print qq{Expires: @{[scalar gmtime (time + $option{-media}->{expires})]}\n};
282 }
283 }
284 if ($option{-media}->{charset} && $UA =~ m#Mozilla/[12]\.#) {
285 ## UAs don't support official charset names but do non-official names
286 my $ct = qq{$option{-media}->{type}; charset=@{[ &main::get_charset_name ($main::kanjicode, compatible => 1) ]}};
287 print qq{Content-Type: $ct\n};
288 for ($option{o}->{-header}->{additional_html_element}->append_new_node
289 (namespace_uri => $NS_XHTML1, local_name => 'meta')) {
290 $_->set_attribute ('http-equiv' => 'content-type');
291 $_->set_attribute (content => $ct);
292 }
293 } elsif (!$option{-media}->{charset} || $UA =~ m#Infomosaic|Mozilla/0\.#) {
294 ## Media types or UAs don't support charset parameter in HTTP header
295 print qq{Content-Type: $option{-media}->{type}\n};
296 if ($option{-media}->{charset}) {
297 for ($option{o}->{-header}->{additional_html_element}->append_new_node
298 (namespace_uri => $NS_XHTML1, local_name => 'meta')) {
299 $_->set_attribute ('http-equiv' => 'content-type');
300 $_->set_attribute (content => qq($option{-media}->{type}; charset=).main::get_charset_name ($main::kanjicode, compatible => 1));
301 }
302 }
303 } else {
304 ## Modern UAs and Media types with charset parameter
305 my $type = $option{-media}->{type};
306 $type = 'application/xml' if ($type =~ m!^application/r(?:df|ss)\+xml$!) && ($UA =~ m#Gecko#);
307 print qq{Content-Type: $type; charset=@{[&main::get_charset_name ($main::kanjicode)]}\n};
308 ## meta element is not needed
309 }
310
311 print <<"EOD";
312 Content-Style-Type: text/css
313
314 EOD
315 }
316
317 sub get_charset_name ($;%) {
318 my ($charset, %option) = (lc shift, @_);
319 if ($charset =~ 'euc') {
320 $charset = $option{compatible} ? 'x-euc-jp' : 'euc-jp';
321 } elsif ($charset =~ 'sjis' || $charset =~ 'shift') {
322 $charset = $option{compatible} ? 'x-sjis' : 'shift_jis';
323 } elsif ($charset =~ 'jis') {
324 $charset = 'iso-2022-jp';
325 }
326 $charset;
327 }
328
329 =pod
330
331 sub _decode_argv () {
332 my $QS = $main::ENV{QUERY_STRING};
333 if ($main::ENV{PATH_INFO}) {
334 die;
335 # new format: not implemented yet
336 } else {
337 my %argv;
338 if ($QS =~ /[&;=]/) { ## ?FOO=foo;BAR=bar;BAZ=baz
339 for (split /[;&]/, $QS) {
340 if (my ($n, $v) = split /=/, $_, 2) {
341 for ($n, $v) {tr/+/ /; s/%([0-9A-Fa-f][0-9A-Fa-f])/pack 'HH', $1/ge};
342 $argv{$n} = $v;
343 }
344 }
345 } else { ## ?FOO-BAR
346 $argv{page} = $QS;
347 $argv{page} =~ tr/+/ /;
348 $argv{page} =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack 'HH', $1/ge;
349 }
350 my $ie = $argv{ie}; ## Input coding system
351 for ([qw/mypage page/], [qw/mycmd mode/]) {
352 $argv{$_->[1]} ||= $argv{$_->[0]};
353 delete $argv{$_->[0]};
354 }
355 for (keys %argv) {
356 $argv{$_} = main::code_convert ($argv{$_}, $main::kanjicode, $ie);
357 }
358 for ([qw/mypage page/], [qw/mycmd mode/]) {
359 $argv{$_->[0]} = $argv{$_->[1]};
360 }
361 }
362 }
363
364 =cut
365
366 sub init_form {
367 ## TODO: Support multipart/form-data
368 my $query = '';
369 if (uc $main::ENV{REQUEST_METHOD} eq 'POST') {
370 if (lc ($main::ENV{CONTENT_TYPE}) eq 'application/x-www-form-urlencoded'
371 || lc ($main::ENV{CONTENT_TYPE}) eq 'application/sgml-form-urlencoded') {
372 read STDIN, $query, $main::ENV{CONTENT_LENGTH};
373 } else {
374 $main::form{mycmd} = '___unsupported_media_type___';
375 $main::form{mypage} = $main::PageName{FrontPage};
376 return;
377 }
378 }
379 $query .= ($query ? ';' : '') . $main::ENV{QUERY_STRING};
380 if ($main::ENV{REQUEST_METHOD} ne 'POST' && $main::ENV{QUERY_STRING} && $main::ENV{QUERY_STRING} !~ /[&;=]/) {
381 my $query = SuikaWiki::Plugin->decode ($main::ENV{QUERY_STRING});
382 $query = &main::code_convert (\$query, $main::kanjicode);
383 $main::form{mypage} = $query;
384 $main::form{mycmd} = 'default';
385 } else {
386 for (split /[;&]/, $query) {
387 if (my ($n, $v) = split /=/, $_, 2) {
388 for ($n, $v) {tr/+/ /; s/%([0-9A-Fa-f][0-9A-Fa-f])/pack 'C', hex $1/ge};
389 $main::form{$n} = $v;
390 }
391 }
392 unless (defined $form{mypage}) {
393 $form{mypage} = $form{epage};
394 $form{mypage} =~ s/([0-9A-F]{2})/ord hex $1/g;
395 }
396 $form{mypage} = &main::code_convert (\$form{mypage}, $kanjicode);
397 }
398 $form{mypage} =~ tr/\x00-\x20\x7F//d;
399 $form{mypage} = SuikaWiki::Name::Space::normalize_name ($form{mypage}) || $PageName{FrontPage};
400 $form{mycmd} ||= $form{mode} || 'default';
401 $form{mycmd} =~ tr/-/_/;
402
403 for ('mymsg', 'myname', grep /^(?:wikiform__|pi_)/, keys %form) {
404 $form{$_} = &main::code_convert (\$form{$_}, $kanjicode);
405 }
406 }
407
408 # [move to SuikaWiki::WikiDB]
409 sub open_db {
410 if ($main::modifier_dbtype eq 'dbmopen') {
411 dbmopen(%main::database, $PathTo{WikiDataBase}, 0666) or die "(dbmopen) $main::PathTo{WikiDataBase}";
412 } elsif ($main::modifier_dbtype eq 'AnyDBM_File') {
413 eval q{use AnyDBM_File};
414 tie(%main::database, "AnyDBM_File", $main::PathTo{WikiDataBase}, O_RDWR|O_CREAT, 0666) or die ("(tie AnyDBM_File) $main::PathTo{WikiDataBase}");
415 } elsif ($main::modifier_dbtype eq 'Yuki::YukiWikiDB') {
416 eval q{use Yuki::YukiWikiDB};
417 tie(%main::database, "Yuki::YukiWikiDB", $main::PathTo{WikiDataBase}) or die ("(tie Yuki::YukiWikiDB) $main::PathTo{WikiDataBase}");
418 } else { ## Yuki::YukiWikiDB || Yuki::YukiWikiDBMeta
419 eval qq{use $modifier_dbtype};
420 $database = tie (%database, $modifier_dbtype => $PathTo{WikiDataBase},
421 -lock => 0, -backup => $wiki::diff::UseDiff, ## TODO: new diff i/f
422 -logfile => $main::PathTo{WikiDatabaseErrorLog})
423 or die ("(tie $modifier_dbtype) $PathTo{WikiDataBase}");
424 }
425 }
426
427 # [move to SuikaWiki::WikiDB]
428 sub close_db {
429 if ($modifier_dbtype eq 'dbmopen') {
430 dbmclose(%database);
431 } else {
432 untie(%database);
433 }
434 }
435
436 # [move to SuikaWiki::Plugin::WikiEdit]
437 sub editform (@) {
438 my %option = @_;
439 my $frozen = &is_frozen ($option{page});
440 $option{content} = $database{$option{page}} unless defined $option{content};
441 $option{content} = $database{NewPageTemplate} unless length $option{content};
442 $option{last_modified} = $database->mtime ($option{page}) unless defined $option{last_modified};
443 my $magic = '';
444 $magic = $1 if $option{content} =~ m/^([^\x0A\x0D]+)/s;
445
446 my $selected = 'default';
447 if ($form{after_edit_cmd}) {
448 $selected = $form{after_edit_cmd};
449 } elsif ($magic =~ /Const|Config|CSS/) {
450 $selected = 'edit';
451 }
452 my $afteredit = <<EOH;
453 <select name="after_edit_cmd">
454 <option value="default" label="@{[&Resource('Edit:SaveAndDefault',escape=>1)]}"@{[$selected eq 'default' ? ' selected="selected"':'']}>@{[&Resource('Edit:SaveAndDefault',escape=>1)]}</option>
455 <option value="read" label="@{[&Resource('Edit:SaveAndView',escape=>1)]}"@{[$selected eq 'read' ? ' selected="selected"':'']}>@{[&Resource('Edit:SaveAndView',escape=>1)]}</option>
456 <option value="edit" label="@{[&Resource('Edit:SaveAndEdit',escape=>1)]}"@{[$selected eq 'edit' ? ' selected="selected"':'']}>@{[&Resource('Edit:SaveAndEdit',escape=>1)]}</option>
457 </select>
458 EOH
459
460 =pod
461
462 my $f = SuikaWiki::Markup::XML->new (namespace_uri => $NS_XHTML1, local_name => 'form');
463 $f->set_attribute (action => SuikaWiki::Plugin->uri ('wiki');
464 $f->set_attribute (method => 'post');
465 if (!$option{conflict}) {
466 for ($f->append_new_node (namespace_uri => $NS_XHTML1, local_name => 'label')) {
467 for ($_->append_new_node (namespace_uri => $NS_XHTML1, local_name => 'input')) {
468 $f->set_attribute (type => 'submit');
469 $f->set_attribute (value => SuikaWiki::Plugin->resource ('Edit:Save'));
470 }
471 #<input type=hidden name=mycmd value=write/>
472 $_->append_new_node (namespace_uri => $NS_XHTML1, local_name => 'kbd', value => 'S');
473 }
474 }
475
476 =cut
477
478 my $f = <<"EOD";
479 <form action="$uri{wiki}" method="post">
480 @{[ $option{conflict} ? '' : qq(<label><input type="submit" value="@{[SuikaWiki::Plugin->resource('Edit:Save',escape=>1)]}" /><kbd>S</kbd></label>) ]}
481 @{[ $option{admin} ? qq(<label>@{[SuikaWiki::Plugin->resource('Edit:Password=',escape=>1)]}<input type="password" name="mypassword" value="" size="10" /></label>) : "" ]} [@{[&get_new_anchor_index($option{content})]}]<br />
482 <input type="hidden" name="myLastModified" value="$option{last_modified}" />
483 <input type="hidden" name="mycmd" value="write" />
484 <input type="hidden" name="mypage" value="@{[SuikaWiki::Plugin->escape($form{mypage})]}" />
485 <textarea cols="@{[SuikaWiki::Plugin->resource('Edit:Form:Cols')+0||35]}" rows="@{[SuikaWiki::Plugin->resource('Edit:Form:Rows')+0||15]}" name="mymsg" tabindex="1"@{[$main::UA =~ m{Mozilla/[0-4]\.} ? ' wrap="virtual"':'']}>@{[SuikaWiki::Plugin->escape($option{content})]}</textarea><br />
486 @{[
487 $option{admin} ?
488 qq(
489 <label><input type="radio" name="myfrozen" value="1" @{[$frozen ? qq(checked="checked") : ""]} />@{[SuikaWiki::Plugin->resource('Edit:Freeze',escape=>1)]}</label>
490 <label><input type="radio" name="myfrozen" value="0" @{[$frozen ? "" : qq(checked="checked")]} />@{[SuikaWiki::Plugin->resource('Edit:DontFreeze',escape=>1)]}</label><br />)
491 : ""
492 ]}
493 @{[
494 $option{conflict} ? "" :
495 qq(
496 <label><input type="checkbox" name="mytouch" value="on" checked="checked" />@{[SuikaWiki::Plugin->resource('Edit:UpdateTimeStamp',escape=>1)]}</label><br />
497 <label><input type="submit" value="@{[SuikaWiki::Plugin->resource('Edit:Save',escape=>1)]}" accesskey="S" /><kbd>S</kbd></label>
498 $afteredit
499 )
500 ]}
501 </form>
502 EOD
503 $f;
504 }
505
506 # [move to SuikaWiki::WikiDB]
507 sub is_editable {
508 my ($page) = @_;
509 return 0 unless SuikaWiki::Name::Space::validate_name ($page);
510 return 0 if $page =~ /[\x00-\x20\[\]\x7F]/;
511 1;
512 }
513
514 # [move to SuikaWiki::WikiDB]
515 sub frozen_reject {
516 my ($isfrozen) = $database->meta (IsFrozen => $form{mypage});
517 my ($willbefrozen) = $form{myfrozen};
518 if (not $isfrozen and not $willbefrozen) {
519 # You need no check.
520 return 0;
521 } elsif (valid_password($form{mypassword})) {
522 # You are admin.
523 return 0;
524 } else {
525 &_do_view_msg (-view => '-error', -page => $form{mypage},
526 error_message => SuikaWiki::Plugin->resource ('Error:PasswordIsIncorrect'));
527 exit;
528 }
529 }
530
531 # [move to SuikaWiki::WikiDB]
532 sub is_frozen ($) { SuikaWiki::Plugin->_database->meta (IsFrozen => $_[0]) ? 1 : 0 }
533
534 # [to be obsolete]
535 sub do_comment {
536 my ($content) = $database{$form{mypage}};
537 my $default_name; ## this code is not strict.
538 $default_name = $1 if $content =~ /default-name="([^"]+)"/;
539 my @time = gmtime (time);
540 my $datestr = sprintf '[WEAK[%04d-%02d-%02d %02d:%02d:%02d +00:00]]', $time[5]+1900,$time[4]+1,@time[3,2,1,0];
541 my $namestr = $form{myname} || $default_name || &Resource('WikiForm:WikiComment:DefaultName');
542 ($namestr = '', $datestr = '') if $form{myname} eq 'nodate';
543 if ($namestr =~ /^(?:>>)?[0-9]/) {
544 $namestr = qq( ''$namestr'': );
545 } elsif (length $namestr) {
546 $namestr = qq( ''[[$namestr]]'': );
547 }
548 my $anchor = &get_new_anchor_index ($content);
549 my $i = 1; my $o = 0;
550 $content =~ s{(\[\[\#r?comment\]\])}{
551 my $embed = $1;
552 if ($i == $form{comment_index}) {
553 if ($embed ne '[[#rcomment]]') {
554 $embed = "- [$anchor] $datestr$namestr$form{mymsg}\n$embed"; $o = 1;
555 } else {
556 $embed .= "\n- [$anchor] $datestr$namestr$form{mymsg}"; $o = 1;
557 }
558 }
559 $i++; $embed;
560 }ge;
561 unless ($o) {
562 $content = "#?SuikaWiki/0.9\n\n" unless $content;
563 $content .= "\n" unless $content =~ /\n$/s;
564 $content .= "- [$anchor] $datestr$namestr$form{mymsg}\n";
565 }
566 $form{__comment_anchor_index} = $anchor;
567 if ($form{mymsg} || $form{myname}) {
568 $form{mymsg} = $content;
569 $form{mytouch} = 'on';
570 &do_write;
571 } else { ## Don't write
572 $form{mycmd} = 'default';
573 &do_view;
574 }
575 }
576
577 # [move to SuikaWiki::Plugin::WikiForm]
578 sub get_new_anchor_index ($) {
579 my $content = shift;
580 my $anchor = 0;
581 $content =~ s/^(?:[-=]+\s*)?\[([0-9]+)\]/$anchor = $1 if $1 > $anchor; $&/mge;
582 $anchor + 1;
583 }
584
585 # [move to SuikaWiki::Plugin::WikiForm]
586 sub do_wikiform {
587 my $content = $database{$form{mypage}};
588 my $anchor = &get_new_anchor_index ($content);
589 my $write = 0;
590 my $i = 1;
591 $content =~ s{$embed_command{form}}{
592 my ($embed, $wfname, $template, $option) = ($&, $1, $3, $4);
593 if (($wfname && $wfname eq $form{wikiform_targetform})
594 || $i == $form{wikiform_index}) {
595 $template =~ s/\\([\\'])/$1/g;
596 $option =~ s/\\([\\'])/$1/g;
597 my $param = bless {depth=>10}, 'SuikaWiki::Plugin';
598 $param->{page} = $form{mypage};
599 $param->{form_index} = $i;
600 $param->{form_name} = $wfname;
601 $param->{anchor_index} = $anchor;
602 $param->{argv} = \%form;
603 $param->{default_name} = $1 if $content =~ /default-name="([^"]+)"/;
604 $param->{default_name} ||= &Resource('WikiForm:WikiComment:DefaultName');
605 SuikaWiki::Plugin->formatter ('form_option')->replace ($option, $param);
606 my $t = 1;
607 for (keys %{$param->{require}||{}}) {
608 (undef $t, last) unless length $param->{argv}->{'wikiform__'.$_};
609 }
610 $t = SuikaWiki::Plugin->formatter ('form_template')->replace ($template, $param) if $t;
611 if (length $t) {
612 if ($param->{output}->{reverse}) {
613 $embed .= "\n" . $t;
614 } else {
615 $embed = $t . "\n" . $embed;
616 }
617 $write = 1;
618 $form{__comment_anchor_index} = $anchor
619 if $param->{anchor_index_}; ## $anchor is used!
620 }
621 $form{__wikiform_anchor_index} = $i;
622 undef $form{wikiform_targetform}; ## Make sure never to match
623 undef $form{wikiform_index}; ## with WikiForm in rest of page!
624 }
625 $i++; $embed;
626 }ge;
627 unless ($write) {
628 #$content = "#?SuikaWiki/0.9\n\n" unless $content;
629 #$content .= "\n" unless $content =~ /\n$/s;
630 #
631 }
632 if ($write) {
633 $form{mymsg} = $content;
634 $form{mytouch} = 'on';
635 &do_write;
636 } else { ## Don't write!
637 $form{mycmd} = 'default';
638 &do_view;
639 }
640 }
641
642 # [to be obsolete] ->Message::MIME::Charset
643 sub code_convert {
644 require Jcode;
645 my ($contentref, $code, $srccode) = (shift, shift || $kanjicode, shift || undef);
646 if ($code =~ /euc/) { $code = 'euc' }
647 elsif ($code =~ /iso/) { $code = 'jis' }
648 elsif ($code =~ /shi/) { $code = 'sjis' }
649 elsif ($code =~ /utf/) { $code = 'utf8' }
650 $$contentref = Jcode->new ($contentref, $srccode)->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;
651 return $$contentref;
652 }
653
654 # [to be obsolete] ->Message::Field::Date
655 sub _rfc3339_date ($) {
656 my @time = gmtime (shift);
657 sprintf '%04d-%02d-%02dT%02d:%02d:%02d+00:00', $time[5]+1900,$time[4]+1,@time[3,2,1,0];
658 }
659
660 # [obsolete] ->SuikaWiki::SrcFormat
661 sub convert_format ($$$;%) {
662 my ($content, $d => $t, %option) = @_;
663 my $f = SuikaWiki::Plugin->format_converter ($d => $t);
664 if (ref $f) {
665 $option{content} = $content;
666 $option{from} = $d;
667 $option{to} = $t;
668 &$f ({}, bless (\%option, 'SuikaWiki::Plugin'));
669 } elsif ($option{-error_no_return}) {
670 return undef;
671 } elsif ($t =~ /HTML|xml/) {
672 if (length $content) {
673 my $r = SuikaWiki::Markup::XML->new (namespace_uri => $NS_XHTML1, local_name => 'pre');
674 $r->append_text ($content);
675 return $r;
676 } else {
677 return '';
678 }
679 } else {
680 $content;
681 }
682 }
683
684
685
686 # [obsolete] SuikaWiki::WikiDB
687 package wiki::dummy;
688 sub mtime (@) {undef}
689 sub meta (@) {undef}
690 sub Yuki::YukiWikiDB2::meta (@) {undef}
691
692 package main;
693 SuikaWiki::Plugin->import_plugins ();
694 $main::UA = $main::ENV{HTTP_USER_AGENT};
695 &open_db;
696 &init_form;
697 for (@{$SuikaWiki::Plugin::On{WikiDatabaseLoaded}||[]}) { &{$_} }
698 if ($command_do{$form{mycmd}}) {
699 &{$command_do{$form{mycmd}}}; # [to be obsolete]
700 } else {
701 &{$command_do{default}};
702 }
703 _wiki_exit ();
704
705 =head1 NAME
706
707 lib/suikawiki.pl --- SuikaWiki transitional library
708
709 =head1 AUTHOR
710
711 Hiroshi Yuki <hyuki@hyuki.com> <http://www.hyuki.com/yukiwiki/> (YukiWiki)
712
713 Makio Tsukamoto <http://digit.que.ne.jp/> (WalWiki)
714
715 Wakaba <w@suika.fam.cx>
716
717 =head1 LICENSE
718
719 Copyright AUTHORS 2000-2003
720
721 This program is free software; you can redistribute it and/or
722 modify it under the same terms as Perl itself.
723
724 =cut
725
726 1; # $Date: 2003/08/06 02:54:52 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24