#!/disk5/futique/barrie/perl-4.035/perl
# tree
# 
#
# Hacker:  Fred Barrie, University of Nevada
#
# Usage:
#       tree site port
#
#		example:  tree futique.scs.unr.edu 70
#
#
# Description:
#
#    This program recursively decends a gopher server tree and returns
# Gopher protocol ready lines (tab deliminated).  This program is a
# major HACK of gophertree from Univ. of Michagan by Boone
# (AS IF I TOOK A MACHETE TO IT).

$first = $ARGV[0];

open (LOG,">> $first");                  #Log file by site
open(HOST,">> gopher-server-list");      #Sites of "other" gopher servers
open(BAD,">> out-of-order");             #Sites that can't get name 
open(Two,">> 2");						 #Log of all type 2
open(Three,">> 3");						 #Log of all type 3
open(Four,">> 4");						 #Log of all type 4
open(Five,">> 5");						 #Log of all type 5
open(Six,">> 6");						 #Log of all type 6
open(Seven,">> 7");						 #Log of all type 7
open(Eight,">> 8");						 #Log of all type 8
open(Nine,">> 9");						 #Log of all type 9
open(Caps,">> Caps");					 #Log of all type with Cap Letters
open(Lower,">> Lowers");			     #Log of all type with Lower Letters
open(Other,">> Other");					 #Log of all type Other

# Standard Perl Networking...

($name,$aliases,$addrtype,$length,@addrs)=gethostbyname($first);

if ($name eq "")
{
    print BAD $first,"\n";
    exit(1);
}

# Initialize some variables

$firsthost=$CurrentHost=$name;
$firstport = $Port = $ARGV[1];

$Path = "";

$AF_INET = 2;                                 # Socket Domain
$depth = 1;                                   # How deep into the maze are we?
chop($hostname = `hostname`);                 # Hostname
$hostable{$firsthost} = 
unpack("L", (gethostbyname($firsthost))[4]);  #
$SIG{'INT'}='dokill';                         # If catch INT do dokill
$sockaddr = 'S n a4 x8';                      # Socket Mask
$SOCK_STREAM = 1;                             # Socket Type

# Network Stuff 

($name,$aliases,$proto) = getprotobyname('tcp');
($name,$aliases,$type,$len,$thisaddr) = gethostbyname($hostname);
($name,$aliases,$type,$len,$thataddr) = gethostbyname($firsthost);

$this = pack($sockaddr, $AF_INET, $sockaddr, $thisaddr);
$that = pack($sockaddr, $AF_INET, $Port, $thataddr);

# Start the real work

&GetList($CurrentHost, $Port, $Path);
exit(0);

# Just plain old boring subroutines below

sub dokill
{
    kill 9,$child if $child;
}


sub Opengopher
{
    # Make the socket filehandle.
    socket(S, $AF_INET, $SOCK_STREAM, $proto);

    # Give the socket an address.
    bind(S, $this);

    # 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) = @_;
    local(@dirx, $Name, $Obj, $fname, $ftype, $fhost);
    &Opengopher($CurrentHost, $Port);
    print S "$Path\n";
    @dirx = <S>;
    close(S);

    
    foreach (@dirx) 
    {
        last if /^\./;
        $Line=$_;
	chop; chop;
        ($ObjName, $Path, $CurrentHost, $Port) = split('\t', $_);
        $Name = substr($ObjName, 1);
        $Obj = substr($ObjName, 0, 1);
        $fhost = $CurrentHost;
        $Entry{$Path}.="X";
        if ($Entry{$Path} =~ /^XX$/) {last;}

	&PutinFile(Two, $Line), next if ($Obj =~ /^2/);
	&PutinFile(Three, $Line), next if ($Obj =~ /^3/);
	&PutinFile(Four, $Line), next if ($Obj =~ /^4/);
	&PutinFile(Five, $Line), next if ($Obj =~ /^5/);
	&PutinFile(Six, $Line), next if ($Obj =~ /^6/);
	&PutinFile(Seven, $Line), next if ($Obj =~ /^7/);
	&PutinFile(Eight, $Line), next if ($Obj =~ /^8/);
	&PutinFile(Nine, $Line), next if ($Obj =~ /^9/);
	&PutinFile(Lowers, $Line), next if ($Obj =~ /^[a-z]/);
	&PutinFile(Caps, $Line), next if ($Obj =~ /^[A-Z]/);
	&PutinFile(Other, $Line), next if ($Obj !~ /^[0-1]/);

#Save other gopher server info to a file and skip to next
#@dirx object

	if (($Obj eq "1") && ($CurrentHost ne $firsthost))
	{
		$CurrentHost =~ tr/A-Z/a-z/;
		print HOST "$CurrentHost $Port\n";
		next;
	}

# If it is a text file and is _not_ at this site then
# don't log it...cuts down on repetition

	if (($Obj eq "0") && ($CurrentHost ne $firsthost))
	{
		next;
	}	

#if the Path contains the evil words usenet or clari skip them

	if (($Path =~ /usenet/i) || ($Path =~ /clari/i))
	{
		next;
	}

        print LOG join("\t",$ObjName,$Path,$CurrentHost,$Port),"\n";    

        if ($hostable{$CurrentHost} eq "")
        {
            $hostable{$CurrentHost} =
             unpack("L", (gethostbyname($CurrentHost))[4]);
        }

        
        if (($Obj eq "1") && 
            ($hostable{$CurrentHost} eq $hostable{$firsthost}) && 
            (($Port != $firstport) || ($Path != ""))) 
        {
            $depth++;
            if ($Path =~ /^1/)
            {
                &GetList($CurrentHost, $Port, 
                 $Path);
            }
            $depth--;
        }
    }
}

sub PutinFile
{
	local($Filehandle, $Line) =  @_;
	{
		print $Filehandle $Line;
	}
}

sub Hit
{
	local($Filehandle, $Line, $FirstHost, $Host, $FirstPort, $Port) = @_;

	if (($FirstHost eq $Host) && ($FirstPort eq $Port))
	{
		print $Filehandle $Line;
		$j++;
	}
}
