#/usr/local/bin/perl # gophertree v1.0 # Prints pretty indented listings of a Gopher menu tree # Copyright (C) 1992, Trustees of Michigan State University # # Modifications: # Original author unknown # 07/07/92 Boone Major conversion from gopherls # 08/14/92 Boone Fixes: # added code to allow command line limit on recursion # depth # quit indenting after 15 levels to avoid filling the # title field with spaces # changed to use IP address instead of hostname when # checking for off-host links; this should make # aliased machine names (e.g. gopher.someschool.edu) # work much better # Enhancements: # Added option to list only directories # Changed limit on number of items listed to apply to # all types except directories, instead of just # files; still no per-type limits though # Changed command line processing to use Getopts, # allowing better option processing # End Modifications require "getopts.pl"; sub dokill { kill 9,$child if $child; } sub Opengopher { $sockaddr++; local($them,$port) = @_; $them = 'localhost' unless $them; $AF_INET = 2; $SOCK_STREAM = 1; $SIG{'INT'} = 'dokill'; $sockaddr = 'S n a4 x8'; chop($hostname = `hostname`); ($name,$aliases,$proto) = getprotobyname('tcp'); ($name,$aliases,$port) = getservbyname($port,'tcp') unless $port =~ /^\d+$/;; ($name,$aliases,$type,$len,$thisaddr) = gethostbyname($hostname); ($name,$aliases,$type,$len,$thataddr) = gethostbyname($them); $this = pack($sockaddr, $AF_INET, $sockaddr, $thisaddr); $that = pack($sockaddr, $AF_INET, $port, $thataddr); # Make the socket filehandle. socket(S, $AF_INET, $SOCK_STREAM, $proto) || die $!; # Give the socket an address. bind(S, $this) || die $!; # Call up the server. connect(S,$that) || die $!; # Set socket to be command buffered. select(S); $| = 1; select(STDOUT); } sub GetList { local($CurrentHost, $Port, $Path, $indent) = @_; local(@dirx, $Name, $Obj, $fname, $ftype, $fhost, %i, $truncated); &Opengopher($CurrentHost, $Port); print S "$Path\n"; @dirx = ; close(S); $truncated = 0; foreach (@dirx) { last if /^\./; chop; chop; ($ObjName, $Path, $CurrentHost, $Port) = split('\t', $_); $Name = substr($ObjName, 1); $Obj = substr($ObjName, 0, 1); $fname = $indent . $Name; $ftype = ""; $ftype = "File" if ($Obj eq "0"); $ftype = "Dir" if ($Obj eq "1"); $ftype = "Phone" if ($Obj eq "2"); $ftype = "Error" if ($Obj eq "3"); $ftype = "MacHqx" if ($Obj eq "4"); $ftype = "PcHqx" if ($Obj eq "5"); $ftype = "Uue" if ($Obj eq "6"); $ftype = "Index" if ($Obj eq "7"); $ftype = "Telnet" if ($Obj eq "8"); $ftype = "Bin" if ($Obj eq "9"); $ftype = "File" if ($Obj eq "R"); $ftype = "TN3270" if ($Obj eq "T"); $ftype = "File" if ($Obj eq "e"); $ftype = "Ftp" if ($Obj eq "f"); $ftype = "HTML" if ($Obj eq "h"); $ftype = "Info" if ($Obj eq "i"); $ftype = "Mail" if ($Obj eq "m"); $ftype = "Sound" if ($Obj eq "s"); $ftype = "Index" if ($Obj eq "w"); $fhost = $CurrentHost; $writeme = 1; if ((! $opt_d) && ($Obj ne "1") && ($i{$Obj} > $breaklong)) { $writeme = 0; $truncated = 1; } if ($Obj eq "i") { $writeme = 0; } if ($opt_d && ($Obj ne "1")) { $writeme = 0; } if ($writeme) { write; } if ($hostable{$CurrentHost} eq "") { $hostable{$CurrentHost} = unpack("L", (gethostbyname($CurrentHost))[4]); } if (($Obj eq "1") && ($hostable{$CurrentHost} eq $hostable{$firsthost}) && (($Port != $firstport) || ($Path != ""))) { $newindent = $indent; if ($depth < $nomoreindent) { $newindent .= $iadd; } $depth++; if ($depth <= $maxdepth) { &GetList($CurrentHost, $Port, $Path, $newindent); } $depth--; } $i{$Obj}++; } if ($truncated) { print "$indent . . .\n"; --$-; } } # ************************************************************************** # * Main # ************************************************************************** # Parse command line &Getopts("b:l:dr:"); if ($#ARGV < 1) { print "Usage: gophertree [-d -bn -ln -rn] host port path\n"; exit(1); } $firsthost = $CurrentHost = $ARGV[0]; $firstport = $Port = $ARGV[1]; $Path = ""; if ($#ARGV == 2) { $Path = $ARGV[2]; } # Initialize some variables ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $today = $mon+1 . "/" . $mday . "/" . $year; $^ = 'TOP'; # Report header format $~ = 'STDOUT'; # Report body format $indent = ""; # Goes in front of description to indicate treeness $depth = 1; # How deep into the maze are we? $hostable{$firsthost} = unpack("L", (gethostbyname($firsthost))[4]); # CHANGE--User-configurable defaults $breaklong = 15; # CHANGE--Where to break long lists $= = 55; # CHANGE--Lines per page $iadd = " "; # CHANGE--Amount to indent each new level $nomoreindent = 15; # CHANGE--How far down before we quit indenting $maxdepth = 999; # CHANGE--How deep to go before "pruning" layers # Stuff command line changes into the config variables if ($opt_b) { $breaklong = $opt_b; } if ($opt_l) { $= = $opt_l; } if ($opt_r) { $maxdepth = $opt_r; } # Real work &GetList($CurrentHost, $Port, $Path, $indent); exit(0); # # Formats # format TOP = MSU Gopher Road Map Host: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $firsthost Last Update: @<<<<<<< Page: @>> $today $% Lev Name Type Destination --- ------------------------------------------ ------ ------------------------- . format STDOUT = @>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<< @<<<<<<<<<<<<<<<<<<<<<<<< $depth $fname $ftype $fhost .