#!/usr/um/bin/perl

# Clark version 0.96b August 18, 1995
# Copyright (c) 1995 David S. Carter. All rights reserved.
# Permission is granted to freely use and modify for personal use, but not to distribute.
# Information on Clark, licensing agreement, and the latest version, 
# can be obtained at http://www.sils.umich.edu/~superman/AP/

# Get filename for input
$t1 = 1;
while ($t1) {
	print "Input Filename: ";
	$infile = <STDIN>;
	chop($infile);
	if (-e $infile) {
		$t1 = 0;
		}
	else {
		print "$infile does not exist!\n";
		}
	}

# Get filename for output
$t2 = 1;
while ($t2) {
	print "Output Filename: ";
	$outfile = <STDIN>;
	chop($outfile);
	if (-e $outfile) {
		print "$outfile already exists. Okay to overwrite (y/n)[n]? ";
		$q1 = <STDIN>;
		if ($q1 =~ /^(y|Y)/) {
			$t2 = 0;
			}
		}
	else {
		$t2 = 0;
		}
	}

# Open $infile, read in data, close $infile
open (IN, "$infile");
print "Reading $infile \n";
@log = <IN>;
$shtuff = $#log + 1;
print "Read $shtuff lines of data\n";
close (IN);

# Get gapsize
print "Gap size, in minutes [30]: ";
$ingap = <STDIN>;
chop($ingap);
if ($ingap =~ /^\d/) {
	$gap = $ingap;
	}
else {
	$gap = 30;
	}

# Exclude, Include, or Neither?
print "Would you like to Exclude hosts, Only Include certain hosts, or neither (e/i/n)[n]? ";
$opt = <STDIN>;
chop($opt);
if ($opt =~ /^(e|E)/) {
	$t3 = 1;
	$ctr = 0;
	while ($t3) {
		print "Enter host or IP address to exclude (return to end): ";
		$exc = <STDIN>;
		chop($exc);
		if ($exc =~ /^\S/) {
			$exclude[$ctr++] = $exc;
			}
		else {
			$t3 = 0;
			}
		}
	}

elsif ($opt =~ /^(i|I)/) {
	$t3 = 1;
	$ctr = 0;
	while ($t3) {
		print "Enter host or IP address to include (return to end): ";
		$inc = <STDIN>;
		chop($inc);
		if ($inc =~ /^\S/) {
			$include[$ctr++] = $inc;
			}
		else {
			$t3 = 0;
			}
		}
	}


# Get the ball rolling
$logc = 0;
$numtrans = 0;
$numdone = 0;

print "Processing data -- please be patient\n";

foreach $line (@log) {

	&parse; # subroutine for parsing $line of @log
			# will assign the following values:
			# $host    : host or IP address of request
			# $rfc     : information returned by identd
			# $user    : user name
			# $date    : date of request
			# $time    : time or request
			# $request : request and result
			
	# check to see if this request should be included
	
	$doit = 1;
	
	if ($opt =~ /^(e|E)/) {
		for ($tt = 0; $tt <= $#exclude; $tt++) {
			if ($host eq $exclude[$tt]) {
				$doit = 0;
				}
			}
		}
		
	elsif ($opt =~ /^(i|I)/) {
		$doit = 0;
		for ($tt = 0; $tt <= $#include; $tt++) {
			if ($host eq $include[$tt]) {
				$doit = 1;
				}
			}
		}
	
	# if okay to include, then do it
	if ($doit) {
	
		if ($numtrans eq 0) {
			&new; # subroutine to create new transaction
			$numtrans++;
			}
			
		else {
			if (&check_for_exist) {	# subroutine to check for existing transaction
						  			# will assign $where to be the location in @trans where the existing transaction starts
						  			#  and $next for where the next transaction starts, if not to be new
				&insert; #subroutine to insert into proper transaction
				}
			else {
				&new;
				$numtrans++;
				}
			}
			
		$numdone++;
		
		}
	}
	
	
# Write @trans to $outfile
open (OUT, ">$outfile");
print "Writing transaction log to $outfile \n";
foreach $line (@trans) {
                print OUT ("$line\n");
        }
close (OUT);

# Give summary statistics

print "$shtuff requests were processed\n";
print "$numdone met the given criteria\n";
print "$numtrans transactions were logged, using a gap size of $gap minutes\n";




# Subroutine for parsing
sub parse {
	
	$posd = index($line, " ");
	$host = substr($line, 0, $posd);

	$posr = index($line, " ", $posd + 1);
	$rfc = substr($line, $posd + 1, $posr - $posd);

	$posa = index($line, " ", $posr + 1);
	$user = substr($line, $posr + 1, $posa - $posr);

	$posmb = index($line, '[');
	$posme = index($line, ']');
	$moment = substr($line, $posmb + 1, $posme - $posmb - 1);

	$date = substr($moment, 0, 11);
	$time = substr($moment, 12, 8);

	$request = substr($line, $posme + 2, length($line) - $posme + 1);
	chop($request);
	}


#Subroutine for creating a new trasaction
sub new {
	$st = $#trans + 1;
	$kk = $numtrans + 1;
	$trans[$st] = "*$kk";
	$trans[$st + 1] = $host;
	$trans[$st + 2] = $rfc;
	$trans[$st + 3] = $user;
	$trans[$st + 4] = 1;
	$trans[$st + 5] = $trans[$st + 6] = $date;
	$trans[$st + 7] = $trans[$st + 8] = $time;
	$trans[$st + 9] = 0;
	if ($request =~ /\.gif/) {
		$trans[$st + 10] = 1;
		}
	else {
		$trans[$st + 10] = 0;
		}
	$trans[$st + 11] = $request;
	$trans[$st + 12] = " ";
	}
	
	
# Subroutine for inserting a request into an existing transaction
sub insert {

	for ($ii = $#trans; $ii >= ($next + 1); $ii--) {
		$trans[$ii + 1] = $trans[$ii];
		}

	$trans[$where + 4]++;
	$trans[$where + 6] = $date;
	$trans[$where + 8] = $time;
	$trans[$where + 9] = &elapsed($trans[$where + 7], $trans[$where + 8]);
	
	if ($request =~ /\.gif/) {
		$trans[$where + 10] = 1;
		}
	
	$trans[$next + 1] = $request;
	
	}
	
	

# Subroutine to check for an existing transaction
sub check_for_exist {

	$dd = $#trans;
	
	foreach $entry (reverse(@trans)) {
	
		if ($entry =~ /^\*/) {
		
			if (($trans[$dd + 1] eq $host) && ($trans[$dd + 3] eq $user) && (&compare_t($trans[$dd + 8], $time, $trans[$dd + 6], $date) )) {
				$where = $dd;
				$next = $dd + 10 + $trans[$dd + 4];
				return (1);
				}
				
			elsif (&datecheck($trans[$dd + 5], $date)) {
				return (0);
				}
		
			}
		$dd--;
		}
	
	return (0);
	
	}
	
	
	
# Subroutine for determining the elapsed time, in seconds
sub elapsed {

	local($lower, $upper) = @_;
	
	$lh = substr($lower, 0, 2);
	$lm = substr($lower, 3, 2);
	$ls = substr($lower, 6, 2);
	
	$uh = substr($upper, 0, 2);
	$um = substr($upper, 3, 2);
	$us = substr($upper, 6, 2);
	
	$lt = $ls + ($lm * 60) + ($lh * 3600);
	$ut = $us + ($um * 60) + ($uh * 3600);
	
	$diff = $ut - $lt;
	
	}
	
	

# Subroutine for comparingnew time to trans time, to determine if new transaction
sub compare_t {

	local($endtime, $newtime, $enddate, $newdate) = @_;
	
	if ($newdate eq $enddate) {
		if (&elapsed($endtime, $newtime) <= $gap * 60) {
			return (1);
			}
		}
		
	else {
		$endday = substr($enddate, 0, 2);
		$endmo = substr($enddate, 3, 3);
		$newday = substr($newdate, 0, 2);
		$newmo = substr($newdate, 3, 3);
		
		if (($endmo eq $newmo) && ($newday eq ($endday + 1)) && ((&elapsed($endtime, $newtime) + 86400) <= $gap * 60)) {
			return (1);
			}
		else {
			return (0);
			}
		}
		
	}
	
# Subroutine for checking if date is two or more days old
sub datecheck {

	local($enddate, $newdate) = @_;
	
	$endday = substr($enddate, 0, 2);
	$endmo = substr($enddate, 3, 3);
	$newday = substr($newdate, 0, 2);
	$newmo = substr($newdate, 3, 3);
	
	return (($endmo eq $newmo) && ($newday >= $endday + 2));
	
	}
