xref: /netbsd-src/external/bsd/am-utils/dist/scripts/lostaltmail.in (revision a53f50b9b44dc9467ccc9c464999b1d1c509cb0c)
1*a53f50b9Schristos#!@PERL@ -sw
2*a53f50b9Schristos#
3*a53f50b9Schristos# Package:	am-utils-6.x
4*a53f50b9Schristos# Author:	James Tanis <jtt@cs.columbia.edu>
5*a53f50b9Schristos#
6*a53f50b9Schristos
7*a53f50b9Schristos############################################################################
8*a53f50b9Schristos#
9*a53f50b9Schristos# lostaltmail -- remail files files found alt_mail (or -a argument to hlfsd) to
10*a53f50b9Schristos# whomever should receive it. This version is for SMTP varient which
11*a53f50b9Schristos# support VRFY as a non-expanding verifier!!! (sendmail V8 is a an
12*a53f50b9Schristos# example).
13*a53f50b9Schristos#
14*a53f50b9Schristos# Usage: lostaltmail [-debug] [-nomail] [-noverify]
15*a53f50b9Schristos#
16*a53f50b9Schristos# 		GLOBAL VARIABLES (as if you care :-) )
17*a53f50b9Schristos# Probably a very incomplete list.
18*a53f50b9Schristos#
19*a53f50b9Schristos# Everything in the config file for this program *and* ...
20*a53f50b9Schristos#
21*a53f50b9Schristos# $debug: set it from the command line with -debug. Does the obvious
22*a53f50b9Schristos# $nomail: set it from the command line with -nomail. *Not* implied by
23*a53f50b9Schristos#	 $debug
24*a53f50b9Schristos# $currentTO: The addresss we are currently checking on.  Actually this is
25*a53f50b9Schristos#	left over from an earlier version of lostaltmail and will hopefully
26*a53f50b9Schristos#	go away.
27*a53f50b9Schristos# $noverify: set it from the address line. Avoid verification of $currentTO.
28*a53f50b9Schristos#	This should be relatively safe as long as you are willing to
29*a53f50b9Schristos#	endure bounces from mail that cannot be redelivered as opposed to
30*a53f50b9Schristos#	just getting a warning. UNTESTED (but should work).
31*a53f50b9Schristos#
32*a53f50b9Schristos# $logopen: state variable indicating weather the log file (should there be
33*a53f50b9Schristos#	one) is in fact open.
34*a53f50b9Schristos#
35*a53f50b9Schristos# @allentries: Array of all the directory entries in $MAILDIR
36*a53f50b9Schristos# @allnames: Array of all *likely* recipients. It is created from @allentries
37*a53f50b9Schristos#	sans junk files (see $MAILJUNK and $LOCALMAILJUNK)
38*a53f50b9Schristos# @wanderers: Array of all the files associated with a *single* address
39*a53f50b9Schristos#	which might need remailing.  Should lostaltmail die unexpectedly,
40*a53f50b9Schristos#	it might leave a temporary file containing messages it was
41*a53f50b9Schristos#	currently trying to deliver.  These will get picked and resent
42*a53f50b9Schristos#	later.
43*a53f50b9Schristos#
44*a53f50b9Schristos# VRFY: Handle onto SMTP verification channel.  Not to be confused with mail
45*a53f50b9Schristos#	delivery; only verification occurs accross this handle.
46*a53f50b9Schristos#
47*a53f50b9Schristos############################################################################
48*a53f50b9Schristos
49*a53f50b9Schristos##############################################################################
50*a53f50b9Schristos#									     #
51*a53f50b9Schristos#				SMTP_SEND				     #
52*a53f50b9Schristos#								     	     #
53*a53f50b9Schristos##############################################################################
54*a53f50b9Schristos#
55*a53f50b9Schristos# Send a message to the smtp channel. Inserts the necessary NEWLINE if it
56*a53f50b9Schristos# does not exist;
57*a53f50b9Schristos# I stole this from myself. It shouldn nott be printing errors to STDERR, but
58*a53f50b9Schristos# this is a quick hack.
59*a53f50b9Schristos#
60*a53f50b9Schristossub smtp_send {
61*a53f50b9Schristos    local ($msg) = @_;
62*a53f50b9Schristos    local ($length);
63*a53f50b9Schristos
64*a53f50b9Schristos    $length=length($msg);
65*a53f50b9Schristos
66*a53f50b9Schristos    if ( $msg !~ /^.*\n$/ ) {
67*a53f50b9Schristos	$msg = $msg . "\n";
68*a53f50b9Schristos	$length++;
69*a53f50b9Schristos    }
70*a53f50b9Schristos
71*a53f50b9Schristos
72*a53f50b9Schristos    if ( ! syswrite (VRFY, $msg, $length)) {
73*a53f50b9Schristos	print STDERR "Failing SMTP write: $msg";
74*a53f50b9Schristos	return 0;
75*a53f50b9Schristos    }
76*a53f50b9Schristos
77*a53f50b9Schristos    return 1;
78*a53f50b9Schristos}
79*a53f50b9Schristos
80*a53f50b9Schristos##############################################################################
81*a53f50b9Schristos#									     #
82*a53f50b9Schristos#				SMTP_RECV				     #
83*a53f50b9Schristos#								     	     #
84*a53f50b9Schristos##############################################################################
85*a53f50b9Schristos#
86*a53f50b9Schristos# Read in lines from SMTP connection and return the final
87*a53f50b9Schristos# 	Really hideous -- please excuse.
88*a53f50b9Schristos#
89*a53f50b9Schristossub smtp_recv {
90*a53f50b9Schristos    local ($line,$rin, $win, $ein, $readbuf, $ret);
91*a53f50b9Schristos    $readbuf = "";
92*a53f50b9Schristos
93*a53f50b9Schristos    $rin = $win = $ein = '';	# Null fd sets,
94*a53f50b9Schristos    vec ($rin, fileno(VRFY), 1) = 1; # Stolen straight from the example;
95*a53f50b9Schristos    $ein = $rin | $win;		# This is probably useless
96*a53f50b9Schristos
97*a53f50b9Schristos
98*a53f50b9SchristosLINE_OF_INPUT:
99*a53f50b9Schristos    while (1) {			# Read in all the input
100*a53f50b9Schristos
101*a53f50b9Schristos	if ((select ( $rin, $win, $ein, 600.0))[0]  == 0 ) {
102*a53f50b9Schristos	    print "select returned -1" if ($debug);
103*a53f50b9Schristos	    return -1;	# timeout
104*a53f50b9Schristos	}
105*a53f50b9Schristos	sysread (VRFY, $readbuf, 1024);
106*a53f50b9Schristos	chop ($readbuf);
107*a53f50b9Schristos
108*a53f50b9Schristos	foreach $line (	split('\n', $readbuf)) {
109*a53f50b9Schristos
110*a53f50b9Schristos	    # This loop is actually needed since V8 has a multi-line greet.
111*a53f50b9Schristos
112*a53f50b9Schristos	    ( $line =~ /^(\d\d\d).*/ && ($SMTP_retval=$1)) ||
113*a53f50b9Schristos		warn "Badly formed reply from SMTP peer: $line\n";
114*a53f50b9Schristos
115*a53f50b9Schristos	    # Space after return code indicates EOT
116*a53f50b9Schristos
117*a53f50b9Schristos	    if ($line =~ /^\d\d\d /) {
118*a53f50b9Schristos		$ret = $line;	# Oddly $line is in a different context here;
119*a53f50b9Schristos				# and thus we need to export it out of the
120*a53f50b9Schristos				# while loop via $ret.
121*a53f50b9Schristos		last LINE_OF_INPUT;
122*a53f50b9Schristos	    }
123*a53f50b9Schristos	} # End of read.
124*a53f50b9Schristos    } # End of input.
125*a53f50b9Schristos
126*a53f50b9Schristos    return $ret;
127*a53f50b9Schristos}
128*a53f50b9Schristos
129*a53f50b9Schristos
130*a53f50b9Schristos
131*a53f50b9Schristos
132*a53f50b9Schristos##############################################################################
133*a53f50b9Schristos#									     #
134*a53f50b9Schristos#				LOG_INFO				     #
135*a53f50b9Schristos#								     	     #
136*a53f50b9Schristos##############################################################################
137*a53f50b9Schristos#
138*a53f50b9Schristos#
139*a53f50b9Schristos# Opens appropriate logging file -- STDOUT (cron) or temp file (mail).
140*a53f50b9Schristos#
141*a53f50b9Schristossub Log_info {
142*a53f50b9Schristos    local($message) = @_;
143*a53f50b9Schristos
144*a53f50b9Schristos    if ( !$logopened )  {
145*a53f50b9Schristos	if ( $MAILGRUNT eq "" || $debug) {
146*a53f50b9Schristos	    open (LOGFILE, ">-") || die  "Unable to open stdout";
147*a53f50b9Schristos	}
148*a53f50b9Schristos	else {
149*a53f50b9Schristos	    # Snarf the log into a tmp file for final mailing to MAILGRUNT
150*a53f50b9Schristos	    $logfile = $LOGFILE . ".$$";
151*a53f50b9Schristos	    open (LOGFILE, (">". "$logfile")) || die "Unable to create log file";
152*a53f50b9Schristos	}
153*a53f50b9Schristos    }
154*a53f50b9Schristos
155*a53f50b9Schristos    $logopened=1;		# Note that the log is now open
156*a53f50b9Schristos
157*a53f50b9Schristos    # Heart of the function.
158*a53f50b9Schristos    print LOGFILE "$message";
159*a53f50b9Schristos
160*a53f50b9Schristos    print LOGFILE "\n" if ( index($message,"\n") == -1 );
161*a53f50b9Schristos}
162*a53f50b9Schristos
163*a53f50b9Schristos##############################################################################
164*a53f50b9Schristos#									     #
165*a53f50b9Schristos#				LOCK_FILE				     #
166*a53f50b9Schristos#									     #
167*a53f50b9Schristos##############################################################################
168*a53f50b9Schristos
169*a53f50b9Schristos#
170*a53f50b9Schristos# Tries to grab a lock on the supplied file name.
171*a53f50b9Schristos# Spins for a bit if it can't on the assumption that the lock will be released
172*a53f50b9Schristos#	quickly.  If it times out and it's allowed to requeue, it will defer
173*a53f50b9Schristos#	until later, other wise write a message to loginfo.
174*a53f50b9Schristos
175*a53f50b9Schristos# If a recurring error or really unexpected situation arrises, return
176*a53f50b9Schristos# 	ABORT_RESEND
177*a53f50b9Schristos#
178*a53f50b9Schristos#  PARAMETERS
179*a53f50b9Schristos# mailfile: path to the file to resend.
180*a53f50b9Schristos# should_requeue: BOOLEAN - TRUE if the mailfile should be put on the
181*a53f50b9Schristos# queue for a later retry if we can not finish
182*a53f50b9Schristos# now.
183*a53f50b9Schristos
184*a53f50b9Schristossub Lock_file {
185*a53f50b9Schristos
186*a53f50b9Schristos    local($mailfile,$should_requeue,$i,$new_lost_file) = @_;
187*a53f50b9Schristos
188*a53f50b9Schristos# We need to rename the current mailbox so that mail can loop back into it if
189*a53f50b9Schristos# the resent mail just gets looped right back to us.
190*a53f50b9Schristos    $new_lost_file = $mailfile . ".$$";
191*a53f50b9Schristos
192*a53f50b9Schristos#  make a tmpfile name based on mailfile;
193*a53f50b9Schristos    $lostlockfile = "$mailfile" . "$LOCKEXT";
194*a53f50b9Schristos
195*a53f50b9Schristos    if ( ! open(LOCKFILE, (">" . $lostlockfile)) ) {
196*a53f50b9Schristos	printf(STDERR "Could not create lostlockfile for %s: %s\n", $mailfile,$!);
197*a53f50b9Schristos	return $ABORT_RESEND;
198*a53f50b9Schristos    }
199*a53f50b9Schristos    close(LOCKFILE);
200*a53f50b9Schristos
201*a53f50b9Schristos    $maillockfile = "$mailfile" . "$LOCAL_LOCK_EXT";
202*a53f50b9Schristos
203*a53f50b9Schristos    for ($i=0; $i < $LOCK_RETRIES && ! link ($lostlockfile, $maillockfile);
204*a53f50b9Schristos	 $i++) {
205*a53f50b9Schristos	sleep(1);
206*a53f50b9Schristos    }
207*a53f50b9Schristos
208*a53f50b9Schristos    unlink($lostlockfile);	# No matter what eliminate our cruft
209*a53f50b9Schristos
210*a53f50b9Schristos    if ( $i == $LOCK_RETRIES ) {
211*a53f50b9Schristos	&Log_info("Could not grab lock on: " . "$mailfile" . " :timed out");
212*a53f50b9Schristos	if ( $should_requeue ) {
213*a53f50b9Schristos	    &Log_info("Requeing " . "$mailfile" . " for later retry");
214*a53f50b9Schristos	    $retry_list .= " $mailfile";
215*a53f50b9Schristos	}
216*a53f50b9Schristos	else {
217*a53f50b9Schristos	    &Log_info("Giving up on: " . "$mailfile");
218*a53f50b9Schristos	}
219*a53f50b9Schristos
220*a53f50b9Schristos	return $ABORT_RESEND;
221*a53f50b9Schristos    }
222*a53f50b9Schristos
223*a53f50b9Schristos    # We created the link and therefore have the lock
224*a53f50b9Schristos
225*a53f50b9Schristos    if (rename ($mailfile, $new_lost_file) == 0 ){
226*a53f50b9Schristos	# Failed to rename file -- this is serious.
227*a53f50b9Schristos	unlink($maillockfile);
228*a53f50b9Schristos	return $ABORT_RESEND;
229*a53f50b9Schristos    }
230*a53f50b9Schristos
231*a53f50b9Schristos    unlink($maillockfile);
232*a53f50b9Schristos    return $new_lost_file;
233*a53f50b9Schristos
234*a53f50b9Schristos}
235*a53f50b9Schristos
236*a53f50b9Schristos##############################################################################
237*a53f50b9Schristos#									     #
238*a53f50b9Schristos#			PARSE NEXT MAIL MESSAGE				     #
239*a53f50b9Schristos#									     #
240*a53f50b9Schristos##############################################################################
241*a53f50b9Schristos#
242*a53f50b9Schristos# Parameters:
243*a53f50b9Schristos#  mailfile: handle of mailfile to use.
244*a53f50b9Schristos#
245*a53f50b9Schristos# Parses the next message in the mail file and inserts it in $current_msg
246*a53f50b9Schristos#
247*a53f50b9Schristossub Get_next_msg {
248*a53f50b9Schristos    local($mailfile,$found_body_delimiter) = @_;
249*a53f50b9Schristos
250*a53f50b9Schristos    # If this is the first message in the spool file, read the first line
251*a53f50b9Schristos    # otherwise use the MESSAGE_DELIM line from the previous message (which we
252*a53f50b9Schristos    # were forced to overread).
253*a53f50b9Schristos
254*a53f50b9Schristos    $done=$FALSE;
255*a53f50b9Schristos    $found_body_delimiter=$FALSE;
256*a53f50b9Schristos
257*a53f50b9Schristos    # This if eats the very first "From " line and should never fire again.
258*a53f50b9Schristos    if ( ! defined $current_msg ) {<$mailfile>};
259*a53f50b9Schristos    undef ($current_msg);	# Erase the old message.
260*a53f50b9Schristos
261*a53f50b9Schristos
262*a53f50b9Schristos    # Read the mailfile and pass through all the lines up until the next
263*a53f50b9Schristos    # message delimiter. Kill any previous resend headers.
264*a53f50b9Schristos    while ( <$mailfile> ) {
265*a53f50b9Schristos	last if (/$MESSAGE_DELIM/);
266*a53f50b9Schristos	next if ( !$found_body_delimiter && /[Rr][Ee][Ss][Ee][Nn][Tt]-.+:/);
267*a53f50b9Schristos	if (  !$found_body_delimiter && /^$HEADER_BODY_DELIM/) {
268*a53f50b9Schristos	    &Splice_in_resent_headers();
269*a53f50b9Schristos	    $found_body_delimiter=$TRUE;
270*a53f50b9Schristos	}
271*a53f50b9Schristos	if (defined($current_msg)) {
272*a53f50b9Schristos	    $current_msg .= $_;
273*a53f50b9Schristos	} else {
274*a53f50b9Schristos	    $current_msg = $_;
275*a53f50b9Schristos	}
276*a53f50b9Schristos    }
277*a53f50b9Schristos
278*a53f50b9Schristos    # Return TRUE when we have hit the end of the file.
279*a53f50b9Schristos    if (!defined($_) || $_ eq "" ) {
280*a53f50b9Schristos	return $TRUE;
281*a53f50b9Schristos    } else {
282*a53f50b9Schristos	return $FALSE;
283*a53f50b9Schristos    }
284*a53f50b9Schristos}
285*a53f50b9Schristos
286*a53f50b9Schristos##############################################################################
287*a53f50b9Schristos#									     #
288*a53f50b9Schristos#			SPLICE IN RESENT_HEADERS			     #
289*a53f50b9Schristos#									     #
290*a53f50b9Schristos##############################################################################
291*a53f50b9Schristos#
292*a53f50b9Schristos# Insert the Resent- headers at the *current location* of the message stream
293*a53f50b9Schristos# (In Engish, print out a few Resent-X: lines and return :-) )
294*a53f50b9Schristos# In addition splice in the X-resent-info: header.
295*a53f50b9Schristos
296*a53f50b9Schristos#
297*a53f50b9Schristos# Paremters: None.
298*a53f50b9Schristos# Return: None
299*a53f50b9Schristos#
300*a53f50b9Schristossub Splice_in_resent_headers {
301*a53f50b9Schristos    local($date,$utctime,$weekday,$time,$month,$hostname);
302*a53f50b9Schristos
303*a53f50b9Schristos    $current_msg .= "$RESENT_TO" . "$currentTO" . "\n";
304*a53f50b9Schristos    $current_msg .= "$RESENT_FROM" . "$SYSTEM_FROM_ADDRESS" . "\n";
305*a53f50b9Schristos
306*a53f50b9Schristos    # Calculate date and time.  It is a bit of a shame to do this each time
307*a53f50b9Schristos    # the time needs to be acurate.
308*a53f50b9Schristos
309*a53f50b9Schristos    @utctime=gmtime(time);
310*a53f50b9Schristos
311*a53f50b9Schristos    $weekday=(Sun,Mon,Tue,Wed,Thu,Fri,Sat)[$utctime[6]];
312*a53f50b9Schristos
313*a53f50b9Schristos
314*a53f50b9Schristos    # If the minutes or second do not take two columns each, patch em up.
315*a53f50b9Schristos    if ( $utctime[1] < 10 ) {
316*a53f50b9Schristos	if ( $utctime[0] < 10 ) {
317*a53f50b9Schristos	    $time=sprintf("%d:0%d:0%d",$utctime[2],$utctime[1],$utctime[0]);
318*a53f50b9Schristos	}
319*a53f50b9Schristos	else {
320*a53f50b9Schristos	    $time=sprintf("%d:0%d:%d",$utctime[2],$utctime[1],$utctime[0]);
321*a53f50b9Schristos	}
322*a53f50b9Schristos    }
323*a53f50b9Schristos    else {
324*a53f50b9Schristos	if ( $utctime[0] < 10 ) {
325*a53f50b9Schristos	    $time=sprintf("%d:%d:0%d",$utctime[2],$utctime[1],$utctime[0]);
326*a53f50b9Schristos	}
327*a53f50b9Schristos        else {
328*a53f50b9Schristos	    $time=sprintf("%d:%2d:%2d",$utctime[2],$utctime[1],$utctime[0]);
329*a53f50b9Schristos	}
330*a53f50b9Schristos    }
331*a53f50b9Schristos
332*a53f50b9Schristos    $month=(Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)[$utctime[4]];
333*a53f50b9Schristos
334*a53f50b9Schristos    # Ensure Y2K format
335*a53f50b9Schristos    $date=sprintf("%s, %d %s %d %s UTC", $weekday, $utctime[3], $month, $utctime[5]+1900, $time);
336*a53f50b9Schristos
337*a53f50b9Schristos    $current_msg .= "$RESENT_DATE" . $date . "\n";
338*a53f50b9Schristos
339*a53f50b9Schristos    if ( defined $RESENT_INFO && $RESENT_INFO ne "") {
340*a53f50b9Schristos	$hostname=`uname -n`;
341*a53f50b9Schristos	$current_msg .= "$RESENT_INFO" . "Lost mail resent from ". $hostname;
342*a53f50b9Schristos    }
343*a53f50b9Schristos
344*a53f50b9Schristos    return;
345*a53f50b9Schristos}
346*a53f50b9Schristos
347*a53f50b9Schristos##############################################################################
348*a53f50b9Schristos#									     #
349*a53f50b9Schristos#				DO_REMAIL				     #
350*a53f50b9Schristos#									     #
351*a53f50b9Schristos##############################################################################
352*a53f50b9Schristos#
353*a53f50b9Schristos# Actually resends the mail.   Talks to the process configured as $MAILER
354*a53f50b9Schristos# We need better handling.
355*a53f50b9Schristos#
356*a53f50b9Schristossub Do_remail {
357*a53f50b9Schristos    open (MAILER, "| $MAILER $currentTO") || return $ABORT_RESEND;
358*a53f50b9Schristos    print MAILER $current_msg;
359*a53f50b9Schristos    close (MAILER);
360*a53f50b9Schristos}
361*a53f50b9Schristos
362*a53f50b9Schristos##############################################################################
363*a53f50b9Schristos#									     #
364*a53f50b9Schristos#				CLEAN_UP				     #
365*a53f50b9Schristos#									     #
366*a53f50b9Schristos##############################################################################
367*a53f50b9Schristos#
368*a53f50b9Schristos# Clean up my messes.
369*a53f50b9Schristos#
370*a53f50b9Schristossub Clean_up {
371*a53f50b9Schristos    local ($hostname);
372*a53f50b9Schristos
373*a53f50b9Schristos    # Ugly local hack that you should never have seen, but I forgot to
374*a53f50b9Schristos    # remove.  Hopefully it did not kill you (I tried as you see), but you
375*a53f50b9Schristos    # should eiter remove or update it for yourself.  I find the message
376*a53f50b9Schristos    # subject needs to have the hostname to be useful.
377*a53f50b9Schristos    #
378*a53f50b9Schristos    chop ($hostname=`uname -n`);
379*a53f50b9Schristos    $LOG_SUBJECT="$LOG_SUBJECT from $hostname" if ( $hostname =~ /.*\.cs\.columbia\.edu/ );
380*a53f50b9Schristos    #
381*a53f50b9Schristos    # End of ugly local hack
382*a53f50b9Schristos
383*a53f50b9Schristos    # Mail any log info to MAILGRUNT.
384*a53f50b9Schristos    if (defined($logfile) && $logfile ne "" ) {
385*a53f50b9Schristos	close (LOGFILE);	# Flush logfile output.
386*a53f50b9Schristos	if ( -s $logfile ) {
387*a53f50b9Schristos	    open (MAILER, "| $MAILER $MAILGRUNT");
388*a53f50b9Schristos
389*a53f50b9Schristos	    print MAILER "To: $MAILGRUNT\n";
390*a53f50b9Schristos	    print MAILER "Subject: $LOG_SUBJECT\n";
391*a53f50b9Schristos	    print MAILER "$HEADER_BODY_DELIM";
392*a53f50b9Schristos
393*a53f50b9Schristos	    open (LOGFILE, "< $logfile");
394*a53f50b9Schristos
395*a53f50b9Schristos	    while (<LOGFILE>) {
396*a53f50b9Schristos		print MAILER $_;
397*a53f50b9Schristos	    }
398*a53f50b9Schristos	    close (MAILER);
399*a53f50b9Schristos	    close (LOGFILE);
400*a53f50b9Schristos	}
401*a53f50b9Schristos
402*a53f50b9Schristos	unlink($logfile);
403*a53f50b9Schristos    }
404*a53f50b9Schristos    exit(0);
405*a53f50b9Schristos}
406*a53f50b9Schristos
407*a53f50b9Schristos
408*a53f50b9Schristos##############################################################################
409*a53f50b9Schristos#									     #
410*a53f50b9Schristos#				COLLECT_WANDERERS			     #
411*a53f50b9Schristos#									     #
412*a53f50b9Schristos##############################################################################
413*a53f50b9Schristos
414*a53f50b9Schristos#
415*a53f50b9Schristos# Collects other files that appear to be mail file for the $currentTO
416*a53f50b9Schristos# but were not remailed successfully.
417*a53f50b9Schristos#
418*a53f50b9Schristos# Parameters: none (but uses $currentTO)
419*a53f50b9Schristos# Return:  True if a old mail directory is found. False otherwise.
420*a53f50b9Schristos# Side effects: $wanderers set.
421*a53f50b9Schristos#
422*a53f50b9Schristossub Collect_wanderers {
423*a53f50b9Schristos
424*a53f50b9Schristos    undef (@wanderers);
425*a53f50b9Schristos
426*a53f50b9Schristos    # Slurp in the directory and close.
427*a53f50b9Schristos
428*a53f50b9Schristos    return ($found);
429*a53f50b9Schristos}
430*a53f50b9Schristos
431*a53f50b9Schristos#############################################################################
432*a53f50b9Schristos#									    #
433*a53f50b9Schristos#				REMAIL ALL				    #
434*a53f50b9Schristos#									    #
435*a53f50b9Schristos#############################################################################
436*a53f50b9Schristos
437*a53f50b9Schristos#
438*a53f50b9Schristos# Takes an array of files that all seem to share a common repcipient and
439*a53f50b9Schristos# remails them if possible.
440*a53f50b9Schristos#
441*a53f50b9Schristos# Parameters: None (uses @wanderers).
442*a53f50b9Schristos#
443*a53f50b9Schristossub Remail_all {
444*a53f50b9Schristos    local($file,$i);
445*a53f50b9Schristos
446*a53f50b9Schristos    $i=0;
447*a53f50b9Schristos    foreach $file (@wanderers) {
448*a53f50b9Schristos	if ( !open (LOSTFILE, "< $file"))  {
449*a53f50b9Schristos	    &Log_info("Could not open " . "$file" . " for remailing");
450*a53f50b9Schristos	    next;
451*a53f50b9Schristos	}
452*a53f50b9Schristos
453*a53f50b9Schristos	do {			# Power loop!
454*a53f50b9Schristos	    $done = &Get_next_msg(LOSTFILE); # Retrieve the next message...
455*a53f50b9Schristos	    &Do_remail;		# and remail it.
456*a53f50b9Schristos	} until $done;
457*a53f50b9Schristos	undef ($current_msg);	# Erase the final remailed message.
458*a53f50b9Schristos
459*a53f50b9Schristos	close(LOSTFILE);	# Tidy up.
460*a53f50b9Schristos
461*a53f50b9Schristos	unlink ($file);		# Remove the remailed file
462*a53f50b9Schristos	$i++;
463*a53f50b9Schristos    }
464*a53f50b9Schristos
465*a53f50b9Schristos}
466*a53f50b9Schristos
467*a53f50b9Schristos#############################################################################
468*a53f50b9Schristos#									    #
469*a53f50b9Schristos#				CHECK_USER				    #
470*a53f50b9Schristos#									    #
471*a53f50b9Schristos#############################################################################
472*a53f50b9Schristos
473*a53f50b9Schristos#
474*a53f50b9Schristos# Checks the password tables for the uid of $currentTO. If the user is
475*a53f50b9Schristos# uid 0 (ie *supposed* to get mail in altmail) or unknown the resend is
476*a53f50b9Schristos# aborted.
477*a53f50b9Schristos#
478*a53f50b9Schristos#
479*a53f50b9Schristossub Check_user {
480*a53f50b9Schristos    local (@passwdinfo);
481*a53f50b9Schristos    undef (@passwdinfo);
482*a53f50b9Schristos
483*a53f50b9Schristos    if (!$noverify && !&vrfy_user($currentTO) ) {
484*a53f50b9Schristos    	&Log_info("Possible non user mail file: $currentTO");
485*a53f50b9Schristos	return $ABORT_RESEND;
486*a53f50b9Schristos    }
487*a53f50b9Schristos
488*a53f50b9Schristos    @passwdinfo = getpwnam($currentTO);
489*a53f50b9Schristos
490*a53f50b9Schristos    print "Non user mailable mail: Name: $currentTO\n"
491*a53f50b9Schristos	if ( $debug && ! defined @passwdinfo );
492*a53f50b9Schristos
493*a53f50b9Schristos    return !$ABORT_RESEND if ( ! defined @passwdinfo ); # A non user but evidently mailable
494*a53f50b9Schristos
495*a53f50b9Schristos    print "Check User(): Name: $currentTO  -- UID: $passwdinfo[2]\n" if ($debug);
496*a53f50b9Schristos
497*a53f50b9Schristos    return $ABORT_RESEND if ( $passwdinfo[2] == 0 );
498*a53f50b9Schristos
499*a53f50b9Schristos
500*a53f50b9Schristos    return !$ABORT_RESEND;
501*a53f50b9Schristos}
502*a53f50b9Schristos
503*a53f50b9Schristos#############################################################################
504*a53f50b9Schristos#									    #
505*a53f50b9Schristos#				VRFY USER				    #
506*a53f50b9Schristos#									    #
507*a53f50b9Schristos#############################################################################
508*a53f50b9Schristos#
509*a53f50b9Schristos# Use SMTP VRFY to insure that argument is in fact a legal mail id.
510*a53f50b9Schristos#  Boolean: TRUE if mailable account, FALSE if not.
511*a53f50b9Schristos
512*a53f50b9Schristossub vrfy_user {
513*a53f50b9Schristos
514*a53f50b9Schristos	local ($mailname,$repl) = @_;
515*a53f50b9Schristos
516*a53f50b9Schristos	if ( !&smtp_send("vrfy $mailname") ) {
517*a53f50b9Schristos	    &Log_info("Failed sending to vrfy smtp command for: $mailname");
518*a53f50b9Schristos	    return 0;
519*a53f50b9Schristos	}
520*a53f50b9Schristos
521*a53f50b9Schristos	$repl = &smtp_recv;
522*a53f50b9Schristos
523*a53f50b9Schristos	print "VRFY REPLY: $repl\n" if ($debug);
524*a53f50b9Schristos
525*a53f50b9Schristos	return ( $repl =~ /^2\d\d/ );
526*a53f50b9Schristos
527*a53f50b9Schristos
528*a53f50b9Schristos}
529*a53f50b9Schristos
530*a53f50b9Schristos
531*a53f50b9Schristos#############################################################################
532*a53f50b9Schristos#									    #
533*a53f50b9Schristos#				MAIN PROC				    #
534*a53f50b9Schristos#									    #
535*a53f50b9Schristos#############################################################################
536*a53f50b9Schristos
537*a53f50b9Schristos# dummy code to shut up perl -w
538*a53f50b9Schristos$debug = 0 if !defined($debug);
539*a53f50b9Schristosprint $nomail if $debug > 1;
540*a53f50b9Schristosprint $RESENT_FROM if $debug > 1;
541*a53f50b9Schristosprint $logopen if $debug > 1;
542*a53f50b9Schristosprint $LOCAL_LOCK_EXT if $debug > 1;
543*a53f50b9Schristosprint $RESENT_TO if $debug > 1;
544*a53f50b9Schristosprint $LOCKEXT if $debug > 1;
545*a53f50b9Schristosprint $RESENT_DATE if $debug > 1;
546*a53f50b9Schristosprint $MESSAGE_DELIM if $debug > 1;
547*a53f50b9Schristosprint $SMTP_retval if $debug > 1;
548*a53f50b9Schristosprint $found if $debug > 1;
549*a53f50b9Schristosprint $retry_list if $debug > 1;
550*a53f50b9Schristosprint $MAILJUNK if $debug > 1;
551*a53f50b9Schristosprint $noverify if $debug > 1;
552*a53f50b9Schristosprint $SYSTEM_FROM_ADDRESS if $debug > 1;
553*a53f50b9Schristos
554*a53f50b9Schristos# BEGIN: stuff
555*a53f50b9Schristos$prefix="@prefix@";
556*a53f50b9Schristos$CONFIGDIR="@sysconfdir@";	# Directory where global config lives
557*a53f50b9Schristosrequire "$CONFIGDIR/lostaltmail.conf" if (-f "$CONFIGDIR/lostaltmail.conf");
558*a53f50b9Schristosrequire "/etc/global/lostaltmail.conf" if (-f "/etc/global/lostaltmail.conf");
559*a53f50b9Schristosrequire "/etc/os/lostaltmail.conf" if (-f "/etc/os/lostaltmail.conf");
560*a53f50b9Schristosrequire "/etc/local/lostaltmail.conf" if (-f "/etc/local/lostaltmail.conf");
561*a53f50b9Schristos
562*a53f50b9Schristos
563*a53f50b9Schristosrequire "ctime.pl";
564*a53f50b9Schristosuse Socket;
565*a53f50b9Schristos#require "sys/socket.ph";
566*a53f50b9Schristos
567*a53f50b9Schristos# SET some initial state variales
568*a53f50b9Schristos$logopen = 0;
569*a53f50b9Schristos
570*a53f50b9Schristos#
571*a53f50b9Schristos# Change to alt_dir
572*a53f50b9Schristos#
573*a53f50b9Schristos# Important!! This directory should be local.  Folks will be responsible
574*a53f50b9Schristos# for finding this out for themselves.
575*a53f50b9Schristos#
576*a53f50b9Schristosif (!defined($MAILDIR) || $MAILDIR eq "") {
577*a53f50b9Schristos    die "MAILDIR must be defined\n";
578*a53f50b9Schristos}
579*a53f50b9Schristoschdir ( $MAILDIR ) || die "Cannot change to $MAILDIR (`x' bit not set?)";
580*a53f50b9Schristos
581*a53f50b9Schristos#
582*a53f50b9Schristos# slurp in directory
583*a53f50b9Schristos#
584*a53f50b9Schristosopendir (MAIL, ".") || die "Cannot open $MAILDIR (`r' bit not set?)";
585*a53f50b9Schristos@allentries= readdir (MAIL);
586*a53f50b9Schristosclosedir (MAIL);
587*a53f50b9Schristos@allnames = grep (!/$LOCALMAILJUNK|$MAILJUNK/, @allentries);
588*a53f50b9Schristos
589*a53f50b9Schristos# Open chanel to SMTP for verification -- unless this option is
590*a53f50b9Schristos# configured off.
591*a53f50b9Schristos
592*a53f50b9Schristosif ( ! $noverify ) {
593*a53f50b9Schristos    local($addr, $port,$sockaddr);
594*a53f50b9Schristos
595*a53f50b9Schristos    socket (VRFY, &AF_INET, &SOCK_STREAM, 0) ||
596*a53f50b9Schristos	die "Could not create TCP socket (SMTP channel)";
597*a53f50b9Schristos
598*a53f50b9Schristos    $addr = (gethostbyname($SMTPHOST))[4]; # Just use the first addr
599*a53f50b9Schristos
600*a53f50b9Schristos    die "Could not obtain STMP host ($SMTPHOST) address"
601*a53f50b9Schristos	if ( $addr eq "" );
602*a53f50b9Schristos
603*a53f50b9Schristos    $port = (getservbyname('smtp','tcp'))[2]; # Get smtp port.
604*a53f50b9Schristos    die "Could not obtain SMTP port number" if (!defined($port));
605*a53f50b9Schristos
606*a53f50b9Schristos    printf("SMTP: address: %s   port: $port\n",
607*a53f50b9Schristos	   join ('.',unpack('C4',$addr))) if ($debug);
608*a53f50b9Schristos
609*a53f50b9Schristos    $sockaddr = sockaddr_in($port, $addr);
610*a53f50b9Schristos
611*a53f50b9Schristos    printf("Sockaddr: %s\n", join (' ',unpack('C14',$sockaddr))) if ($debug);
612*a53f50b9Schristos
613*a53f50b9Schristos    connect (VRFY, $sockaddr) ||
614*a53f50b9Schristos	die "Could not connect to SMTP daemon on $SMTPHOST";
615*a53f50b9Schristos
616*a53f50b9Schristos    print "Establshed SMTP channel\n" if ($debug);
617*a53f50b9Schristos
618*a53f50b9Schristos    &smtp_recv;	# Greet wait
619*a53f50b9Schristos    &smtp_send("helo $SMTPHOST"); # Helo message for picky SMTPs
620*a53f50b9Schristos    &smtp_recv;		# Helo reply
621*a53f50b9Schristos
622*a53f50b9Schristos    # Connection is up and ready to VRFY
623*a53f50b9Schristos}
624*a53f50b9Schristos
625*a53f50b9Schristos# main stuff starts here
626*a53f50b9Schristosforeach $currentTO (@allnames) {
627*a53f50b9Schristos    next if ( &Check_user == $ABORT_RESEND);
628*a53f50b9Schristos
629*a53f50b9Schristos    # just delete the file if too small to be real mail
630*a53f50b9Schristos    if ((stat($currentTO))[7] < 5) {
631*a53f50b9Schristos	print "Too small to be real mail, unlinking $currentTO" if $debug;
632*a53f50b9Schristos	unlink $currentTO;
633*a53f50b9Schristos    }
634*a53f50b9Schristos
635*a53f50b9Schristos    undef (@wanderers);	# Just reset this at each pass.
636*a53f50b9Schristos    @wanderers=grep (/$currentTO\.\d+/, @allentries);
637*a53f50b9Schristos
638*a53f50b9Schristos    $remail_file = &Lock_file($currentTO,$FALSE); # Need to lock the spool.
639*a53f50b9Schristos
640*a53f50b9Schristos    next if ( $remail_file eq $ABORT_RESEND); # Could not get that lock
641*a53f50b9Schristos
642*a53f50b9Schristos    push (@wanderers, $remail_file); # Try to resend "old" files.
643*a53f50b9Schristos    print "List to remail: @wanderers\n" if ($debug);
644*a53f50b9Schristos    # check if  there is something to remail
645*a53f50b9Schristos    &Remail_all if ( defined @wanderers && !$nomail);
646*a53f50b9Schristos}
647*a53f50b9Schristos
648*a53f50b9Schristos# this stuff should run at the end
649*a53f50b9Schristosforeach $file (grep (/$LOCALMAILJUNK/,@allentries)) {
650*a53f50b9Schristos
651*a53f50b9Schristos    if ($debug) {
652*a53f50b9Schristos	print "Would unlink $file\n" if ($debug);
653*a53f50b9Schristos    } else {
654*a53f50b9Schristos	unlink $file  if (-f $file);
655*a53f50b9Schristos    }
656*a53f50b9Schristos
657*a53f50b9Schristos}
658*a53f50b9Schristos&Clean_up;			# Do a clean exit.
659