| 1 | #!/usr/bin/perl -w |
|---|
| 2 | use Benchmark qw(:all :hireswallclock); |
|---|
| 3 | use vars qw( $begin ); |
|---|
| 4 | BEGIN { $begin = new Benchmark; } |
|---|
| 5 | END{ print STDERR "\nTotal " . timestr(timediff(new Benchmark, $begin))."\n"; } |
|---|
| 6 | # |
|---|
| 7 | # Foswiki - The Free and Open Source Wiki, http://foswiki.org/ |
|---|
| 8 | # |
|---|
| 9 | # Copyright (C) 1999-2003 Peter Thoeny, peter@thoeny.com |
|---|
| 10 | # |
|---|
| 11 | # Based on parts of Ward Cunninghams original Wiki and JosWiki. |
|---|
| 12 | # Copyright (C) 1998 Markus Peter - SPiN GmbH (warpi@spin.de) |
|---|
| 13 | # Some changes by Dave Harris (drh@bhresearch.co.uk) incorporated |
|---|
| 14 | # |
|---|
| 15 | # For licensing info read license.txt file in the TWiki root. |
|---|
| 16 | # This program is free software; you can redistribute it and/or |
|---|
| 17 | # modify it under the terms of the GNU General Public License |
|---|
| 18 | # as published by the Free Software Foundation; either version 2 |
|---|
| 19 | # of the License, or (at your option) any later version. |
|---|
| 20 | # |
|---|
| 21 | # This program is distributed in the hope that it will be useful, |
|---|
| 22 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 23 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 24 | # GNU General Public License for more details, published at |
|---|
| 25 | # http://www.gnu.org/copyleft/gpl.html |
|---|
| 26 | |
|---|
| 27 | # Set library paths in @INC, at compile time |
|---|
| 28 | BEGIN { unshift @INC, '.'; require 'setlib.cfg'; } |
|---|
| 29 | |
|---|
| 30 | use CGI::Carp qw( fatalsToBrowser ); |
|---|
| 31 | use CGI; |
|---|
| 32 | |
|---|
| 33 | use strict; |
|---|
| 34 | |
|---|
| 35 | &main(); |
|---|
| 36 | |
|---|
| 37 | # Uncomment the body of either routine to enable debugging |
|---|
| 38 | sub writeDebug |
|---|
| 39 | { |
|---|
| 40 | my( $text ) = @_; |
|---|
| 41 | # TWiki::writeDebug( $text ); |
|---|
| 42 | } |
|---|
| 43 | |
|---|
| 44 | sub writeDebugTimes |
|---|
| 45 | { |
|---|
| 46 | my( $text ) = @_; |
|---|
| 47 | # TWiki::writeDebugTimes( $text ); |
|---|
| 48 | } |
|---|
| 49 | |
|---|
| 50 | sub main |
|---|
| 51 | { |
|---|
| 52 | my $query; |
|---|
| 53 | my $thePathInfo; |
|---|
| 54 | my $theRemoteUser; |
|---|
| 55 | my $theUrl; |
|---|
| 56 | use Data::Dumper; |
|---|
| 57 | if( $ENV{'DOCUMENT_ROOT'} ) { |
|---|
| 58 | # script is called by browser |
|---|
| 59 | $query = new CGI; |
|---|
| 60 | $thePathInfo = $query->path_info(); |
|---|
| 61 | $theRemoteUser = $query->remote_user(); |
|---|
| 62 | $theUrl = $query->url; |
|---|
| 63 | |
|---|
| 64 | open(OF,'>/tmp/twiki_bm.cgi') || die "Store failed"; |
|---|
| 65 | print OF Dumper(\$query, $thePathInfo, $theRemoteUser, $theUrl); |
|---|
| 66 | close(OF); |
|---|
| 67 | `chmod 777 /tmp/twiki_bm.cgi` |
|---|
| 68 | } else { |
|---|
| 69 | open(IF, "</tmp/twiki_bm.cgi") || die "Retrieve failed"; |
|---|
| 70 | undef $/; |
|---|
| 71 | my $blah = <IF>; |
|---|
| 72 | close(IF); |
|---|
| 73 | my ( $VAR1, $VAR2, $VAR3, $VAR4 ); |
|---|
| 74 | eval $blah; |
|---|
| 75 | ( $query, $thePathInfo, $theRemoteUser, $theUrl ) = |
|---|
| 76 | ( $$VAR1, $VAR2, $VAR3, $VAR4 ) |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | use TWiki; |
|---|
| 80 | |
|---|
| 81 | ##### for debug only: Remove next 2 comments (but redirect does not work) |
|---|
| 82 | #print "Content-type: text/html\n\n"; |
|---|
| 83 | #open(STDERR,'>&STDOUT'); # redirect error to browser |
|---|
| 84 | #$| = 1; # no buffering |
|---|
| 85 | |
|---|
| 86 | my $theTopic = $query->param( 'topic' ); |
|---|
| 87 | |
|---|
| 88 | writeDebugTimes( "view - start $thePathInfo" ); |
|---|
| 89 | |
|---|
| 90 | my( $topic, $webName, $scriptUrlPath, $userName ) = |
|---|
| 91 | &TWiki::initialize( $thePathInfo, $theRemoteUser, $theTopic, $theUrl, $query ); |
|---|
| 92 | |
|---|
| 93 | writeDebugTimes( "view - initialized" ); |
|---|
| 94 | |
|---|
| 95 | my $tmpl = ""; |
|---|
| 96 | my $text = ""; |
|---|
| 97 | my $meta = ""; |
|---|
| 98 | my $rev = $query->param( "rev" ); |
|---|
| 99 | my $maxrev = 1; |
|---|
| 100 | my $extra = ""; |
|---|
| 101 | my $wikiUserName = &TWiki::userToWikiName( $userName ); |
|---|
| 102 | my $revdate = ""; |
|---|
| 103 | my $revuser = ""; |
|---|
| 104 | my $viewRaw = $query->param( "raw" ) || ""; |
|---|
| 105 | my $unlock = $query->param( "unlock" ) || ""; |
|---|
| 106 | my $skin = $query->param( "skin" ) || &TWiki::Prefs::getPreferencesValue( "SKIN" ); |
|---|
| 107 | |
|---|
| 108 | # Set page generation mode to RSS if using an RSS skin |
|---|
| 109 | if( $skin =~ /^rss/ ) { |
|---|
| 110 | TWiki::setPageMode( 'rss' ); |
|---|
| 111 | } |
|---|
| 112 | |
|---|
| 113 | # get view template, standard view or a view with a different skin |
|---|
| 114 | $tmpl = &TWiki::Store::readTemplate( "view", $skin ); |
|---|
| 115 | if( ! $tmpl ) { |
|---|
| 116 | TWiki::writeHeader( $query ); |
|---|
| 117 | print "<html><body>\n" |
|---|
| 118 | . "<h1>TWiki Installation Error</h1>\n" |
|---|
| 119 | . "Template file view.tmpl not found or template directory \n" |
|---|
| 120 | . "$TWiki::templateDir not found.<p />\n" |
|---|
| 121 | . "Check the \$templateDir variable in TWiki.cfg.\n" |
|---|
| 122 | . "</body></html>\n"; |
|---|
| 123 | return; |
|---|
| 124 | } |
|---|
| 125 | writeDebugTimes( "view - readTemplate" ); |
|---|
| 126 | |
|---|
| 127 | if( ! &TWiki::Store::webExists( $webName ) ) { |
|---|
| 128 | my $url = &TWiki::getOopsUrl( $webName, $topic, "oopsnoweb" ); |
|---|
| 129 | TWiki::redirect( $query, $url ); |
|---|
| 130 | return; |
|---|
| 131 | } |
|---|
| 132 | writeDebugTimes( "view - webExists" ); |
|---|
| 133 | |
|---|
| 134 | if( $unlock eq "on" ) { |
|---|
| 135 | # unlock topic, user cancelled out of edit |
|---|
| 136 | &TWiki::Store::lockTopic( $topic, "on" ); |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | # Most recent topic read in even if earlier topic requested - makes |
|---|
| 140 | # code simpler and performance impact should be minimal |
|---|
| 141 | my $topicExists = &TWiki::Store::topicExists( $webName, $topic ); |
|---|
| 142 | if( $topicExists ) { |
|---|
| 143 | if( $viewRaw ) { |
|---|
| 144 | $text = &TWiki::Store::readTopicRaw( $webName, $topic ); |
|---|
| 145 | } else { |
|---|
| 146 | ( $meta, $text ) = &TWiki::Store::readTopic( $webName, $topic ); |
|---|
| 147 | } |
|---|
| 148 | ( $revdate, $revuser, $maxrev ) = &TWiki::Store::getRevisionInfoFromMeta( $webName, $topic, $meta, "isoFormat" ); |
|---|
| 149 | |
|---|
| 150 | writeDebug( "maxrev = $maxrev" ); |
|---|
| 151 | if( $rev ) { |
|---|
| 152 | $rev =~ s/r?1\.//go; # cut 'r' and major |
|---|
| 153 | if( $rev < 1 ) { $rev = 1; } |
|---|
| 154 | if( $rev > $maxrev ) { $rev = $maxrev; } |
|---|
| 155 | } else { |
|---|
| 156 | $rev = $maxrev; |
|---|
| 157 | } |
|---|
| 158 | |
|---|
| 159 | if( $rev < $maxrev ) { |
|---|
| 160 | if( $viewRaw ) { |
|---|
| 161 | $text = &TWiki::Store::readTopicRaw( $webName, $topic, "1.$rev" ); |
|---|
| 162 | } else { |
|---|
| 163 | ( $meta, $text ) = &TWiki::Store::readTopicVersion( $webName, $topic, "1.$rev" ); |
|---|
| 164 | } |
|---|
| 165 | ( $revdate, $revuser ) = &TWiki::Store::getRevisionInfo( $webName, $topic, "1.$rev", 1 ); |
|---|
| 166 | $extra .= "r1.$rev"; |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | } else { |
|---|
| 170 | $rev = 1; |
|---|
| 171 | if( &TWiki::isWikiName( $topic ) || &TWiki::isAbbrev( $topic ) ) { |
|---|
| 172 | ( $meta, $text ) = &TWiki::Store::readTemplateTopic( "WebTopicViewTemplate" ); |
|---|
| 173 | } else { |
|---|
| 174 | ( $meta, $text ) = &TWiki::Store::readTemplateTopic( "WebTopicNonWikiTemplate" ); |
|---|
| 175 | } |
|---|
| 176 | $extra .= " (not exist)"; |
|---|
| 177 | } |
|---|
| 178 | |
|---|
| 179 | if( $viewRaw ) { |
|---|
| 180 | my $vtext = "<form><textarea readonly=\"readonly\" wrap=\"virtual\" rows=\"%EDITBOXHEIGHT%\" cols=\"%EDITBOXWIDTH%\">"; |
|---|
| 181 | $vtext = &TWiki::handleCommonTags( $vtext, $topic ); |
|---|
| 182 | $text =~ s/&/&\;/go; |
|---|
| 183 | $text =~ s/</<\;/go; |
|---|
| 184 | $text =~ s/>/>\;/go; |
|---|
| 185 | $text =~ s/\t/ /go; |
|---|
| 186 | $text = "$vtext$text</textarea></form>"; |
|---|
| 187 | if( $viewRaw !~ /debug/i ) { |
|---|
| 188 | $text =~ s/%META[\:A-Z]*{[^\}]*}%[\n\r]*//gos; |
|---|
| 189 | } |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | writeDebugTimes( "view - get rev info" ); |
|---|
| 193 | |
|---|
| 194 | if( ! $viewRaw ) { |
|---|
| 195 | $text = &TWiki::handleCommonTags( $text, $topic ); |
|---|
| 196 | writeDebugTimes( "view - handleCommonTags done" ); |
|---|
| 197 | $text = &TWiki::getRenderedVersion( $text ); |
|---|
| 198 | writeDebugTimes( "view - getRendereredVersion done" ); |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | if( $TWiki::doLogTopicView ) { |
|---|
| 202 | # write log entry |
|---|
| 203 | &TWiki::Store::writeLog( "view", "$webName.$topic", $extra ); |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | my( $mirrorSiteName, $mirrorViewURL, $mirrorLink, $mirrorNote ) = &TWiki::readOnlyMirrorWeb( $webName ); |
|---|
| 207 | |
|---|
| 208 | if( $mirrorSiteName ) { |
|---|
| 209 | # disable edit and attach |
|---|
| 210 | # FIXME: won't work with non-default skins, see %EDITURL% |
|---|
| 211 | $tmpl =~ s/%EDITTOPIC%/$mirrorLink | <strike>Edit<\/strike>/o; |
|---|
| 212 | $tmpl =~ s/<a [^>]*?>Attach<\/a>/<strike>Attach<\/strike>/oi; |
|---|
| 213 | if( $topicExists ) { |
|---|
| 214 | # remove the NOINDEX meta tag |
|---|
| 215 | $tmpl =~ s/<meta name="robots"[^>]*>//goi; |
|---|
| 216 | } else { |
|---|
| 217 | $text = ""; |
|---|
| 218 | } |
|---|
| 219 | $tmpl =~ s/%REVTITLE%//go; |
|---|
| 220 | |
|---|
| 221 | } elsif( $rev < $maxrev ) { |
|---|
| 222 | # disable edit of previous revisions - FIXME consider change to use two templates |
|---|
| 223 | # FIXME: won't work with non-default skins, see %EDITURL% |
|---|
| 224 | $tmpl =~ s/%EDITTOPIC%/<strike>Edit<\/strike>/o; |
|---|
| 225 | $tmpl =~ s/<a [^>]*?>Attach<\/a>/<strike>Attach<\/strike>/oi; |
|---|
| 226 | $tmpl =~ s|<a [^>]*?>Rename/move<\/a>|<strike>Rename/move<\/strike>|oi; |
|---|
| 227 | $tmpl =~ s/%REVTITLE%/\(r1.$rev\)/go; |
|---|
| 228 | $tmpl =~ s/%REVARG%/&rev=1.$rev/go; |
|---|
| 229 | } else { |
|---|
| 230 | # Remove the NOINDEX meta tag (for robots) from both Edit and |
|---|
| 231 | # Create pages |
|---|
| 232 | $tmpl =~ s/<meta name="robots"[^>]*>//goi; |
|---|
| 233 | my $editAction = $topicExists ? 'Edit' : 'Create'; |
|---|
| 234 | |
|---|
| 235 | # Special case for 'view' to handle %EDITTOPIC% and Edit vs. Create. |
|---|
| 236 | # New %EDITURL% variable is implemented by handleCommonTags, suffixes |
|---|
| 237 | # '?t=NNNN' to ensure that every Edit link is unique, fixing |
|---|
| 238 | # Codev.RefreshEditPage bug relating to caching of Edit page. |
|---|
| 239 | $tmpl =~ s!%EDITTOPIC%!<a href=\"%EDITURL%\"><b>$editAction</b></a>!go; |
|---|
| 240 | |
|---|
| 241 | # FIXME: Implement ColasNahaboo's suggested %EDITLINK% along the |
|---|
| 242 | # same lines, within handleCommonTags |
|---|
| 243 | |
|---|
| 244 | $tmpl =~ s/%REVTITLE%//go; |
|---|
| 245 | $tmpl =~ s/%REVARG%//go; |
|---|
| 246 | } |
|---|
| 247 | |
|---|
| 248 | my $i = $maxrev; |
|---|
| 249 | my $j = $maxrev; |
|---|
| 250 | my $revisions = ""; |
|---|
| 251 | my $breakRev = 0; |
|---|
| 252 | if( ( $TWiki::numberOfRevisions > 0 ) && ( $TWiki::numberOfRevisions < $maxrev ) ) { |
|---|
| 253 | $breakRev = $maxrev - $TWiki::numberOfRevisions + 1; |
|---|
| 254 | } |
|---|
| 255 | while( $i > 0 ) { |
|---|
| 256 | if( $i == $rev) { |
|---|
| 257 | $revisions = "$revisions | r1.$i"; |
|---|
| 258 | } else { |
|---|
| 259 | $revisions = "$revisions | <a href=\"$scriptUrlPath/view%SCRIPTSUFFIX%/%WEB%/%TOPIC%?rev=1.$i\">r1.$i</a>"; |
|---|
| 260 | } |
|---|
| 261 | if( $i != 1 ) { |
|---|
| 262 | if( $i == $breakRev ) { |
|---|
| 263 | $i = 1; |
|---|
| 264 | } else { |
|---|
| 265 | $j = $i - 1; |
|---|
| 266 | $revisions = "$revisions | <a href=\"$scriptUrlPath/rdiff%SCRIPTSUFFIX%/%WEB%/%TOPIC%?rev1=1.$i&rev2=1.$j\">></a>"; |
|---|
| 267 | } |
|---|
| 268 | } |
|---|
| 269 | $i = $i - 1; |
|---|
| 270 | } |
|---|
| 271 | $tmpl =~ s/%REVISIONS%/$revisions/go; |
|---|
| 272 | |
|---|
| 273 | if( $topicExists ) { |
|---|
| 274 | $revuser = &TWiki::userToWikiName( $revuser ); |
|---|
| 275 | my $temp = &TWiki::getRenderedVersion( "r1.$rev - $revdate GMT - $revuser" ); |
|---|
| 276 | $tmpl =~ s/%REVINFO%/$temp$mirrorNote/go; |
|---|
| 277 | } else { |
|---|
| 278 | $tmpl =~ s/%REVINFO%/$mirrorNote/go; |
|---|
| 279 | } |
|---|
| 280 | |
|---|
| 281 | $tmpl = &TWiki::handleCommonTags( $tmpl, $topic ); |
|---|
| 282 | if( $viewRaw ) { |
|---|
| 283 | $tmpl =~ s/%META{[^}]*}%//go; |
|---|
| 284 | } else { |
|---|
| 285 | $tmpl = &TWiki::handleMetaTags( $webName, $topic, $tmpl, $meta, ( $rev == $maxrev ) ); |
|---|
| 286 | } |
|---|
| 287 | writeDebugTimes( "view - handleCommonTags for template done" ); |
|---|
| 288 | $tmpl = &TWiki::getRenderedVersion( $tmpl, "", $meta ); ## better to use meta rendering? |
|---|
| 289 | $tmpl =~ s/%TEXT%/$text/go; |
|---|
| 290 | $tmpl =~ s/%MAXREV%/1.$maxrev/go; |
|---|
| 291 | $tmpl =~ s/%CURRREV%/1.$rev/go; |
|---|
| 292 | $tmpl =~ s|( ?) *</*nop/*>\n?|$1|gois; # remove <nop> tags (PTh 06 Nov 2000) |
|---|
| 293 | |
|---|
| 294 | # check access permission |
|---|
| 295 | my $viewAccessOK = &TWiki::Access::checkAccessPermission( "view", $wikiUserName, $text, $topic, $webName ); |
|---|
| 296 | if( $TWiki::readTopicPermissionFailed ) { |
|---|
| 297 | # Can't read requested topic and/or included (or other accessed topics |
|---|
| 298 | # user could not be authenticated, may be not logged in yet? |
|---|
| 299 | my $viewauthFile = $ENV{'SCRIPT_FILENAME'}; |
|---|
| 300 | $viewauthFile =~ s|/view|/viewauth|o; |
|---|
| 301 | if( ( ! $theRemoteUser ) && (-e $viewauthFile ) ) { |
|---|
| 302 | # try again with authenticated viewauth script |
|---|
| 303 | # instead of non authenticated view script |
|---|
| 304 | my $url = $ENV{"REQUEST_URI"}; |
|---|
| 305 | if( $url ) { |
|---|
| 306 | # $url i.e. is "twiki/bin/view.cgi/Web/Topic?cms1=val1&cmd2=val2" |
|---|
| 307 | $url =~ s|/view|/viewauth|o; |
|---|
| 308 | $url = "$TWiki::urlHost$url"; |
|---|
| 309 | } else { |
|---|
| 310 | $url = "$TWiki::urlHost$scriptUrlPath/$viewauthFile/$webName/$topic"; |
|---|
| 311 | } |
|---|
| 312 | TWiki::redirect( $query, $url ); |
|---|
| 313 | return; |
|---|
| 314 | } |
|---|
| 315 | } |
|---|
| 316 | if( ! $viewAccessOK ) { |
|---|
| 317 | my $url = &TWiki::getOopsUrl( $webName, $topic, "oopsaccessview" ); |
|---|
| 318 | TWiki::redirect( $query, $url ); |
|---|
| 319 | return; |
|---|
| 320 | } |
|---|
| 321 | |
|---|
| 322 | writeDebugTimes( "view - checked access permissions" ); |
|---|
| 323 | |
|---|
| 324 | # Write header based on "contenttype" parameter, used to produce |
|---|
| 325 | # MIME types like text/plain or text/xml, e.g. for RSS feeds. |
|---|
| 326 | my $contentType = $query->param( "contenttype" ); |
|---|
| 327 | if( $contentType ) { |
|---|
| 328 | TWiki::writeHeaderFull( $query, 'basic', $contentType, 0); |
|---|
| 329 | if( $skin =~ /^rss/ ) { |
|---|
| 330 | $tmpl =~ s/<img [^>]*>//g; # remove image tags |
|---|
| 331 | $tmpl =~ s/<a [^>]*>//g; # remove anchor tags |
|---|
| 332 | $tmpl =~ s/<\/a>//g; # remove anchor tags |
|---|
| 333 | } |
|---|
| 334 | } elsif( $skin =~ /^rss/ ) { |
|---|
| 335 | TWiki::writeHeaderFull( $query, 'basic', 'text/xml', 0); |
|---|
| 336 | $tmpl =~ s/<img [^>]*>//g; # remove image tags |
|---|
| 337 | $tmpl =~ s/<a [^>]*>//g; # remove anchor tags |
|---|
| 338 | $tmpl =~ s/<\/a>//g; # remove anchor tags |
|---|
| 339 | } else { |
|---|
| 340 | TWiki::writeHeader( $query ); |
|---|
| 341 | } |
|---|
| 342 | |
|---|
| 343 | # print page content |
|---|
| 344 | print $tmpl; |
|---|
| 345 | |
|---|
| 346 | writeDebugTimes( "view - done" ); |
|---|
| 347 | } |
|---|
| 348 | |
|---|
| 349 | # EOF |
|---|