From: schemers@leland.Stanford.EDU (Roland Schemers)
Subject: go4gw daemon (Was: Re: Wish List Re:  gopher<->NNTP et al.)
Organization: Distributed Computing Group, Stanford University
Date: Thu, 30 Jul 92 07:40:45 GMT

go4gw  (gopher gateway)
-------------------------
Ok, here it is! A master perl gopher gateway daemon, and some sample
gateways. Using this gateway, you only need to add one program to
/etc/inetd.conf, and it can handle requests for many different
perl gateways.

There is a go4gw.conf file which configures which gateways can be run.
Instead of forking off a process, or including all the gateways
in one huge perl script, the gateways can be written independent
of each other, and are dynamically loaded at the time they are invoked.
Also, common routines have been placed in go4gw which all the gateways
can use.

I'm including the shar file here for people without access to boombox.
I'll also down load it to boombox as go4gw.shar.

I've included re-written webster/whois/nntp scripts. The whois script
is Stanford specific, and if Paul chooses to use go4gw then he can
modify his general purpose whois gateway to follow go4gw conventions.
The new gateways are called: g2whois g2nntp g2webster. You'll notice
they are much smaller (since they use some common routines in go4gw)
and even easier to understand ;-)

enjoy,

Roland

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README go4gw go4gw.conf g2nntp g2nntp_groups g2whois
#   g2webster
# Wrapped by schemers@Slapshot.Stanford.EDU on Thu Jul 30 00:36:18 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(4449 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
Xgo4gw is a daemon which can handle many different gopher gateways
Xwritten in perl. It should be started from inetd.
X
XYou need to put the following line in /etc/services:
X
Xgo4gw     	4320/tcp
X
XAnd the following line in /etc/inetd.conf (depending on your system type):
X
Xgo4gw  stream  tcp     nowait  /usr/local/etc/go4gw  go4gw
X
XThe go4gw script has a few variables you might want to change:
X
X$Gconf_file = "/usr/local/etc/go4gw.conf"; # configuration file
X$Gport=4320;                               # port THIS daemon is running on
X$Ghost="Slapshot.Stanford.EDU";            # host THIS daemon is running on
X
XYou need to set Gport to the same port as in /etc/services, and Ghost to
Xyour fully qualified host name.
X
XWhy aren't these two auto-magically figured out?
XMainly for speed, but also because some `hostname` commands don't
Xhave the domain, some do, etc. Its easier just to define them here.
XSince all the other gateways are run in the context of this perl script,
Xthe gateways don't need any of this stuff in them.
X
XGconf_file should be set to the location of your go4gw.conf file. The
Xformat of this file is:
X
X#
X# format
X# gateway : user : module : gopher title
X#
Xwhois:-2:/usr/local/etc/g2whois:Whois:
Xnntp:-2:/usr/local/etc/g2nntp:USENET News:
Xwebster:-2:/usr/local/etc/g2webster:Webster:
X#
X
XWhere gateway is the name of the gateway, user is either a numeric uid
Xor name,  module is the name of the perl script that go4gw will dynamically 
Xload, and title is the title that will show up in the gopher menu if go4gw 
Xis sent the string "". If the gateway doesn't take an empty string, the title
Xshould be "" and it won't show up in the menu. By writing all your gateways so
Xthey take a "" command, you can point a link at the go4gw daemon with
Xpath set to "" and get a menu of all your gateways. The menu order will
Xbe the same order as the go4gw.conf file.
X
XWriting go4gw gateways
X-----------------------
Xgo4gw gateways need to a follow a few simple conventions:
X
XYou need to have a routine called "${gateway}_main", where gateway
Xis the name of your gateway. For example, if your gateway is called 
Xwhois, then you need:
X
Xwhois_main {
X  local($_) = @_;
X  ...
X}
X
XIn your module (/usr/local/etc/g2whois for example).
X
XYour *_main will be passed the string sent to go4gw WITHOUT your gateway 
Xprefix. For example, if someone sends the following string to go4gw:
X
Xnntp ls su.jobs
X
XThen go4gw will call &nntp_main("ls su.jobs"),  after loading g2nntp.
X
XYou should define any variables that users might have to change at the
Xfront of your script, and prefix them with your gateway name. 
X
XWhen your gateway has to return selector string, hostname, and port, it
Xshould use the following variables:
X
X$Ggw    -> name of this gateway
X$Gport  -> port this gateway is running on
X$Ghost  -> host this gateway is running on
X
XFor example, nntp might do the following:
X
X&Greply("0$Subject\t$Ggw article $group $article\t$Ghost\t$Gport");
X
XSo when the user selects this they will send:
X
Xnntp article su.jobs 104
X
XBack to the go4gw daemon, which will figure out that "article su.jobs 104"
Xneeds to get passed to g2nntp.
X
XThe following variables and routines are defined in go4gw, and can be used 
Xby gateways:
X
X$GnotServer    You can define this in perl scripts that want to include
X               the go4gw script without running the server. See the
X               g2nntp_groups script.
X
X$Ggw           Can be used by gateway routines to determine their gateway     
X               name.
X
X$Gport         Can be used by gateway routines to determine which port go4gw
X               is running on.
X
X$Ghost         Can be used by gateway routines to determine which host go4gw
X               is running on.
X
XGSERVER        File handle which is opened when GopenServer is called.
X
X&Greply(reply) Sends string back to gopher client with \r\n on the end.
X
X&Gabort(mess)  Sends error message back to gopher client with 
X               "3mess\r\n.\r\n" on end.
X              
X&GopenServer(server,port)
X               Opens TCP port at server or calls Gabort.
X
X&GcloseServer  Closes server.
X
X$Gdebug        define this to turn on debugging in &Gsend and &Grecv.
X
X&Gsend(cmd)    Sends "cmd\r\n" to GSERVER.
X
X$_ = &Grecv;   Gets response from GSERVER and strips \r and \n.
X
X&Gsorry        Sends message about data that cannot be delivered due to
X               restrictions.
X
XOther "standard" routines and variables may be added. They will start
Xwith a 'G'.
X
XRolandEND_OF_FILE
if test 4449 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'go4gw' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'go4gw'\"
else
echo shar: Extracting \"'go4gw'\" \(2497 characters\)
sed "s/^X//" >'go4gw' <<'END_OF_FILE'
X#!/usr/local/bin/perl
X#----------------------------------------------------------------------
X# variables to change
X
X$Gconf_file = "/usr/local/etc/go4gw.conf"; # configuration file
X$Gport=4320;                               # port THIS daemon is running on
X$Ghost="Slapshot.Stanford.EDU";            # host THIS daemon is running on
X
X#----------------------------------------------------------------------
X
X&go4gw_main if (!defined($GnotServer));
X
Xsub go4gw_main {
X
X# get command
X$_ = <STDIN>; s/\r//; s/\n//;
X
X($gw,$args) = /^(\w+)\s*(.*)$/ if (!/^$/);
X
Xopen(CONF,$Gconf_file) || &Gabort("$Gconf_file: $!");
Xwhile(<CONF>) { 
X     chop;
X     next if /^#/ || /^$/;
X     ($gateway,$user,$module,$title) = split(/:/);
X     if ($gw eq '') { &Greply("1$title\t$gateway\t$Ghost\t$Gport"); }
X     elsif ($gw eq $gateway) { &launch_gateway($user,$gateway,$module,$args); }
X}
X
Xif ($gw eq '') { &Greply("."); exit; }
Xelse { &Gabort("3No such gateway: $gw"); }
X
X}
Xsub launch_gateway {
X   local($user,$gateway,$module,$args) = @_;
X
X   if ($user =~ /^\-?\d+$/) { $Guid = $user; }
X   elsif ($user eq '') { $Guid = -2; }
X   else {           
X       ($n,$pw,$Guid) = getpwnam($user);
X       if ($Guid eq '') { $Guid = "-2"; }
X   }
X
X  ($<,$>) = ($Guid,$Guid) unless $>;
X   &Gabort("Can't load gateway: $module") if (! -e $module);
X   require "$module";
X   $main = "${gateway}_main";
X   $Ggw = $gateway;
X   &$main($args);
X   &Greply(".");  # shouldn't really get here, but what the hack!
X   exit;
X}
X
X#
X# standard routines
X#
X
Xsub Greply { print "$_[0]\r\n"; }
X
Xsub Gabort { print "3$_[0]\r\n.\r\n"; exit; }
X
Xsub GopenServer {
X
X local($server,$port) = @_;
X $sockaddr = 'S n a4 x8';
X (($name, $aliases, $type, $len, $saddr) = gethostbyname($server))
X        || &Gabort("3Can't get address of: $server");
X $sin = pack($sockaddr, 2, $port, $saddr);
X socket(GSERVER, 2, 1, 0) || &Gabort("Can't create socket: $!");
X connect(GSERVER, $sin)   || &Gabort("Can't connect to server: $!");
X select(GSERVER); $| = 1; select(STDOUT); $| = 1;
X}
X
Xsub GcloseServer {
X  close(GSERVER);
X}
X
Xsub Gsend { 
X     print "send -> |$_[0]|\n" if (defined($Gdebug));
X     print GSERVER "$_[0]\r\n"; 
X}
X
Xsub Grecv { 
X   local ($_); 
X   $_= <GSERVER>; 
X   s/\n$//;
X   s/\r$//;
X   print "recv -> |$_|\n" if (defined($Gdebug));
X   return $_; 
X}
X
Xsub Gsorry {
X
Xprint<<EOF;
X
XSorry! You have selected information that cannot be delivered off
Xof campus due to restrictions.
X
X   -- The Mole Hole Guardian
X
XEOF
X
X&Greply(".");
Xexit;
X
X}
X
X1;  # for require
END_OF_FILE
if test 2497 -ne `wc -c <'go4gw'`; then
    echo shar: \"'go4gw'\" unpacked with wrong size!
fi
chmod +x 'go4gw'
# end of 'go4gw'
fi
if test -f 'go4gw.conf' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'go4gw.conf'\"
else
echo shar: Extracting \"'go4gw.conf'\" \(193 characters\)
sed "s/^X//" >'go4gw.conf' <<'END_OF_FILE'
X#
X# format
X# gateway : username (or uid):module : gopher title
X#
Xwhois:-2:/usr/local/etc/g2whois:Whois:
Xnntp:-2:/usr/local/etc/g2nntp:USENET News:
Xwebster:-2:/usr/local/etc/g2webster:Webster:
X#END_OF_FILE
if test 193 -ne `wc -c <'go4gw.conf'`; then
    echo shar: \"'go4gw.conf'\" unpacked with wrong size!
fi
chmod +x 'go4gw.conf'
# end of 'go4gw.conf'
fi
if test -f 'g2nntp' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'g2nntp'\"
else
echo shar: Extracting \"'g2nntp'\" \(4088 characters\)
sed "s/^X//" >'g2nntp' <<'END_OF_FILE'
X#!/usr/local/bin/perl
X
X#----------------------------------------------------------------------
X# variables you might have to change:
X
X$nntp_server = "leland.stanford.edu";
X$nntp_port   = 119;
X$nntp_groups = "/usr/local/etc/newsgroups.gopher"; # could be active file
X$nntp_reverse = 0;  # to list articles in reverse order
X
X#----------------------------------------------------------------------
X
X@nntp_acl=(
X#     ipaddress  group    access + = allow, - = deny    
X     '^36\.      .*       +',
X     '.*         ^clari   -',
X     '.*         .*       +'
X  );
X# end of variables
X
X# Commands this server responds to:
X# 
X# ""                         -> list top level groups
X# ls $group                  -> list group's articles and sub-groups
X# article $group $number     -> get 1 article
X# sorry                      -> send sorry message
X#
X
Xsub nntp_main {
X  local($_) = @_;
X
X  &do_ls("") if /^$/;
X  &do_ls($1) if /^ls\s+(.*)/i;
X  &do_article($1,$2) if /^article\s+(\S+)\s+(\d+)/i;
X  &Gsorry if /^sorry$/;
X  &Gabort("Unknown command!");
X  exit;
X}
X
Xsub do_article {
X  local($group,$number) = @_;
X
X  if (&check_access($group) eq '-')  { &Gsorry; }
X  &open_nntp;
X
X  &Gsend("GROUP $group");
X  $_ = &Grecv;
X  &Gabort($_) if !/^211/;
X
X  &Gsend("ARTICLE $number");
X  $_ = &Grecv;
X  &Gabort($_) if !/^220/;
X 
X  while(<GSERVER>) {
X    print;
X    last if /^\.\r\n$/;
X  }
X
X  &close_nntp;
X  exit;
X}
X
Xsub list_group {
X  local($group) = @_;
X
X  &Gsend("GROUP $group");
X  $_ = &Grecv;
X  &Gabort($_) if !/^211/;
X
X  ($n,$f,$l) = /211\s+(\d+)\s+(\d+)\s+(\d+)/;
X
X  &Gsend("XHDR Subject $f-$l");
X  $_ = &Grecv;
X  &Gabort($_) if !/^221/;
X 
X  while(<GSERVER>) {
X    chop; chop;
X    last if /^\.$/;
X    ($article,$subject) = /^(\d+)\s+(.*)/;
X    $subject =~ s/\t/ /g; # just in case!
X    if ($nntp_reverse) {
X       push(@reply,"0$subject\t$Ggw article $group $article\t$Ghost\t$Gport");
X    } else {
X       &Greply("0$subject\t$Ggw article $group $article\t$Ghost\t$Gport");
X    }
X  }
X
X  if ($nntp_reverse) {
X    for ($i=$#reply; $i!= -1; $i--) { &Greply($reply[$i]); } 
X  }
X
X  &Greply(".");
X  &close_nntp;
X  exit;
X}
X
Xsub do_ls {
X  local($prefix) = @_;
X
X  if (&check_access($prefix) eq '-') {
X      &Greply("0Sorry! No access off of campus!\t$Ggw sorry\t$Ghost\t$Gport");
X      &Greply("."); 
X      exit; 
X  }
X
X  &open_nntp;
X  &get_groups;
X
X  foreach ( sort @groups) {
X    if ($_ eq $prefix) { $do_list_group = $_; }
X    elsif (/^$prefix\.([^.]*)\.?/) {
X      $leaf=$1;
X      $save{"$prefix.$leaf"} = "1$leaf\t$Ggw ls $prefix.$leaf\t$Ghost\t$Gport";
X    }
X    elsif ($prefix eq '' && /([^.]*)/) {
X         $save{"$1"} = "1$1\t$Ggw ls $1\t$Ghost\t$Gport";
X    }
X  }
X
X  foreach ( sort keys %save) { &Greply($save{$_}); }
X  &list_group($do_list_group) if ($do_list_group);
X
X  &Greply(".");
X  &close_nntp;
X  exit;
X}
X
Xsub open_nntp {
X  local($_);
X  &GopenServer($nntp_server,$nntp_port);
X  $_ = &Grecv;
X  &Gabort($_) if !/^2/;
X}
X
Xsub close_nntp {
X  &Gsend("QUIT");
X  close(GSERVER);
X}
X
Xsub get_groups {
X if (open(GROUPS,$nntp_groups)) {
X      while(<GROUPS>) {
X          chop;
X          ($grp) = /^(\S+)/;
X          push(@groups,$grp);
X      }
X      close(GROUPS);
X } else {                  # can't open file, get list from server!
X  &load_groups;
X }
X}
X
Xsub load_groups {
X
X  &open_nntp;
X  &Gsend("LIST");
X  $_ = &Grecv;
X  &Gabort($_) if !/^215/;
X
X  while(<GSERVER>) {
X    chop; chop;
X    last if /^\.$/;
X    s/^(\S+).*/$1/;
X    push(@groups,$_);
X  }
X
X}
X
Xsub create_groups { 
X  &load_groups;
X  open(GROUPS,">$nntp_groups") || die "$nntp_groups: $!";
X  foreach (@groups) { print GROUPS "$_\n"; }
X  close GROUPS;
X  &close_nntp;
X  exit;
X}
X
Xsub check_access {
X   local($group)=@_;
X
X   return 1 if (-t STDIN);
X   $sockaddr = 'S n a4 x8';
X   $mysockaddr = getpeername(STDIN);
X   ($ramily,$rport,$raddr) = unpack($sockaddr,$mysockaddr);
X   ($a,$b,$c,$d) = unpack('C4',$raddr);
X   $ipaddress = "$a.$b.$c.$d";
X
X   foreach (@nntp_acl) {
X      ($ipacl,$groupacl,$access)=split;
X      return $access if  ($ipaddress =~ /$ipacl/) && ($group =~ /$groupacl/);
X   }
X   return '-'; #default is to restrict access
X}
X
X1; # for require
END_OF_FILE
if test 4088 -ne `wc -c <'g2nntp'`; then
    echo shar: \"'g2nntp'\" unpacked with wrong size!
fi
chmod +x 'g2nntp'
# end of 'g2nntp'
fi
if test -f 'g2nntp_groups' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'g2nntp_groups'\"
else
echo shar: Extracting \"'g2nntp_groups'\" \(428 characters\)
sed "s/^X//" >'g2nntp_groups' <<'END_OF_FILE'
X#!/usr/local/bin/perl
X
X#----------------------------------------------------------------------
X# variables you might have to change
X
X$g2nntp = "/usr/local/etc/g2nntp";
X$go4gw  = "/usr/local/etc/go4gw";
X
X#----------------------------------------------------------------------
X
X$GnotServer=1;  # so go4gw doesn't think its a server!
X
Xrequire "$go4gw";
Xrequire "$g2nntp";
X
X#create the group file listed in g2nntp.
X
X&create_groups;
END_OF_FILE
if test 428 -ne `wc -c <'g2nntp_groups'`; then
    echo shar: \"'g2nntp_groups'\" unpacked with wrong size!
fi
chmod +x 'g2nntp_groups'
# end of 'g2nntp_groups'
fi
if test -f 'g2whois' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'g2whois'\"
else
echo shar: Extracting \"'g2whois'\" \(1424 characters\)
sed "s/^X//" >'g2whois' <<'END_OF_FILE'
X#!/usr/local/bin/perl
X
X#----------------------------------------------------------------------
X# variables you should change:
X
X$whois_server = "stanford.edu";   
X$whois_port   = 43;
X
X#----------------------------------------------------------------------
X
Xsub whois_main {
X local($_) = @_;
X
X if (/^$/) {
X    &Greply("0Whois Help\thelp\t$whois_server\t$whois_port");
X    &Greply("7Query Whois\t$Ggw\t$Ghost\t$Gport");
X    &Greply(".");
X    exit(0);
X }
X
X $query = $_;
X &GopenServer($whois_server,$whois_port);
X &Gsend($query);
X
X  while(<GSERVER>) {
X        chop; chop;
X        push(@lines,$_);
X  }
X
X  &Greply("0Raw search results\t$query\t$whois_server\t$whois_port");
X
X  if ($lines[$#lines] eq '') {
X        foreach (@lines) {
X           if (/^\s+name:\s+(.*)/) {
X               &Greply("0$1\t$query\t$whois_server\t$whois_port");
X               &Greply(".");
X               exit(0);
X           }
X        }
X    } elsif ($lines[$#lines] eq 'NO MATCH') {
X       &Greply("0No Match Was Found!\thelp\t$gopher_server\t$gopher_port");
X    } elsif ($lines[$#lines] =~ /^\(returned/) {
X       foreach (@lines) {
X           if (/(.*)<(.*)>.*\s+(.*)$/) {
X               $text=$1; $handle=$2; $rest = $3;
X               $text =~ s/\s+$//;
X               $rest =~ s/\s+/ /g;
X               &Greply("0$text ($rest)\t!$handle\t$whois_server\t$whois_port");
X           }
X        }
X    }
X    &Greply(".");
X    exit(0);
X}
X
X
X
X
X1; # for requireEND_OF_FILE
if test 1424 -ne `wc -c <'g2whois'`; then
    echo shar: \"'g2whois'\" unpacked with wrong size!
fi
chmod +x 'g2whois'
# end of 'g2whois'
fi
if test -f 'g2webster' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'g2webster'\"
else
echo shar: Extracting \"'g2webster'\" \(2572 characters\)
sed "s/^X//" >'g2webster' <<'END_OF_FILE'
X#!/usr/local/bin/perl
X
X#----------------------------------------------------------------------
X# variables you can change:
X
X#$webster_server  = "webster.lcs.mit.edu";
X#$webster_port    = 103;
X
X$webster_server = "webster-server.stanford.edu";
X$webster_port   = 765;
X
X@webster_acl=(
X#     ipaddress  access + = allow, - = deny    
X     '^36\.      +',
X     '.*         -'
X  );
X
X#----------------------------------------------------------------------
X
Xsub webster_main {
X local($_ )= @_;
X
X &Gsorry if /^sorry$/;
X
X  if (&check_access() eq '-') {
X      &Greply("0Sorry! No access off of campus!\t$Ggw sorry\t$Ghost\t$Gport");
X      &Greply("."); 
X      exit; 
X  }
X
X if (/^$/) {
X  &Greply("7Lookup word in dictionary\t$Ggw default SPELL\t$Ghost\t$Gport");
X  &Greply("7Lookup word in dictionary (phonetic match)\t$Ggw default PSPELL\t$Ghost\t$Gport");
X  &Greply("7Search text of entire dictionary\t$Ggw dictionary-full SPELL\t$Ghost\t$Gport");
X  &Greply("7Show words that start with\t$Ggw default ENDINGS\t$Ghost\t$Gport");
X  &Greply("7Thesaurus\t$Ggw thesaurus SPELL\t$Ghost\t$Gport");
X  &Greply(".");
X  exit(0);
X }
X
X ($index,$cmd,$query) = /^(\S+)\s+(\S+)\s+(.+)$/;
X
X  &GopenServer($webster_server,$webster_port);
X
X  &Gsend("INDEX $index") if ($index ne 'default');
X
X  if ($cmd eq "PSPELL") {                     # phonetic lookup
X       &Gsend("SPELL $query ?");
X  } else {
X       &Gsend("$cmd $query");
X  }
X
X$_ = &Grecv;
X
X  if (/^SPELLING 0/ || /^WILD 0/) {
X        &Greply(".");
X   } elsif (/^SPELLING 1/) {
X      &Greply("0$query\t$Ggw $index DEFINE $query\t$Ghost\t$Gport"); 
X      &Greply(".");
X   } elsif (/^SPELLING$/ || /^MATCHS$/ || /^WILD/) {
X        $/ = "\200";
X        $buf = <GSERVER>;
X        $buf =~ s/[\r\200]//g;
X        foreach (split(/\n/,$buf)) { /\d+\s+(\S+)/; $words{$1}=""; }
X        foreach (sort keys %words) { 
X               &Greply("0$_\t$Ggw $index DEFINE $_\t$Ghost\t$Gport"); 
X        }
X        &Greply(".");
X   } elsif (/^DEFINITION/) {
X        $/ = "\200";
X        $buf = <GSERVER>;
X        $buf =~ s/[\r\200]//g;
X        print $buf;
X   } else {
X        &Greply(".");
X   }
X  &Gsend("QUIT");
X  &GcloseServer;
X  exit;
X}
X
Xsub check_access {
X
X   return 1 if (-t STDIN);
X   $sockaddr = 'S n a4 x8';
X   $mysockaddr = getpeername(STDIN);
X   ($ramily,$rport,$raddr) = unpack($sockaddr,$mysockaddr);
X   ($a,$b,$c,$d) = unpack('C4',$raddr);
X   $ipaddress = "$a.$b.$c.$d";
X
X   foreach (@webster_acl) {
X      ($ipacl,$access)=split;
X      return $access if  ($ipaddress =~ /$ipacl/);
X   }
X   return '-'; #default is to restrict access
X}
X
X1; # for requireEND_OF_FILE
if test 2572 -ne `wc -c <'g2webster'`; then
    echo shar: \"'g2webster'\" unpacked with wrong size!
fi
chmod +x 'g2webster'
# end of 'g2webster'
fi
echo shar: End of shell archive.
exit 0
-- 
Roland J. Schemers III              |            Networking Systems
Systems Programmer                  |            168 Pine Hall   (415)-723-6740
Distributed Computing Group         |            Stanford, CA 94305-4122
Stanford University                 |            schemers@Slapshot.Stanford.EDU
Newsgroups: alt.gopher