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