#!/usr/bin/perl

# $Id: fido7d,v 1.6 1997/11/24 21:43:34 crosser Exp $
#
# $Log: fido7d,v $
# Revision 1.6  1997/11/24 21:43:34  crosser
# empty $firstlines
#
# Revision 1.5  1997/11/24 01:14:27  crosser
# fix
#
# Revision 1.4  1997/11/24 00:43:26  crosser
# Add parameter to rfc822putheader: filter or not filter?  That is the question.
#
# Revision 1.3  1997/11/23 23:47:22  crosser
# add comment
#

# daemon for fido7 "automoderator"
# Copyright (c) 1997 Eugene G. Crosser

$LIBDIR="/usr/local/lib/fido7";
$LOGDIR="/var/fido7/log";
$ERRLOG="process";

unshift(@INC,$LIBDIR);
chdir($LOGDIR);
open(STDERR,">>".$ERRLOG) || die "cannot open $errlog: $!";
print STDERR time," starting\n";

require "config.pl";
require "db.pl";
require "rfc822.pl";
require "talkuser.pl";
require "baddom.pl";
require "kosher.pl";

%count;

&lockme || die "cannot lock daemon";

while (1) {
	$total=0;
	foreach $mode('i','r','m','b') {
		$count{$mode}=0;
		unless (chdir($SPOOL.'/'.$mode)) {
			print STDERR time," chdir \"$SPOOL/$mode\": $!\n";
			next;
		}
		unless (opendir(DIR,'.')) {
			print STDERR time," opendir \"$SPOOL/$mode\": $!\n";
			next;
		}
		while ($de=readdir(DIR)) {
			next if ($de=~/^\./);
			next if ($de=~/core/);
			next if ($de=~/^run/);
			next if ($de=~/^bad/);
			unless (rename($de,'run'.$de)) {
				print STDERR time," reanme \"$SPOOL/$mode/$de\": $!\n";
				next;
			}
			&process($mode,'run'.$de);
		}
		closedir(DIR);
	}
	
	if ($total) {
		print STDERR time," processed:";
		foreach $mode('i','r','m','b') {
			print STDERR " $mode:$count{$mode}";
		}
		print STDERR "\n";
	}
	&u_sync;
	sleep($DELAY);
}

###########################################################################

sub process {
	local($mode,$fn)=@_;

	unless (open(IN,"<".$fn)) {
		print STDERR time," open $mode/$fn: $!\n";
		return;
	}
	($sender,@header)=&rfc822parse(IN);
	print STDERR time," process: '$mode' \"$fn\" <$sender>\n";
	unless ($sender) {
		close(IN);
		local($nfn)=$fn;
		$nfn=~s/^run/bad/;
		rename($fn,$nfn);
		print STDERR time," saved \"$mode/$nfn\"\n";
		close(IN);
		return;
	}
	if ($mode eq 'i') {
		open(STDOUT,"|".$SENDMAIL);
		&sendinfo($sender);
		close(STDOUT);
		while (<IN>) {;}
	} elsif ($mode eq 'b') {
		open(STDOUT,"|".$SENDMAIL);
		print STDERR time," mailing bounce message to $sender\n";
		&sendbounce($sender);
		&rfc822putheader(STDOUT,0,@header);
		print "\n";
		while (<IN>) {
			print;
		}
		&closebounce;
		close(STDOUT);
	} else {
		%rec=&u_find($sender);
		unless (%rec) {
			$rec{'user'}=$sender;
			if (&baddom($sender)) {
				$rec{'deny'}=$BADDOM;
			} else {
				$rec{'deny'}=$UNREG;
			}
			$rec{'regtime'}=time;
			$rec{'rejectcount'}=-1;
			srand;
			$rec{'challenge'}=int(rand 4294836225);
		}
		if ($rec{'denyuntil'} && ($rec{'denyuntil'} < time)) {
			print STDERR time," denial period expired for $sender\n";
			delete $rec{'deny'};
			delete $rec{'denyuntil'};
			&u_insert(%rec);
		}
		if (($mode eq 'm') && (! $rec{'deny'})) {
			# read first few lines for charset checking
			$firstlines="";
			for ($i=0;$i<$EXCERPT;$i++) {
				$firstlines.=<IN>;
			}
			# if the header and the beginning of the body is
			# kosher, post it away.
			if (($reason=&kosher($firstlines,@header)) eq "OK") {
				print STDERR time," posting from $sender\n";
				$rec{'posttime'}=time;
				$rec{'postid'}=&rfc822hdr('Message-ID',@header);
				&u_insert(%rec);
				open(STDOUT,"|".$INEWS);
				&rfc822putheader(STDOUT,1,@header);
				print "Approved: $APPROVE\n";
				print "\n";
				print $firstlines;
				while (<IN>) {
					print;
				}
				close(STDOUT);
			} else {
				open(STDOUT,"|".$SENDMAIL);
				print STDERR time," mailing nonkosher ($reason) to $sender\n";
				&sendnonkosher($sender,$reason);
				&rfc822putheader(STDOUT,0,@header);
				print "\n";
				print $firstlines;
				while (<IN>) {
					print;
				}
				&closenonkosher;
				close(STDOUT);
			}
		} elsif (($rec{'rejectcount'}++) < $MAXREJECT) {
			open(STDOUT,"|".$SENDMAIL);
			$ok=0;
			if (($mode eq 'r') && ($rec{'deny'} eq $UNREG)) {
				while (<IN>) {
					if (/$rec{'challenge'}/) {
						delete $rec{'deny'};
						$ok=1;
					}
				}
			}
			if ($mode eq 'r') {
				print STDERR time," mailing result $ok to $sender\n";
				&sendok($sender,$ok,$rec{'deny'},
					$rec{'challenge'});
				while (<IN>) {;}
			} else {
				print STDERR time," mailing hello to $sender\n";
				&sendhello($sender,$rec{'challenge'},
							$rec{'deny'});
				&rfc822putheader(STDOUT,0,@header);
				print "\n";
				while (<IN>) {
					print;
				}
				&closehello;
			}
			close(STDOUT);
			&u_insert(%rec);
		} else {
			print STDERR time," reject count for $sender\n";
			while (<IN>) {;}
		}
	}
	close(IN);
	unlink($fn);
	$count{$mode}++;
	$total++;
}

sub lockme {
	local($theirpid,$i);
	local($pid)=$PID;

	if (open(LF,"<$pid.pid")) {
		$theirpid=<LF>;
		close(LF);
		return 1 if ($theirpid == $$);
	}

	open(LF,">$pid.$$") || die "cannot create $pid.$$: $!";
	print LF "$$\n";
	close(LF);

	for ($i=1;$i<=5;$i++) {
		if (link($pid.'.'.$$,$pid.'.pid')) {
			unlink($pid.'.'.$$);
			return 1;
		}
		if (open(LF,"<$pid.pid")) {
			$theirpid=<LF>;
			close(LF);
			unlink($pid.'.pid') unless (kill 15,$theirpid);
		}
		sleep 2;
	}
	unlink($pid.'.'.$$);
	return 0;
}
