#!/usr/bin/perl

# squidtaild V2.1a6
# Written by Maurice Smiley
# msmiley@gie.com
# Gulf Interstate Engineering
# 1700 West Loop South, Suite 600
# Houston, TX 77027

# --- Version info ---

# squidtaild Version 2.1a3 
# Trailer conversion to Perl by Maurice Smiley
# of Gulf Interstate Engineering.
# 11/01/99.
# Hopefully it does justice to the work of the
# original author, Stefan Folkerts.

# 01/04/2000 - 2.1a4
# - Fixed excludes bug where only one item would be
# excluded even though more than one item was listed.
# - Matches are now case insensitive for all filters.

# 01/10/2000 - 2.1a5
# - Added mailstyle configuration directive, allowing
# users to choose between html and plaintext email
# reporting.

# 03/01/2000 - 2.1a6
# - Removed Proc::Daemon and replaced code with
# stock Perl code.  This should improve reliability,
# as Proc::Daemon was just too finicky.  Also, 
# people were having problems getting squidtaild
# to work with it.  It is GONE!
# - Fixed writing the first entry in the log file
# twice on startup.
# - Fixed "list of violators" not being properly
# updated after the initial run.
# - Fixed non-functional pieces of the startup
# script (/etc/rc.d/init.d/squidtaild).
# - Fixed the detection of existing files while
# in incremental mode, and reuses them.   
# - Moved some code to their own separate functions
# to avoid duplication of effort.
# - Added configuration directives, 'truncate_url'
# and 'urllength' to allow the user to specify
# how many characters of a url to display on
# the status page.
# - Added configuration directive 'dnslookups'
# for ip address to hostname lookups.
# Applied user submitted patch, fixing a typo
# where 'mailto://' should have been 'mailto:'


# --- End version info ---

use Socket;
use ConfigReader::Simple;


#############################################
#			Begin subroutines				#
#############################################

#
# parse the log file subroutine
#

sub parse_log {
	$exclude_flag = 0;
	foreach $exc_filterword (@exc_filteredwords){
		if ($location =~ /$exc_filterword/i){
			$exclude_flag = 1;	
		}
	}
	if ($exclude_flag ne 1) {
			
			foreach $def_filterword (@def_filteredwords) {
				if ($location =~ /$def_filterword/i) {
					if ($match ne "") {
						last;
					}
					else {
						$match = $location;
					}		
					$violator{$ip_address} = "$ip_address\t"."$location\t"."$timedate\t"."red";
					$def_ip_address = $ip_address;
					$def_location = $location;
					$def_num_violations += 1;
					$def_violation_date = scalar localtime ($timedate);
					
					# update the last_def file...
					$last_def_file = "/etc/squidtaild/last_definite";
					open (LAST_DEF, "> $last_def_file") or die ("$0: Cannot open \"$last_def_file\": $!~\n");
					select LAST_DEF;
					print "$def_ip_address\t$def_location\t$timedate\n";
					select STDOUT;
					close LAST_DEF;
						
					# send the user or admin or both a popup message		
					if ($winpopups eq "yes") {
						if ($winpopup_users eq "yes"){
							$ip = inet_aton($def_ip_address);
							$fullname = (gethostbyaddr($ip, AF_INET))[0];
							$_ = $fullname;
							($hostname, $domain, $type) = split(/\./,$_,3);
							system "echo $user_msg | $smbclient -M $hostname";
						}
						if ($winpopup_admin eq "yes"){
							system "echo $admin_msg | $smbclient -M $admin_computer";
						}
					}
					
					# send the administrator an email
					if ($mailreport eq "yes"){
						if ($mailstyle eq "html"){
							open (SM, "| $sendmail -bm -t");
							select SM;
							print "To: $mailto\n";
							print "Subject: squidtaild violation from $ip_address\n";
							print "Content-Type: text/html;\n";
							print "\n";
							print "<html><head><title>squidtaild violation alert</title></head><body>\n";
							print "<h2>The following violation has just occurred:</h2>\n";
							print "<br><br>\n";							
							print "<table width = \"100%\" border = \"0\" cellpadding = \"2\" cellspacing = \"0\">\n";
							print "<tr><td align = left bgcolor = \"#999999\"><b>Date/Time Occurred</b></td>
							<td align = left bgcolor = \"#999999\">";
							print "<b>IP Address</b></td><td align = left bgcolor = \"#999999\"><b>URL</b></td></tr>";
							print "<tr>";
							print "<td align = left bgcolor = \"#cccccc\" nowrap><font color = \"#ff0000\">$def_violation_date</font></td>";
							print "<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$ip_address.html\">
							<font color = \"#ff0000\">$ip_address</font></a></td>";
							print "<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$location\">
							<font color = \"#ff0000\">$location</font></a></td>";
							print "</tr></table>\n";
							print "<br><br>\n";	
							print "<hr>\n";	
							print "<br><br>\n";
							print "For a complete breakdown of all violations, see <a href = \"$url\">$url</a>\n";
							print "</body></html>\n";
							select STDOUT;
							close SM;
						}
						if ($mailstyle ne "html"){
							open (SM, "| $sendmail -bm -t");
							select SM;
							print "To: $mailto\n";
							print "Subject: squidtaild violation from $ip_address\n";
							print "\n";
							print "The following violation has just occured:\n";
							print "\n\n";
							print "$def_violation_date --> $ip_address --> $location\n";
							print "\n\n";
							print "For a complete breakdown of all violations, see $url\n";
							select STDOUT;
							close SM;
						}
					}	

					# write an entry in the violations page...
					# but first, whack the </table> entry...
					open (VIOLOG, "+<$violations_file") or die ("$0: Cannot open \"$violations_file\": $!~\n");
					seek VIOLOG, -9, 2;
					select VIOLOG;
					print "<tr>";
					print "<td align = left bgcolor = \"#cccccc\" nowrap><font color = \"#ff0000\">$def_violation_date </font></td>";
					print "<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$ip_address.html\">
					<font color = \"#ff0000\">$ip_address</font></a></td>";
					print "<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$location\">
					<font color = \"#ff0000\">$location</font></a></td>";
					print "</tr>\n";
					print "</table>\n";
					select STDOUT;
					close VIOLOG;

					# write an entry in the definite violations page...
					# but first, whack the </table> entry...
					open (DEFLOG, "+<$def_violations_file") or die ("$0: Cannot open \"$def_violations_file\": $!~\n");
					seek DEFLOG, -9, 2;
					select DEFLOG;
					print "<tr><td align = left bgcolor = \"#cccccc\" nowrap>$def_violation_date</td>
					<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$ip_address.html\">$ip_address</a></td>
					<td align = left bgcolor = \"#cccccc\" nowrap><a  href = \"$location\">$location</a></td></tr>\n";
					print "</table>\n";
					select STDOUT;
					close DEFLOG;
			
					# write an entry in the offender's file...
					$offender_file = "$htmldir"."$ip_address".".html";
											
					# if the offender doesn't already have a file, set one up...
					if (! -f $offender_file){
						open (OFFEND, ">$offender_file") or die ("$0: Cannot open \"$offender_file\": $!~\n");
						chmod 0644, $offender_file;
						select OFFEND;
						print "<html>";
						print "<head>";
						print "<title>Violations from $ip_address</title>\n";
						print "<meta http-equiv=pragma content = no-cache>\n";
						print "<meta http-equiv=refresh content = 60>\n";
						print "</head>\n";
						print "<body bgcolor=\"#ffffff\" text=\"#000000\">\n";
						print "<center><h1>Violations from $ip_address</h1></center><p>\n";
						print "<center><h4>Violations as of $start_date</h4></center><p>\n";
						print "<table width = \"100%\" border = \"0\" cellpadding = \"2\" cellspacing = \"0\">";
						print "<tr><td align = left bgcolor = \"#999999\"><b>Date/Time Occurred</b></td>
						<td align = left bgcolor = \"#999999\"><b>URL</b></td></tr>";
						print "<tr><td align = left bgcolor = \"#cccccc\"
						nowrap>
						<font color = \"#ff0000\">$def_violation_date></font></td><td align = left bgcolor = \"#cccccc\" nowrap>
						<a href = \"$location\"><font color = \"#ff0000\">$location</font></a>\n";
						print "</table>\n";
						select STDOUT;
						close OFFEND;
					}

					# if the offender already has a file, write some more...
					# but first, whack the </table> entry...
					else {
						open (OFFEND, "+<$offender_file") or die ("$0: Cannot open \"$offender_file\": $!~\n");
						seek OFFEND, -9, 2;
						select OFFEND;
						print "<tr><td align = left bgcolor = \"#cccccc\"
						nowrap>
						<font color = \"#ff0000\">$def_violation_date</font></td><td align = left bgcolor = \"#cccccc\" nowrap>
						<a href = \"$location\"><font color = \"#ff0000\">$location</font></a>\n";
						print "</table>";
						select STDOUT;
						close OFFEND;
					}
				}
			}
			foreach $prob_filterword (@prob_filteredwords) {
				if ($location =~ /$prob_filterword/i) {
					if ($match ne "") {
						last;
					}
					else {
						$match = $location;
					}				
					$violator{$ip_address} = "$ip_address\t"."$location\t"."$timedate\t"."yellow";
					$prob_ip_address = $ip_address;
					$prob_location = $location;
					$prob_num_violations += 1;
					$prob_violation_date = scalar localtime ($timedate);
					
					# update the last_prob file...
					open (LAST_PROB, "> $last_prob_file") or die ("$0: Cannot open \"$last_prob_file\": $!~\n");
					select LAST_PROB;
					print "$prob_ip_address\t$prob_location\t$timedate\n";
					select STDOUT;
					close LAST_PROB;
													
					# write an entry in the violations page...
					# but first, whack the </table> entry...
					open (VIOLOG, "+<$violations_file") or die ("$0: Cannot open \"$violations_file\": $!~\n");
					seek VIOLOG, -9, 2;
					select VIOLOG;
					print "<tr>";
					print "<td align = left bgcolor = \"#cccccc\" nowrap><font color = \"#ffff00\">
					$prob_violation_date</font></td>";
					print "<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$ip_address.html\">
					<font color = \"#ffff00\">$ip_address</font></a></td>";
					print "<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$location\">
					<font color = \"#ffff00\">$location</font></a></td>";
					print "</tr>\n";
					print "</table>\n";
					select STDOUT;
					close VIOLOG;

					# write an entry in the probable violations page...
					# but first, whack the </table> entry...
					open (PROBLOG, "+<$prob_violations_file") or die ("$0: Cannot open \"$prob_violations_file\": $!~\n");
					seek PROBLOG, -9, 2;
					select PROBLOG;
					print "<tr><td align = left bgcolor = \"#cccccc\" nowrap>$prob_violation_date</td>
					<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$ip_address.html\">$ip_address</a></td>
					<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$location\">$location</a></td></tr>\n";
					print "</table>\n";
					select STDOUT;
					close PROBLOG;
		
					# write an entry in the offender's file...
					$offender_file = "$htmldir"."$ip_address".".html";
							
					# if the offender doesn't already have a file, set one up...
					if (! -f $offender_file){
						open (OFFEND, ">$offender_file") or die ("$0: Cannot open \"$offender_file\": $!~\n");
						chmod 0644, $offender_file;
						select OFFEND;
						print "<html>";
						print "<head>";
						print "<title>Violations from $ip_address</title>\n";
						print "<meta http-equiv=pragma content = no-cache>\n";
						print "<meta http-equiv=refresh content = 60>\n";
						print "</head>\n";
						print "<body bgcolor=\"#ffffff\" text=\"#000000\">\n";
						print "<center><h1>Violations from $ip_address</h1></center><p>\n";
						print "<center><h4>Violations as of $start_date</h4></center><p>\n";
						print "<table width = \"100%\" border = \"0\" cellpadding = \"2\" cellspacing = \"0\">";
						print "<tr><td align = left bgcolor = \"#999999\" nowrap><b>Date/Time Occurred</b></td>
						<td align = left bgcolor = \"#999999\"><b>URL</b></td></tr>";
						print "<tr><td align = left bgcolor = \"#cccccc\"
						nowrap>
						<font color = \"#ffff00\">$prob_violation_date</font></td><td align = left bgcolor = \"#cccccc\" nowrap>
						<a href = \"$location\"><font color = \"#ffff00\">$location</font></a>\n";
						print "</table>\n";
						select STDOUT;
						close OFFEND;
					}
				
					# if the offender already has a file, write some more...
					# but first, whack the </table> entry...
					else {	
						open (OFFEND, "+<$offender_file") or die ("$0: Cannot open \"$offender_file\": $!~\n");
						seek OFFEND, -9, 2;
						select OFFEND;
						print "<tr><td align = left bgcolor = \"#cccccc\"
						nowrap>
						<font color = \"#ffff00\">$prob_violation_date</font></td><td align = left bgcolor = \"#cccccc\" nowrap>
						<a href = \"$location\"><font color = \"#ffff00\">$location</font></a>\n";
						print "</table>";
						select STDOUT;
						close OFFEND;
					}
				}
			}		
			foreach $poss_filterword (@poss_filteredwords) {
				if ($location =~ /$poss_filterword/i) {
					if ($match ne "") {
						last;
					}
				else {
					$match = $location;
				}	
				$violator{$ip_address} = "$ip_address\t"."$location\t"."$timedate\t"."green";
				$poss_ip_address = $ip_address;
				$poss_location = $location;
				$poss_num_violations += 1;
				$poss_violation_date = scalar localtime ($timedate);
				
				# update the last_poss file...
				open (LAST_POSS, "> $last_poss_file") or die ("$0: Cannot open \"$last_poss_file\": $!~\n");
				select LAST_POSS;
				print "$poss_ip_address\t$poss_location\t$timedate\n";
				select STDOUT;
				close LAST_POSS;
												
				# write an entry in the violations page...
				# but first, whack the </table> entry...
				open (VIOLOG, "+<$violations_file") or die ("$0: Cannot open \"$violations_file\": $!~\n");
				seek VIOLOG, -9, 2;
				select VIOLOG;
				print "<tr>";
				print "<td align = left bgcolor = \"#cccccc\" nowrap><font color = \"#006600\">$poss_violation_date</font></td>";
				print "<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$ip_address.html\">
				<font color = \"#006600\">$ip_address</font></a></td>";
				print "<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$location\">
				<font color = \"#006600\">$location</font></a></td>";
				print "</tr>\n";
				print "</table>\n";
				select STDOUT;
				close VIOLOG;

				# write an entry in the  possible violations page...
				# but first, whack the </table> entry...
				open (POSSLOG, "+<$poss_violations_file") or die ("$0: Cannot open \"$poss_violations_file\": $!~\n");
				seek POSSLOG, -9, 2;
				select POSSLOG;
				print "<tr><td align = left bgcolor = \"#cccccc\" nowrap>$poss_violation_date</td>
				<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$ip_address.html\">$ip_address</a></td>
				<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$location\">$location</a></td></tr>\n";
				print "</table>\n";
				select STDOUT;
				close POSSLOG;
			
				# write an entry in the offender's file...
				$offender_file = "$htmldir"."$ip_address".".html";
								
				# if the offender doesn't already have a file, set one up...
				if (! -f $offender_file){
					open (OFFEND, ">$offender_file") or die ("$0: Cannot open \"$offender_file\": $!~\n");
					chmod 0644, $offender_file;
					select OFFEND;
					print "<html>";
					print "<head>";
					print "<title>Violations from $ip_address</title>\n";
					print "<meta http-equiv=pragma content = no-cache>\n";
					print "<meta http-equiv=refresh content = 60>\n";
					print "</head>\n";
					print "<body bgcolor=\"#ffffff\" text=\"#000000\">\n";
					print "<center><h1>Violations from $ip_address</h1></center><p>\n";
					print "<center><h4>Violations as of $start_date</h4></center><p>\n";
					print "<table width = \"100%\" border = \"0\" cellpadding = \"2\" cellspacing = \"0\">";
					print "<tr><td align = left bgcolor = \"#999999\"><b>Date/Time Occurred</b></td>
					<td align = left bgcolor = \"#999999\"><b>URL</b></td></tr>";
					print "<tr><td align = left bgcolor = \"#cccccc\" nowrap>
					<font color = \"#006600\">$poss_violation_date</font></td><td align = left bgcolor = \"#cccccc\" nowrap>
					<a href = \"$location\"><font color = \"#006600\">$location</font></a>\n";
					print "</table>\n";
					select STDOUT;
					close OFFEND;
				}
			
				# if the offender already has a file, write some more...
				# but first, whack the </table> entry...
				else {	
					open (OFFEND, "+<$offender_file") or die ("$0: Cannot open \"$offender_file\": $!~\n");
					seek OFFEND, -9, 2;
					select OFFEND;
					print "<tr><td align = left bgcolor = \"#cccccc\" nowrap>
					<font color = \"#006600\">$poss_violation_date</font></td><td align = left bgcolor = \"#cccccc\" nowrap>
					<a href = \"$location\"><font color = \"#006600\">$location</font></a>\n";
					print "</table>";
					select STDOUT;
					close OFFEND;
				}
		   }
     }
	    undef $match;		
	 }
  }
#
# update the status page subroutine
#
sub status_write {
	seek SQUIDLOG,0,1;
	
	# update the status page...
	$status_file = "$htmldir"."index.html";
	$date = scalar localtime;
	
	# read from the history and last violations files, if incremental...
	if ($incremental eq "yes") {

		# get history...
		open (HISTORY, "< $history_file") or die ("$0: Cannot open \"$history_file\": $!~\n");
		while (<HISTORY>){
			chop;
			($last_timedate, $poss_num_violations, $prob_num_violations, 
			$def_num_violations)= split(/\s+/);
		}
		close HISTORY;
		
		# read in last violations files...
		open (LAST_DEF, "$last_def_file") or die ("$0: Cannot open \"$last_def_file\": $!~\n");
		while (<LAST_DEF>){
			chop;
			($def_ip_address, $def_location, $def_vio_date) = split(/\s+/);
			$def_violation_date = scalar localtime($def_vio_date);
		}
		close LAST_DEF;
		open (LAST_PROB, "$last_prob_file") or die ("$0: Cannot open \"$last_prob_file\": $!~\n");
		while (<LAST_PROB>){
			chop;
			($prob_ip_address, $prob_location, $prob_vio_date) = split(/\s+/);
			$prob_violation_date = scalar localtime($prob_vio_date);
		}
		close LAST_PROB;
		open (LAST_POSS, "$last_poss_file") or die ("$0: Cannot open \"$last_poss_file\": $!~\n");
		while (<LAST_POSS>){
			chop;
			($poss_ip_address, $poss_location, $poss_vio_date) = split(/\s+/);
			$poss_violation_date = scalar localtime($poss_vio_date);
		}
		close LAST_POSS;
}

	# update the violators file...
	@violators = values(%violator);
	open (VIOLATORS, "> $violators_file") or die ("$0: Cannot open \"$violators_file\": $!~\n");
	foreach $offender (@violators){
		select VIOLATORS;
		print "$offender\n";
	}
	close VIOLATORS;
	$total_num_violations = ($poss_num_violations + $prob_num_violations + $def_num_violations);
	open (STATUS, ">$status_file") or die  ("$0: Cannot open \"$status_file\": $!~\n");
	chmod 0644, $status_file;
	select STATUS;
	print "<head>";
	print "<title>squidtaild Status Page</title>\n";
	print "<meta http-equiv=pragma content = no-cache>\n";
	if ($refresh ne 0){
		print "<meta http-equiv=refresh content = $refresh>\n";
	}
	print "</head>\n";
	print "<body bgcolor=\"#ffffff\" text=\"#000000\">\n";
	print "<center><h1>Squidtaild status as of $date</h1></center><p>\n";
	print "<br><br>\n";
	print "<b>Log file being watched is:</b> $squidlog<br><br>\n";
	print "<b>Violations are being sent to:</b> <a href=mailto\:$mailto>$mailto</a><br><br>\n";
	print "<br><br>\n";

	#
	# List of violation numbers and links to appropriate pages
	#
	print "<table width = \"100%\" border = \"0\" cellpadding = \"2\" cellspacing = \"0\">\n";
	print "<th align = left><b>Breakdown of violations:</b></th>\n";
	print "<tr><td align = center bgcolor = \"#999999\"><b>Total Hits</b></td>";
	print "<td align = center bgcolor = \"#999999\"><font color = \"#006600\"><b>Possible Hits</b></font></td>";
	print "<td align = center bgcolor = \"#999999\"><font color = \"#ffff00\"><b>Probable Hits</b></font></td>";
	print "<td align = center bgcolor = \"#999999\"><font color = \"#ff0000\"><b>Definite Hits</font></b></td><tr>\n";
	print "<tr><td align = center bgcolor = \"#cccccc\" nowrap><a href = \"violations.html\">$total_num_violations</a></td>";
	if ($poss_num_violations > 0){
		print "<td align = center bgcolor = \"#cccccc\" nowrap><a href = \"possible_violations.html\">$poss_num_violations</a></td>";
	}
	else {
		print "<td align = center bgcolor = \"#cccccc\" nowrap>None</td>";
	}
	if ($prob_num_violations > 0){
		print "<td align = center bgcolor = \"#cccccc\" nowrap><a href = \"probable_violations.html\">$prob_num_violations</a></td>";
	}
	else {
		print "<td align = center bgcolor = \"#cccccc\" nowrap>None</td>";
	}
	if ($def_num_violations > 0){
		print "<td align = center bgcolor = \"#cccccc\" nowrap>
		<a href = \"definite_violations.html\">$def_num_violations</a></tc></tr>\n";
	}
	else {
		print "<td align = center bgcolor = \"#cccccc\" nowrap>None</td>";
	}
	print "</table>\n";
	print "<br><br><br><hr>\n";
	print "<br><br><br>\n";

	#
	# Last Green, Yellow, and Red violation with links to the appropriate pages
	#



	# lookup ip addresses if requested		
	if ($dnslookups eq "yes"){
		$ip = inet_aton($poss_ip_address);
		$fullname = (gethostbyaddr($ip, AF_INET))[0];
		$_ = $fullname;
		($hostname, $domain, $type) = split(/\./,$_,3);
		if ($hostname ne ""){
			$dns_poss_ip_address=$hostname;
		}
		else {
			$dns_poss_ip_address=$poss_ip_address;
		}	

		$ip = inet_aton($prob_ip_address);
		$fullname = (gethostbyaddr($ip, AF_INET))[0];
		$_ = $fullname;
		($hostname, $domain, $type) = split(/\./,$_,3);
		if ($hostname ne ""){
			$dns_prob_ip_address=$hostname;
		}
		else {
			$dns_prob_ip_address=$prob_ip_address;
		}	

		$ip = inet_aton($def_ip_address);
		$fullname = (gethostbyaddr($ip, AF_INET))[0];
		$_ = $fullname;
		($hostname, $domain, $type) = split(/\./,$_,3);
		if ($hostname ne ""){
			$dns_def_ip_address=$hostname;
		}
		else {
			$dns_def_ip_address=$def_ip_address;
		}	
	}
	else {
		$dns_poss_ip_address=$poss_ip_address;
		$dns_prob_ip_address=$prob_ip_address;
		$dns_def_ip_address=$prob_ip_address;
	}

	#truncate the GREEN, YELLOW, and RED urls if requested 
	if ($truncate_url eq "yes") {
		$trunc_poss_location=substr($poss_location, 0, $url_length);
		$trunc_prob_location=substr($prob_location, 0, $url_length);
		$trunc_def_location=substr($def_location, 0, $url_length);
	
 		if (length($trunc_poss_location) lt length($poss_location)){
			$possdots="...";
		}
		else {
			$possdots="";
		}
	
 		if (length($trunc_prob_location) lt length($prob_location)){
			$probdots="...";
		}
		else {
			$probdots="";
		}
	
		if (length($trunc_def_location) lt length($def_location)){
			$defdots="...";
		}
		else {
			$defdots="";
		}
	}
	else {
		$trunc_poss_location=$poss_location;
		$trunc_prob_location=$prob_location;
		$trunc_def_location=$def_location;
	}

	print "<table width = \"100%\" border = \"0\" cellpadding = \"2\" cellspacing = \"0\">\n";
	print "<th align = left><b>Last violation:</b></th>\n";
	print "<tr><td align = left bgcolor = \"#999999\"></td><td align = left bgcolor = \"#999999\"><b>IP Address</b></td>
	<td align = left bgcolor = \"#999999\"><b>URL</b></td><td align = left bgcolor = \"#999999\"><b>Time/Date</b></td><tr>\n";
	if ($poss_ip_address ne ""){
		print "<tr><td align = left bgcolor = \"#cccccc\"><font color = \"#006600\">Possible</font></td>
		<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$poss_ip_address.html\">
		<font color = \"#006600\">$dns_poss_ip_address</font></a></td><td align = left bgcolor = \"#cccccc\" nowrap>
		<a href= \"$poss_location\"><font color = \"#006600\">$trunc_poss_location$possdots</font></a></td>
		<td align = left bgcolor = \"#cccccc\" nowrap><font color = \"#006600\" nowrap>$poss_violation_date</font></td></tr>\n";
	}
	else {
		print "<tr><td align = left bgcolor = \"#cccccc\"><font color = \"#006600\">Possible</font></td>
		<td align = left bgcolor = \"#cccccc\"><font color = \"#006600\">None</font></td>
		<td align = left bgcolor = \"#cccccc\"><font color = \"#006600\">None</font></td>
		<td align = left bgcolor = \"#cccccc\"><font color = \"#006600\">None</font></td></tr>\n";	
	}
	if ($prob_ip_address ne ""){
		print "<tr><td align = left bgcolor = \"#cccccc\"><font color = \"#ffff00\">Probable</font></td>
		<td align = left bgcolor = \"#cccccc\" nowrap> <a href = \"$prob_ip_address.html\">
		<font color = \"#ffff00\">$dns_prob_ip_address</font></a></td><td align = left bgcolor = \"#cccccc\" nowrap>
		<a href = \"$prob_location\"><font color = \"#ffff00\">$trunc_prob_location$probdots</font></a></td>
		<td align = left bgcolor = \"#cccccc\" nowrap><font color = \"#ffff00\" nowrap>$prob_violation_date</font></td></tr>\n";	
	}
	else {
		print "<tr><td align = left bgcolor = \"#cccccc\"><font color = \"#ffff00\">Probable</font></td>
		<td align = left bgcolor = \"#cccccc\"><font color = \"#ffff00\">None</font></td>
		<td align = left bgcolor = \"#cccccc\"><font color = \"#ffff00\">None</font></td>
		<td align = left bgcolor = \"#cccccc\"><font color = \"#ffff00\">None</font></td></tr>\n";	
	}
	if ($def_ip_address ne ""){
		print "<tr><td align = left bgcolor = \"#cccccc\"><font color = \"#ff0000\">Definite</font></td>
		<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$def_ip_address.html\">
		<font color = \"#ff0000\">$dns_def_ip_address</font></a></td><td align = left bgcolor = \"#cccccc\" nowrap>
		<a href = \"$def_location\"><font color = \"#ff0000\">$trunc_def_location$defdots</font></a></td>
		<td align = left bgcolor = \"#cccccc\" nowrap><font color = \"#ff0000\" nowrap>$def_violation_date</font></td></tr>\n";
	}
	else {
		print "<tr><td align = left bgcolor = \"#cccccc\"><font color = \"#ff0000\">Definite</font></td>
		<td align = left bgcolor = \"#cccccc\"><font color = \"#ff0000\">None</font></td>
		<td align = left bgcolor = \"#cccccc\"><font color = \"#ff0000\">None</font></td>
		<td align = left bgcolor = \"#cccccc\"><font color = \"#ff0000\" nowrap>None</font></td></tr>\n";
	}
	print "</table>\n";
	print "<br><br><br><hr>\n";
	print "<br><br><br>\n";

	#
	# IP addresses of violators with their last violation listed
	#
	undef @violator;
	undef @violators;
	undef @offender;
	open (VIOLATORS, "< $violators_file") or die ("$0: Cannot open \"$violators_file\": $!~\n");
	while (<VIOLATORS>){
		chop;
		($violator_ip, $violator_location, $violator_date, $violator_color) = split(/\s+/);
		if ($violator_ip ne "Violator_IP"){
			$violator{$violator_ip} = "$violator_ip\t"."$violator_location\t"."$violator_date\t"."$violator_color";
		}		
	}
	print "<table width = \"100%\" border = \"0\" cellpadding = \"2\" cellspacing = \"0\">\n";
	print "<th align = left><b>List of violators:</b></th>\n";
	print "<tr><td align = left bgcolor = \"#999999\"><b>IP Address</b></td><td align = left bgcolor = \"#999999\">
	<b>Last URL violation</b></td>";
	print "<td align = left bgcolor = \"#999999\"><b>Time visited</b></td></tr>\n";
	@violators = values(%violator);
	foreach $offender (@violators){
		$_ = $offender;
		($violator_ip, $violator_location, $violator_date, $violator_color) = split (/\t/);
		$violator_timedate = scalar localtime($violator_date);
	
		# lookup ip addresses if requested		
		if ($dnslookups eq "yes"){
			$ip = inet_aton($violator_ip);
			$fullname = (gethostbyaddr($ip, AF_INET))[0];
			$_ = $fullname;
			($hostname, $domain, $type) = split(/\./,$_,3);
			if ($hostname ne ""){
				$dns_violator_ip=$hostname;
			}
			else {
				$dns_violator_ip=$violator_ip;
			}	
		}
		else {
			$dns_violator_ip=$violator_ip;
		}
	
		#truncate the url if requested 
		if ($truncate_url eq "yes") {
			$trunc_location=substr($violator_location, 0, $url_length);
			if (length($trunc_location) lt length($violator_location)){
				$adddots="...";
			}
			else {
				$adddots="";
			}
		}
		else {
			$trunc_location=$violator_location;
		}

		print "<tr><td align = left bgcolor = \"#cccccc\" nowrap>";
		if ($violator_color eq "red"){
			print "<a href = \"$violator_ip.html\"><font color = \"#ff0000\">$dns_violator_ip</font></a></td>
			<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$violator_location\">
			<font color = \"#ff0000\">$trunc_location$adddots</font></a></td><td align = left bgcolor = \"#cccccc\" nowrap>
			<font color = \"#ff0000\">$violator_timedate</font></td></tr>\n";
		}
		elsif ($violator_color eq "yellow"){
			print "<a href = \"$violator_ip.html\"><font color = \"#ffff00\">$dns_violator_ip</font></a></td>
			<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$violator_location\">
			<font color = \"#ffff00\">$trunc_location$adddots</font></a></td><td align = left bgcolor = \"#cccccc\" nowrap>
			<font color = \"#ffff00\">$violator_timedate</font></td></tr>\n";	
		}
		elsif ($violator_color eq "green"){
			print "<a href = \"$violator_ip.html\"><font color = \"#006600\">$dns_violator_ip</font></a></td>
			<td align = left bgcolor = \"#cccccc\" nowrap><a href = \"$violator_location\">
			<font color = \"#006600\">$trunc_location$adddots</font></a></td><td align = left bgcolor = \"#cccccc\" nowrap>
			<font color = \"#006600\">$violator_timedate</font></td></tr>\n";
		}
	}
	select STATUS;
	print "</table>\n";
	print "<br><br><br><hr>\n";
	print "<br><br><br>\n";
	print "<center>For information please contact <a href=mailto\:$mailto>$mailto</a></center>\n";
	select STDOUT;
	close STATUS;
	sleep 10;
}

sub violations_setup {
	open (VIOLOG, ">$violations_file") or die("$0: Cannot open \"$violations_file\" :$!~\n");
	chmod 0644, $violations_file;
	select VIOLOG;
	print "<html>";
	print "<head>";
	print "<title>Violations Page</title>\n";
	print "<meta http-equiv=pragma content = no-cache>\n";
	print "<meta http-equiv=refresh content = 60>\n";
	print "</head>\n";
	print "<body bgcolor=\"#ffffff\" text=\"#000000\">\n";
	print "<center><h1>Violations Page</h1></center><p>\n";
	print "<center><h4>Violations as of $start_date</h4></center><p>\n";
	print "<table width = \"100%\" border = \"0\" cellpadding = \"2\" cellspacing = \"0\">\n";
	print "<td align = left bgcolor = \"#999999\"><b>Date/Time Occurred</b></td>
	<td align = left bgcolor = \"#999999\"><b>IP Address</b></td><td align = left bgcolor = \"#999999\"><b>URL</b></td>";
	select STDOUT;
	close VIOLOG;
}

sub poss_violations_setup {
	open (POSSLOG, ">$poss_violations_file") or die("$0: Cannot open \"$poss_violations_file\" :$!~\n");
	chmod 0644, $poss_violations_file;
	select POSSLOG;
	print "<html>";
	print "<head>";
	print "<title>Possible Violations Page</title>\n";
	print "<meta http-equiv=pragma content = no-cache>\n";
	print "<meta http-equiv=refresh content = 60>\n";
	print "</head>\n";
	print "<body bgcolor=\"#ffffff\" text=\"#000000\">\n";
	print "<center><h1>Possible Violations Page</h1></center><p>\n";
	print "<center><h4>Possible Violations as of $start_date</h4></center><p>\n";
	print "<table width = \"100%\" border = \"0\" cellpadding = \"2\" cellspacing = \"0\">\n";
	print "<td align = left bgcolor = \"#999999\"><b>Date/Time Occurred</b></td>
	<td align = left bgcolor = \"#999999\"><b>IP Address</b></td><td align = left bgcolor = \"#999999\"><b>URL</b></td>";
	select STDOUT;
	close POSSLOG;
}
		
sub prob_violations_setup {
	open (PROBLOG, ">$prob_violations_file") or die("$0: Cannot open \"$prob_violations_file\" :$!~\n");
	chmod 0644, $prob_violations_file;
	select PROBLOG;
	print "<html>";
	print "<head>";
	print "<title>Probable Violations Page</title>\n";
	print "<meta http-equiv=pragma content = no-cache>\n";
	print "<meta http-equiv=refresh content = 60>\n";
	print "</head>\n";
	print "<body bgcolor=\"#ffffff\" text=\"#000000\">\n";
	print "<center><h1>Probable Violations Page</h1></center><p>\n";
	print "<center><h4>Probable Violations as of $start_date</h4></center><p>\n";
	print "<table width = \"100%\" border = \"0\" cellpadding = \"2\" cellspacing = \"0\">\n";
	print "<td align = left bgcolor = \"#999999\"><b>Date/Time Occurred</b></td>
	<td align = left bgcolor = \"#999999\"><b>IP Address</b></td><td align = left bgcolor = \"#999999\"><b>URL</b></td>";
	select STDOUT;
	close PROBLOG;	
}	
		
sub def_violations_setup {
	open (DEFLOG, ">$def_violations_file") or die("$0: Cannot open \"$def_violations_file\" :$!~\n");
	chmod 0644, $def_violations_file;
	select DEFLOG;
	print "<html>";
	print "<head>";
	print "<title>Definite Violations Page</title>\n";
	print "<meta http-equiv=pragma content = no-cache>\n";
	print "<meta http-equiv=refresh content = 60>\n";
	print "</head>\n";
	print "<body bgcolor=\"#ffffff\" text=\"#000000\">\n";
	print "<center><h1>Definite Violations Page</h1></center><p>\n";
	print "<center><h4>Definite Violations as of $start_date</h4></center><p>\n";
	print "<table width = \"100%\" border = \"0\" cellpadding = \"2\" cellspacing = \"0\">\n";
	print "<td align = left bgcolor = \"#999999\"><b>Date/Time Occurred</b></td>
	<td align = left bgcolor = \"#999999\"><b>IP Address</b></td><td align = left bgcolor = \"#999999\"><b>URL</b></td>";
	select STDOUT;
	close DEFLOG;
}

sub last_poss_setup {
	open (LAST_POSS, "> $last_poss_file") or die ("$0: Cannot open \"$last_poss_file\": $!~\n");
	select LAST_POSS;
	print "\n";
	select STDOUT;
	close LAST_POSS;
}

sub last_prob_setup {
	open (LAST_PROB, "> $last_prob_file") or die ("$0: Cannot open \"$last_prob_file\": $!~\n");
	select LAST_PROB;
	print "\n";
	select STDOUT;
	close LAST_PROB;
}

sub last_def_setup {
	open (LAST_DEF, "> $last_def_file") or die ("$0: Cannot open \"$last_def_file\": $!~\n");
	select LAST_DEF;
	print "\n";
	select STDOUT;
	close LAST_DEF;
}

sub setup_violators_file {
	open (VIOLATORS, "> $violators_file") or die ("$0: Cannot open \"$violators_file\" :$!~\n");
	select VIOLATORS;
	print "Violator_IP\tViolator_Location\tViolator_Date\tViolator_Color\n";
	select STDOUT;
	close VIOLATORS;
}

sub setup_history_file {
	$poss_num_violations = 0;
	$prob_num_violations = 0;
	$def_num_violations = 0;
	open (HISTORY, "> $history_file") or die ("$0: Cannot open \"$history_file\" :$!~\n");
	select HISTORY;
	print "0\t$poss_num_violations\t$prob_num_violations\t$def_num_violations\t0\n";
	select STDOUT;
	close HISTORY;
}

#########################################
#			End subroutines				#
#########################################

# Parse the config file...
my $config = ConfigReader::Simple->new("/etc/squidtaild/squidtaild.conf",
[qw(url htmldir squidlog mailreport mailstyle mailrecipient excludes possible probable 
definite sendmail incremental winpopups winpopup_users winpopup_admin 
smbclient admin_computer admin_msg user_msg truncate_url url_length refresh
dnslookups)]);

$config->parse();
$url = $config->get("url");
$htmldir = $config->get("htmldir");
$squidlog = $config->get("squidlog");
$excludes = $config->get("excludes");
$possible = $config->get("possible");
$probable = $config->get("probable");
$definite = $config->get("definite");
$sendmail = $config->get("sendmail");
$smbclient = $config->get("smbclient");
$incremental = $config->get("incremental");
$mailstyle = $config->get("mailstyle");
$truncate_url = $config->get("truncate_url");
$url_length = $config->get("url_length");
$refresh = $config->get("refresh");
$dnslookups = $config->get("dnslookups");

if ($incremental ne "yes"){
	$mailreport = $config->get("mailreport");
	$mailto = $config->get("mailrecipient");
	$winpopups = $config->get("winpopups");
	$winpopup_users = $config->get("winpopup_users");
	$winpopup_admin = $config->get("winpopup_admin");
	$admin_computer = $config->get("admin_computer");
	$admin_msg = $config->get("admin_msg");
	$user_msg = $config->get("user_msg");
}

# setup a pid file...
$pid_file = "/var/run/squidtaild.pid";

# Make sure we're not already running...
if (-f $pid_file) {
	open (PID, "<$pid_file") or die("$0: Cannot open \"$pid_file\" :$!~\n");
	while (<PID>){
		chop;
		($session_id) = split (/\n/);
		print "squidtaild appears to be already running --> PID $session_id\n";
		print "If you're sure squidtaild is not running, whack (rm) $pid_file and try again\n";
	}
	close PID;
exit;
}

# Write a pid file if we're not already running...
else {
	open (PID, ">$pid_file") or die("$0: Cannot open \"$pid_file\" :$!~\n");
	$session_id = $$;
	select PID;
	print "$session_id\n";
	select STDOUT;
	close PID;
}

# check for a history file...
$history_file = "/etc/squidtaild/history";
if ($incremental eq "yes") {
	if (! -f $history_file){
		&setup_history_file;
	}
	else {
		open (HISTORY, "< $history_file") or die ("$0: Cannot open \"$history_file\" :$!~\n");
		while (<HISTORY>){
			($last_timedate, $poss_num_violations, $prob_num_violations, $def_num_violations) = split(/\s+/);
		}
	}
}
else {
	&setup_history_file;
}

# check for a violators file...
$violators_file = "/etc/squidtaild/violators";
if ($incremental eq "yes") {
	if (-f $violators_file) {
		open (VIOLATORS, "< $violators_file") or die ("$0: Cannot open \"$violators_file\": $!~\n");
		while (<VIOLATORS>){
			chop;
			($violator_ip, $violator_location, $violator_date, $violator_color) = split(/\s+/);
			if ($violator_ip ne "Violator_IP"){
				$violator{$violator_ip} = "$violator_ip\t"."$violator_location\t"."$violator_date\t"."$violator_color";
			}		
		}
	}
	else {
		&setup_violators_file;
	}
}
else {
		&setup_violators_file;
}

# setup the violations page...
$start_date = scalar localtime;
$violations_file = "$htmldir"."violations.html";
if ($incremental eq "yes"){
	if (-f $violations_file){
	}
	else {
		&violations_setup;
	}
}
else {
	&violations_setup;
}


# setup the possible violations page...
$poss_violations_file = "$htmldir"."possible_violations.html";
if ($incremental eq "yes"){
	if (-f $poss_violations_file){
	}
	else {
		&poss_violations_setup;
	}
}
else {
	&poss_violations_setup;
}

# setup the probable violations page...
$prob_violations_file = "$htmldir"."probable_violations.html";
if ($incremental eq "yes"){
	if (-f $prob_violations_file){
	}	
	else {
		&prob_violations_setup;
	}
}
else {
	&prob_violations_setup;
}


# setup the definite violations page...
$def_violations_file = "$htmldir"."definite_violations.html";
if ($incremental eq "yes") {
	if (-f $def_violations_file){
	}
	else {
		&def_violations_setup;
	}
}
else {
	&def_violations_setup;
}

# read the excludes filter file...
open (FILTER, "<$excludes") or die("$0: Cannot open \"$excludes\" :$!~\n");
while(<FILTER>){
	chop;
	($keyword) = split (/\n/);
	if ($keyword ne ""){
		$exc_filterword{$keyword} = $keyword;
	}
	else {
		break;
	}
}
if ($exc_filterword eq ""){
	$keyword = "NO_EXCLUDES";
	$exc_filterword{$keyword}  = $keyword;
}
@exc_filteredwords = keys(%exc_filterword);
close FILTER;

# read the possible filter file...
open (FILTER, "<$possible") or die("$0: Cannot open \"$possible\" :$!~\n");
while(<FILTER>){
	chop;
	($keyword) = split (/\n/);
	if ($keyword ne ""){
		$poss_filterword{$keyword} = $keyword;
	}
	else {
		break;
	}
}
if ($poss_filterword eq ""){
	$keyword = "NO_POSSIBLES";
	$poss_filterword{$keyword}  = $keyword;
}
@poss_filteredwords = keys(%poss_filterword);
close FILTER;

# read the probable filter file...
open (FILTER, "<$probable") or die("$0: Cannot open \"$probable\" :$!~\n");
while(<FILTER>){
	chop;
	($keyword) = split (/\n/);
	if ($keyword ne ""){
		$prob_filterword{$keyword} = $keyword;
	}
	else {
		break;
	}
}
if ($prob_filterword eq ""){
	$keyword = "NO_PROBABLES";
	$prob_filterword{$keyword}  = $keyword;
}
@prob_filteredwords = keys(%prob_filterword);
close FILTER;

# read the definite filter file...
open (FILTER, "<$definite") or die("$0: Cannot open \"$definite\" :$!~\n");
while(<FILTER>){
	chop;
	($keyword) = split (/\n/);
	if ($keyword ne ""){
		$def_filterword{$keyword} = $keyword;
	}
	else {
		break;
	}
}	

if ($def_filterword eq ""){
	$keyword = "NO_DEFINITES";
	$def_filterword{$keyword}  = $keyword;
}
@def_filteredwords = keys(%def_filterword);
close FILTER;

# setup last hit files...
$last_prob_file = "/etc/squidtaild/last_probable";
if ($incremental eq "yes") {
	if (-f $last_prob_file) {
	}
	else {
		&last_prob_setup;
	}
}
else {
	&last_prob_setup;
}

$last_def_file = "/etc/squidtaild/last_definite";
if ($incremental eq "yes") {
	if (-f $last_def_file) {
	}
	else {
		&last_def_setup;
	}
}
else {
		&last_def_setup;
}

$last_poss_file = "/etc/squidtaild/last_possible";
if ($incremental eq "yes") {
	if (-f $last_poss_file) {
	}
	else {
		&last_poss_setup;
	}
}
else {
		&last_poss_setup;
}

# main event loop
open (SQUIDLOG, "<$squidlog") or die ("$0: Cannot open \"$squidlog\": $!~\n");
for (;;) {
	while (<SQUIDLOG>) {
		chop;	
		($timedate, $unknown, $ip_address, $message, $code, $action, $location, $direct, $dash, $mime_type) = split (/\s+/);	
		if ($incremental eq "yes"){
			open (HISTORY, "< /etc/squidtaild/history") or die ("$0: Cannot open \"/etc/squidtaild/history\": $!~\n");
			while(<HISTORY>){
				chop;
				($last_timedate, $poss_violations, $prob_violations, 
				$def_violations)= split(/\s+/);		
			}
			close HISTORY;		
			if ($timedate > $last_timedate){
				open (HISTORY, "> /etc/squidtaild/history") or die ("$0: Cannot open \"/etc/squidtaild/history\": $!~\n");
				$scalar_timedate = scalar localtime($timedate);
				select HISTORY;
				print "$timedate\t$poss_num_violations\t$prob_num_violations\t$def_num_violations\t$scalar_timedate\n";
				select STDOUT;
				close HISTORY;
				&parse_log;
			}	
		}
		else {
			open (HISTORY, "> /etc/squidtaild/history") or die ("$0: Cannot open \"/etc/squidtaild/history\": $!~\n");
			$scalar_timedate = scalar localtime($timedate);
			select HISTORY;	
			print "$timedate\t$poss_num_violations\t$prob_num_violations\t$def_num_violations\t$scalar_timedate\n";
			select STDOUT;
			close HISTORY;
			&parse_log;
		}
	}
	if ($incremental eq "yes"){
		$mailreport = $config->get("mailreport");
		$mailto = $config->get("mailrecipient");
		$winpopups = $config->get("winpopups");
		$winpopup_users = $config->get("winpopup_users");
		$winpopup_admin = $config->get("winpopup_admin");
		$admin_computer = $config->get("admin_computer");
		$admin_msg = $config->get("admin_msg");
		$user_msg = $config->get("user_msg");
	}
	&status_write;
}
