[alt.sources] Kill file for mail.

falk@peregrine.Eng.Sun.COM (Ed Falk) (11/07/90)

In article <1990Nov06.052117.26136@ddsw1.MCS.COM>, arf@ddsw1.MCS.COM (Jack Schmidling) writes:
> 
>  
>                    HATE MAIL FROM A FOOL
>  
>  	[complaint about hate mail]

Here's a handy shell script I use all the time.  If you're running
unix, you can use this program to sort your incoming mail based on
anything in the header.  You can send your mail to different folders,
or even /dev/null.  It's also possible to send mail through a filter,
say to reformat it or something.  It would even be easy to take mail
from a particular user, and bounce it back to that person, or
Postmaster at that person's site....

Make this script executable, name it "sortmail", put it where the
mailer daemon can access it (watch those permissions), and create a
.forward file in your home directory to divert your mail through the
script.

CAVEAT:  Whenever you install any script or program to filter
your mail, test it thoroughly by sending yourself mail from other
accounts and from other machines.

This script works on Suns, I haven't tried it on other machines.

#!/bin/csh -f
#
#
#
#   create this $HOME/.forward file:
#
#	"| /home/myname/bin/sortmail myname"
#
# (exact path depends on where you put this script.  You must use a
# full path)
#
# mail is classified according to the "$list" variable.
# Classifiable mail goes to the corresponding mailbox entry.
#
# unclasifiable mail drops out at the bottom and goes to "$default"
#
# Don't forget to make sortmail executable.
#
# To classify mail according to who it was directed
# to, use the variable "${TO}" rather than the string
# "To:.*"  Look at the definition of "${TO}" to see why.
#
# leading '+' in a filename expands to $maildir/
#
# if the filename is '|', then the next item in the list is the full
# pathname of a program to run with the message as stdin.  No arguments
# may be passed, so your program will probably be a short shell script.
#
# Setting the "$vacation" variable also activates vacation for all mail sent
# directly to you.  If you set 'vacation', make sure there's a
# .vacation.msg file as described in vacation(1).  Also run "vacation -I"
# as per the vacation(1) man page.
#
#
# variables you may want to customize:
#
#	list		list of test lines and folder names.
#	user		username.  Normally provided in .forward
#	mailbox		where user's mail would normally be stored.
#	maildir		where user's mail folders are stored.
#	vacation	set to turn on vacation program.
#	default		Where unclassifiable mail goes.

set user=$1
set mailbox=/usr/spool/mail/$user
set maildir=~$user/Mail
#set vacation
set noglob

set TO="^(To|Cc|Apparently-To):.*"

# pairs of test lines and mailbox names
#
# In this example, mail from MAILER-DAEMON  goes to +bounces
#	mail from joe with the 132-character terminal
#		gets passed through a script to reformat it.
#	mail from isaac@goanna goes to /dev/null.
#	mail from realjerk@psuvm.edu goes through a script that
#		sends it to Postmaster@psuvm.edu.
#	mail to me specificly goes to my mailbox
#	mail to the scuba mailing list goes to the +scuba folder.
#	mail with a "Precedence: junk" line goes to +other.
#	everything else goes to +other.

set list=( \
	"^From:.*MAILER-DAEMON" +bounces \
	"^From:.*joe@shmoe" | /home/myname/bin/fixjoe \
	"^From:.*isaac@goanna.cs.rmit.OZ.AU" /dev/null \
	"^From:.*realjerk@psuvm.edu" /dev/null \
	"${TO}$user" $mailbox \
	"${TO}scuba" +scuba \
	"^Precedence: junk" +other \
	)

#set default=$mailbox
set default=+other

set logfile = /dev/console
#set logfile = ~$user/msglog

# end of user-customized variables




set path=(/usr/ucb /usr/bin /bin)
set HOST=`/bin/hostname`
set SCRIPT=`basename $0`
set SYNTAX="$SCRIPT username [param-file]"
set MSGTMP=/usr/tmp/sortmail-tmp_$$
set HDRTMP=/usr/tmp/sortmail-hdr_$$

rm -f $MSGTMP $HDRTMP		# Make sure temp files clear

sed -e '2,$s/^From />From /' -e '1s/>From /From /' > $MSGTMP
sed -e '/^$/,$d' < $MSGTMP > $HDRTMP

#echo ===================== >> $logfile
#cat $HDRTMP >> $logfile
#echo ===================== >> $logfile
#cat $MSGTMP >> $logfile
#echo ===================== >> $logfile

#egrep '^From:' $HDRTMP >> $logfile
#egrep '^To:' $HDRTMP >> $logfile
#egrep '^Subject:' $HDRTMP >> $logfile

if ( $status != 0 ) then
  echo ${SCRIPT}: Sorry - error while receiving your message to $user.
  echo ${SCRIPT}: /usr/tmp filesystem on $HOST probably full
  cat $MSGTMP >> $mailbox
  /bin/rm -f $MSGTMP $HDRTMP
  echo `date` $SCRIPT lost a mail message >> /dev/console
  exit 1
endif

echo "" >> $MSGTMP

while ( $#list > 1  &&  $?FILED == 0 )
  egrep -i -s "$list[1]" $HDRTMP
  if ( $status == 0 ) then
    if ( $list[2] == '|' ) then
#      echo piped through $list[3] >> $logfile
      $list[3] < $MSGTMP
    else
      set box=`echo $list[2] | sed "s.^+.$maildir/."`
      cat $MSGTMP >> $box
#      echo filed to $box >> $logfile
    endif
    if ( $status == 0 ) then
      set FILED
      break
    endif
  endif
  if ( $list[2] == '|' ) shift list
  shift list
  shift list
end



if ( $?FILED == 0 ) then
  set box=`echo $default | sed "s.^+.$maildir/."`
  cat $MSGTMP >> $box
#  echo not classified, filed to $box >> $logfile
endif



if ( $?vacation ) then
  egrep -i -s "$(TO)$user" $MSGTMP
  if ( $status == 0 ) /usr/ucb/vacation $user < $MSGTMP
endif


/bin/rm -f $MSGTMP $HDRTMP
exit 0
--
	-ed falk, sun microsystems -- sun!falk, falk@sun.com
	"What are politicians going to tell people when the
	Constitution is gone and we still have a drug problem?"
			-- William Simpson, A.C.L.U.

Harald.Eikrem@elab-runit.sintef.no (11/08/90)

Here's another approach to sorting mailboxes.  Perl based, what else?
There's no separate man page.  It does not pipe messages to programs, because
it is strictly a mail sorter.  True improvements are of course welcomed.

--Harald E


++++Perl script follows, save as `mailsort' in your favourite bin directory++++

#!/usr/local/bin/perl

# Usage "mailsort [ MAILBOX... ]"    Requires perl 3.0 patchlevel 4 up.
# Sorts Unix mailbox file(s) into mailbox folders at ~/Mail/<folder>,
# default input file is /usr{/spool,}/mail/<login>.
# Produces two kinds of folder summaries, one building up for each
# folder (~/Mail/.sum/<folder>), and another about all new messages
# from the last sort (~/Mail/.sum/NEW).
# The sorting is based on a sort file (~/Mail/.fsort)
# using the following conventions:
#  - Each line should contain a keyword and a folder name.
#  - The keyword and folder tokens are separated by one or more <tab>.
#  - A blank character in the keyword matches any number of whitespaces.
#  - Keyword matches are always case-INsensitive.
#  - Regular expressions are valid, but take care. Not everything is
#    going to work.
#  - Key order might be significant.
#  - Mail header reserved words should only be preceeded by a circumflex
#    (^) and end in a colon (:). There is no need to insert random string
#    matches in beetween the MHRW and the matching string, a single
#    space is suitable, e.g. "^From: henry@vcu<tab>henry"
#    will match a From: header field with "henry@vcu" anywhere on that
#    line, the message is written to the folder named "henry".
#    "^To:" will match both To: and Cc: header records.
#  - Mail header continuation lines are not recognised on a regular basis.
#  - Mail header trace lines are not rendered in the folder decisions.
#  - Any other kind of keyword will match *anything* in the mail header.
#  - Default folder name is "inbox".
#
# Written 5. Feb 90 by Harald Eikrem, SINTEF, Trondheim, Norway.
# (Some ideas lent from `from' script by Johan Vromans).
#      <Harald.Eikrem@elab-runit.sintef.no>
# PS. I am sure someone can optimise this algorithm. A perl novice I am.
#
# Modified 8. Feb 90 -- redesigned key struct
# Modified 21. Mar 90 -- modified "^To:" keyword to match both To: and Cc:.
# Modified 1. Apr 90 -- now handles absolute or relative folder file
#			referencing, e.g. /dev/null (this is no joke)

if ( $#ARGV < 0 ) {
  if ( ! ($user = getlogin)) {
    @a = getpwuid($<);
    $user = $a[0];
  }
  if ( -r "/usr/spool/mail/$user" ) {
    @ARGV = ("/usr/spool/mail/$user");
  }
  elsif ( -r "/usr/mail/$user" ) {
    @ARGV = ("/usr/mail/$user");
  }
  else {
    printf STDERR "No mail for $user.\n";
    exit 1;
  }
}

$Maildir = $ENV{"HOME"}."/Mail";

if ( ! -d $Maildir ) {
    printf STDERR "No ~/Mail directory.\n";
    exit 1;
}

$fsort = ".fsort";

if ( ! -r "$Maildir/$fsort" ) {
    printf STDERR "No sort file ~/Mail/$fsort\n";
    exit 1;
}

# read sort file
open(srt, "<$Maildir/$fsort");
for ($index = 1; $line = <srt>; ++$index ) {
  chop($line);
  next if $line =~ /^#/ || $line =~ /^\s*$/;
  $line =~ /^([^\t]+)\t+(\S+)\s*$/;
  $key[$index] = $1;
  $val[$index] = $2 ? $2 : "inbox";
  $key[$index] =~ s/^\^?([\w-]+\s*:)\s*(.+)/^$1[^\\n]*$2/;
  $key[$index] =~ s/\s+/\\s+/g;
  $key[$index] =~ s/(\[[^\]]*)\\s+/$1 /g;
  $key[$index] =~ s/\\\\s\+?/ /g;
  $key[$index] =~ s/^\^/\\n/;
  if (/^(\n)To(:.*)/i) { $key[++$index] = s//$1Cc$2/; }
#  printf "%3d KEY = %-42s VAL = %-s\n",$index,$key[$index],$val[$index];
}
close(srt);
$MAXKEY = $index-1;

if ( ! -d "$Maildir/.sum" ) { mkdir("$Maildir/.sum", 0755); }

# go through input file(s)
while ( $line = <> ) {

  # scan until "From_" header found
  if ( $line !~ /^From\s+(\S+)\s+[^\n]*(\w{3}\s+\d+\s+\d+:\d+)/ ) {
    print fld $line if $folder;
    next;
  }

  $from = $1; $date = $2;
  $full_header = $line;
  $header = $line;
  $Recline = 0;

  # get user name from uucp path
  $from = $1 if $from =~ /.*!([^\n]+)/;

  # now, scan for Subject or empty line
  $subj = "";
  while ( $line = <> ) {

    if ( $line =~ /^$/ ) {
      # force fall-though
      $subj = "(none)" unless $subj;
      last;
    }
    $full_header .= $line;
    # Skip trace header lines
    if ($Recline && $line !~ /^\s/) { $Recline = 0; }
    if ($Recline || $line =~ /^Received\s*:/) { $Recline = 1; } 
    else { $header .= $line; }
    $subj = $1 if $line =~ /^Subject\s*:\s*([^\n]*)/;
    if ( $line =~ /^From\s*:\s*/ ) {
      $line = $';
      if ( $line =~ /\(([^\n]+)\)/ ) { $from = $1; } 
      elsif ( $line =~ /^"?([^<\n"]+)"?\s*<[^\n]+>/ ) { $from = $1; } 
      elsif ( $line =~ /^<?([^>\n]+)>?/ ) { $from = $1; } 
    }
  }

  $folder = "";
  study($header);
  for ($index = 1; !$folder && $index <= $MAXKEY; ++$index ) {
    $folder = $val[$index] if $header =~ /$key[$index]/i;
  }
  $folder = "inbox" unless $folder;
  $summary{$folder} .=
	 sprintf(" %-12.12s \"%-17.17s\" %-.45s\n", $date,$from,$subj);
  close(fld);
  if ($folder =~ m#^[/.]#) {
    open(fld, ">>$folder");
  } else {
    open(fld, ">>$Maildir/$folder");
  }
  print fld $full_header,"\n";
}

close(fld);

open(new, ">>$Maildir/.sum/NEW");

while ( ($folder,$sumtext) = each(%summary) ) {
  print new $folder,":\n",$sumtext;
  open(sum, ">>$Maildir/.sum/$folder");
  print sum $sumtext;
  close(sum);
}
close(new);