diff -rcN sendmail-8.8.7-orig/COPYING.SPAMCAN sendmail-8.8.7-spamcan-95/COPYING.SPAMCAN
*** sendmail-8.8.7-orig/COPYING.SPAMCAN	Wed Dec 31 16:00:00 1969
--- sendmail-8.8.7-spamcan-95/COPYING.SPAMCAN	Sat Sep 20 18:53:01 1997
***************
*** 0 ****
--- 1,2 ----
+ 
+ This version is hereby in the public domain.  There is no warranty.
diff -rcN sendmail-8.8.7-orig/COPYRIGHT.SPAMCAN sendmail-8.8.7-spamcan-95/COPYRIGHT.SPAMCAN
*** sendmail-8.8.7-orig/COPYRIGHT.SPAMCAN	Wed Dec 31 16:00:00 1969
--- sendmail-8.8.7-spamcan-95/COPYRIGHT.SPAMCAN	Sat Sep 20 18:54:18 1997
***************
*** 0 ****
--- 1,8 ----
+ For all software in this distribution:
+ 
+ 	Copyright 1997 Timothy Berger -- All Rights Reserved
+ 
+ This program is free software; distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ 
diff -rcN sendmail-8.8.7-orig/INSTALL.SPAMCAN sendmail-8.8.7-spamcan-95/INSTALL.SPAMCAN
*** sendmail-8.8.7-orig/INSTALL.SPAMCAN	Wed Dec 31 16:00:00 1969
--- sendmail-8.8.7-spamcan-95/INSTALL.SPAMCAN	Tue Sep 30 00:14:00 1997
***************
*** 0 ****
--- 1,32 ----
+ 
+  1) Apply context diff to clean Sendmail 8.8.7 distribution.
+ 	You might need gnu patch.
+ 
+ 	Eg: 
+ 	tar xzvf sendmail.8.8.7.tar.gz
+ 	tar xzvf spamcan.tar.gz
+ 	cd sendmail-8.8.7
+ 	patch -p1 < ../spamcan_for_v887_diff.patch
+ 
+  2) Do **NOT** use gnu rx unless your system is missing some form
+ 	of regex.  I have observed segmentation faults in the rx
+ 	library	on systems with regexec and regcomp in the system's 
+ 	libc.  Sorry for previously recommending this on solaris.
+ 
+  3) Tailor spamcan.c to suit your environment.  Chose the type 
+ 	of messages you'd like to pass through un-scanned.  This is documented
+ 	in the source code.
+ 
+  4) Create /etc/spamcan.cf and put some regular expressions there.
+ 	An example regular expression file has been included.
+ 
+  5) Create /etc/spamcan-exceptins.cf.  Optionally put some regular expressions
+     there.  Note, this exceptions file does not understand header names.  Because
+     of added overhead, I decided this did not add much value.
+ 
+  6) Touch /var/spool/mail/spamcan on linux or /var/mail/spamcan on Solaris.
+     Make it writable by daemon or root on solaris or by mail on linux.
+ 
+  7) Make and install sendmail.
+ 
+ -tim
diff -rcN sendmail-8.8.7-orig/NEWS.SPAMCAN sendmail-8.8.7-spamcan-95/NEWS.SPAMCAN
*** sendmail-8.8.7-orig/NEWS.SPAMCAN	Wed Dec 31 16:00:00 1969
--- sendmail-8.8.7-spamcan-95/NEWS.SPAMCAN	Mon Sep 29 23:42:14 1997
***************
*** 0 ****
--- 1,47 ----
+ 
+ Since spamcan .94
+ -----------------
+ * Version .95 is a pretty minor release for sendmail-8.8.7.
+   It will not be back-patched for 8.8.6.
+ * Has an exceptions list feature.
+ * Fixes a buffer overflow problem.
+ * Conversion from net byte order to host byte order for hosts where this
+   differs.  Contributed by toivo@ucs.uwa.edu.au.
+ 
+ Since spamcan .92
+ -----------------
+ * There were some spam catching problems with this version.
+   Fixed this.
+ * Added user-ownable spamcan support.  If a user touches
+   /var/spool/mail/username.spam, caught spam will be
+   sent there.  As with .nospamcan.username, this has to 
+   be owned by the appropriate user.
+ * Added support for using the header name in the regular
+   expression.
+ 
+ Since spamcan .90
+ -----------------
+ * Fixed possible segmentation fault problem if ctladdr is NULL
+ 
+ Since spamcan .87
+ -----------------
+ * users can now disable spam catching if they touch
+   /var/spool/mail/.nospamcan.username
+ * fixed possible problem where delivery to the spamcan would not
+   work if the recipient was a file.
+ * misc. bug fixes.
+ * added logging all over the place.  commented much of it out though.
+   this should be #ifdef'd
+ * learned not to use the rx package.  yes, this bit me.
+ * seems over-all much more stable
+ 
+ Since spamcan .86
+ -----------------
+ * got rid of x-spamcan-to and x-spamcan-from headers; not useful for much
+ * included simple report script
+ * make context diff
+ * small change to use the right path for spamcan file
+ 
+ Since spamcan .85
+ -------------------
+ * fixed documentation bug 
diff -rcN sendmail-8.8.7-orig/TODO.SPAMCAN sendmail-8.8.7-spamcan-95/TODO.SPAMCAN
*** sendmail-8.8.7-orig/TODO.SPAMCAN	Wed Dec 31 16:00:00 1969
--- sendmail-8.8.7-spamcan-95/TODO.SPAMCAN	Mon Sep 29 23:52:31 1997
***************
*** 0 ****
--- 1,37 ----
+ spamcan TODO list
+ ------------------
+ 
+ * Impliment a scoring system.  Assign points to regular expressions.
+   Add up the points for a mail message; if this number reaches some 
+   threashold, identify the message as spam.  Otherwise deliver mail
+   with an X-Spamlevel header with the number of points as the header
+   value.  For example, procmail's ~/.procmailrc would look like so:
+ 
+ :0 h
+ SPAMLEVEL=|formail -xX-Spamlevel:
+ 
+ :0
+ * ? test $SPAMLEVEL -gt 60
+ Mail/spamorama
+ 
+ :0
+ * ? test $SPAMLEVEL -gt 40
+ Mail/spam
+ :0
+ 
+ * ? test $SPAMLEVEL -gt 30
+ Mail/junk
+ 
+ :0
+ * ? test $SPAMLEVLE -gt 20
+ Mail/junk_lists
+ 
+ :0
+ * ? test $SPAMLEVEL -gt 10
+ Mail/lists
+ 
+ * Assign spamlevel on a per message basis rather than on a per-recipient
+   basis.  This should speed things up slightly for multiple hits.
+ 
+ * Fix X-Spamcan-Reason header.  Sometimes the wrong recipient is shown if
+   there were multiple hits.
diff -rcN sendmail-8.8.7-orig/sample-spamcan.cf sendmail-8.8.7-spamcan-95/sample-spamcan.cf
*** sendmail-8.8.7-orig/sample-spamcan.cf	Wed Dec 31 16:00:00 1969
--- sendmail-8.8.7-spamcan-95/sample-spamcan.cf	Thu Aug 21 23:27:45 1997
***************
*** 0 ****
--- 1,39 ----
+ productlink@earthlink\.com
+ sales@claythay\.com
+ keepmailing
+ x-advertisement
+ sexyhot
+ marathon4com
+ (^Subject:.*(free|making).*money)
+ fresh.*addresses
+ mega-mailer
+ ExtractorPro
+ ((stealth|mass).*mailer)
+ corporate.*marketing.*lists
+ marketing.*make.*you.*rich
+ make.*money.*fast
+ health\.information\.news
+ mail.*for.*sale
+ million.*messages.*per.*hour
+ message.*millions.*hour
+ bulk.*mail
+ (^(From|To):.*[0-9]{8}@.*\.(org|net|com))
+ (cyber(market|shop|promo|gold))
+ e-mail.*marketing
+ ((From|To):.*(sales|srhot|foryou|allvip|mailman|succeed|success|everyon|megaweb|emailer|allinternetusers|market|4u|Friend)@.*\.(org|net|com))
+ ((sallynet|scholarship|shoppingplanet|answerme|onlineprofit|yourdomain|ispam|devotion|quantcom|savetrees|nowhere|bank)\.(com|org))
+ ^\$.*per.*month
+ ^\$.*a.*minute
+ E-X-P-0-S-E
+ major.*credit.*card
+ --- CLOAKED! ---
+ Internet\.Mail\.Delivery
+ low.*cost.*service
+ (long.*distance.*(service|rates))
+ ^([a-z]*[0-9]+@juno.com)
+ Adults Only
+ (international.*(rates|service))
+ VideoSex
+ (Floodgate.*(pro|bulk))
+ save.*over.*[0-9]+%
+ save the [a-z]+.*(!|\*).*(!|\*)
diff -rcN sendmail-8.8.7-orig/spamcan.html sendmail-8.8.7-spamcan-95/spamcan.html
*** sendmail-8.8.7-orig/spamcan.html	Wed Dec 31 16:00:00 1969
--- sendmail-8.8.7-spamcan-95/spamcan.html	Thu Aug 21 23:27:45 1997
***************
*** 0 ****
--- 1,137 ----
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+ <HTML>
+ <HEAD>
+    <TITLE>Spamcan: A Sendmail patch to capture spam by regular expression</TITLE>
+    <META NAME="Author" CONTENT="Tim Berger">
+    <META NAME="Keywords" CONTENT="spamcan regular expression anti-spam sendmail patches capture site-wide">
+ </HEAD>
+ 
+ <BODY BGCOLOR="#FFFFFF">
+ <P><FONT SIZE=+3>Spamcan: A Sendmail patch to capture spam by regular expression</font>
+ 
+ <p>
+ <DL>
+ <DD> <A HREF="ftp://consult.ml.org/pub/">Get the current release</A></DD>
+ 
+ <DD><BR>
+ </DD>
+ </DL>
+ 
+ <p>
+ 
+ <i>Spamcan</i> is a simple yet extremely powerful junkmail
+ capturing/nuking sofware patch to Sendmail v8.  It is designed to
+ capture site-wide junkmail to a global capture file, a user owned spam
+ mailbox if it exists, or to /dev/null.
+ 
+ <P>
+ 
+ While user-level filtering programs such as procmail may be used to
+ filter out spam by regular expression, Spamcan is the first of it's
+ kind designed to capture spam site-wide by regular expression.  In my
+ experience, bouncing spam is futile and wasts bandwidth.  Most spam
+ has forged addresses and invalid return addresses.
+ 
+ <p>
+ 
+ <i>Spamcan</i> was written with the philosophy that unsolicited email is an
+ evil and disruptive presence.  In my opinion it is unreasonable to
+ ask or require each and every user at a site with hundreds of users to
+ put up with unsolicited email or to manage their own anti-spam rules.
+ I beleve it is up to the system administration group to provide
+ excellent service to the user community and I belive Spamcan is a
+ powerful tool that aids in providing excellent service.
+ 
+ <p>
+ 
+ <i>Spamcan</i> works by comparing every header line of a mail message,
+ including subject line, with a list of regular expressions you've
+ prepared.  By default matching is not case sensitive.  The expression
+ list typically contains lines such as the following:
+ 
+ <pre>
+ x-advertisement
+ sexyhot
+ (Subject: ((free|making).*money))
+ fresh.*addresses
+ mega-mailer
+ ExtractorPro
+ ((stealth|mass).*mailer)
+ make.*money.*fast
+ ((From|To): ([0-9]{8}@.*\.(org|net|com)))
+ (cyber(market|shop|promo|gold))
+ ((sales|srhot|foryou|allvip|mailman|succeed|success|everyon|megaweb|emailer|allinternetusers|market|4u|Friend)@.*\.(org|net|com))
+ ((sallynet|scholarship|shoppingplanet|answerme|onlineprofit|yourdomain|ispam|devotion|quantcom|savetrees|nowhere|bank)\.(com|org))
+ --- CLOAKED! ---
+ </pre>
+ 
+ The envelope "from" is also examined.  Using regular expressions
+ is a very powerful and dangerous capability.  Extreme caution must be
+ taken in formulating your expressions.  Fortunately, Spamcan does not
+ discard or bounce email.  Rather, Spamcan <i>cans</i> it to a
+ <i>spamcan</i>.  In the unfortunate event that you've managed to
+ capture non-spam, it may be forwarded to the appropriate user.
+ <i>Spamcan</i> adds the header X-Spamcan-Reason to every message it
+ identifies as spam before sending it to the spamcan.  It contains the
+ reason for identifying the mail as spam and the intended recipient.
+ 
+ <p>
+ 
+ All spamcan diagnostics are logged via syslog with the mail facility
+ at the debug level.  Look for any problems relating to spamcan there.
+ 
+ <p>
+ 
+ Spamcan was designed to be installed on the internal mailhost for
+ several reasons.  /var/spool/mail is used for <i>username</i>.spam and
+ .nospamcan.<i>username</i> because in many installations it is
+ globablly writable.  It's generally not a good idea to access user
+ home directories because large mail distributions may cause your
+ automounter to mount everyone's home.  I recommend you don't do this
+ with .forward either.
+ 
+ <p>
+ 
+ <ul>
+ 
+ <li>It's not a good idea to mess with your relay host since it
+ resides outside the firewall.  Since you're beind the firewall, it's
+ probably inconvenient to mess with anything on the other side.<br>
+ 
+ <li> Users at your site may choose not to have <i>Spamcan</i> scan
+ their mail by touching /var/spool/mail/.nospamcan.<i>username</i>.
+ <i>Spamcan</i> needs to look for this.
+ 
+ <li> Users at your site may choose to have spam directed a personal
+ spam mailbox owned by them by touching /var/spool/mail/<i>username</i>.spam.
+ 
+ </ul>
+ 
+ <i>Spamcan</i> was designed stay out of the way of valid mail message
+ traffic.  It examines all non-message-id headers.  Internal mail and
+ outgoing mail is not examined.  Incoming mail messages containing the
+ in-reply-to header are also passed through un-examined.  If spammers
+ use this as a back-door this feature may have to be removed.
+ 
+ <p>
+ 
+ Spamcan is known to work on Linux, Solaris and Irix but I'm sure it
+ would not take much to make it work on other platforms.
+ 
+ <p>
+ 
+ Please let me know if you find Spamcan useful.  Send bug reports,
+ enhancements, or comments to <a
+ href=mailto:spamcan-proj@consult.ml.org">
+ spamcan-proj@consult.ml.org</a>
+ 
+ <P>
+ 
+ I'm always interested in hearing from sites that have feedback,
+ good or bad.<BR>
+ <P>
+ <p>
+ Tim Berger
+ 
+ </BODY>
+ </HTML>
diff -rcN sendmail-8.8.7-orig/spamreport.pl sendmail-8.8.7-spamcan-95/spamreport.pl
*** sendmail-8.8.7-orig/spamreport.pl	Wed Dec 31 16:00:00 1969
--- sendmail-8.8.7-spamcan-95/spamreport.pl	Thu Aug 21 23:27:45 1997
***************
*** 0 ****
--- 1,25 ----
+ #!/usr/local/bin/perl
+ 
+ # Tim Berger
+ # 7.7.97
+ 
+ $spamcan = "/var/mail/spamcan";
+ 
+ print "Content-Type: text/plain\n\n";
+ 
+ print "Captured Spam\n\n";
+ 
+ open(SPAMCAN, $spamcan) || print "Unavailable";
+ 
+ $date = 0;
+ while (<SPAMCAN>) {
+     if (/^Date: ([a-z]{3}), ([0-9]{1,2}) ([a-z]{3})/i && $date == 0) {
+       print "$3 $2: ";
+ 	$date = 1;
+       }
+     if (/^X-Spamcan-Reason: (.*)/ && $date == 1) {
+ 	print "$1\n";
+ 	$date = 0;	
+     }
+ }
+ 
diff -rcN sendmail-8.8.7-orig/src/Makefiles/Makefile.Linux sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.Linux
*** sendmail-8.8.7-orig/src/Makefiles/Makefile.Linux	Sun Jul  6 11:22:57 1997
--- sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.Linux	Thu Aug 21 23:27:45 1997
***************
*** 24,30 ****
  #
  
  # use O=-O (usual) or O=-g (debugging)
! O=	-O
  
  # define the database mechanisms available for map & alias lookups:
  #	-DNDBM -- use new DBM
--- 24,30 ----
  #
  
  # use O=-O (usual) or O=-g (debugging)
! O=	-g
  
  # define the database mechanisms available for map & alias lookups:
  #	-DNDBM -- use new DBM
***************
*** 61,67 ****
  HFDIR=	${DESTDIR}/usr/lib
  
  # additional .o files needed
! OBJADD=
  
  # additional pseudo-sources needed
  BEFORE=
--- 61,67 ----
  HFDIR=	${DESTDIR}/usr/lib
  
  # additional .o files needed
! OBJADD= spamcan.o
  
  # additional pseudo-sources needed
  BEFORE=
diff -rcN sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.1 sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.1
*** sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.1	Tue Jun 24 14:56:27 1997
--- sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.1	Thu Aug 21 23:27:45 1997
***************
*** 32,45 ****
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include
  
  # library directories
! LIBDIRS=-L/usr/sww/lib
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
! LIBS=	-lresolv -l44bsd -lsocket -lnsl -lelf
  
  # location of sendmail binary (usually /usr/sbin or /usr/lib)
  BINDIR=	${DESTDIR}/usr/lib
--- 32,45 ----
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include -I/usr/local/include
  
  # library directories
! LIBDIRS=-L/usr/sww/lib -L/usr/local/lib
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
! LIBS=	-lresolv -l44bsd -lsocket -lnsl -lelf 
  
  # location of sendmail binary (usually /usr/sbin or /usr/lib)
  BINDIR=	${DESTDIR}/usr/lib
***************
*** 51,57 ****
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD=
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
--- 51,57 ----
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD= spamcan.o
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
diff -rcN sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.2 sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.2
*** sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.2	Tue Jun 24 14:56:27 1997
--- sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.2	Thu Aug 21 23:27:45 1997
***************
*** 32,45 ****
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include
  
  # library directories
! LIBDIRS=-L/usr/sww/lib
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
! LIBS=	-lresolv -l44bsd -lsocket -lnsl -lelf
  
  # location of sendmail binary (usually /usr/sbin or /usr/lib)
  BINDIR=	${DESTDIR}/usr/lib
--- 32,46 ----
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include  -I/usr/local/include
  
  # library directories
! LIBDIRS=-L/usr/sww/lib -L/usr/local/lib
! 
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
! LIBS=	-lresolv -l44bsd -lsocket -lnsl -lelf 
  
  # location of sendmail binary (usually /usr/sbin or /usr/lib)
  BINDIR=	${DESTDIR}/usr/lib
***************
*** 51,57 ****
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD=
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
--- 52,58 ----
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD= spamcan.o
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
diff -rcN sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.3 sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.3
*** sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.3	Tue Jun 24 14:56:27 1997
--- sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.3	Thu Aug 21 23:27:45 1997
***************
*** 31,40 ****
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include
  
  # library directories
! LIBDIRS=-L/usr/sww/lib
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
--- 31,40 ----
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include -I/usr/local/include
  
  # library directories
! LIBDIRS=-L/usr/sww/lib  -L/usr/local/lib
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
***************
*** 50,56 ****
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD=
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
--- 50,56 ----
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD= spamcan.o
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
diff -rcN sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.4 sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.4
*** sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.4	Tue Jun 24 14:56:27 1997
--- sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.4	Thu Aug 21 23:27:45 1997
***************
*** 33,42 ****
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include
  
  # library directories
! LIBDIRS=-L/usr/sww/lib
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
--- 33,42 ----
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include  -I/usr/local/include
  
  # library directories
! LIBDIRS=-L/usr/sww/lib -L/usr/local/lib
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
***************
*** 53,59 ****
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD=
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
--- 53,59 ----
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD= spamcan.o
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
diff -rcN sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.5 sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.5
*** sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.5	Tue Jun 24 14:56:27 1997
--- sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.5	Thu Aug 21 23:27:45 1997
***************
*** 12,18 ****
  
  # use O=-O (usual) or O=-g (debugging)
  # warning: do not use -O with versions of gcc prior to 2.6
! O=	-O
  
  CC=	gcc
  
--- 12,18 ----
  
  # use O=-O (usual) or O=-g (debugging)
  # warning: do not use -O with versions of gcc prior to 2.6
! O=	-g
  
  CC=	gcc
  
***************
*** 23,29 ****
  # The really old (V7) DBM library is no longer supported.
  # See READ_ME for a description of how these flags interact.
  #
! DBMDEF=	-DNDBM -DNIS -DNISPLUS
  
  # environment definitions (e.g., -D_AIX3)
  ENVDEF=	-DSOLARIS=20500
--- 23,29 ----
  # The really old (V7) DBM library is no longer supported.
  # See READ_ME for a description of how these flags interact.
  #
! DBMDEF=	-DNDBM -DNIS
  
  # environment definitions (e.g., -D_AIX3)
  ENVDEF=	-DSOLARIS=20500
***************
*** 31,45 ****
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include
  
  # library directories
! LIBDIRS=-L/usr/sww/lib
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
  #  add -ldb if you add -DNEWDB above (in DBMDEF)
! LIBS=	-lresolv -l44bsd -lsocket -lnsl -lkstat
  
  # location of sendmail binary (usually /usr/sbin or /usr/lib)
  BINDIR=	${DESTDIR}/usr/lib
--- 31,45 ----
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include -I/usr/local/include 
  
  # library directories
! LIBDIRS=-L/usr/sww/lib -L/usr/local/lib
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
  #  add -ldb if you add -DNEWDB above (in DBMDEF)
! LIBS=	-lresolv -lsocket -lnsl -lkstat
  
  # location of sendmail binary (usually /usr/sbin or /usr/lib)
  BINDIR=	${DESTDIR}/usr/lib
***************
*** 51,57 ****
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD=
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
--- 51,57 ----
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD= spamcan.o
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
diff -rcN sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.6 sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.6
*** sendmail-8.8.7-orig/src/Makefiles/Makefile.SunOS.5.6	Tue Jun 24 14:56:27 1997
--- sendmail-8.8.7-spamcan-95/src/Makefiles/Makefile.SunOS.5.6	Thu Aug 21 23:27:45 1997
***************
*** 31,40 ****
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include
  
  # library directories
! LIBDIRS=-L/usr/sww/lib
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
--- 31,40 ----
  # see also conf.h for additional compilation flags
  
  # include directories
! INCDIRS=-I/usr/sww/include -I/usr/local/include 
  
  # library directories
! LIBDIRS=-L/usr/sww/lib  -L/usr/local/lib
  
  # libraries required on your system
  #  delete -l44bsd if you are not running BIND 4.9.x
***************
*** 50,56 ****
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD=
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
--- 50,56 ----
  HFDIR=	${DESTDIR}/etc/mail
  
  # additional .o files needed
! OBJADD= spamcan.o
  
  # things to be made before compilation begins
  BEFORE=	sysexits.h
diff -rcN sendmail-8.8.7-orig/src/SPAMCAN.CREDITS sendmail-8.8.7-spamcan-95/src/SPAMCAN.CREDITS
*** sendmail-8.8.7-orig/src/SPAMCAN.CREDITS	Wed Dec 31 16:00:00 1969
--- sendmail-8.8.7-spamcan-95/src/SPAMCAN.CREDITS	Fri Aug 22 00:07:36 1997
***************
*** 0 ****
--- 1,3 ----
+ 
+ Credits/Notes
+ 
diff -rcN sendmail-8.8.7-orig/src/conf.c sendmail-8.8.7-spamcan-95/src/conf.c
*** sendmail-8.8.7-orig/src/conf.c	Sat Aug  2 11:06:54 1997
--- sendmail-8.8.7-spamcan-95/src/conf.c	Thu Aug 21 23:27:45 1997
***************
*** 1001,1010 ****
  */
  
  int
! checkcompat(to, e)
  	register ADDRESS *to;
  	register ENVELOPE *e;
  {
  # ifdef lint
  	if (to == NULL)
  		to++;
--- 1001,1020 ----
  */
  
  int
! checkcompat(to, e, is_spam)
  	register ADDRESS *to;
  	register ENVELOPE *e;
+ 	int *is_spam;
  {
+   int spamcan(ADDRESS *to, ENVELOPE *e, int *is_spam );
+   int retval;
+ 
+   retval = spamcan(to, e, is_spam);
+ 
+   if (retval != EX_OK)
+     return( retval );
+ 
+ 
  # ifdef lint
  	if (to == NULL)
  		to++;
***************
*** 1014,1019 ****
--- 1024,1030 ----
  		printf("checkcompat(to=%s, from=%s)\n",
  			to->q_paddr, e->e_from.q_paddr);
  
+ 
  # ifdef EXAMPLE_CODE
  	/* this code is intended as an example only */
  	register STAB *s;
***************
*** 1973,1979 ****
  
  /* Non Apollo stuff removed by Don Lewis 11/15/93 */
  #ifndef lint
! static char  rcsid[] = "@(#)$Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $";
  #endif /* !lint */
  
  #ifdef apollo
--- 1984,1990 ----
  
  /* Non Apollo stuff removed by Don Lewis 11/15/93 */
  #ifndef lint
! static char  rcsid[] = "@(#)$Id: conf.c,v 1.2 1997/07/18 07:31:18 timb Exp timb $";
  #endif /* !lint */
  
  #ifdef apollo
***************
*** 2929,2935 ****
   * causing nast effects.
   **************************************************************/
  
! /*static char _id[] = "$Id: snprintf.c,v 1.2 1995/10/09 11:19:47 roberto Exp $";*/
  static void	sm_dopr();
  static char	*DoprEnd;
  static int	SnprfOverflow;
--- 2940,2946 ----
   * causing nast effects.
   **************************************************************/
  
! /*static char _id[] = "$Id: conf.c,v 1.2 1997/07/18 07:31:18 timb Exp timb $";*/
  static void	sm_dopr();
  static char	*DoprEnd;
  static int	SnprfOverflow;
diff -rcN sendmail-8.8.7-orig/src/deliver.c sendmail-8.8.7-spamcan-95/src/deliver.c
*** sendmail-8.8.7-orig/src/deliver.c	Sat Aug  2 08:05:09 1997
--- sendmail-8.8.7-spamcan-95/src/deliver.c	Mon Sep 29 23:35:46 1997
***************
*** 860,865 ****
--- 860,866 ----
  	char rpathbuf[MAXNAME + 1];	/* translated return path */
  	extern int checkcompat();
  	extern void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int));
+ 	int is_spam;
  
  	errno = 0;
  	if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags))
***************
*** 1027,1032 ****
--- 1028,1034 ----
  
  		user = to->q_user;
  		e->e_to = to->q_paddr;
+ 
  		if (tTd(10, 5))
  		{
  			printf("deliver: QDONTSEND ");
***************
*** 1057,1071 ****
  				e->e_from.q_paddr, to->q_paddr, e);
  		if (rcode == EX_OK)
  		{
! 			/* do in-code checking */
! 			rcode = checkcompat(to, e);
! 		}
! 		if (rcode != EX_OK)
! 		{
! 			markfailure(e, to, NULL, rcode);
! 			giveresponse(rcode, m, NULL, ctladdr, xstart, e);
! 			continue;
! 		}
  
  		/*
  		**  Strip quote bits from names if the mailer is dumb
--- 1059,1079 ----
  				e->e_from.q_paddr, to->q_paddr, e);
  		if (rcode == EX_OK)
  		{
! 		  /* do in-code checking */
! 		  rcode = checkcompat(to, e, &is_spam);
! 		  /*		  sm_syslog(LOG_DEBUG, e->e_id, "Ran checkcompat"); */
! 		}
!                 if (rcode != EX_OK)
!                 {
! 		  sm_syslog(LOG_DEBUG, e->e_id, "Bad code from checkcompat, rcode = %d", rcode);
! 		  markfailure(e, to, NULL, rcode);
! 		  giveresponse(rcode, m, NULL, ctladdr, xstart, e);
! 		  continue;
!                 }
! 		
! 		/* reset because spamcan modifies these */
! 		user = to->q_user; 
! 		m = to->q_mailer;
  
  		/*
  		**  Strip quote bits from names if the mailer is dumb
***************
*** 1079,1086 ****
  		}
  
  		/* hack attack -- delivermail compatibility */
! 		if (m == ProgMailer && *user == '|')
! 			user++;
  
  		/*
  		**  If an error message has already been given, don't
--- 1087,1095 ----
  		}
  
  		/* hack attack -- delivermail compatibility */
! 		if (m == ProgMailer && *user == '|') {
! 		  user++;
! 		}
  
  		/*
  		**  If an error message has already been given, don't
***************
*** 1092,1098 ****
  		*/
  
  		if (bitset(QBADADDR|QQUEUEUP, to->q_flags))
! 			continue;
  
  		/*
  		**  See if this user name is "special".
--- 1101,1107 ----
  		*/
  
  		if (bitset(QBADADDR|QQUEUEUP, to->q_flags))
! 		  continue;
  
  		/*
  		**  See if this user name is "special".
***************
*** 1104,1110 ****
  
  		if (strcmp(m->m_mailer, "[FILE]") == 0)
  		{
! 			rcode = mailfile(user, ctladdr, SFF_CREAT, e);
  			giveresponse(rcode, m, NULL, ctladdr, xstart, e);
  			e->e_nsent++;
  			if (rcode == EX_OK)
--- 1113,1120 ----
  
  		if (strcmp(m->m_mailer, "[FILE]") == 0)
  		{
! 
! 		  rcode = mailfile(user, ctladdr, SFF_CREAT, e, is_spam);
  			giveresponse(rcode, m, NULL, ctladdr, xstart, e);
  			e->e_nsent++;
  			if (rcode == EX_OK)
***************
*** 1559,1564 ****
--- 1569,1575 ----
  			(void) setsignal(SIGHUP, SIG_IGN);
  			(void) setsignal(SIGTERM, SIG_DFL);
  
+ 
  			if (m != FileMailer || stat(tochain->q_user, &stb) < 0)
  				stb.st_mode = 0;
  
***************
*** 3097,3112 ****
  */
  
  int
! mailfile(filename, ctladdr, sfflags, e)
  	char *filename;
  	ADDRESS *ctladdr;
  	int sfflags;
  	register ENVELOPE *e;
  {
  	register FILE *f;
  	register pid_t pid = -1;
  	int mode = ST_MODE_NOFILE;
  	bool suidwarn = geteuid() == 0;
  
  	if (tTd(11, 1))
  	{
--- 3108,3126 ----
  */
  
  int
! mailfile(filename, ctladdr, sfflags, e, is_spam)
  	char *filename;
  	ADDRESS *ctladdr;
  	int sfflags;
  	register ENVELOPE *e;
+ 	int is_spam;
  {
  	register FILE *f;
  	register pid_t pid = -1;
  	int mode = ST_MODE_NOFILE;
  	bool suidwarn = geteuid() == 0;
+ 	int spamcan_exists = 0;
+ 
  
  	if (tTd(11, 1))
  	{
***************
*** 3162,3170 ****
  			mode = FileMode;
  			oflags |= O_CREAT|O_EXCL;
  		}
! 		else if (bitset(0111, stb.st_mode) || stb.st_nlink != 1 ||
  			 (SafeFileEnv != NULL && !S_ISREG(stb.st_mode)))
  			exit(EX_CANTCREAT);
  		if (mode == ST_MODE_NOFILE)
  			mode = stb.st_mode;
  
--- 3176,3187 ----
  			mode = FileMode;
  			oflags |= O_CREAT|O_EXCL;
  		}
! 		else {
! 		  if (bitset(0111, stb.st_mode) || stb.st_nlink != 1 ||
  			 (SafeFileEnv != NULL && !S_ISREG(stb.st_mode)))
  			exit(EX_CANTCREAT);
+ 		  spamcan_exists = is_spam; 
+ 		}
  		if (mode == ST_MODE_NOFILE)
  			mode = stb.st_mode;
  
***************
*** 3191,3200 ****
  			}
  		}
  
  		/* select a new user to run as */
  		if (!bitset(SFF_RUNASREALUID, sfflags))
  		{
! 			if (bitset(S_ISUID, mode))
  			{
  				RealUserName = NULL;
  				RealUid = stb.st_uid;
--- 3208,3226 ----
  			}
  		}
  
+ 
+ 		/* set uid and gid for spam file */
+ 
+ 		if ( is_spam ) {
+ 		  sfflags |= SFF_ROOTOK;
+ 		}
+ 
  		/* select a new user to run as */
+ 
  		if (!bitset(SFF_RUNASREALUID, sfflags))
  		{
! 		  
! 			if (bitset(S_ISUID, mode) || spamcan_exists)
  			{
  				RealUserName = NULL;
  				RealUid = stb.st_uid;
***************
*** 3206,3211 ****
--- 3232,3238 ----
  				else
  					RealUserName = ctladdr->q_user;
  				RealUid = ctladdr->q_uid;
+ 
  			}
  			else if (FileMailer != NULL && FileMailer->m_uid != 0)
  			{
***************
*** 3219,3232 ****
  			}
  
  			/* select a new group to run as */
! 			if (bitset(S_ISGID, mode))
  				RealGid = stb.st_gid;
! 			else if (ctladdr != NULL && ctladdr->q_uid != 0)
  				RealGid = ctladdr->q_gid;
! 			else if (FileMailer != NULL && FileMailer->m_gid != 0)
  				RealGid = FileMailer->m_gid;
! 			else
  				RealGid = DefGid;
  		}
  
  		/* last ditch */
--- 3246,3276 ----
  			}
  
  			/* select a new group to run as */
! 			if ( bitset(S_ISGID, mode) || spamcan_exists ) {
  				RealGid = stb.st_gid;
! 			}
! 			else if (ctladdr != NULL && ctladdr->q_uid != 0) {
  				RealGid = ctladdr->q_gid;
! 				if (is_spam && LogLevel > 15)
! 				  sm_syslog(LOG_DEBUG, e->e_id, 
! 					    "using cltaddr gid %d", ctladdr->q_gid);
! 			}
! 			else if (FileMailer != NULL && FileMailer->m_gid != 0) {
  				RealGid = FileMailer->m_gid;
! 				sm_syslog(LOG_DEBUG, e->e_id,
! 					  "using filemailer gid %d", FileMailer->m_gid);
! 			}
! 			else {
  				RealGid = DefGid;
+ 				sm_syslog(LOG_DEBUG, e->e_id,
+ 					  "using default gid %d", DefGid);
+ 			}
+ 
+                         /* spamcan diag */
+ 			if (is_spam && LogLevel > 12)
+ 			  sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: selected owner (%d, %d) for %s",
+ 				    RealUid, RealGid, filename);
+ 				  
  		}
  
  		/* last ditch */
diff -rcN sendmail-8.8.7-orig/src/savemail.c sendmail-8.8.7-spamcan-95/src/savemail.c
*** sendmail-8.8.7-orig/src/savemail.c	Sat Aug  2 11:06:53 1997
--- sendmail-8.8.7-spamcan-95/src/savemail.c	Thu Aug 21 23:27:45 1997
***************
*** 348,354 ****
  			expand("\201z/dead.letter", buf, sizeof buf, e);
  			flags = SFF_NOLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
  			e->e_to = buf;
! 			if (mailfile(buf, NULL, flags, e) == EX_OK)
  			{
  				int oldverb = Verbose;
  
--- 348,354 ----
  			expand("\201z/dead.letter", buf, sizeof buf, e);
  			flags = SFF_NOLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
  			e->e_to = buf;
! 			if (mailfile(buf, NULL, flags, e, 0) == EX_OK)
  			{
  				int oldverb = Verbose;
  
diff -rcN sendmail-8.8.7-orig/src/sendmail.h sendmail-8.8.7-spamcan-95/src/sendmail.h
*** sendmail-8.8.7-orig/src/sendmail.h	Sat Aug  2 11:06:53 1997
--- sendmail-8.8.7-spamcan-95/src/sendmail.h	Thu Aug 21 23:27:45 1997
***************
*** 1411,1417 ****
  extern void	markstats __P((ENVELOPE *, ADDRESS *));
  extern void	poststats __P((char *));
  extern char	*arpadate __P((char *));
! extern int	mailfile __P((char *, ADDRESS *, int, ENVELOPE *));
  extern void	loseqfile __P((ENVELOPE *, char *));
  extern int	prog_open __P((char **, int *, ENVELOPE *));
  extern bool	getcanonname __P((char *, int, bool));
--- 1411,1417 ----
  extern void	markstats __P((ENVELOPE *, ADDRESS *));
  extern void	poststats __P((char *));
  extern char	*arpadate __P((char *));
! extern int	mailfile __P((char *, ADDRESS *, int, ENVELOPE *, int));
  extern void	loseqfile __P((ENVELOPE *, char *));
  extern int	prog_open __P((char **, int *, ENVELOPE *));
  extern bool	getcanonname __P((char *, int, bool));
diff -rcN sendmail-8.8.7-orig/src/spamcan.c sendmail-8.8.7-spamcan-95/src/spamcan.c
*** sendmail-8.8.7-orig/src/spamcan.c	Wed Dec 31 16:00:00 1969
--- sendmail-8.8.7-spamcan-95/src/spamcan.c	Mon Sep 29 23:39:35 1997
***************
*** 0 ****
--- 1,612 ----
+ /*
+ 
+  Tim Berger
+  timb@consult.ml.org
+  
+  Capture mail messages having regular expression matches with any
+  header.
+ 
+  Version 0.95
+ 
+  **
+ 
+  Copyright 1997 Timothy Berger - All Rights Reserved
+ 
+  This program is free software distributed in the hope that it will be
+  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ 
+  **
+ 
+  */
+ 
+ 
+ # include "sendmail.h"
+ # include "pathnames.h"
+ # include <sys/ioctl.h>
+ # include <sys/param.h>
+ # include <sys/stat.h>
+ 
+ # ifdef __linux__
+ #   include <rx.h>
+ #   define SPOOL_DIR "/var/spool/mail/"
+ # else
+ #   include <regex.h>
+ #   define SPOOL_DIR "/var/mail/"
+ # endif
+ 
+ /* concat the spool directory with the following filename */
+ 
+ #define SPAMCAN SPOOL_DIR  "spamcan"
+ 
+ /* enable personal spam mail files */
+ 
+ #define PERSONAL_SPAMCAN
+ 
+ /* You probably shouldn't have too many regular expressions.
+  This default is probably way to big.  */
+ 
+ #define SPAMCAN_MAX_REGEX_COUNT 4096
+ 
+ /* for concat of header name with value */
+ 
+ #define MAX_HEADER_LENGTH 4096
+ 
+ /* The max string lengh of any regular expression.  I imagine regcomp
+    would barf on a 4k regular expression. */
+ 
+ #define SPAMCAN_MAX_REGEX_STRLEN 4096
+ 
+ /* Allow users to disable spam capture bound for them. */
+ 
+ #define USER_CONTROL
+ 
+ /* Set FILTER_DISCRIMNATION to ONE OF THESE to decide what types of
+    messages you don't wish to filter.  Breifly, 
+ 
+    NO_DISCRIMINATION will make spamcan scan every mail message
+    connecting to your sendmail daemon.
+ 
+    RELAY_DISCRIMINATION will make spamcan only scan messages
+    originating from discrimination_mask.
+ 
+    SUBNET_DISCRIMINATION will make spamcan only scan messages not
+    originating from the subnet your specify in discrimination_mask.
+    Standard stuff from the O'Rielly Sendmail book.
+ 
+    LOCALHOST_DISCRIMINATION will make spamcan scan all messages not
+    originating from the local machine.
+ 
+    */
+ 
+ #define NO_DISCRIMINATION		0
+ #define RELAY_DISCRIMINATION		1
+ #define SUBNET_DISCRIMINATION           2
+ #define LOCALHOST_DISCRIMINATION        3
+ 
+ #define FILTER_DISCRIMNATION		LOCALHOST_DISCRIMINATION
+ 
+ #define SPRINTF_BUFFSIZE                512
+ 
+ 
+ /*
+ 
+   here is an example of how to convert your ip or netmask to hex:
+   echo 24.1.16.108 | awk -F. '{printf("0x%02x%02x%02x%02x\n", $1, $2, $3, $4)}'
+ 
+   The following discrimination mask is only used if  FILTER_DISCRIMNATION	
+   is defined as SUBNET_DISCRIMINATION
+ 
+ */
+ 
+ #define SUBNET_MASK 0xffffff00
+ 
+ /* set this to your relay, local ip, or subnet mask */
+ 
+ static long discrimination_mask = 0x1801106c;
+ 
+ /* the regular expression buffer */
+ static char *spamcan_cf = "/etc/spamcan.cf";
+ regex_t spamcan_regex_list[SPAMCAN_MAX_REGEX_COUNT];
+ static int spamcan_regex_count = 0;
+ static int spamcan_mtime = 0;
+ 
+ /* regular expressions that let mail pass through */
+ static char *spamcan_exceptions = "/etc/spamcan-exceptions.cf";
+ regex_t spamcan_exceptions_list[SPAMCAN_MAX_REGEX_COUNT];
+ static int spamcan_rx_exceptions_count = 0;
+ static int spamcan_exceptions_mtime = 0;
+ 
+ void spamcan_load_regex(filename, explist, expcount, filename_mtime ) 
+      char *filename;
+      regex_t *explist;
+      int *expcount, *filename_mtime;
+ {
+ 
+   int loop;
+   FILE *fp;
+   struct stat st;
+   int error;
+   char regex_message[SPAMCAN_MAX_REGEX_STRLEN];
+   char regexbuff[SPAMCAN_MAX_REGEX_STRLEN];
+ 
+   if (stat(filename, &st) == -1) {
+     sm_syslog(LOG_DEBUG, NOQID, "SPAMCAN: Can't stat %s", filename);
+     return;
+   }
+ 
+   if ( st.st_mtime > *filename_mtime ) {
+     *filename_mtime = st.st_mtime;
+   }
+   else {
+     return;
+   }
+ 
+   if ( ! (fp = fopen(filename, "r")) ) {
+     sm_syslog(LOG_DEBUG, NOQID, "SPAMCAN: Problem reading %s", filename);
+     return;
+   }
+ 
+   if (LogLevel > 12)
+     sm_syslog(LOG_DEBUG, NOQID, "SPAMCAN: Loading spam file %s", filename);
+ 
+   loop = 0;
+   while( (fgets(regexbuff, SPAMCAN_MAX_REGEX_STRLEN, fp) != NULL) && loop < SPAMCAN_MAX_REGEX_COUNT ) {
+     *(regexbuff + strlen(regexbuff) -1 ) = '\0';
+     if (strlen(regexbuff) < 4) {
+       sm_syslog(LOG_DEBUG, NOQID, "SPAMCAN: expression [%s] from [%s] is too small, possible typo", 
+ 		regexbuff, filename);
+       continue;
+     }
+     if (LogLevel > 19)
+       sm_syslog(LOG_DEBUG, NOQID, "SPAMCAN: read expression %s", regexbuff);
+     if ( (error=regcomp(& explist[loop], regexbuff, REG_EXTENDED|REG_ICASE)) ) {
+       regerror(error, & explist[loop], regex_message, (size_t)SPAMCAN_MAX_REGEX_STRLEN);
+       sm_syslog(LOG_DEBUG, NOQID, "SPAMCAN: unable to compile expression [%s] from [%s].  index = %d, %s", 
+ 		regexbuff, filename, loop, regex_message);
+     }
+     else {
+       if (LogLevel > 12)
+ 	sm_syslog(LOG_DEBUG, NOQID, "SPAMCAN: compiled expression [%s] to index %d",
+ 		  regexbuff, loop);
+       loop++;
+     }
+   }
+ 
+   fclose (fp);
+ 
+   *expcount = loop;
+ 
+   if (LogLevel > 12) 
+     sm_syslog(LOG_DEBUG, NOQID, "SPAMCAN: Compiled %d regular expressions",  
+ 	      *expcount); 
+ 
+ 
+ }
+ 
+ void spamcan_mark_to_save(to, e, reason, to_username, to_uid)
+      ADDRESS *to;
+      ENVELOPE *e;
+      char *reason;
+      char *to_username;
+      uid_t to_uid;
+ {
+ 
+   char *spamcap;
+   HDR *header;
+   int found;
+   char *personal_spamcan;
+   struct stat st;
+ 
+   personal_spamcan = NULL;
+ 
+ #if defined(PERSONAL_SPAMCAN)
+ 
+   if (to_username != NULL) {
+     personal_spamcan = (char*) 
+       malloc( strlen(SPOOL_DIR) + strlen(to_username) + strlen(".spam") + 1 );
+ 
+     if (personal_spamcan == NULL) {
+       sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: out of memory");
+       return;
+     }
+ 
+     strcpy(personal_spamcan, SPOOL_DIR);
+     strcat(personal_spamcan, to_username);
+     strcat(personal_spamcan, ".spam");
+     if (stat(personal_spamcan, &st) == 0) {
+       if (to_uid == st.st_uid) {
+ 	to->q_user = personal_spamcan;
+ 	to->q_mailer = FileMailer;
+       }
+       else {
+ 	sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: %s exists, but has wrong ownership %d",
+ 		  personal_spamcan, st.st_uid);
+       }
+     }
+   }
+   else {
+     sm_syslog(LOG_DEBUG, e->e_id, "username is NULL");
+   }
+ 
+ #endif
+   
+   if (personal_spamcan != to->q_user) {
+     spamcap = (char *)malloc( strlen(SPAMCAN ) + 1 );
+ 
+     if (spamcap == NULL) {
+       sm_syslog(LOG_DEBUG, e->e_id, "out of memory");
+       return;
+     }
+ 
+     strcpy (spamcap, SPAMCAN);
+     to->q_user = spamcap;
+     to->q_mailer = FileMailer;
+   }
+ 
+   if (LogLevel > 9)
+     sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: selected spamcan %s",
+ 	      to->q_user);
+ 
+   for(header = e->e_header, found = 0; header && !found; header = header->h_link) {
+     if ( strcasecmp("X-Spamcan-Reason", header->h_field) == 0) {
+        header->h_value = reason;
+       found = 1;
+     }
+   }
+ 
+   if ( !found ) {
+     addheader("X-Spamcan-Reason", reason, &e->e_header);
+   }
+ 
+ }
+ 
+ int spamcan_find_header(e, name, value)
+      ENVELOPE *e;
+      char *name, **value;
+ {
+ HDR *h_ptr;
+ int found = 0;
+ 
+ for(h_ptr = e->e_header;h_ptr != NULL; h_ptr = h_ptr->h_link) {
+   if (strcasecmp(name, h_ptr->h_field) == 0) {
+     *value = h_ptr->h_value;
+     return (1);
+   }
+ }
+ return(0);
+ 
+ }
+ 
+ 
+   /* This is completely incompatable with most mailing lists.
+    Forget this for now.  May use some of this code in a future release */
+ 
+ int sanity_check(to, e, to_username, to_uid)
+      ADDRESS *to;
+      ENVELOPE *e;
+      char *to_username;
+      uid_t to_uid;
+ {
+   char *print_to;
+   HDR *h_ptr;
+   char *from_header, *to_header, *reply_header, *sender_header;
+   char *reason_alloc;
+   char reason[SPRINTF_BUFFSIZE];
+   ADDRESS *ctladdr;
+ 
+   reason_alloc = (char*)malloc(SPRINTF_BUFFSIZE);
+ 
+   if ( reason_alloc == NULL) {
+     sm_syslog(LOG_DEBUG, e->e_id, "out of memory");
+     return(0);
+   }
+ 
+ 
+   if (to_username != NULL) {
+     print_to = to_username;
+   }
+   else {
+     print_to = to->q_user;
+     ctladdr = getctladdr(to);
+     if ( ctladdr != NULL ) {
+       if (ctladdr->q_user != NULL) {
+ 	print_to =  ctladdr->q_user;
+       }
+     }
+   }
+ 
+ 
+   /* don't accept outside mail without to header */
+ 
+   if( !spamcan_find_header(e, "To", &to_header) ) {
+     sprintf(reason, "No \"To\" header from [%s] to [%s]",
+ 	    e->e_from.q_paddr, print_to );
+     strcpy(reason_alloc, reason);
+     sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: %s", reason_alloc);
+     spamcan_mark_to_save(to, e, reason_alloc, to_username, to_uid);
+     return (1);
+   }
+ 
+   /* don't accept outside mail without from header */
+ 
+   if ( !spamcan_find_header(e, "From", &from_header) ) {
+     sprintf(reason, "No \"From\" header from [%s] to [%s]",
+ 	    e->e_from.q_paddr, print_to );
+     strcpy(reason_alloc, reason);
+     sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: %s", reason_alloc);
+     spamcan_mark_to_save(to, e, reason_alloc, to_username, to_uid);
+     return (1);
+   }
+ 
+   /* check if to matches from */
+ 
+   if ( strcasecmp(from_header, to_header) == 0) {
+     sprintf(reason, "Identical headers \"From\" and \"To\" from [%s] to [%s]",
+ 	    e->e_from.q_paddr, print_to );
+     strcpy(reason_alloc, reason);
+     sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: %s", reason_alloc);
+     spamcan_mark_to_save(to, e, reason_alloc, to_username, to_uid);
+     return(1);
+   }
+ 
+   /* check if to matches reply-to */
+ 
+   if ( spamcan_find_header(e, "Reply-To", &reply_header)) {
+     if ( strcasecmp(to_header, reply_header) == 0) {
+       sprintf(reason, "Identical headers \"Reply-To\" and \"To\" from [%s] to [%s]",
+ 	      e->e_from.q_paddr, print_to );
+       strcpy(reason_alloc, reason);
+       sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: %s", reason_alloc);
+       spamcan_mark_to_save(to, e, reason_alloc, to_username, to_uid);
+       return(1);
+     }
+   }
+ 
+   /* check if sender maches to */
+ 
+   if ( spamcan_find_header(e, "Sender", &sender_header)) {
+     if ( strcasecmp(to_header, sender_header) == 0) {
+       sprintf(reason, "Identical headers \"Sender\" and \"To\" from [%s] to [%s]",
+ 	      e->e_from.q_paddr, print_to );
+       strcpy(reason_alloc, reason);
+       sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: %s", reason_alloc);
+       spamcan_mark_to_save(to, e, reason_alloc, to_username, to_uid);
+       return(1);
+     }
+   }
+ 
+ 
+   return (0);
+ 
+ }
+ 
+   
+ int spamcan_match ( name, substr, e, to, to_username, to_uid )
+ char *name;
+ char *substr;
+ ENVELOPE *e;
+ ADDRESS *to;
+ char *to_username;
+ uid_t to_uid;
+ 
+ {
+ 
+   int loop, error;
+   regmatch_t pmatch[1];
+   char reason_prime[SPRINTF_BUFFSIZE], reason[SPRINTF_BUFFSIZE], *reason_alloc;
+   char *print_to;
+   ADDRESS *ctladdr;
+ 
+   reason_alloc = (char*)malloc(SPRINTF_BUFFSIZE);
+ 
+   if ( reason_alloc == NULL) {
+     sm_syslog(LOG_DEBUG, e->e_id, "out of memory");
+     return(0);
+   }
+ 
+  if (to_username != NULL) {
+     print_to = to_username;
+   }
+   else {
+     print_to = to->q_user;
+     ctladdr = getctladdr(to);
+     if ( ctladdr != NULL ) {
+       if (ctladdr->q_user != NULL) {
+ 	print_to =  ctladdr->q_user;
+       }
+     }
+   }
+   
+ 
+ 
+   for(loop = 0; loop < spamcan_regex_count; ++loop) {
+     
+     /* sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: looking at string [%s]", substr);  */
+     
+     if ( (error=regexec(& spamcan_regex_list[loop],
+ 			substr, 1, &pmatch[0], 0)) == 0) {
+       /*      sm_syslog(LOG_DEBUG, e->e_id, "there was a match"); */
+       snprintf(reason_prime, SPRINTF_BUFFSIZE,
+ 	       "substring [%%.%ds] matched [%%s] with expression [#%%d] from [%s] to [%s]",
+ 	       pmatch[0].rm_eo - pmatch[0].rm_so,
+ 	       e->e_from.q_paddr,
+ 	       print_to );
+       snprintf(reason,  SPRINTF_BUFFSIZE, reason_prime,
+ 	       substr  + pmatch[0].rm_so, name, loop);
+ 
+       sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: %s", reason);
+       strcpy(reason_alloc, reason);
+       spamcan_mark_to_save(to, e, reason_alloc, to_username, to_uid);
+       return( 1 );
+     }
+     else {
+       /*      sm_syslog(LOG_DEBUG, e->e_id, "No match with regex #%d", loop);  */
+     }
+   }
+ 
+   return( 0 );
+ 
+ }
+ 
+ int spamcan(to, e, is_spam )
+      register ADDRESS *to;
+      register ENVELOPE *e;
+      int *is_spam;
+ 
+ {
+   HDR *h_ptr;
+   struct stat st;
+   char user_disable_spamcan_file[512];
+   char *to_username;
+   struct passwd *pwent;
+   ADDRESS *alist;
+   int username_found;
+   uid_t to_uid;
+   char full_header[MAX_HEADER_LENGTH];
+   struct in_addr natural_in;
+   int loop;
+ 
+   *is_spam = 0;
+ 
+   if ( RealHostAddr.sa.sa_family != AF_INET )
+     return (EX_OK);
+ 
+   if( RealHostAddr.sin.sin_addr.s_addr == 0x7f000001 )
+     return( EX_OK );
+ 
+   /* Convert net byte order to host byte order - toivo@ucs.uwa.edu.au */
+   natural_in.s_addr = ntohl(RealHostAddr.sin.sin_addr.s_addr);
+ 
+     /* pass through locally generated mail - check specific ip address */
+ 
+   if ( FILTER_DISCRIMNATION == LOCALHOST_DISCRIMINATION &&
+        natural_in.s_addr == discrimination_mask )
+     return( EX_OK );
+ 
+     /* don't filter mail unless from relay */
+ 
+   if ( FILTER_DISCRIMNATION == RELAY_DISCRIMINATION &&
+ 	 natural_in.s_addr != discrimination_mask)
+       return ( EX_OK );
+   
+   /* don't filter mail generated from specified subnet */
+   if (  FILTER_DISCRIMNATION == SUBNET_DISCRIMINATION &&
+ 	(natural_in.s_addr & SUBNET_MASK) == discrimination_mask
+ 	)
+     return ( EX_OK );
+ 
+   /* pass through mail with In-Reply-To header */
+   for(h_ptr = e->e_header;h_ptr != NULL; h_ptr = h_ptr->h_link) {
+     if ( (strcasecmp("In-reply-to", h_ptr->h_field) == 0) )
+       return (EX_OK);
+   }
+ 
+   username_found = 0;
+   to_username = NULL;
+   alist = to;
+   while ( alist && ! username_found) {
+     pwent = getpwnam(alist->q_user);
+     if (pwent != NULL) {
+       to_username = alist->q_user;
+       to_uid = pwent->pw_uid;
+       username_found = 1;
+     }
+     alist = alist->q_alias;
+   }
+ 
+ #if defined(USER_CONTROL)
+ 
+   /* Need to know username here.  If I knew how to get this reliably any 
+    other way this wouldn't be necessary.  */
+ 
+   strcpy(user_disable_spamcan_file, SPOOL_DIR ".nospamcan.");
+   if ( username_found ) {
+     strcat(user_disable_spamcan_file, to_username);
+     if (LogLevel > 12) 
+       sm_syslog(LOG_DEBUG, e->e_id, 
+ 		"SPAMCAN: Checking for file %s", user_disable_spamcan_file);
+   }
+ 
+   if( stat(user_disable_spamcan_file, &st) == 0 && to_username != NULL) {
+     if( to_uid == st.st_uid) {
+       sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: %s exists, not capturing mail for %s",
+ 		user_disable_spamcan_file, to_username);
+       return (EX_OK);
+     }
+     else {
+        sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: %s exists but has wrong ownership %d",
+ 		user_disable_spamcan_file,  st.st_uid);
+     }
+   }
+ 
+ #endif
+ 
+   spamcan_load_regex(spamcan_cf, spamcan_regex_list, &spamcan_regex_count,
+ 		     &spamcan_mtime);
+ 
+   /* load exceptions */
+ 
+   spamcan_load_regex(spamcan_exceptions, spamcan_exceptions_list, 
+ 		     &spamcan_rx_exceptions_count, &spamcan_exceptions_mtime);
+ 
+     for(h_ptr = e->e_header; h_ptr != NULL; h_ptr = h_ptr->h_link) {
+       for(loop=0; loop < spamcan_rx_exceptions_count; ++loop) {
+ 	if ( h_ptr->h_value != NULL &&
+ 	     regexec( &spamcan_exceptions_list[loop], h_ptr->h_value,
+ 		      0, NULL, 0) == 0) {
+ 	  if (LogLevel > 12)
+ 	    sm_syslog(LOG_DEBUG, e->e_id, "SPAMCAN: Passing message through");
+ 	  return(EX_OK);
+ 	}
+       }
+     }
+ 
+   /* check each header for a match */
+ 
+   for(h_ptr = e->e_header; h_ptr != NULL; h_ptr = h_ptr->h_link) {
+     
+     /* skip the message id header, it contains nothing useful
+      and may cause filtering problems */
+ 
+     if ( (strcasecmp( "Message-Id", h_ptr->h_field) == 0) )
+       continue;
+ 
+     if ( (strcasecmp( "Resent-Message-Id", h_ptr->h_field) == 0) )
+       continue;
+ 
+     /* terminate last byte with null character in the event that we run out of space */
+ 
+     *( full_header +  MAX_HEADER_LENGTH - 1 ) = '\0';
+ 
+     strncpy(full_header, h_ptr->h_field, MAX_HEADER_LENGTH - 1);
+ 
+     strncpy(full_header + strlen(full_header), ": ", 
+ 	    MAX_HEADER_LENGTH - 1 - strlen(full_header) );
+ 
+     if ( h_ptr->h_value != NULL ) {
+       strncpy(full_header + strlen(full_header), h_ptr->h_value, 
+ 	      MAX_HEADER_LENGTH - 1 - strlen(full_header));
+     }
+ 
+ 
+     if ( spamcan_match(h_ptr->h_field, full_header, e, to, to_username, to_uid) ) {
+       *is_spam = 1;
+       return( EX_OK);
+     }
+ 
+   }
+ 
+   /* skip possibly null ? value for envelope sender */
+ 
+   if (e->e_from.q_paddr == NULL) {
+     return(EX_OK);
+   }
+ 
+   if ( spamcan_match("Sender from Envelope", e->e_from.q_paddr, e, to, to_username, to_uid) ) {
+     *is_spam = 1;
+     return ( EX_OK );
+   }
+ 
+   return(EX_OK);
+ }
