#!/usr/bin/perl
# --------------------------------------------------------  PerlInterpreter
# PerlInterpreter must be the first line of the file.
#
# Copyright (c) 1995, Cunningham & Cunningham, Inc.
#
# This program is based on code that is copyright Cunningham & Cummingham, Inc.
# Used with permission.  Cunningham & Cunningham, Inc. are not responsible for
# any behaviour of the program or any damages that it may cause.
#
# Peter Merel's patch to this program is 
#
# Copyright (C) 1997  Peter Merel. 
#
# Peter Merel's patch to this program is free software; you can redistribute
# it and/or modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# Peter Merel's patch to this program is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library
# General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# along with this library; if not, write to the Free Foundation, Inc., 59
# Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Code here that is copyright Cunningham & Cunningham is not available under
# this license. For permission to use this code in any way you must apply 
# to Cunningham & Cunningham via ward@c2.com 
#
# --------------------------------------------------------  InitialComments

#
# autoflush
#
$| = 1;

@path = split('/', "$ENV{SCRIPT_NAME}");
$ScriptName = pop(@path); 
# --------------------------------------------------------  ScriptName

$DataBase = "/serv/wiki/$ScriptName"; 
# --------------------------------------------------------  DataBase

$DefaultTitle = Tunes . Wiki ;
# --------------------------------------------------------  DefaultTitle

#
# slightly changed to accomodate TLAs as well as WikiNames
#
$LinkPattern = "[A-Z][a-z]*[A-Z0-9][A-Z0-9a-z]*";
# --------------------------------------------------------  LinkPattern

$DefaultRequest = "browse";
# --------------------------------------------------------  DefaultRequest

$LogoUrl2 = 'http://127.0.0.1/uw_sm.gif';
# --------------------------------------------------------  LogoUrl

$LogoImage = "<img src=\"$LogoUrl2\" border=0>";
# --------------------------------------------------------  LogoImage

$ScriptUrl = "http://www2.tunes.org/cgi-bin/$ScriptName";
# --------------------------------------------------------  ScriptUrl

$SignatureUrl = "http://127.0.0.1/uw_sm.gif";
# --------------------------------------------------------  SignatureUrl

$WaybackLogo = "<a href=\"http://127.0.0.1/mrp.wav\" hidden=true><img src=\"http://127.0.0.1/wayback.jpg\" height=300 width=400></a>";
# --------------------------------------------------------  WaybackLogo


if ($ENV{REQUEST_METHOD} eq GET)
{
  $RawInput = $ENV{QUERY_STRING} || $DefaultTitle;
  $RawInput =~ s/^($LinkPattern)/$DefaultRequest=$1/; 
} 

if ($ENV{REQUEST_METHOD} eq POST)
{
  read(STDIN, $RawInput, $ENV{CONTENT_LENGTH});
} 
# --------------------------------------------------------  RawInput

$FieldSeparator = "\263";
# --------------------------------------------------------  FieldSeparator

foreach $_ (split(/&/, $RawInput)) 
{
  s/\+/ /g;
  s/\%(..)/pack(C, hex($1))/geo;
  s/$FieldSeparator//g;
  ($_, $CookedInput) = split (/=/, $_, 2);
  $CookedInput{$_} = $CookedInput;
}
# --------------------------------------------------------  CookedInput

sub AbortScript 
{
  local ($msg) = @_;

print <<EOF ;
  <h3>TunesWiki Can't Process Your Request</h3>
  $msg<p>
  This information has been logged.<br>
  We are sorry for any inconvenience.
EOF

  die "<pre>$msg</pre>";
}
# --------------------------------------------------------  AbortScript

sub RetrievePage 
{
  local($title) = pop(@_);


  if ( -f "$title.db")
  {
    $CookedInput{date} =~ s/-/ /g;

    $CookedInput{date} ?
      open IN, "cvs update -p -D \"$CookedInput{date} GMT\" $title.db|" :
      open IN, "<$title.db" ;

#
# gotta check return status of CVS ...
#

    #
    # stuff whole file into %db
    #
    undef $/;                        
    $db{$title} = <IN>;
    close IN;

    $db{$title} = undef if 
      $db{$title} =~ /^cvs/; # this only happens if cvs can't find the rev.
  }

  split
  (
    $FieldSeparator, 
    $db{$title} 
    || 
    (
      $CookedInput{date} ?
        "text${FieldSeparator}$title not defined $CookedInput{date}." :
        "text${FieldSeparator}Describe $title here."
    )
  );
#  print "RetrievePage:\n";
#  &DumpBinding(@_);  
}
# --------------------------------------------------------  RetrievePage

sub EscapeMetaCharacters 
{
  s/&/&amp;/g;
  s/</&lt;/g;
  s/>/&gt;/g;
}
# --------------------------------------------------------  EscapeMetaCharacters

sub InPlaceUrl 
{
  local($num) = (@_);
  local($ref) = $InPlaceUrl[$num];

  $ref =~ /\.(jpg|gif)$/         ? 
    "<img src=\"$ref\">"         : 
    "<a href=\"$ref\">$ref</a>"  ;
}
# --------------------------------------------------------  InPlaceUrl

$TranslationToken = $FieldSeparator;
# --------------------------------------------------------  TranslationToken

sub EmitCode 
{
  ($code, $depth) = @_;
  while (@code > $depth) 
  {
    local($_) = pop @code; 
    print "</$_>\n"
  }

  while (@code < $depth) 
  {
    push (@code, ($code)); 
    print "<$code>\n"
  }

  if ($code[$#code] ne $code)
  {
    print "</$code[$#code]><$code>\n";
    $code[$#code] = $code;
  }
}
# --------------------------------------------------------  EmitCode

sub AsAnchor 
{
  local($title) = pop(@_);

  $CookedInput{date} =~ s/ /-/g;

  $datestring = $CookedInput{date} ? 
		     "&date=$CookedInput{date}" :
                     "";

  ( -f "$title.db" )
  ? 
    "<a href=\"$ScriptUrl\?browse=$title$datestring\">$title<\/a>"
  : 
    "$title<a href=\"$ScriptUrl\?edit=$title\">(?)<\/a>";
}
# --------------------------------------------------------  AsAnchor

sub AsLink 
{
  local($num) = (@_);
  local($ref) = $old{"r$num"};

  defined $ref
  ? 
    ($ref =~ /\.(jpg|gif)$/ 
    ? 
      "<img src=\"$ref\">" 
    : 
      "<a href=\"$ref\">[$num]<\/a>")
  : 
    "[$num]";
}
# --------------------------------------------------------  AsLink

sub PrintBodyText 
{
  s/\\\n/ /g;
  foreach (split(/\n/, $_))
  {
    #
    # stack off the URLs out so they don't get munged
    #
    $InPlaceUrl=0;
    while 
    (
      s
      /
        \b
        ((http)|(ftp)|(mailto)|(news)|(file)|(gopher))
        :
        [^\s\<\>\[\]"'\(\)]*
        [^\s\<\>\[\]"'\(\)\,\.\?]
      /
        $TranslationToken$InPlaceUrl$TranslationToken
      /x
    ) 
    {
      $InPlaceUrl[$InPlaceUrl++] = $&;
    }

    $code = "";

    #
    # encapsulate indenting changes
    #
    s/^\s*$/<p>/                  && ($code = '...');             
    s/^(\t+)(.+):\t/<dt>$2<dd>/   && &EmitCode(DL, length $1);
    s/^(\t+)\*/<li>/              && &EmitCode(UL, length $1);
    s/^(\t+)\d\.?/<li>/           && &EmitCode(OL, length $1);
    /^\s/                         && &EmitCode(PRE, 1);
    $code                         || &EmitCode("", 0);

    #
    # add some formatting doohickeys
    #
    s/'{3}(.*?)'{3}/<strong>$1<\/strong>/g;
    s/'{2}(.*?)'{2}/<em>$1<\/em>/g;
    s/^-----*/<hr>/;
    s/\b$LinkPattern\b/&AsAnchor($&)/geo;
    s/\[(\d+)\]/&AsLink($1)/geo;
    s/$TranslationToken(\d+)$TranslationToken/&InPlaceUrl($1)/geo;
    print "$_\n";
  }
  &EmitCode("", 0);
}
# --------------------------------------------------------  PrintBodyText

sub HandleWayback 
{
  $title = $CookedInput{wayback};

print <<EOF ;
  <html>
      <HEAD>
        <TITLE>Wayback: $title</TITLE>
      </HEAD>
      <body bgcolor="#ffffff">
      <hr>
      <h2>Select revision</h2>
        <ul>
          <li><a href="$ScriptUrl\?$title">Now</a><p>
EOF
#      <br><p><center>
#        $WaybackLogo
#      <p><\/center>
# ...
#        <a href="$ScriptUrl\?$DefaultTitle">$LogoImage</a> 
#        "Sherman, set the WayBack to --"</h2>

  undef $/;                        
  open LOG, "cvs log $title.db |";
  $_ = <LOG>;
  close LOG;

  while 
  (
    /
      revision\s+([\d.]+)\s*\n
      date:\s+(\d+)\/(\S+)\s+(\S+);.*author:\s+(\S+);.*?\n
      (.*?)\n
    /gmx
  )
  {
    ($rev, $year, $md, $time, $author, $msg) = ($1, $2, $3, $4, $5, $6);

    next if $rev =~ /(\d+\.){3,}/; # skip import revs
    next if $msg =~ /backlinks/;       # skip backlink changes

    print "<li><a href=\"$ScriptUrl\?browse=$title&date=$md/${year}-$time\">"
          .
          "$md/$year, $4</a> . . . . . . $title modified by $author <p>";
  }

print <<EOF;
  </ul>
	<form>
	  <input
	    type=hidden
	    size=0
	    name=browse
	    value="$title"
	  >
	  <ul><li><input 
	    type="text" 
	    size="40" 
	    name="date" 
	    value="$CookedInput{date}">
	  </ul>
	<\/form>
  </body>
</html>
EOF
#          (See <a
#href="$ScriptUrl\?WorkingTheWayBack">WorkingTheWayBack</a>)

}
# --------------------------------------------------------  HandleWayback

sub HandleBrowse 
{
  $title = $CookedInput{browse};

  %old = &RetrievePage($title);
  $_ = $old{text};
  &EscapeMetaCharacters;

  ($datelink = $CookedInput{date} ?   "&date=$CookedInput{date}" : "")
  =~
  s/ /-/g;

  #
  # if the first character of the first line is a '!', we're
  # transcluding. We make 3 frames for this: HandleHeader and 
  # HandleFooter maintain context while the transclusion appears
  # in the middle
  #
  if (/^!(.*)$/)
  {
print <<EOF ;
      <HTML>
      <HEAD>
        <TITLE>TunesWiki: $title</TITLE>
      </HEAD>
      <FRAMESET 
        BGCOLOR="#FFFFFF"
        TEXT="#000000"
        LINK="#0000FF"
        VLINK="#000080"
        ALINK="#FF0000"
        ROWS="100,*,100" 
        bordercolor="white" 
        frameborder="yes" 
        border="1" 
        framespacing="1"
      >
      <FRAME SRC="$ScriptUrl\?header=$title$datelink" scrolling="no" >
      <FRAME SRC="$1" scrolling="auto" >
      <FRAME SRC="$ScriptUrl\?footer=$title$datelink" scrolling="no" >
      </FRAMESET>
      </HTML>
EOF
  }
  else
  #
  # spit out the text of the page plus a
  # little context
  #
  {
print <<EOF ;
    <head>
      <title>TunesWiki: $title</title>
    </head>
    <body bgcolor="#ffffff">
      <h1>
      <a href="$ScriptUrl\?backlinks=$title$datelink">
      $title $CookedInput{date}
      <\/a>
      <\/h1>
EOF
#      <a href="$ScriptUrl\?$DefaultTitle">$LogoImage</a> 

    &PrintBodyText;
    $EditText = $datelink ? "Revive this version" : "Edit Text";

print <<EOF ;
      <hr>
      <p>
      <form>
        <a href="$ScriptUrl\?edit=$title$datelink">$EditText<\/a> 
         of $title (edited $old{date})<br>
        <a href="$ScriptUrl\?backlinks=$title$datelink">
        Find Links</a> to $title $CookedInput{date}<br>
        <a href="$ScriptUrl\?browse=RecentChanges$datelink">
        View RecentChanges $CookedInput{date}<\/a><br>
        <a href="$ScriptUrl\?wayback=$title$datelink">See past
revisions<\/a><br>
        Search TunesWiki: 
        <input 
          type="text" 
          size="40" 
          name="search" 
          value="$CookedInput{value}"
        >
      <\/form>
    </body>
EOF
  }
}
# --------------------------------------------------------  HandleBrowse

sub HandleHeader 
{
  $title = $CookedInput{header};

  ($datelink = $CookedInput{date} ?   "&date=$CookedInput{date}" : "")
  =~
  s/ /-/g;

print <<EOF ;
  <head>
    <title>$title</title>
  </head>
  <body bgcolor="#ffffff">
    <h1>
    <a href="$ScriptUrl\?backlinks=$title$datelink" target="_top" >  
    $title $CookedInput{date}
    <\/a>
    <\/h1>
  </body>
EOF
#    <a href="$ScriptUrl\?$DefaultTitle" target="_top"> $LogoImage</a> 
}
# --------------------------------------------------------  HandleHeader

sub HandleFooter 
{
  $title = $CookedInput{footer};

  ($datelink = $CookedInput{date} ?   "&date=$CookedInput{date}" : "")
  =~
  s/ /-/g;

  $EditText = $datelink ? "Revive this version" : "Edit Text";

print <<EOF ;
  <head>
    <title>$title</title>
  </head>
  <body bgcolor="#ffffff">
    <h6>
    <form target="_top">
      <a target="_top" href="$ScriptUrl\?edit=$title$datelink"$datelink>$EditText<\/a> 
      of this page (edited $old{date})<br>
      <a target="_top" href="$ScriptUrl\?backlinks=$title$datelink">
      Find Backlinks
      </a> 
      to $title<br>
      <a target="_top" href="$ScriptUrl\?browse=RecentChanges$datelink">
      View RecentChanges
      <\/a><br>
      <a target="_top"
href="$ScriptUrl\?wayback=$title$datelink">See past revisions<\/a><br>
      Or search the (current) TunesWiki: 
      <input 
        target="_top"
        type="text" 
        size="40" 
        name="search" 
        value="$CookedInput{value}"
      >
    <\/form>
    </h6>
  </body>
EOF
}
# --------------------------------------------------------  HandleFooter

sub HandleEdit 
{
  $title = $CookedInput{edit} || $CookedInput{copy};
  $title =~ /^$LinkPattern$/ || &AbortScript("edit: improper name: $title");

  %old = &RetrievePage($title);
  $_ = $CookedInput{copy} ? $old{copy} : $old{text};

  $note = 'Copy of ' if $CookedInput{copy};
  s/\r\n/\n/g;
  &EscapeMetaCharacters;

  $save = $CookedInput{date} ? "Clobber current with this" : "Save";

print <<EOF ;
  <head>
  <title>Edit $note$title</title>
  </head>
  <body bgcolor="#ffffff">
  <form method="POST" action="$ScriptUrl">
  <h1>$note$title 
  <input type="submit" value=" $save ">
  <input type="reset" value=" Reset ">
  </h1>
  <TEXTAREA NAME="text" ROWS=30 COLS=80 wrap=virtual>$_</TEXTAREA><br>
  <input type="checkbox" name="convert" value="tabs" checked >
  I can't type tabs. 
  Please <a href="$ScriptUrl?ConvertSpacesToTabs">ConvertSpacesToTabs</a>
  for me when I save.<p>
  <a href="$ScriptUrl?links=$title">EditLinks</a> to other web servers.<br>
EOF
#  <a href="$ScriptUrl?GoodStyle">GoodStyle</a> tips for editing.<br>
print <<EOF  if $old{copy} && !$CookedInput{copy};
  <a href="$ScriptUrl?copy=$title">EditCopy</a> from previous author.<br>
EOF
print <<EOF ;
  <input type="hidden" size=1 name="post" value="$title">
  </form>
  </body>
EOF
}
# --------------------------------------------------------  HandleEdit
sub HandleLinks {
$title = $CookedInput{links};
$title =~ /^$LinkPattern$/ || &AbortScript("link: improper name: $title");
%old = &RetrievePage($title);
print <<EOF ;
<head><title>$title Links</title></head>
<body bgcolor="#ffffff"><form method="POST" action="$ScriptUrl">
<h1>$title Links 
<input type="submit" value=" Save ">
<input type="reset" value=" Reset "></h1>
[1] <input type="text" size=55 name="r1" value="$old{r1}"><br>
[2] <input type="text" size=55 name="r2" value="$old{r2}"><br>
[3] <input type="text" size=55 name="r3" value="$old{r3}"><br>
[4] <input type="text" size=55 name="r4" value="$old{r4}"><p>
Type the full URL (http:// ...) for each reference cited in the text.<p>
<input type="hidden" size=1 name="post" value="$title"></form>
EOF
}
# --------------------------------------------------------  HandleLinks

sub HandleSearch  
{
  local($m, $n, @rec);
  $pat = $CookedInput{search};

  #
  # backquote any special characters ... probably silly to exclude
  # the regexps, but backquoting $ when it's not at the pattern end 
  # is sensible
  #
  $pat =~ s/[$=&]/\\$&/g;

  $results = "Results";
  $results = "for $&" if $pat =~ /\W+/;

  print "<head><title>Search $results</title></head>\n";
  print "<body bgcolor=\"#ffffff\"><h1>";
#  print "<a href=\"$ScriptUrl\?$DefaultTitle\">$LogoImage</a>";
  print "Search Results</h1>\n";

  #
  # now do some searching. Happily we're in $DataBase ...
  #
    opendir(DIR,".") || die "can't opendir .: $!";
    @files = readdir(DIR);
    closedir(DIR);
    foreach $f (@files)
    {
#      $f =~ s/.db//;
#      %rec = &RetrievePage($f);

#  while (<*.db>)
#  {
    $n++;

    ($page = $f) =~ s/\.db//;

    %rec = &RetrievePage($page);
    if 
    (
      $page =~ /($pat)/ 
      ||
      $rec{text} =~ /($pat)/s
    )
    {
      $phrase = $&;
      $m++;

      print 
      "<a href=\"$ScriptUrl\?$page\">$page<\/a> . . . . . . $phrase<br>\n";
    }
  }
  $m = $m || "No";
  print "<hr>$m pages found out of $n pages searched.</body>";
}
# --------------------------------------------------------  HandleSearch

sub HandleBacklinks  
{
  local(@rec);

  $title = $CookedInput{backlinks};

  ($datelink = $CookedInput{date} ?   "&date=$CookedInput{date}" : "")
  =~
  s/ /-/g;

  print "<head><title>Links to $title $CookedInput{date}</title></head>\n";
  print "<body bgcolor=\"#ffffff\"><h1>";
  print "<a href=\"$ScriptUrl\?$DefaultTitle\">$LogoImage</a>";
  print "Links To $title $CookedInput{date}</h1>\n";

  %rec = &RetrievePage($title);
  @backlinks = split(' +', $rec{backlinks});

  foreach (sort @backlinks)
  {
    next if ! $_;
    print "<a href=\"$ScriptUrl\?browse=$_$datelink\">$_ $CookedInput{date}<\/a> <br>";
  }

  print <p>;

  print "<hr></body>";
}
# --------------------------------------------------------  HandleSearch

#
# this routine is for dumping out the contents of a dbm database
# into a form suitable for cvs use. You'll probably want to disable
# this once you've used it to retrieve your old stuff
#
sub HandleDump  
{
  local($m, $n, @rec, @backlinks); 
  $DumpDir = $CookedInput{"dump"};
  $dumper = (($DumpDir =~ /\S+/) ? $DumpDir : "C:/wikidump");

  print "<head><title>Dumping pages to $dumper</title></head>\n";
  print "<body bgcolor=\"#ffffff\"><h1>";
  print "<a href=\"$ScriptUrl\?$DefaultTitle\">$LogoImage</a>";
  print "Dumping Pages to $dumper</h1>\n";

  dbmopen(%db, "C:/wiki/dump.pl", 0666) || &AbortScript("can't open DBM");

  #
  # find backlinks - use hashes to ensure uniqueness
  #
  while (($key, $value) = each %db)
  {
    %rec = split($FieldSeparator, $value);

    while 
    (
      $rec{"text"} =~ /\b($LinkPattern)\b/g
    )
    {
      print "$1 backlinks to $key<br>\n";
      $backlinks{$1}{$key} = 1;
    }
  }

  #
  # add backlinks and spit all the pages into files
  #
  while (($key, $value) = each %db) 
  {
    %rec = split($FieldSeparator, $value); 

    @backlinks = (keys %{ $backlinks{$key} }); 
    print "so $key has these backlinks:  ", "@backlinks", "<br>\n";
    $rec{backlinks} = join(' ', @backlinks);

    @value = %rec;
    $value = join($FieldSeparator, @value); 

    if (!open OUT, ">$dumper/$key.db")
    {
      print "couldn't open $dumper / $key.db <br>\n";
    }
    print OUT $value;
    close OUT;

    print "<a href=\"$ScriptUrl\?$key\">$key<\/a> . . . . . .  dumped<br>\n";
  }

  dbmclose (%db);
  print "<hr>Dumped $n pages.</body>";
}
# --------------------------------------------------------  HandleDump

sub CookSpaces 
{
  $CookedInput{text} =~ s/ {3,8}/\t/g if $CookedInput{convert};
}
# --------------------------------------------------------  CookSpaces
$LockDirectory = "/tmp/$ScriptName"; 
# --------------------------------------------------------  LockDirectory
sub RequestLock 
{
  local ($n) = 0;
  while (mkdir($LockDirectory, 0555) == 0) 
  {
    #
    # EEXIST == 17 is OK, try later.
    #
    $! == 17 || &AbortScript("can't make $LockDirectory: $!\n");
    $n++ < 30 || &AbortScript("timed out waiting for $LockDirectory\n");
    sleep(1);
  }
}
# --------------------------------------------------------  RequestLock
($sec, $min, $hour, $mday, $mon, $year) = localtime($^T);
$DateToday = (January, February, March, April, May, June, July, 
August, September, October, November, December)[$mon]
. " " . $mday . ", " . ($year+1900);
# --------------------------------------------------------  DateToday
sub ReplacePage 
{
  local($title, *page) = @_;
  local($value, @value);
  $page{date} = $DateToday;
  $page{host} = $ENV{REMOTE_HOST};
  $page{agent} = $ENV{HTTP_USER_AGENT};
  $page{rev}++;
  @value = %page;
  $value = join($FieldSeparator, @value);
  open (OUT, ">$title.db");
  print OUT $value;
  close OUT;
#  print "Wrote to $title.db:\n$value\n";
}
# --------------------------------------------------------  ReplacePage
sub ReleaseLock {
rmdir($LockDirectory);
}
# --------------------------------------------------------  ReleaseLock

sub HandlePost 
{
  $title = $CookedInput{post};
  &CookSpaces;
  &RequestLock;

  $anchor = &AsAnchor($title);

#print <<EOF ;
#  <head><title>Thanks for $title Edits</title></head>
#  <body bgcolor="#ffffff">
# Thank you for editing <b>$title</b><br>
#EOF

  ($ENV{LOGNAME} = $ENV{REMOTE_HOST}) =~ s/\./_/g;

  #
  # we're not going to screw around
  # with merging for the moment - just clobber
  # the head of the repository
  #
#  print "running cvs update -A |\n";
#  system "cvs update -A";
  open STATUS, "cvs update -A |";
  $status = <STATUS>;
#  print "STATUS is not closed\n";
#  sleep 20;
  close STATUS;
#  print "STATUS is closed\n";

  %old = &RetrievePage($title);

  ##
  ## fix those backlinks
  ##

  @oldlinks = ($old{text} =~ /\b($LinkPattern)\b/gs);
  @newlinks = ($CookedInput{text} =~ /\b($LinkPattern)\b/gs);

  #
  # make some hashes for searching
  #
  @oldlinks{@oldlinks} = 1 x @oldlinks;
  @newlinks{@newlinks} = 1 x @newlinks;

  #
  # remove lost backlinks
  #
  foreach (keys %oldlinks)
  {
    next if exists $newlinks{$_};
    next if $_ eq $title;
    next if (! -f "$_.db");
#    print "Deleting lost backlink from $_\n" if (! -f "$_.db");
    %page = RetrievePage($_);
    $page{backlinks} =~ s/\b$title\b//gs; 
    ReplacePage($_, *page);
  }

  #
  # add new backlinks
  #
  foreach (keys %newlinks)
  {
    next if exists $oldlinks{$_};
    next if $_ eq $title;
    next if (! -f "$_.db");
    %page = RetrievePage($_);
    $page{backlinks} = "$page{backlinks} $title";
#    print "Adding new backlink from $_\n";
    ReplacePage($_, *page);
  }

  #
  # override with new values if we got 'em
  #
  for (keys(%CookedInput)) 
  {
    next if /post/ || /form/ || /title/;
    $old{$_} = $CookedInput{$_} if $CookedInput{$_};
  }

  #
  # if this is a new page, find its backlinks
  #
  if (! -f "$title.db")
  {
#    print "Finding backlinks to new page $title ...<br>";
    opendir(DIR,".") || die "can't opendir .: $!";
    @files = readdir(DIR);
    closedir(DIR);
    foreach $f (@files)
    {
      $f =~ s/.db//;
      %rec = &RetrievePage($f);
#      print "looking at $f\n";
      next unless ($rec{text} =~ /$title/);
#      print "adding backlink from $f\n";
#      print "$rec{text}\n";
      $old{backlinks} = "$old{backlinks} $f";
    }

#    &DumpBinding(*old);
    &ReplacePage($title, *old);

#    print "running cvs add $title.db|\n";
    open STATUS, "cvs add $title.db |";
    $status = <STATUS>;
    close STATUS;
    #print "cvs add says: $status <br>\n";
#    system "cvs add $title.db";
  }
  else
  {
    &ReplacePage($title, *old);
  }

#print <<EOF ;
#  Your careful attention to detail is much appreciated.<p>
#  When you <a href=\"$ScriptUrl\?$title\"><em><b>Reload</b></em></a> 
#  the page you should see your changes.<br>
#EOF
#  <img src="$SignatureUrl" align=middle >

  #
  # add a mention to RecentChanges
  #
  %rc = &RetrievePage(RecentChanges);
  $rc{text} =~ s/\t\* $title .*\n//;
  $rc{text} .= "\n$DateToday\n\n" unless $rc{text} =~ /$DateToday/;
  $rc{text} .= "\t* $title . . . . . . $ENV{REMOTE_HOST}\n";
  &ReplacePage(RecentChanges, *rc);
#  print "DateToday is $DateToday\n";
  #
  # Check in the changes on the page
  #
#  sleep 20;
#  print "running cvs ci -m \"wiki edit\" $title.db |\n";
  open STATUS, "cvs ci -m \"wikiedit\" $title.db |";
  $status = <STATUS>;
  close STATUS;
#  system "cvs ci -m \"wiki edit\" $title.db";
#  system "rcs -x,v/ -i -tCVS/$title.db,t $ENV{CVSROOT}/$title.db,v";
#  system "ci -x,v/ -f -r1 -m\"wiki edit\" $ENV{CVSROOT}/$title.db,v";
  #
  # check in the changes to backlinks and recentchanges
  #
  open STATUS, "cvs ci -m \"backlinks\" |";
  $status = <STATUS>;
  close STATUS;
#  system "cvs ci -m \"\"";

  &ReleaseLock;

#print <<EOF ;
#  </body>
#EOF

#automatically reload page
$CookedInput{browse} = "$title";
&HandleBrowse;
}
# --------------------------------------------------------  HandlePost
sub DumpBinding {
local(*dict) = @_;
print "<hr><dl>\n";
for (keys(%dict)){print "<dt>$_<dd>$dict{$_}\n";}
print "</dl><hr>\n";
}
# --------------------------------------------------------  DumpBinding
# InitialComments
print "Content-type: text/html\n\n";
chdir $DataBase || &AbortScript("can't open $DataBase");
#$CookedInput{wayback} && print "HandleWayback";
#$CookedInput{browse} && print "HandleBrowse";
#$CookedInput{edit}   && print "HandleEdit";
#$CookedInput{copy}   && print "HandleEdit";
#$CookedInput{links}  && print "HandleLinks";
#$CookedInput{header} && print "HandleHeader";
#$CookedInput{footer} && print "HandleFooter";
#$CookedInput{search} && print "HandleSearch";
#$CookedInput{backlinks} && print "HandleBacklinks";
#$CookedInput{"dump"} && print "HandleDump";
$CookedInput{wayback} && &HandleWayback;
$CookedInput{browse} && &HandleBrowse;
$CookedInput{edit}   && &HandleEdit;
$CookedInput{copy}   && &HandleEdit;
$CookedInput{links}  && &HandleLinks;
$CookedInput{header} && &HandleHeader;
$CookedInput{footer} && &HandleFooter;
$CookedInput{search} && &HandleSearch;
$CookedInput{backlinks} && &HandleBacklinks;
#$CookedInput{"dump"} && &HandleDump;
#dbmclose (%db);
if ($ENV{REQUEST_METHOD} eq POST) 
{
  $CookedInput{post}   && &HandlePost;
}
# &DumpBinding(*CookedInput);
# &DumpBinding(*old);
# &DumpBinding(*ENV);
# --------------------------------------------------------  WikiInHyperPerl
