#!/usr/bin/perl
#####
## Simple script to do mail filtering with bounce or local delivery option
# Rev 1.3
# By: Laird Bedore
# Date: 5/8/03
#####
## The following variables are read from the config file
#   BOUNCE
#   DELIVER
#   SPAMFOLDER
#   REWRITE_SUBJ
#####
## Exit codes:
#  0 = Go ahead and deliver (default)
# 99 = Don't do anything after this filter.
#100 = bounce back to sender.
#111 = defer for later delivery.
#####

# 1. Read config file variables.
# 2. Run STDIN through checking filter
# 3. Route mail based on output of filter

sub write_to_folder {
	# Exit codes: 0 = temporary failure, 1 = success, 255 = cant open folder
	my($folder,$data) = @_;
	my $retries = 0;
	open(FOLDER,">>.mail/$folder") or return 255;
	while ($retries < 5) {
		if (flock(FOLDER,6)) {
			seek(FOLDER,0,2);
			print FOLDER $data."\n";
			flock(FOLDER,8);
			close(FOLDER);
			return 1;
		}
		sleep 1;
		$retries++;
	}	
	close(FOLDER);
	return 0;
}

sub read_config {
	my $var,$val;
	open(CONF,".mailfilter.conf") or return 0;
	while ($line = <CONF>) {
		# strip newlines
		$line =~ s/\n//g;
		# Strip quotes
		$line =~ s/\"//g;
		($var,$val) = split(/=/,$line);
		$conf{$var} = $val;
	}
	close(CONF);
	return 1;
}

sub replace_subject {
	my(@mailjunk) = @_;
	for ($n = 0; $n <= $#mailjunk;$n++) {
		if ($mailjunk[$n] =~ /^Subject:/) {
			$mailjunk[$n] =~ s/^Subject: /Subject: (SPAM) /;
		}
	}
	return @mailjunk;
}

sub log_err {
	my($err) = @_;
	open(ERRLOG,">>/var/log/mailfilter.log") or return 0;
	my $date = `date -R`;
	chomp($date);
	my $uname = `whoami`;
	chomp($uname);

	print ERRLOG "$date: user=$uname $err\n";
	close(ERRLOG);
}

#####
## Start of main code chunk
#

#####
## Read the user's config file
if (!&read_config) {
	# No mailfilter.conf - do not filter, just pass through
	log_err("Configuration file not found or not readable.");
	exit 0;
}

#####
## Grab the STDIN and add a From line, so it's a standard mail
$mailheader = "From $ENV{'SENDER'} ".`date -u "+%a %b %d %T %Y"`;
@maildata = <STDIN>;

open(FILTER,"|grep -i -f .mailrules") or (log_err("Could not run grep") && exit 0);
print FILTER $mailheader."\n";

for ($n = 0; $n <= $#maildata;$n++) {
	print FILTER $maildata[$n];
}
close(FILTER);
$filter_result = $?;
# 256 = no match
# 0 = match

if ($filter_result == 0) {
	if ($conf{'DELIVER'} == 1) {
		if ($conf{'REWRITE_SUBJ'} == 1) {
			@maildata = replace_subject(@maildata);
			log_err("Spam found. Rewriting email header before delivery.");
		}
		if (! -w ".mail/$conf{'SPAMFOLDER'}") {
			log_err("During delivery, spam folder \"$conf{'SPAMFOLDER'}\" either not found or not writeable. Defaulting to INBOX.");
			$conf{'SPAMFOLDER'}="INBOX";
		}
		##
		## Execute delivery of the message!
		##
		$mailchunk = $mailheader.join("",@maildata);
		$ret = write_to_folder($conf{'SPAMFOLDER'},$mailchunk);
		# Exit codes: 0 = temporary failure, 1 = success, 255 = cant open folder
		if ($ret == 1) { 
			# Delivery successful
			log_err("Spam mail saved to folder \"$conf{'SPAMFOLDER'}\".");
			if ($conf{'BOUNCE'} != 1) {
				exit 99;
			}
		} elsif ($ret == 255) {
			# Explicit error opening mailbox file.
			log_err("Error: Could not open $conf{'SPAMFOLDER'} for writing. Delivery deferred.");
			exit 111;
		} else {
			# Temp failure - probably a file locking problem. deliver later.
			log_err("Temporary delivery error. Probably timed out (5sec) on file lock. Message deferred.");
			exit 111;
		}
		#End if deliver=1
	}
	if ($conf{'BOUNCE'} == 1) {
		print "Email rejected: spam mail is not allowed here!";
		log_err("Spam found. Bouncing.");
		# exit for a bounce
		exit 100;
	}
	if ($conf{'BOUNCE'} != 1 && $conf{'DELIVER'} != 1) { 
		# If neither bounce nor deliver... drop!
		log_err("Spam found - neither bouncing nor delivering. Message dropped.");
		exit 99;
	} #if bounce or deliver
} else { 
	#exitcode - not a spam match - just deliver
	exit 0;
}

### End of File.
