#!/usr/bin/perl
# smk stands for Smart Mailing list Keeper
# $Id: smk,v 1.1 1998/05/14 21:50:20 root Exp $
# $Log: smk,v $
# Revision 1.1  1998/05/14 21:50:20  root
# Initial revision
#

$user_unknown = 'user unknown';
$quota_exceeded = 'quota exceeded';
$service_unavailable = 'service unavailable';
$too_many_hops = 'too many hops';
$time_out = 'time out';
$unknown_host = 'unknown host';
$no_route_to_host = 'no route to host';
$connection_refused = 'connection refused';

# Let's get command line options
require 'getopts.pl';
&Getopts('m:i:f:lvqustohrcL:P:');

# Print usage and exit if command line options are not enough
&Usage if (!($opt_f) || !($opt_i || $opt_m));

pv("Using mailing list file $opt_f");
error("Cannot access mailing list file $opt_f, please check that this file exists and you have read/write permissions", 1) if ( !(-w $opt_f));

if ($opt_i) {
	pv("Using smk format input file $opt_i");
	error("Cannot read from smk format input file $opt_i, please check that this file exists and you are allowed to read it", 1) if ( !(-r $opt_i) );
}
if ($opt_m) {
	pv("Using mail format input file $opt_m");
	error("Cannot read from mail format input file $opt_m, please check that this file exists and you are allowed to read it", 1) if ( !(-r $opt_m) );
	error("You choose to examine a mail format input file so you must specify at least one of the command line options 'qustohrc'", 1) 
		if ( 	!($opt_q) && !($opt_u) && !($opt_s) && !($opt_t) &&
				!($opt_o) && !($opt_h) && !($opt_r) && !($opt_c) );
}

if ($opt_l || $opt_L) {
	if ($opt_L) {
		$logfile = $opt_L;
	} else {
		$logfile = "$ENV{'HOME'}/.smk.log";
	}
	pv("Logging enabled to file $logfile");
	error("Cannot access log file $logfile, $!", 1) if ( !(open(LOG, ">> $logfile")) );
	$log = 1;	# Sets logging flag to true
}

if ( !($opt_P) ) {
	# Let's see if default preserve file exists
	$preserve_file = "$ENV{'HOME'}/.smk.preserve"
		if (-r "$ENV{'HOME'}/.smk.preserve");
} else {
	# Let's see if specified preserved file exists
	$preserve_file = $opt_P if (-r $opt_P);
}

if ($preserve_file) {
	pv("Using preserve file $preserve_file");
	open(PRV, $preserve_file);
	while(<PRV>) {
	chop;	y/A-Z/a-z/;
	push(@preserve,$_);
	}
	close(PRV);
} else {
	pv("No preserve file found");
}

# Process the mail format input file
if ($opt_m) {

	pv("Checking for 'quota exceeded' lines") if ($opt_q);
	pv("Checking for 'user unknown' lines") if ($opt_u);
	pv("Checking for 'service unavailable' lines") if ($opt_s);
	pv("Checking for 'too many hops' lines") if ($opt_t);
	pv("Checking for 'time out' lines") if ($opt_o);
	pv("Checking for 'unknown host' lines") if ($opt_h);
	pv("Checking for 'no route to host' lines") if ($opt_r);
	pv("Checking for 'connection refused' lines") if ($opt_c);

	open(IN,$opt_m);
	while(<IN>) {
		if ((	/user unknown/i 		||
				/user not found/i		||
				/unknown user/i			||
				/recipient unknown/i	||
				/recipient not found/i	||
				/unknown recipient/i	||
				/addressee unknown/i	||
				/mailbox not found/i	) 
				&& ($opt_u)) {
			foreach $value (&strip($_)) {
				add_to_list($value, $user_unknown);
			}
		} elsif (/quota exceeded/i && ($opt_q)) {
			foreach $value (&strip($_)) {
				add_to_list($value, $quota_exceeded);
			}
		} elsif (/service unavailable/i && ($opt_s)) {
			foreach $value (&strip($_)) {
				add_to_list($value, $service_unavailable);
			}
		} elsif (/too many hops/i && ($opt_t)) {
			foreach $value (&strip($_)) {
				add_to_list($value, $too_many_hops);
			}
		} elsif ((	/time out/i		||
					/timed out/i	||
					/deferred/i		) 
					&& ($opt_o)) {
			foreach $value (&strip($_)) {
				add_to_list($value, $time_out);
			}
		} elsif ((	/unknown host/i		||
					/host unknown/i		||
					/host not found/i		) 
					&& ($opt_h)) {
			foreach $value (&strip($_)) {
				add_to_list($value, $unknown_host);
			}
		} elsif (/no route to host/i && ($opt_r)) {
			foreach $value (&strip($_)) {
				add_to_list($value, $no_route_to_host);
			}
		} elsif (/connection refused/i && ($opt_c)) {
			foreach $value (&strip($_)) {
				add_to_list($value, $connection_refused);
			}
		}
	}
	close(IN);
}

# Process the smk format input file
if ($opt_i) {
	open(IN,$opt_i);
	while(<IN>) {
		/^(.+)\s(.+)$/i;	$address= $2;	$action = $1;
		add_to_list($address, $action);
	}
	close(IN);
	unlink($opt_i);
}

# Check for preserved addresses
foreach (keys %list) {
	$address = $_;
	foreach (@preserve) {
		$list{$address} = 'preserved' if ($address eq $_);
	}	
}

# Rewrite the mailing list file
open(IN, $opt_f) || error("Can't open mailing list file $opt_f", 1);
open(OUT, "> $opt_f.tmp") || error ("Can't open temporary file $opt_f.tmp", 1);
while(<IN>) {
	chop;
	y/A-Z/a-z/;
	push(@dupe_check, $_);
	if (	!($list{$_}) ||
			$list{$_} eq 'preserved' ||
			$list{$_} eq 'add'			) { 
		print OUT "$_\n";
	} else {
		$msg = "Deleting $_, reason: $list{$_}";
		pv($msg);	flog($msg);
	}
}
# Check actions array for addresses to be subscribed
foreach $key (keys %list) {
	foreach (@dupe_check) {
		$list{$key} = 'preserved' if ($key eq $_);
	}
		if ($list{$key} eq 'add') {
			print OUT "$key\n";
			$msg = "Adding $key";
			pv($msg);	flog($msg);
		}
}
close(IN);
close(OUT);

# Swap the files
rename("$opt_f.tmp", $opt_f);

close(LOG) if ($log);


# Subroutine to print program usage and exit
sub Usage {
	print 'Smart Mailing list Keeper $Id: smk,v 1.1 1998/05/14 21:50:20 root Exp $' . "\n";
	print "Usage: smk [-vlqustohrc] [-L filename] [-P filename] ";
	print "-i filename -m filename -f filename\n\n";
	print "    -v    enables verbose output\n";
	print "    -l    enables logging in \$HOME/.smk.log\n";
	print "    -L    enables logging into specified filename\n";
	print "    -P    preserves addresses listed in filename\n";
	print "    -i    input file in smk format\n";
	print "    -m    input file in mail format\n";
	print "    -f    mailing list file\n\n";
	print "    Flags to be used with mail format input files:\n";
	print "    -q    check for 'quota exceeded'\n";
	print "    -u    check for 'unknown user'\n";
	print "    -s    check for 'service unavailable'\n";
	print "    -t    check for 'too many hops'\n";
	print "    -o    check for 'time out'\n";
	print "    -h    check for 'unknown host'\n";
	print "    -r    check for 'no route to host'\n";
	print "    -c    check for 'connection refused'\n";
	exit;
}

# Subroutine used to print verbose information
sub pv {
	local($msg) = @_;
	print "- $msg\n" if ($opt_v);
}

# Subroutine used to print error messages
sub error {
	local($msg,$exit) = @_; # if $exit eq true then exit
	print "! $msg\n";
	exit if ($exit);
}

# Subroutine to take email addresses from any line of text
sub strip {
	local($line) = @_;
	local(@addresses);
	@addresses = ($line =~ (/\b([\w\.\-!]+\@[\w\.\-!]+)\b/g) );
	return @addresses;
}

# Write to logfile
sub flog {
	local($msg) = @_;
	if($log) {
		($sec,$min,$hour,$day,$month,$year) = localtime(time);
		print LOG "$month/$day/$year $hour:$min $msg\n";
	}
}

# Add an entry to the actions array
sub add_to_list {
	local($address,$reason) = @_;
	$address =~ y/A-Z/a-z/;
	$list{$address} = $reason;
}
