blib/lib/CGI/pWiki.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 17 | 326 | 5.2 |
branch | 1 | 170 | 0.5 |
condition | 1 | 34 | 2.9 |
subroutine | 5 | 29 | 17.2 |
pod | 1 | 25 | 4.0 |
total | 25 | 584 | 4.2 |
line | stmt | bran | cond | sub | pod | time | code | |
---|---|---|---|---|---|---|---|---|
1 | #!/usr/bin/perl | |||||||
2 | ||||||||
3 | 1 | 1 | 7135 | use 5.00503; | ||||
1 | 4 | |||||||
1 | 51 | |||||||
4 | package CGI::pWiki; | |||||||
5 | 1 | 1 | 5 | use strict; | ||||
1 | 2 | |||||||
1 | 39 | |||||||
6 | 1 | 1 | 1125 | use URI::Escape qw(uri_escape uri_unescape); | ||||
1 | 1529 | |||||||
1 | 126 | |||||||
7 | 1 | 1 | 6 | use vars qw($VERSION); $VERSION = "0.15"; | ||||
1 | 1 | |||||||
1 | 5246 | |||||||
8 | ||||||||
9 | #------------------------------------------------------------------------------# | |||||||
10 | ||||||||
11 | =pod | |||||||
12 | ||||||||
13 | =head1 NAME | |||||||
14 | ||||||||
15 | CGI::pWiki - Perl Wiki Environment | |||||||
16 | ||||||||
17 | =head1 SYNOPSIS | |||||||
18 | ||||||||
19 | #!/usr/bin/perl | |||||||
20 | use CGI::pWiki; | |||||||
21 | use strict; | |||||||
22 | my $pWiki = new CGI::pWiki()->server(); | |||||||
23 | 0; | |||||||
24 | ||||||||
25 | =head1 DESCRIPTION | |||||||
26 | ||||||||
27 | The B |
|||||||
28 | a WikiWikiWeb for virtual hosts and multiple databases. | |||||||
29 | ||||||||
30 | =head1 USAGE | |||||||
31 | ||||||||
32 | =head2 Installation | |||||||
33 | ||||||||
34 | At first install the CGI::pWiki module either on the CPAN, | |||||||
35 | or the Debian or by hand as usual with : | |||||||
36 | ||||||||
37 | perl Makefile.PL && | |||||||
38 | make && | |||||||
39 | make test && | |||||||
40 | su -c "make install" | |||||||
41 | ||||||||
42 | First check your /etc/apache/httpd.conf for the system wide | |||||||
43 | ScriptAlias path and directory path. | |||||||
44 | ||||||||
45 | ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ | |||||||
46 | ||||||||
47 | The pWiki distibution includes a pWiki.cgi to be symlinked | |||||||
48 | from your install point to your system wide cgi-bin directory. | |||||||
49 | ||||||||
50 | ln -s /usr/local/bin/pWiki.cgi /usr/lib/cgi-bin/ | |||||||
51 | ||||||||
52 | Next check your /etc/apache/httpd.conf to contain at least | |||||||
53 | those modules : | |||||||
54 | ||||||||
55 | LoadModule mime_module /usr/lib/apache/1.3/mod_mime.so | |||||||
56 | LoadModule dir_module /usr/lib/apache/1.3/mod_dir.so | |||||||
57 | LoadModule cgi_module /usr/lib/apache/1.3/mod_cgi.so | |||||||
58 | LoadModule alias_module /usr/lib/apache/1.3/mod_alias.so | |||||||
59 | LoadModule access_module /usr/lib/apache/1.3/mod_access.so | |||||||
60 | LoadModule auth_module /usr/lib/apache/1.3/mod_auth.so | |||||||
61 | LoadModule setenvif_module /usr/lib/apache/1.3/mod_setenvif.so | |||||||
62 | LoadModule action_module /usr/lib/apache/1.3/mod_actions.so | |||||||
63 | ||||||||
64 | Add a virtual host directive : | |||||||
65 | ||||||||
66 | NameVirtualHost * | |||||||
67 | |
|||||||
68 | ServerName test.copyleft.de | |||||||
69 | DocumentRoot /var/www/test.copyleft.de | |||||||
70 | DirectoryIndex index.wiki index.xml index.html index.htm index.text | |||||||
71 | Action wiki-script /cgi-bin/pWiki.cgi | |||||||
72 | # Some Apaches need the next line, also. | |||||||
73 | # ErrorDocument 404 /cgi-bin/pWiki.cgi | |||||||
74 | ||||||||
75 | AddHandler wiki-script .wiki | |||||||
76 | AddHandler wiki-script .text | |||||||
77 | AddHandler wiki-script .html | |||||||
78 | AddHandler wiki-script .htm | |||||||
79 | AddHandler wiki-script .pod | |||||||
80 | AddHandler wiki-script .xml | |||||||
81 | # The next line should be in 127.0.0.1 virtual hosts, only ! | |||||||
82 | # AddHandler wiki-script .xsl | |||||||
83 | ||||||||
84 | ||||||||
85 | There is no need to add any handler besides B<.wiki> and B<.text>, | |||||||
86 | if you dont want to manage the other files with B |
|||||||
87 | Handling B<.xsl> files in fact opens a wide security hole, and should | |||||||
88 | B |
|||||||
89 | ||||||||
90 | =head2 Security | |||||||
91 | ||||||||
92 | CGI::pWiki will offer users from outside to write files in the | |||||||
93 | document root of your webserver. It is therefore a possible | |||||||
94 | security hole. The minimal security is to constrain write access | |||||||
95 | by using the Unix C |
|||||||
96 | ||||||||
97 | mkdir /var/www/test.copyleft.de | |||||||
98 | echo "=location /open/index.wiki" /var/www/test.copyleft.de/index.wiki | |||||||
99 | mkdir /var/www/test.copyleft.de/open | |||||||
100 | touch /var/www/test.copyleft.de/open/index.wiki | |||||||
101 | chmod a+w /var/www/test.copyleft.de/open | |||||||
102 | chmod a+w /var/www/test.copyleft.de/open/index.wiki | |||||||
103 | ||||||||
104 | This will create a document root for the test site, installs | |||||||
105 | a relocation of the index page, and creates an open area and | |||||||
106 | its index page, and makes it world writeable, while other | |||||||
107 | areas will stay read only. | |||||||
108 | ||||||||
109 | A typical all public site for creating open content may want | |||||||
110 | to allow every directory to be writeable. Adopt the following | |||||||
111 | lines to migrate existing content. | |||||||
112 | ||||||||
113 | find /var/www/test.copyleft.de/ -print | xargs sudo chown kraehe.www-data | |||||||
114 | find /var/www/test.copyleft.de/ -type d -print | xargs chmod 6775 | |||||||
115 | find /var/www/test.copyleft.de/ ! -type d -print | xargs chmod 664 | |||||||
116 | ||||||||
117 | You may want to restrict edit access to the Wiki as a webmaster | |||||||
118 | by defining a directory directive : | |||||||
119 | ||||||||
120 | |
|||||||
121 | AuthUserFile /usr/local/etc/test.copyleft.de.htpasswd | |||||||
122 | AuthName "For Test Only" | |||||||
123 | AuthType Basic | |||||||
124 | |
|||||||
125 | require valid-user | |||||||
126 | ||||||||
127 | ||||||||
128 | ||||||||
129 | Or leave this as an option for .htaccess : | |||||||
130 | ||||||||
131 | AuthUserFile /usr/local/etc/test.copyleft.de.htpasswd | |||||||
132 | AuthName "For Test Only" | |||||||
133 | AuthType Basic | |||||||
134 | |
|||||||
135 | require valid-user | |||||||
136 | ||||||||
137 | ||||||||
138 | =head2 First Test | |||||||
139 | ||||||||
140 | You can now test the pWiki by reloading Apache. Create a directories | |||||||
141 | for your virtual host to contain a database called pWiki. The second | |||||||
142 | directory needs to be writeable by the webserver, as it contains the | |||||||
143 | shadow pages, if people change the content online. | |||||||
144 | ||||||||
145 | mkdir -p /var/www/test.copyleft.de/pWiki | |||||||
146 | mkdir -p /var/lib/pWiki/test.copyleft.de/pWiki | |||||||
147 | chmod a+w /var/lib/pWiki/test.copyleft.de/pWiki | |||||||
148 | ||||||||
149 | Browse at your fresh created test site and enter the URL : | |||||||
150 | ||||||||
151 | http://test.copyleft.de/pWiki/index.wiki | |||||||
152 | ||||||||
153 | This should show an edit window. Submit something like the following : | |||||||
154 | ||||||||
155 | This is a test for pWiki. | |||||||
156 | ||||||||
157 | Click on the pWiki and submit the following : | |||||||
158 | ||||||||
159 | The CGI_pWiki Perl_Module is an Apache_Handler acting as a | |||||||
160 | wrapper around a WikiWikiWeb for creating content in a | |||||||
161 | [comunity] on the fly. | |||||||
162 | ||||||||
163 | Benefits : | |||||||
164 | ||||||||
165 | * rapid content creation | |||||||
166 | * easy formatting rules | |||||||
167 | * multiple authors | |||||||
168 | ||||||||
169 | CGI_pWiki is able to handle the following extensions : | |||||||
170 | ||||||||
171 | | .html | normal hypertext pages | | |||||||
172 | | .text | preformated text pages | | |||||||
173 | | .wiki | pWiki formated hypertext pages | | |||||||
174 | | .xml | XSL formated hypertext pages | | |||||||
175 | | .pod | PlainOldDocumentation | | |||||||
176 | ||||||||
177 | Ensure that there are no leading white space when cut and paste. | |||||||
178 | ||||||||
179 | =head2 Adding Style | |||||||
180 | ||||||||
181 | The CGI-pWiki distribution contains an example database. | |||||||
182 | Copy it to your document root : | |||||||
183 | ||||||||
184 | cp htdocs/pWiki/* /var/www/test.copyleft.de/pWiki/ | |||||||
185 | ||||||||
186 | The style is defined in pairs of files with B<.lnx> and B<.moz> | |||||||
187 | extension. Copy the pWiki/content.{lnx,moz}-exam files to your | |||||||
188 | document root and define the main table of contents. | |||||||
189 | ||||||||
190 | =head2 METHODS | |||||||
191 | ||||||||
192 | =over | |||||||
193 | ||||||||
194 | =item new proto HASH | |||||||
195 | ||||||||
196 | Creates a new pWiki object. Default options are passed as key-value | |||||||
197 | pairs or as a single hash. Options may be changed directly in the | |||||||
198 | object. | |||||||
199 | ||||||||
200 | =head1 AUTHOR | |||||||
201 | ||||||||
202 | (c) 2002 GNU/GPL+Perl/Artistic Michael Koehne kraehe@copyleft.de | |||||||
203 | ||||||||
204 | =head1 SEE ALSO | |||||||
205 | ||||||||
206 | CGI | |||||||
207 | ||||||||
208 | =cut | |||||||
209 | ||||||||
210 | #------------------------------------------------------------------------------# | |||||||
211 | ||||||||
212 | my $ESCAPE1 = '(&|<|>|"|--)'; | |||||||
213 | my $ESCAPE2 = { | |||||||
214 | '&' => '&', | |||||||
215 | '<' => '<', | |||||||
216 | '>' => '>', | |||||||
217 | '"' => '"', | |||||||
218 | '--' => '--' | |||||||
219 | }; | |||||||
220 | my $TEMPLATE= { | |||||||
221 | 'edit' => ' | |||||||
222 | Edit: %TOPIC% |
|||||||
223 | ||||||||
224 | |
|||||||
225 | %TEXT% | |||||||
226 | ', | |||||||
227 | 'notfound' => ' | |||||||
228 | %TOPIC% was not found in pWiki.
|
|||||||
229 | This could be, because this page has moved, | |||||||
230 | or because nothing has been written yet.
|
|||||||
231 | ||||||||
232 | ||||||||
233 | You may want to | |||||||
234 | ||||||||
235 | for | |||||||
236 | ||||||||
237 | ||||||||
238 | ||||||||
239 | ||||||||
240 | ||||||||
241 | You may want to | |||||||
242 | ||||||||
243 | it now. | |||||||
244 | ||||||||
245 | ', | |||||||
246 | 'content' => '', | |||||||
247 | 'style' => '%HTML%' | |||||||
248 | }; | |||||||
249 | ||||||||
250 | #------------------------------------------------------------------------------# | |||||||
251 | ||||||||
252 | sub new { | |||||||
253 | 1 | 1 | 1 | 11 | my $proto = shift; | |||
254 | 1 | 50 | 5 | my $self = ($#_ == 0) ? { %{ (shift) } } : { @_ }; | ||||
0 | 0 | |||||||
255 | 1 | 33 | 8 | my $class = ref($proto) || $proto; | ||||
256 | ||||||||
257 | 1 | 2 | bless($self, $class); | |||||
258 | ||||||||
259 | 1 | 3 | return $self; | |||||
260 | } | |||||||
261 | ||||||||
262 | sub server { | |||||||
263 | 0 | 0 | 0 | my $self=shift; | ||||
264 | ||||||||
265 | 0 | $self->parse_request; | ||||||
266 | 0 | my $html = $self->translate; | ||||||
267 | ||||||||
268 | 0 | 0 | if ($html ne "") { | |||||
269 | 0 | print "Content-type: text/html\n\n"; | ||||||
270 | 0 | print $html; | ||||||
271 | } else { | |||||||
272 | 0 | $self->error("$self->{pt} not found"); | ||||||
273 | } | |||||||
274 | } | |||||||
275 | ||||||||
276 | #------------------------------------------------------------------------------# | |||||||
277 | ||||||||
278 | sub html { | |||||||
279 | 0 | 0 | 0 | my $self = shift; | ||||
280 | ||||||||
281 | 0 | $_ = $self->readfile($self->{pt}); | ||||||
282 | 0 | 0 | $self->{TITLE} = $1 if m! |
|||||
283 | 0 | 0 | $_ = $1 if m!]*>(.+)!is; | |||||
284 | ||||||||
285 | 0 | return $_; | ||||||
286 | } | |||||||
287 | ||||||||
288 | sub text { | |||||||
289 | 0 | 0 | 0 | my $self = shift; | ||||
290 | ||||||||
291 | 0 | $_ = "\n".$self->readfile($self->{pt}); | ||||||
292 | ||||||||
293 | 0 | return "$_"; |
||||||
294 | } | |||||||
295 | ||||||||
296 | sub wiki { | |||||||
297 | 0 | 0 | 0 | my $self = shift; | ||||
298 | 0 | my $html = ""; | ||||||
299 | ||||||||
300 | 0 | $_ = "\n".$self->readfile($self->{pt}); | ||||||
301 | ||||||||
302 | # convert old wiki tags | |||||||
303 | 0 | s! |
||||||
304 | 0 | s! |
||||||
305 | 0 | s! |
||||||
306 | ||||||||
307 | ||||||||
308 | # handle paragraphs, lists and tables. | |||||||
309 | 0 | foreach (split /\n\n+/) { | ||||||
310 | 0 | 0 | next, if /^[ \t\n]*$/; | |||||
311 | 0 | 0 | $_ = "\n$_" unless /^\n/; | |||||
312 | 0 | chomp; | ||||||
313 | 0 | 0 | $html .= $self->format_command($_), next | |||||
314 | if /^(\n=[^\n]+)+$/; | |||||||
315 | 0 | 0 | $html .= $self->format_list($_), next | |||||
316 | if /^(\n[ \t]*[*-][^\n]+)+$/; | |||||||
317 | 0 | 0 | $html .= $self->format_table($_), next | |||||
318 | if /^(\n[ \t]*[|][^\n]+[|][ \t]*)+$/; | |||||||
319 | 0 | 0 | $html .= $self->format_verbatim($_), next | |||||
320 | if /^(\n[ \t]+[^\n]+)+$/; | |||||||
321 | 0 | $html .= $self->format_ordinary($_); | ||||||
322 | } | |||||||
323 | ||||||||
324 | 0 | return "$html"; | ||||||
325 | } | |||||||
326 | ||||||||
327 | #------------------------------------------------------------------------------# | |||||||
328 | ||||||||
329 | sub error { | |||||||
330 | 0 | 0 | 0 | my $self = shift; | ||||
331 | 0 | my $reason = shift; | ||||||
332 | ||||||||
333 | 0 | print "Content-type: text/html\n\n"; | ||||||
334 | ||||||||
335 | 0 | print "
|
||||||
336 | 0 | print $reason,"\n"; | ||||||
337 | 0 | print "\n\n"; |
||||||
338 | ||||||||
339 | 0 | foreach (keys %ENV) { print $_," = ",$ENV{$_}," \n" }; |
||||||
0 | ||||||||
340 | 0 | exit 0; | ||||||
341 | } | |||||||
342 | ||||||||
343 | sub notfound { | |||||||
344 | 0 | 0 | 0 | my $self = shift; | ||||
345 | ||||||||
346 | 0 | return $self->template('notfound'); | ||||||
347 | } | |||||||
348 | ||||||||
349 | sub checkwrite { | |||||||
350 | 0 | 0 | 0 | my $self = shift; | ||||
351 | ||||||||
352 | 0 | my $file = $self->{pt}; | ||||||
353 | 0 | my $dir = $self->{pt}; | ||||||
354 | 0 | $dir =~ s!/[^/]*$!!; | ||||||
355 | ||||||||
356 | 0 | 0 | return "this should be a POST event" unless $self->{rm} eq "POST"; | |||||
357 | ||||||||
358 | 0 | 0 | return "user $self->{ru} not authorized " |
|||||
359 | if $self->{ru} eq "unknown"; | |||||||
360 | 0 | 0 | return "directory $dir not writeable " |
|||||
361 | unless -w $dir; | |||||||
362 | 0 | 0 | 0 | return "file $self->{pt} not writeable " |
||||
363 | if -r $self->{pt} && ! -w $self->{pt}; | |||||||
364 | 0 | 0 | return "file $self->{pt} contains slashdot" | |||||
365 | if $self->{pt} =~ m!/[.]!; | |||||||
366 | 0 | 0 | return "file $self->{pt} contains funnychars" | |||||
367 | unless $self->{pt} =~ m!^[a-zA-Z0-9_./-]+$!; | |||||||
368 | ||||||||
369 | 0 | return; | ||||||
370 | } | |||||||
371 | ||||||||
372 | sub edit { | |||||||
373 | 0 | 0 | 0 | my $self = shift; | ||||
374 | ||||||||
375 | 0 | $_ = $self->checkwrite(); | ||||||
376 | 0 | 0 | return $_ if $_; | |||||
377 | ||||||||
378 | 0 | $_ = $self->readfile($self->{pt}); | ||||||
379 | 0 | s/$ESCAPE1/$ESCAPE2->{$1}/geo; | ||||||
0 | ||||||||
380 | 0 | $self->{TEXT}=$_; | ||||||
381 | ||||||||
382 | 0 | return $self->template('edit'); | ||||||
383 | } | |||||||
384 | ||||||||
385 | sub save { | |||||||
386 | 0 | 0 | 0 | my $self = shift; | ||||
387 | ||||||||
388 | 0 | $_ = $self->checkwrite(); | ||||||
389 | 0 | 0 | return $_ if $_; | |||||
390 | ||||||||
391 | 0 | 0 | if ($self->{VAL}->{text}) { | |||||
392 | 0 | $_ = $self->{VAL}->{text}; | ||||||
393 | 0 | s/\r//g; | ||||||
394 | ||||||||
395 | 0 | 0 | if (-f $self->{pt}) { | |||||
396 | 0 | 0 | rename($self->{pt}, $self->{pt}.'~') unless -f $self->{pt}.'~'; | |||||
397 | } else { | |||||||
398 | 0 | open OUT, ">$self->{pt}~"; print OUT "\n"; close OUT; | ||||||
0 | ||||||||
0 | ||||||||
399 | } | |||||||
400 | 0 | open OUT, ">$self->{pt}"; print OUT "$_\n"; close OUT; | ||||||
0 | ||||||||
0 | ||||||||
401 | } else { | |||||||
402 | 0 | $self->error("no text"); | ||||||
403 | } | |||||||
404 | ||||||||
405 | 0 | return $self->display(); | ||||||
406 | } | |||||||
407 | ||||||||
408 | sub search { | |||||||
409 | 0 | 0 | 0 | my $self = shift; | ||||
410 | 0 | my $want = $self->{qs}; | ||||||
411 | 0 | $want =~ s/^search=//; | ||||||
412 | 0 | 0 | $want = "pWiki" if $want eq ""; | |||||
413 | 0 | my $html = "Search Results\nmatching: $want\n"; |
||||||
414 | 0 | my $rslt = `find . -type f ! -name '*~' -print | fgrep -v /CVS/ | xargs egrep -iE '$want' 2>/dev/null`; | ||||||
415 | 0 | my $hits; | ||||||
416 | 0 | my $matches=0; | ||||||
417 | ||||||||
418 | 0 | SEARCHLOOP: foreach (split( /\n/, $rslt)) { | ||||||
419 | 0 | my ($file,$str) = split /:/, $_, 2; | ||||||
420 | 0 | $file =~ s/^\.//; | ||||||
421 | 0 | $str =~ s/<[^>]+>//g; | ||||||
422 | 0 | 0 | next SEARCHLOOP if $str =~ /^[ \t\r\n]*$/; | |||||
423 | 0 | my $qm = quotemeta $str; | ||||||
424 | 0 | 0 | $hits->{$file} .= "$str \n" if $hits->{$file} !~ m!$qm!; |
|||||
425 | } | |||||||
426 | ||||||||
427 | 0 | $html .= "
|
||||||
428 | 0 | foreach (sort keys %$hits) { | ||||||
429 | 0 | $matches++; | ||||||
430 | 0 | my $tag = $_; | ||||||
431 | 0 | $tag =~ s!^\/!!; | ||||||
432 | 0 | $tag =~ s![_/]! !g; | ||||||
433 | 0 | $tag =~ s![.].*$!!; | ||||||
434 | ||||||||
435 | 0 | $html .= " \n$hits->{$_}"; |
||||||
436 | } | |||||||
437 | 0 | $html .= ""; | ||||||
438 | ||||||||
439 | 0 | 0 | $html .= " ... $matches matches search complete." if ($matches); |
|||||
440 | 0 | 0 | $html .= " ... there are no matches." if (! $matches); |
|||||
441 | ||||||||
442 | 0 | return $html; | ||||||
443 | } | |||||||
444 | ||||||||
445 | sub diff { | |||||||
446 | 0 | 0 | 0 | my $self = shift; | ||||
447 | ||||||||
448 | 0 | my $html = "\npWiki Diff\n
|
||||||
449 | 0 | my $rslt = `find . -type f ! -name '*~' -print | fgrep -v /CVS/`; | ||||||
450 | ||||||||
451 | 0 | DIFFLOOP: foreach (split( /\n/, $rslt)) { | ||||||
452 | 0 | my $file = $_; $file =~ s!^[.]/!!; | ||||||
0 | ||||||||
453 | 0 | my $path = $_; $path =~ s!^[.]!!; | ||||||
0 | ||||||||
454 | 0 | my $old = $file."~"; | ||||||
455 | 0 | 0 | next DIFFLOOP unless -r $old; | |||||
456 | ||||||||
457 | 0 | my $diff = `diff -p $old $file`; | ||||||
458 | 0 | $diff =~ s/$ESCAPE1/$ESCAPE2->{$1}/geo; | ||||||
0 | ||||||||
459 | ||||||||
460 | 0 | $html .= " \n \n$diff\n"; |
||||||
461 | } | |||||||
462 | 0 | $html .= ""; | ||||||
463 | ||||||||
464 | 0 | return $html; | ||||||
465 | } | |||||||
466 | ||||||||
467 | #------------------------------------------------------------------------------# | |||||||
468 | ||||||||
469 | sub parse_request { | |||||||
470 | 0 | 0 | 0 | my $self = shift; | ||||
471 | ||||||||
472 | 0 | 0 | $self->{dr} = $ENV{DOCUMENT_ROOT} || $self->error('DOCUMENT_ROOT not defined'); | |||||
473 | 0 | 0 | $self->{hh} = $ENV{HTTP_HOST} || $self->error('HTTP_HOST not defined'); | |||||
474 | 0 | 0 | $self->{rm} = $ENV{REQUEST_METHOD} || $self->error('REQUEST_METHOD not defined'); | |||||
475 | 0 | 0 | $self->{sn} = $ENV{SCRIPT_NAME} || $self->error('SCRIPT_NAME not defined'); | |||||
476 | 0 | 0 | $self->{ur} = $ENV{REQUEST_URI} || $self->error('REQUEST_URI not defined'); | |||||
477 | 0 | 0 | $self->{ru} = $ENV{REMOTE_USER} || "unknown"; | |||||
478 | 0 | $self->{ua} = ($ENV{HTTP_USER_AGENT} =~ /(links|lynx)/i); | ||||||
479 | ||||||||
480 | 0 | 0 | if ($ENV{PATH_INFO}) { | |||||
481 | 0 | $self->{pi} = $ENV{PATH_INFO}; | ||||||
482 | } else { | |||||||
483 | 0 | $self->{pi} = $self->{ur}; | ||||||
484 | 0 | $self->{pi} =~ s/\?.*//; | ||||||
485 | } | |||||||
486 | ||||||||
487 | 0 | 0 | if ($ENV{QUERY_STRING}) { | |||||
488 | 0 | $self->{qs} = $ENV{QUERY_STRING}; | ||||||
489 | } else { | |||||||
490 | 0 | $self->{qs} = $self->{ur}; | ||||||
491 | 0 | $self->{qs} =~ s/^[^?]*\?//; | ||||||
492 | } | |||||||
493 | ||||||||
494 | 0 | 0 | if ($ENV{PATH_TRANSLATED}) { | |||||
495 | 0 | $self->{pt} = $ENV{PATH_TRANSLATED}; | ||||||
496 | } else { | |||||||
497 | 0 | $self->{pt} = $self->{dr}.$self->{ur}; | ||||||
498 | 0 | $self->{pt} =~ s/\?.*//; | ||||||
499 | } | |||||||
500 | ||||||||
501 | 0 | 0 | if ($self->{rm} eq "POST") { | |||||
502 | 0 | alarm(60); | ||||||
503 | 0 | my $contlen = 0+$ENV{CONTENT_LENGTH}; | ||||||
504 | 0 | 0 | $contlen = 0 if ($contlen < 1); | |||||
505 | 0 | my $query; | ||||||
506 | 0 | my $readlen = read(STDIN, $query, $contlen); | ||||||
507 | 0 | alarm(0); | ||||||
508 | ||||||||
509 | 0 | 0 | $self->error("POST failed") if $readlen != $contlen; | |||||
510 | 0 | $self->{QUERY_BODY} = $query; | ||||||
511 | ||||||||
512 | 0 | $query =~ tr/+/ /; # RFC1630 | ||||||
513 | 0 | my @parts = split(/&/, $query); | ||||||
514 | ||||||||
515 | 0 | $self->{VAL}={}; | ||||||
516 | 0 | foreach (@parts) { | ||||||
517 | 0 | my ($key, $val) = split(/=/,$_,2); | ||||||
518 | 0 | 0 | $val = (defined $val) ? uri_unescape($val) : ''; | |||||
519 | 0 | $key = uri_unescape($key); | ||||||
520 | 0 | $self->{VAL}->{$key} = $val; | ||||||
521 | } | |||||||
522 | ||||||||
523 | 0 | 0 | if ($self->{VAL}->{path}) { | |||||
524 | 0 | $self->{pi} = $self->{VAL}->{path}; | ||||||
525 | 0 | $self->{pt} = $self->{dr}.$self->{VAL}->{path}; | ||||||
526 | } | |||||||
527 | 0 | 0 | $self->{qs} = $self->{VAL}->{query} if $self->{VAL}->{query}; | |||||
528 | } | |||||||
529 | ||||||||
530 | 0 | 0 | $self->error("no path info") unless $self->{pi}; | |||||
531 | 0 | 0 | $self->error("no query string") unless $self->{qs}; | |||||
532 | 0 | 0 | $self->error("no path translated") unless $self->{pt}; | |||||
533 | 0 | 0 | $self->error("can not chdir to doc root") unless chdir $self->{dr}; | |||||
534 | 0 | umask 000; | ||||||
535 | } | |||||||
536 | ||||||||
537 | sub translate { | |||||||
538 | 0 | 0 | 0 | my $self = shift; | ||||
539 | 0 | my $html; | ||||||
540 | ||||||||
541 | 0 | $self->{URL} = "http://$self->{hh}$self->{pi}"; | ||||||
542 | 0 | $self->{SCR} = "http://$self->{hh}$self->{sn}"; | ||||||
543 | 0 | $self->{PATH} = $self->{pi}; | ||||||
544 | 0 | $self->{DIR} = $self->{pi}; | ||||||
545 | 0 | $self->{DIR} =~ s!/[^/]*$!!; | ||||||
546 | 0 | $self->{DIR} =~ s!^/!!; | ||||||
547 | 0 | $self->{TOPIC} = $self->{pi}; | ||||||
548 | 0 | $self->{TOPIC} =~ s!^.*/!!; | ||||||
549 | 0 | $self->{TOPIC} =~ s![.].*$!!; | ||||||
550 | 0 | $self->{TOPIC} =~ s!_! !g; | ||||||
551 | 0 | $self->{TITLE} = $self->{TOPIC}; | ||||||
552 | ||||||||
553 | 0 | 0 | QUERYCASE: { | |||||
554 | 0 | $html = $self->error(), last QUERYCASE if $self->{error}; | ||||||
555 | 0 | 0 | $html = $self->error(), last QUERYCASE if $self->{qs} =~ /^error/; | |||||
556 | 0 | 0 | $html = $self->search(), last QUERYCASE if $self->{qs} =~ /^search=/; | |||||
557 | 0 | 0 | $html = $self->diff(), last QUERYCASE if $self->{qs} eq "diff"; | |||||
558 | 0 | 0 | $html = $self->edit(), last QUERYCASE if $self->{qs} eq "edit"; | |||||
559 | 0 | 0 | $html = $self->save(), last QUERYCASE if $self->{qs} eq "save"; | |||||
560 | 0 | $html = $self->display(); | ||||||
561 | } | |||||||
562 | ||||||||
563 | 0 | $self->{HTML} = $html; | ||||||
564 | 0 | $self->{INDEX} = $self->template("content"); | ||||||
565 | ||||||||
566 | 0 | 0 | return $self->template("style") || $self->{HTML}; | |||||
567 | } | |||||||
568 | ||||||||
569 | sub display { | |||||||
570 | 0 | 0 | 0 | my $self = shift; | ||||
571 | ||||||||
572 | 0 | 0 | return $self->notfound() unless -r $self->{pt}; | |||||
573 | 0 | 0 | return $self->html() if $self->{pt} =~ /\.html$/; | |||||
574 | 0 | 0 | return $self->html() if $self->{pt} =~ /\.htm$/; | |||||
575 | 0 | 0 | return $self->wiki() if $self->{pt} =~ /\.wiki$/; | |||||
576 | 0 | 0 | return $self->wiki() if $self->{pt} =~ /\.pod$/; | |||||
577 | 0 | 0 | return $self->xml() if $self->{pt} =~ /\.xml$/; | |||||
578 | 0 | return $self->text(); | ||||||
579 | } | |||||||
580 | ||||||||
581 | sub readfile { | |||||||
582 | 0 | 0 | 0 | my $self = shift; | ||||
583 | 0 | my $file = shift; | ||||||
584 | ||||||||
585 | 0 | 0 | if (-r $file) { | |||||
586 | 0 | my $oirs = $/; | ||||||
587 | 0 | undef $/; | ||||||
588 | 0 | open IN, $file; | ||||||
589 | 0 | my $html = |
||||||
590 | 0 | close IN; | ||||||
591 | 0 | $/ = $oirs; | ||||||
592 | 0 | return $html; | ||||||
593 | } | |||||||
594 | 0 | return; | ||||||
595 | } | |||||||
596 | ||||||||
597 | sub template { | |||||||
598 | 0 | 0 | 0 | my $self = shift; | ||||
599 | 0 | my $temp = shift; | ||||||
600 | 0 | 0 | my $file = $self->{ua} ? "$temp.lnx" : "$temp.moz"; | |||||
601 | 0 | my $html = ""; | ||||||
602 | ||||||||
603 | 0 | 0 | TEMPLCASE: { | |||||
604 | 0 | $html = $self->readfile("$self->{DIR}/$file"), last TEMPLCASE | ||||||
605 | if -r "$self->{DIR}/$file"; | |||||||
606 | 0 | 0 | $html = $self->readfile("$self->{dr}/$file"), last TEMPLCASE | |||||
607 | if -r $file; | |||||||
608 | 0 | 0 | $html = $self->readfile("pWiki/$file"), last TEMPLCASE | |||||
609 | if -r "pWiki/$file"; | |||||||
610 | 0 | 0 | $html = $TEMPLATE->{$temp} || ""; | |||||
611 | } | |||||||
612 | 0 | $html =~ s!%([A-Z]+)%!$self->{$1}!geo; | ||||||
0 | ||||||||
613 | ||||||||
614 | 0 | return $html; | ||||||
615 | } | |||||||
616 | ||||||||
617 | sub autolink { | |||||||
618 | 0 | 0 | 0 | my ($self,$link) = @_; | ||||
619 | ||||||||
620 | 0 | 0 | return $link if $link =~ /:$/; # oups ... | |||||
621 | ||||||||
622 | 0 | $link =~ tr/[]//d; | ||||||
623 | 0 | my $url = $link; | ||||||
624 | 0 | my $tag = $link; | ||||||
625 | ||||||||
626 | 0 | 0 | if ($link =~ /(.*)[|](.*)/) { | |||||
627 | 0 | $url = $2; | ||||||
628 | 0 | $tag = $1; | ||||||
629 | 0 | $tag =~ s!_! !g; | ||||||
630 | 0 | $url =~ s!::!-!g; | ||||||
631 | 0 | 0 | $url .= ".pod" if $self->{pt} =~ /\.pod/; | |||||
632 | } else { | |||||||
633 | 0 | $url =~ s!/".*!!g; | ||||||
634 | 0 | 0 | $url =~ s!/!_!g if $self->{pt} =~ /\.wiki/; | |||||
635 | 0 | 0 | $url =~ s!/.*$!!g if $self->{pt} =~ /\.pod/; | |||||
636 | 0 | $url =~ s!:+!-!g; | ||||||
637 | 0 | 0 | $url = "$self->{DIR}/$url" if $self->{DIR}; | |||||
638 | 0 | 0 | $url = "/$url" if $url !~ m!^/!; | |||||
639 | 0 | $tag =~ s!_! !g; | ||||||
640 | ||||||||
641 | 0 | 0 | EXTCASE: { | |||||
642 | 0 | $url .= ".wiki", last EXTCASE if -r $self->{dr}.$url.".wiki"; | ||||||
643 | 0 | 0 | $url .= ".text", last EXTCASE if -r $self->{dr}.$url.".text"; | |||||
644 | 0 | 0 | $url .= ".html", last EXTCASE if -r $self->{dr}.$url.".html"; | |||||
645 | 0 | 0 | $url .= ".htm", last EXTCASE if -r $self->{dr}.$url.".htm"; | |||||
646 | 0 | 0 | $url .= ".pod", last EXTCASE if -r $self->{dr}.$url.".pod"; | |||||
647 | 0 | 0 | $url .= ".xml", last EXTCASE if -r $self->{dr}.$url.".xml"; | |||||
648 | ||||||||
649 | 0 | $_ = $self->{pt}; | ||||||
650 | 0 | m/\.([^.]+)$/; | ||||||
651 | 0 | $url .= ".$1"; | ||||||
652 | 0 | $tag = "?".$tag."?"; | ||||||
653 | } | |||||||
654 | } | |||||||
655 | ||||||||
656 | 0 | return "$tag"; | ||||||
657 | } | |||||||
658 | ||||||||
659 | sub expand { | |||||||
660 | 0 | 0 | 0 | my $self = shift; my $cmd = shift; $_ = shift; | ||||
0 | ||||||||
0 | ||||||||
661 | ||||||||
662 | 0 | s!([IBSCLFXE])<+(.*)!$self->expand($1,$2)!geo; | ||||||
0 | ||||||||
663 | ||||||||
664 | 0 | 0 | return "$_" if $cmd eq "I"; | |||||
665 | 0 | 0 | return "$_" if $cmd eq "B"; | |||||
666 | 0 | 0 | return "$_ " if $cmd =~ /[CFX]/; |
|||||
667 | 0 | 0 | return $self->autolink($_) if $cmd eq "L"; | |||||
668 | 0 | 0 | 0 | return "&".$_.";" if ($cmd eq "E") && /^[^0-9]/; | ||||
669 | 0 | 0 | 0 | return "\\0".$_ if ($cmd eq "E") && /^[0-9]/; | ||||
670 | ||||||||
671 | 0 | 0 | s/ / /g if $cmd eq "S"; | |||||
672 | ||||||||
673 | 0 | return "$_"; | ||||||
674 | } | |||||||
675 | ||||||||
676 | sub wikify { | |||||||
677 | 0 | 0 | 0 | my $self = shift; $_ = shift; | ||||
0 | ||||||||
678 | ||||||||
679 | 0 | s!([IBSCLFXE])<+([^>]+)>+!$self->expand($1,$2)!geo; | ||||||
0 | ||||||||
680 | 0 | s!([\n\t ])(\[[0-9A-Za-z_/:-]+\]|[A-Za-z0-9]+[A-Z_/:-][0-9A-Za-z_/:-]*)!$1.$self->autolink($2)!geo; | ||||||
0 | ||||||||
681 | ||||||||
682 | 0 | return $_; | ||||||
683 | } | |||||||
684 | ||||||||
685 | #------------------------------------------------------------------------------# | |||||||
686 | ||||||||
687 | sub format_table { | |||||||
688 | 0 | 0 | 0 | my $self = shift; $_ = $self->wikify(shift); | ||||
0 | ||||||||
689 | ||||||||
690 | 0 | s!^[ \t]*[|]!\n | ||||||
!g; | ||||||||
691 | 0 | s!\n[ \t]*[|]!\n | ||||||
!g; | ||||||||
692 | 0 | s![|][ \t]*$! | ||||||
693 | 0 | s![|][ \t]*\n! | ||||||
694 | 0 | s![|]! | !g; | |||||
695 | ||||||||
696 | 0 | return "\n |
||||||
697 | } | |||||||
698 | ||||||||
699 | sub format_list { | |||||||
700 | 0 | 0 | 0 | my $self = shift; $_ = $self->wikify(shift); | ||||
0 | ||||||||
701 | ||||||||
702 | 0 | s!\n[ \t]*[*-] !\n |
||||||
703 | ||||||||
704 | 0 | return "\n
|
||||||
705 | } | |||||||
706 | ||||||||
707 | sub format_ordinary { | |||||||
708 | 0 | 0 | 0 | my $self = shift; $_ = $self->wikify(shift); | ||||
0 | ||||||||
709 | ||||||||
710 | 0 | s!\n[ \t]+!\n !g; |
||||||
711 | ||||||||
712 | 0 | return "\n$_\n \n"; |
||||||
713 | } | |||||||
714 | ||||||||
715 | sub format_verbatim { | |||||||
716 | 0 | 0 | 0 | my $self = shift; $_ = shift; | ||||
0 | ||||||||
717 | ||||||||
718 | 0 | s/$ESCAPE1/$ESCAPE2->{$1}/geo; | ||||||
0 | ||||||||
719 | ||||||||
720 | 0 | return "\n$_\n\n"; |
||||||
721 | } | |||||||
722 | ||||||||
723 | sub format_command { | |||||||
724 | 0 | 0 | 0 | my $self = shift; $_ = shift; | ||||
0 | ||||||||
725 | 0 | my $html = ""; | ||||||
726 | ||||||||
727 | 0 | 0 | if (/\n=location (.+)/i) { | |||||
728 | 0 | print "Location: $1\n\n"; | ||||||
729 | 0 | exit 0; | ||||||
730 | } | |||||||
731 | 0 | s!([IBSCLFXE])<([^>]+)>!$self->expand($1,$2)!geo; | ||||||
0 | ||||||||
732 | ||||||||
733 | 0 | 0 | $self->{TITLE} = $1 if /\n=title ([^\n]+)/i; | |||||
734 | 0 | 0 | $html .= "$1" if /\n=head1 ([^\n]+)/i; |
|||||
735 | 0 | 0 | $html .= "$1" if /\n=head2 ([^\n]+)/i; |
|||||
736 | 0 | 0 | $html .= "$1" if /\n=head3 ([^\n]+)/i; |
|||||
737 | 0 | 0 | $html .= "
|
|||||
738 | 0 | 0 | $html .= " |
|||||
739 | 0 | 0 | $html .= "" if /\n=back.*/i; | |||||
740 | ||||||||
741 | 0 | return $html; | ||||||
742 | } | |||||||
743 | ||||||||
744 | #------------------------------------------------------------------------------# | |||||||
745 | ||||||||
746 | 1; |