From: Steven Foster Subject: Script to automate your local veronica menu (maltshop-0.2). Apparently-To: wjm@metronet.com Status: OR #!/usr/local/bin/perl # # Copyright (C) Steven Foster 1994 # # You are welcome to modify this software in any way you desire, for # your use or for use AT YOUR SITE. However, you MAY NOT redistribute # any modified forms of this program. To maintain consistency, please # forward your changes, improvements and suggestions to me # ( foster@nevada.edu ). # # DISCLAIMER # No warranty is expressed or implied that this software will be suitable # for any particular purpose, or that it will work at all. This source # code is supplied "as-is", and you should ascertain that it is suitable # for your purpose before running it. Neither I nor any other person or # institution assumes any responsibility or liability for any undesirable # consequences of the use of this software. # # ---------------- What is this program? ------------------------- # # This script will build a veronica-access menu on your local gopher server. # This does not mean you will run a veronica server of your own; rather, you # will have a locally-held menu of veronica servers. The menu will be # updated automatically, to show only those veronica servers currently # operating. # # Reasons to have a local veronica menu: # # 1. Your users will have veronica access in spite of downtime at # Nevada or Minnesota. # # 2. The veronica access menus at Nevada and Minnesota # are getting too busy. Everyone's response time will be # better if gopher sites have locally-held links to the veronica # servers. # # 3. You have the most up-to-date menu. You can configure this # program to check all veronica servers as often as you like. # If a veronica server is down, or too slow, it will not appear # on your menu. # # What it does: # # This script runs as a cron job. It polls a list of known, public # veronica servers, determining which are reachable. It then builds a # link-file in the data heirarchy of your gopher server, at a location # you specify. You should specify a folder called something like: # "Search GopherSpace using veronica". # We recommend that you set the crontab to run the script every # twenty minutes or so. # # Periodically, the script will get a new, updated list of public # veronica servers from an authoritative site. You can set this # update frequency to your liking. The program is shipped with a # setting for six-day intervals. New veronica servers do not come # online all that often, so this is probably often enough. # You can set the update interval ( in days ) by editing a variable # at the top of the program file. # # This program needs no maintenance. After you have edited the # configuration variables, it will run by itself. # # INSTALLATION: # # The script has been tested with perl-4.036 on Ultrix, Solaris, # and NeXT-OS. # # Install this script in a convenient location, for instance as # /usr/local/bin/mkvermenu. Edit the crontab file to run the # script at about 20 minute intervals. A sample crontab entry is: # # 18,38,58 * * * * root /usr/local/bin/mkvermenu # # There is some variation is crontab formats for various systems. # Check the format to be sure. # # Edit the configuration options at the beginning of the program. # You need to specify a file name where the script can keep its # list of known servers, and a directory and filename for the # file of gopher links that constitute the veronica menu. The latter # directory and file must be in your gopher server's data heirarchy, # at the location where you want the veronica menu to appear. # Both these files must be writable by the PID that executes the # script. If you run as root, no problem. # Also, specify a writable tmp directory for the script to use. # # The remaining configuration variables are simple. # A maximum of eight server entries is enough, since each server # needs two lines on the menu, one for item searches and one for # directory-only searches. # Leave the six-day update period as is, unless you have a # good reason to change it. # There is an option that allows you to turn off the presentation # of the search-gopher-directories items on the menu, should you # want to do that. # # -------------------------------------------------------------------- # --- Set the following paths and options for your system --------- # # Full pathname for the local list of known veronica servers. # If not present, this file will be created when program is installed. # NOTE: This program must have write permission to this file. $veronicaList = '/usr/local/etc/veronica.sites'; # Directory (in your gopher menu) where you want to put the # list of veronica servers. # NOTE: This program must have write permission to this directory. $VeronicaDir = '/usr/local/gopher-data/veronica'; # Name for the file of links that will be built in $VeronicaDir. # NOTE: This program must have write permission to this file. $LinkFile = '.Links-veronica'; # readable/writable tmp directory for use by this script. $TmpDir = '/tmp'; # Maximum number of servers you want to appear on your menu: $MaxServers = 8; # Interval in days between auto-updating the veronica site list # This MUST be at least one. $UpdateInterval = 6; # Include "Search gopher directories" searches on the links menu. # Set to 0 to omit directory-type searches from your menu. $Include_gopher_dir_srch = 1; # Include menu items for two veronica documents on the Nevada menu. # Set to 0 to skip them.... $Include_docs = 1; # Set this to see program's progress $Debug = 0; # ------------- End of configuration options --------------------------- # -------------- Don't edit the stuff below. --------------------------- $master_veronica_list = "veronica.scs.unr.edu 70 0/veronica/.veronica.sites\n"; $master_veronica_list2 = "gopher.tc.umn.edu 70 0/Other Gopher and Information Servers/Veronica/.veronica.sites\n"; &Initialize; if ( ! ( $#verList >= 0 ) ) { exit; } if ($Debug){ print "BEFORE connect:\n"; } if ($Debug){ print " servers are: \n\r @verList \n"; } # Try the veronica servers &Connect; # make the file of links &Write; # move file of links into place on gopher menu $cmd = "cp $TmpDir/verlinks.tmp $VeronicaDir/$LinkFile"; system($cmd); unlink ("$TmpDir/verlinks.tmp"); $rm_cache_cmd = "rm $VeronicaDir/.cac*"; system ("$rm_cache_cmd"); exit; #========================================================================== sub Initialize { $SIG{'INT'} = 'IGNORE'; $SIG{'ALRM'} = 'Alarm'; require 'sys/socket.ph'; $Date = `date`; chop ($Date); ($Name, $Aliases, $Proto) = getprotobyname('tcp'); push ( @Listhosts, $master_veronica_list ); push ( @Listhosts, $master_veronica_list2 ); $sockaddr = 'S n a4 x8'; # read list of known veronica servers open (veronicas, "< $veronicaList"); while () { if ( /^\#/ ) { next; } if ( /^\+/ ) { s/^\+\s*//; push ( @Listhosts, $_ ); next; } if ( /^\!/ ) { s/^\!\s*//; push ( @verList, $_); } } close (veronicas); # open temp file for new links list. open (Link, "> $TmpDir/verlinks.tmp"); select (Link); $| = 1; select (STDOUT); print Link "# This file automatically created by crontab on\n"; print Link "# $Date\n"; # Is it time to get a new master list of veronica sites? # If no file of links, this is probably first startup, so get new list if ( ! (-e "$VeronicaDir/$LinkFile" )) { &UpDateHostList; return; } # If no veronica sites file, get new list if ( ! (-e "$veronicaList" )) { &UpDateHostList; return; } # If no servers were found in the veronica sites file, get new list if ( ! ( $#verList >= 0 ) ) { &UpDateHostList; return; } # If sites file is too old, get new list if ( $UpdateInterval < 1 ) { $UpdateInterval = 6; } if ( ( -M $veronicaList) >= $UpdateInterval ) { &UpDateHostList; return;} } # end initialize # ---------------------------------------------------------------------- sub UpDateHostList { foreach $host ( @Listhosts ) { ( $Lhost, $Lport, $Lpath ) = split ( /\s+/, $host, 3); if ($Debug) { print "list host: $Lhost $Lport $Lpath"; } chop ( $Lpath ); $! = ''; if ( &OpenServer ( $Lhost, $Lport ) ) { if ( !$! ) { print SERVER "$Lpath\r\n"; @NewList = ; close (SERVER); # return must be at least two lines long if ( !( $#NewList >= 1) ) { next; } # line format must be ok $BADFORMAT = 0; foreach (@NewList) { s/\r//; if ( /^\#/ ) { next; } if ( /^\./ ) { next; } if ( /^\s*$/ ) { next; } if ( /^\+/ ) { s/^\+\s*//; push ( @NewListhosts, $_ ); next; } if ( /^\!/ ) { s/^\!\s*//; push ( @NewverList, $_); next; } $BADFORMAT = 1; } if ($BADFORMAT) { next; } # Merge old and new lists of site-file-servers foreach $a ( @NewListhosts ) { ( $NLhost, $NLport, $NLpath ) = split ( /\s+/, $a, 3); chop ($NLpath); $HL{"$NLhost\t$NLport\t$NLpath"} = $a; } foreach $a ( @Listhosts ) { ( $NLhost, $NLport, $NLpath ) = split ( /\s+/, $a, 3); chop ($NLpath); $HL{"$NLhost\t$NLport\t$NLpath"} = $a; } if ($Debug) { print "writing new veronica sites list\n"; } open ( TMPLIST, ">$TmpDir/newhostlist.tmp" ); print TMPLIST "# File $veronicaList created on: \n"; print TMPLIST "# $Date\n"; print TMPLIST "# Using veronica site data from:\n"; print TMPLIST "# $Lhost $Lport $Lpath\n"; print TMPLIST "# Do not change the format of lines in this file;\n"; print TMPLIST "# the special characters are required by the program\n"; print TMPLIST "#\n"; # write list of site-file-servers foreach $uniq ( keys ( %HL) ) { print TMPLIST "+$HL{$uniq}"; } # write list of veronica servers foreach ( @NewverList ) { print TMPLIST "!$_"; } close (TMPLIST); # working list of veronicas is now new list undef @verList; @verList = @NewverList; # here copy tempfile to real sites file. $cmd = "cp $TmpDir/newhostlist.tmp $veronicaList"; system($cmd); unlink ("$TmpDir/newhostlist.tmp"); last; } } close ( SERVER ); } } sub OpenServer { local ( $server, $port ) = @_; $sockaddr = 'S n a4 x8'; (($name, $aliases, $type, $len, $saddr) = gethostbyname($server)) || do {warn "Bad gethostbyname!\n"; return (0); }; $sin = pack($sockaddr, &AF_INET, $port, $saddr); socket(SERVER, &AF_INET, &SOCK_STREAM, $Proto) || do {warn "Bad socket call!\n"; return (0);}; connect ( SERVER, $sin) || do {warn "Bad connect call!\n"; return (0);}; select (SERVER); $| = 1; select (STDOUT); $| = 1; return (1); } sub Connect { $Slimit = ( $#verList + 1 ) - $MaxServers; if ($Slimit < 0) { $Slimit = 0; } while ( $#verList >= $Slimit ) { alarm ('40'); $Line = shift(@verList); chop $Line; if($Debug){ print "Now call $Line \n"; } next unless ($Line); ($Host,$Port,$Description,$Version) = split (/\s*\!\s*/, $Line, 4); ($Name, $Aliases, $Type, $Length, $RHostAddr) = gethostbyname($Host); $RHostSocketAddr = pack ($sockaddr, &AF_INET, $Port, $RHostAddr); socket (S, &AF_INET, &SOCK_STREAM, $Proto) || warn "Can't create socket: $!\n"; #bind (S, $HostSocketAddr) # || warn "Can't bind socket: $!\n"; $! = ''; connect (S, $RHostSocketAddr); if (!$!) { select (S); $| = 1; select (STDOUT); print S "-m?\r\n"; $Reply = ; if ($Reply =~ /^.*\t.*\t.*\t\d+/) { push (@veronicas, "$Host $Port $Description"); } } else { print Link "# Can't connect to $Description: $!\n"; } } alarm(0); } sub Write { $Numb = 0; if ( $Include_docs ) { $Numb++; print Link "Type=0\n"; print Link "Name=veronica FAQ (from Nevada)\n"; print Link "Path=0/veronica/veronica-faq\n"; print Link "Host=veronica.scs.unr.edu\n"; print Link "Port=70\n"; print Link "Numb=$Numb\n"; print Link "#\n"; $Numb++; print Link "Type=0\n"; print Link "Name=How to compose veronica queries (from Nevada)\n"; print Link "Path=0/veronica/how-to-query-veronica\n"; print Link "Host=veronica.scs.unr.edu\n"; print Link "Port=70\n"; print Link "Numb=$Numb\n"; print Link "#\n"; } foreach (@veronicas) { next unless ($_); $Numb++; ($Host, $Port, $Description) = split (/\s+/, $_, 3); print Link "Type=7\n"; print Link "Name=veronica server at $Description\n"; print Link "Path=\n"; print Link "Host=$Host\n"; print Link "Port=$Port\n"; print Link "Numb=$Numb\n"; print Link "#\n"; } if ( $Include_gopher_dir_srch ) { foreach (@veronicas) { next unless ($_); $Numb++; ($Host, $Port, $Description) = split (/\s+/, $_, 3); print Link "Type=7\n"; print Link "Name=Search Gopher Directory Titles at $Description\n"; print Link "Path=-t1 \n"; print Link "Host=$Host\n"; print Link "Port=$Port\n"; print Link "Numb=$Numb\n"; print Link "#\n"; } } close (Link); } sub Alarm { alarm (0); print Link "# Alarm $Description\n"; &Connect; } .