Path: utzoo!news-server.csri.toronto.edu!cs.utexas.edu!swrinde!zaphod.mps.ohio-state.edu!sample.eng.ohio-state.edu!icarus!kaul From: kaul@icarus.eng.ohio-state.edu (Rich Kaul) Newsgroups: comp.mail.sendmail Subject: Re: Mail filters Message-ID: Date: 17 Mar 91 05:57:25 GMT References: <1991Mar15.195109.12234@viewlogic.com> Sender: kaul@ee.eng.ohio-state.edu (Rich Kaul) Organization: The Ohio State University Dept of Electrical Engineering Lines: 182 In-Reply-To: kenc@suntan.viewlogic.com's message of 15 Mar 91 19:51:09 GMT In article <1991Mar15.195109.12234@viewlogic.com> kenc@suntan.viewlogic.com (Kenstir) writes: I'd like to set up a filter on my mail, and I'd like it to happen between the time sendmail gets its paws on the text and the time it puts the file in /usr/spool/mail. [...] 2. Set up a .forward: "|/u/kenc/mail-filter2 kenc" And then in /u/kenc/mail-filter2: awk -f foo.awk >> /usr/spool/mail/kenc PROBLEMS: I'm not doing any file locking and I'm sure eventually I would run into race conditions. Use a better tool. I do a similar thing to filter my mail, but I use perl to do the filtering and file locking. I go further and deliver the mail to different directories for use by GNUS to mix reading of the tons of system mail, etc. that I get and news. Only critical stuff from a group of people gets through to my mailbox. I use a .forward that looks like: "|/usr/1/kaul/bin/ppmd /usr/1/kaul kaul >>/usr/1/kaul/.maillog 2>&1" and the following perl script. -rich #!/usr/bin/perl # An attempt at a perl mail delivery agent. The basic premise is # that mail from certain people demands attention immediately, so it # gets put in the normal system mailbox. Mail from mailing lists is # to be placed in various subdirectories in a format that GNUS can # handle for reading. Mail from the system, random users, etc, gets # placed in a third directory ($root). This is, of course, easily # customizable. Delivering into a directory requires a .last file to # keep track of article numbers. # # Pardon the perl style; I'm just learning but this works! Comments # welcome. # # Author: Rich Kaul (kaul@icarus.eng.ohio-state.edu) # Date: 11/13/90 # The credit where credit is due department: the core of the message # parsing is based on Larry Wall's mailagent script, although the rest # of this ugly mess (which nobody else would want to claim) is mine. ($HOME, $USER) = @ARGV; $root = "$HOME/Memos/personal"; # root of personal news tree. $dest = $root; $box = "/usr/spool/mail/$USER"; # default mail box. $GIVE_UP_BOX = "$HOME/mail_dump"; # emergency dumping box. $LOCK_SH = 1; # Values for flock() calls. $LOCK_EX = 2; $LOCK_NB = 4; $LOCK_UN = 8; umask(077); # Get a little privacy. # Now run and get the headers. We have to parse the headers before we # can figure out delivery. while () { # Do this on the From_ line only. if (1 .. 1) { if (/^From\s+(\S+)\s+[^\n]*(\w{3}\s+\d+\s+\d+:\d+)/) { $from = $1; } $from =~ s/@.*//; # remove trailing @machine $from =~ s/%.*//; # remove trailing %machine $from = $1 if $from =~ /.*!([^\n]+)/; # remove leading ! paths } # This section operates on the header of the message. We create # an array of header keys to work on later. if (1 .. /^\s*$/) { s/^From: ([^<]*)\s+<(.*)>$/From: $2 ($1)/; # rewrite ugly header $header .= $_; chop; if (/^\s*$/) { foreach $key (keys(header)) { eval "\$H$key = \$header{'$key'}"; } } else { if (s/^([-\w]+):\s*//) { ($headline = $1) =~ y/A-Z-/a-z_/; $header{$headline} .= "\n" if $header{$headline} ne ''; } else { s/^\s+/ /; } $header{$headline} .= $_; } } # And here we make the body of the message. else { $body .= $_; } } # Now we list the people who can crash into the mailbox. if($from =~ /karl_kl/ || $from =~ /alden/ || $from =~ /monty/) {$dest = $box;} elsif($from=~/pnelson/ || $from=~/wilson/i || $from =~ /gratz/i) {$dest=$box;} elsif($from =~ /bibyk/ || $from =~ /adkins/ || $from =~ /zaka/) {$dest = $box;} elsif($from =~ /kaul/ || $from =~ /aspark/ || $from =~ /george/) {$dest = $box;} # Ok, now figure out where to deliver the message. The first case is # mail from mailing lists. if($from =~ /firearms/) {$dest = "$root/firearms";} elsif($Hto =~ /firearms/i || $Hcc =~ /firearms/i ) {$dest = "$root/firearms";} elsif($from =~ /freemacs/) {$dest = "$root/freemacs";} elsif ($Hto =~ /gif/ || $Hcc =~ /gif/) {$dest = "$root/gif";} elsif($Hto =~ /gnuplot/ || $Hcc =~ /gnuplot/) {$dest = "$root/gnuplot";} elsif ($Hto =~ /freemacs/ || $Hcc =~ /freemacs/) {$dest = "$root/freemacs";} elsif ($Hto =~ /interviews/i || $Hcc =~ /interviews/i ) { $dest = "$root/interviews";} elsif ($Hto =~ /vem/i || $Hto =~ /oct/i || $Hcc =~ /vem/i || $Hcc =~ /oct/i) { $dest = "$root/vem";} elsif($Hto =~ /xviewbug-trackers/ || $Hcc =~ /xviewbug-trackers/) { $dest = "$root/xview";} # Here we dump system messages. It grows too fast and should be split # up soon... if($from =~ /root/ || $from =~ /news/) { $dest = "$root/system";} elsif($Hto =~ /site/ || $Hcc =~ /site/) { $dest = "$root/system";} # Now we do the delivery. There are two cases. If we are delivering # to a directory find and update the .last file there. if ( -d $dest ) { # It's going to be a news article, so change the From_ line $header =~ s/^From /Unix-From: /; $all = $header . $body; $count_file = "$dest/\.last"; open(COUNTER,"+<$count_file")|| do gag("Can't open $dest/.last ($< $>): $!"); while () { chop; $count = $_; $count++; } do flocker(COUNTER,$LOCK_EX); # Lock the file, just in case. seek(COUNTER,0,0); print COUNTER $count,"\n"; do flocker(COUNTER,$LOCK_UN); # We now have the article number we need. open(ART,">>$dest/$count") || do gag("Can't open $dest/$count ($< $>): $!"); print ART $all,"\n"; } else { # Here we're delivering to a file, which is easier. Build and deliver. $all = $header . $body; open(BOX, ">>$dest") || do gag ("Can't open $dest ($< $>): $!"); do flocker(BOX,$LOCK_EX); print BOX $all,"\n\n"; do flocker(BOX,$LOCK_UN); } # File locking subroutine. sub flocker { local ($file, $mode) = @_; eval 'flock($file,$mode);'; seek($file, 0, 2); # in case it was appended while we were waiting } # For some reason mail couldn't get delivered. Dump the message in the # emergency mailbox and exit. sub gag { open(ERR_BOX, ">>$GIVE_UP_BOX") || die "`date`: I'm really hosed. I can't even open the emergency box $GIVE_UP_BOX\n"; print @_; do flocker(ERR_BOX,$LOCK_EX); print ERR_BOX $all,"\n\n"; do flocker(ERR_BOX,$LOCK_UN); exit 1; } -- Rich Kaul | "They that can give up essential liberty kaul@icarus.eng.ohio-state.edu | to obtain a little temporary safety or ...!osu-cis!kaul | deserve neither liberty nor safety."