home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume43
/
SmartList
/
part01
next >
Wrap
Internet Message Format
|
1994-07-05
|
56KB
From: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
Newsgroups: comp.sources.misc
Subject: v43i066: SmartList - mailinglist package v3.03, Part01/05
Date: 5 Jul 1994 21:26:35 -0500
Organization: Sterling Software
Sender: kent@sparky.sterling.com
Approved: kent@sparky.sterling.com
Message-ID: <csm-v43i066=SmartList.212556@sparky.sterling.com>
X-Md4-Signature: b94998e1ac18eb9d62b1a9b8d9d8d2f7
Submitted-by: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
Posting-number: Volume 43, Issue 66
Archive-name: SmartList/part01
Environment: procmail, sendmail, ZMailer, smail, /bin/mail, UNIX, POSIX
The SmartList mailinglist management package. (v3.03 1994/06/30)
The SmartList mailinglist package has been built on top of the procmail
mail processing package. In order to install it you'll need the source
of the procmail package as well.
If you now have just the SmartList sources, get the procmail sources and
unpack them on top of the SmartList source tree.
----------------------
A recent version of both packages can be picked up at various
comp.sources.misc archives.
The latest versions can be obtained directly from the ftp-archive at:
ftp.informatik.rwth-aachen.de
as (g)zipped tar files: /pub/packages/procmail/procmail.tar.gz
/pub/packages/procmail/SmartList.tar.gz
as compressed tar files: /pub/packages/procmail/procmail.tar.Z
/pub/packages/procmail/SmartList.tar.Z
----------------------
Summary of what SmartList provides:
+ The overseeable management of an arbitrary number of mailinglists
+ Convenient and simple creation of new mailinglists
+ Convenient and simple removal of existing mailinglists
+ Fully automated subscription/unsubscription/help-request processing
(no operator intervention needed)
+ Enough intelligence to overcome the ignorance of some subscribers
(will direct subscribe and unsubscribe requests away from the
regular list and automatically onto the -request address)
+ No hardwired format for (un)subscribe requests (i.e. new subscribers
need not be educated, unsubscribing users do not need to remember
any particular syntax)
+ *Intelligent* autoremoval of addresses from the list that cause
too many bounces
+ Submissions can be limited to people on the accept list (which could
be the current list of subscribers)
+ The fully automated subscription mechanism allows for a reject list
of unwanted subscribers and a general address screening mechanism
which allows you to control exactly who is allowed to subscribe
+ Optional implicit subscription upon first submission to the list
+ MIME-compliant auto-digest-generation (configurable per list)
+ Joint management of several mailinglists possible
+ Customisation per mailinglist or mailinglist group possible (simply
remove or create the desired hardlinks)
+ A listmaintainer can be assigned per list; miscellaneous requests
that couldn't be handled by the list automatically are then
forwarded to his mail address (instead of being accumulated in
a file)
+ Allows for remote maintenance of any mailinglist by a
listmaintainer
+ Integrated archiving service
+ Integrated diagnostic aid to give hints to the maintainer about
possible problems
+ Moderated mailinglists with an arbitrary number of moderators
+ Automatically eliminates duplicate submissions
+ You can set up a mailinglist to function as a standalone mail
archive server
+ Extended MIME support (autorecognition of well known file formats)
+ The archive server can send arbitrarily long (even binary) files
in MIME-multipart mails
----------------------
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# Contents: procmail-3.03 procmail-3.03/SmartList
# procmail-3.03/SmartList/INSTALL procmail-3.03/SmartList/bin
# procmail-3.03/SmartList/etc procmail-3.03/SmartList/etc/rc.init
# procmail-3.03/SmartList/examples procmail-3.03/src
# procmail-3.03/src/hsort.h procmail-3.03/src/multigram.c
# Wrapped by kent@sparky on Tue Jul 5 21:10:29 1994
PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 1 (of 5)."'
if test ! -d 'procmail-3.03' ; then
echo shar: Creating directory \"'procmail-3.03'\"
mkdir 'procmail-3.03'
fi
if test ! -d 'procmail-3.03/SmartList' ; then
echo shar: Creating directory \"'procmail-3.03/SmartList'\"
mkdir 'procmail-3.03/SmartList'
fi
if test -f 'procmail-3.03/SmartList/INSTALL' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'procmail-3.03/SmartList/INSTALL'\"
else
echo shar: Extracting \"'procmail-3.03/SmartList/INSTALL'\" \(10257 characters\)
sed "s/^X//" >'procmail-3.03/SmartList/INSTALL' <<'END_OF_FILE'
X SmartList Installation guide:
X
X 1. Prerequisites
X 2. Installing the scripts
X 3. Sharing the scripts on multiple architectures
X 4. If you don't have a sendmail compatible mailer
X 5. Upgrading from previous versions of SmartList
X 6. Moving an existing list to a different directory
X
X ---
X
X1. Prerequisites
X -------------
X
XIn order to make sure that SmartList works reliably for both remote and
Xlocal mail, it has to be run under someone's account.
XThe recommended procedure would be to create a new account and group named
X"list" that is only going to be used to manage SmartList mailinglists.
XYou are of course free to choose any name you'd like instead of "list".
XCommon names would be "list" or "lists". Do not pick "smartlist" because that
Xname is nine characters long. The maximum for most systems is eight.
X
XIf you are unable/unwilling to create a new user just for SmartList,
Xthen it should be installed in a separate subdirectory. The owner of this
Xdirectory will still be able to receive regular mail.
X
XSmartList makes use of the -f option of sendmail. This option makes sure
Xthat the sender address on the envelope (the From_ line) contains the
Xproper list address. In order for this option to work, the user using it
X(either "list" or the regular user the lists run under) must be on the
Xtrusted-user-list of sendmail. To enter the user "list" on the
Xtrusted-user-list simply edit the sendmail.cf file and add a line reading:
X
XTlist
X
XRestarting sendmail is not necessary.
X
XSendmail 6.x and later don't need this anymore. And even if you have an
Xolder sendmail but can't put this in the sendmail.cf file, the mailinglist
Xscripts will still work, albeit under less than ideal circumstances (i.e.
Xautomatic bounce handling is severely impaired).
X
X ---
X
X2. Installing the scripts
X ----------------------
X
XSuppose you have created this pseudo user "list" with a specified home
Xdirectory of /home/list
X
XNow create /home/list by hand and make sure that you chown it to "list".
XAlso chgrp it to "list" now if you created a group for that. If you
Xdo not have a separate group for the list, you have to make sure that you
Xchange the setting of UMASK in the rc.init file. By default the group
Xto which the "list" user belongs can write in many of the files.
X
XNext, make sure that you are running as root (su root) and execute the
X"install.sh" script present in this directory by typing something like:
X
X sh install.sh /home/list
X
XIf you are setting up SmartList under your own account, simply creating
Xa separate directory and running the install.sh script should suffice.
X
XThis script will then create two subdirectories (.bin and .etc) in
X/home/list. These directories will be filled with the files contained
Xin the bin and etc subdirectories here. It will also make sure that
Xthe "multigram" program is compiled from the procmail*/src directory and
Xcopied into /home/list/.bin.
X
X The only program/binary that contains harcoded information is
X the /home/.bin/flist program. It contains both the name of the user
X that owns the lists ("list" in this case) and the absolute path to
X the mailinglist directory (/home/list in this case). This is
X needed for security reasons.
X
X This means that if either the name of the user or the name
X of the directory changes, you'll have to reinstall the mailinglist
X scripts (or at least the flist binary). You can treat it as if it
X were an upgrade, see paragraph 5 below for more information.
X
X This also means that if you like to have several main mailinglist
X directories, you'll need a separately installed flist binary
X for each one of them. Simply install.sh to every directory anew.
X To conserve space, or to centralise administration, you can then
X (hard)link all files in all the .bin and .etc directories with
X their counterparts (except the flist binaries and anything linked
X to them of course).
X
XFurthermore install.sh will link /home/list/.etc/rc.main to
X/home/list/.procmailrc. This is of course superfluous (but nondestructive) if
Xyou are still using this account to receive regular mail.
X
XDepending on your mail configuration, if procmail has not been integrated
Xin the maildelivery system (see procmail*/examples/advanced for more
Xinformation on that topic) you should also create a .forward file with an
Xappropriate content (see "man procmail", the NOTES section at the end). This,
Xhowever, is only necessary if you created a seperate "list" account.
X
X Next, edit the /home/list/.etc/rc.init file. Make sure that
X "domain" is set to the right value, and you can optionally specify a
X "listmaster"; also check if the PATH is correct and make sure
X that procmail and formail are in the path.
X
XOn some sites the aliases file is not exactly /usr/lib/aliases, or its format
Xis slightly incompatible with standard sendmail. In those cases (for
Xyour own convenience) it would be wise to edit the .bin/createlist script
Xto display the proper aliases to insert (so that you can cut and paste
Xin the future).
X
XFor further instructions, you should consult the "Manual" file, it has
Xbeen copied to the /home/list/.etc directory as well, and can serve as a
Xquick reference.
X
X ---
X
X3. Sharing the scripts on multiple architectures
X ---------------------------------------------
X
XFor people that want to run SmartList on a shared filesystem across different
Xarchitectures there exists the possibility of using several .bin directories.
XSimply use something like:
X sh install.sh /home/list .bin.sun4
Xto install to a different .bin directory. Repeat the complete procmail and
XSmartList installation for every architecture, specifying a different .bin
Xdirectory every time.
X
X ---
X
X4. If you don't have a sendmail compatible mailer
X ----------------------------------------------
X
XAs is, SmartList is preconfigured to use sendmail (or a compatible
Xmailer like smail) to actually transport the mails. If your system only
Xsupplies a /bin/rmail or /bin/mail to transport mails, then several of
Xthe options used when invoking sendmail will not work.
X
XFor these cases you have to edit the /home/list/.etc/rc.init file.
XLook for a SENDMAIL assignment. Supplied with these scripts is a poor man's
Xsendmail. It was installed in the .bin directory belonging to the
Xlist. Make sure that the SENDMAIL assignment points at the "sendmails" script.
XAnd, of course, don't forget to uncomment the SENDMAIL assignment and
Xthe two sendmailOPT* assigments following it.
X
X ---
X
X5. Upgrading from previous versions of SmartList
X ---------------------------------------------
X
XYou can simply use the install.sh script again to install directly over
Xthe old installation IF you customised ONLY the master rc.init and rc.custom
Xfiles. Once you ran the install.sh script, you'll have to merge the changes
Xyou made to the old rc.init file (still there) into the rc.init.new file.
X
XSince the install.sh script will create the .etc/rc.lock file for you,
Xyou have 17 minutes to do that. If it should take longer, touch the rc.lock
Xfile every so often. As soon as the difference between its mtime and the
Xcurrent time exceeds 17 minutes, the flist programs start delivering mail to
Xthe lists again.
X
XThen cat (yes, use `cat', because you have to preserve any hardlinks) the
Xrc.init.new file into the rc.init file.
X
XIf there are any new entries in the new rc.custom file template, their
Xomission in the old rc.custom files should not cause any problems (i.e. the
Xnew rc.init already provides the new defaults).
X
XIf you customised more than just the rc.init or rc.custom files, you'll
Xhave to make diffs between the old versions of the scripts, then install
Xthe new scripts and then apply back the diffs (probably by hand).
X
XYou can quickly verify which files are linked to other files by
Xsimply typing something like:
X
X showlink rc.init
X
XAfter you are finished, remove the rc.lock file again. If it is older
Xthan 17 minutes it is ignored anyway, but it's cleaner this way.
X
X ---
X
X6. Moving an existing list to a different directory
X ------------------------------------------------
X
XThis can be safely done by following these steps:
Xa.Create the .etc/rc.lock file.
Xb.Copy the tree to the new location. Be sure to preserve hard and
X softlinks while doing this, tar can do this for you. If you'd like to
X use tar to copy the tree, a suggested /bin/sh command line would be:
X
X cd olddir; tar cf - . | (cd newdir; tar xvf -)
X
X If you are moving the tree instead, make sure you create a symbolic link
X from the old location to the new immediately after moving the tree (there
X is a race condition here, mail arriving after having moved, but before having
X created the symbolic link will bounce).
Xc.Create a symbolic link to the new location with (if your filesystem does not
X support symbolic links, see below):
X
X ln -s newdir olddir/.etc/Moved
X
Xd.If the home directory of the list user needs to be changed, do it now.
X Make sure the change is in effect before proceeding with step e.
X You can buy some time by doing a "touch olddir/.etc/rc.lock" every 16
X minutes.
Xe.Install SmartList from the distribution again, on top of newdir, i.e. simply
X regard it as an upgrade (you can skip this part if "flist -v" indicates that
X it is using the same path relative to the (changed) home directory of the
X list user).
Xf.Update your /usr/lib/aliases (or equivalent) file, make sure the aliases run
X the new flist binary.
Xg.Remove both the olddir/.etc/rc.lock and any newdir/.etc/rc.lock file.
Xh.Wait at least 30 seconds before removing the olddir tree (if at all), in
X order to give the already running flists a chance to wake up and follow the
X symbolic link (if necessary, check that no old flists are running anymore).
X
XThe alternative way to move the lists (mandatory for filesystems that do not
Xsupport symbolic links):
Xa.Remove all */rc.lock files, kill the sendmail daemon (in other words: do
X whatever is necessary to prevent further invocations of the old flist binary)
X and check if any flist or procmail programs belonging to the lists are still
X running, if they do, wait until they are gone.
Xb.As above.
Xc.This step is irrelevant now.
Xd.As above.
Xe.As above.
Xf.As above.
Xg.This step is irrelevant now.
Xh.You can remove the olddir tree without further ado (if you like).
END_OF_FILE
if test 10257 -ne `wc -c <'procmail-3.03/SmartList/INSTALL'`; then
echo shar: \"'procmail-3.03/SmartList/INSTALL'\" unpacked with wrong size!
fi
# end of 'procmail-3.03/SmartList/INSTALL'
fi
if test ! -d 'procmail-3.03/SmartList/bin' ; then
echo shar: Creating directory \"'procmail-3.03/SmartList/bin'\"
mkdir 'procmail-3.03/SmartList/bin'
fi
if test ! -d 'procmail-3.03/SmartList/etc' ; then
echo shar: Creating directory \"'procmail-3.03/SmartList/etc'\"
mkdir 'procmail-3.03/SmartList/etc'
fi
if test -f 'procmail-3.03/SmartList/etc/rc.init' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'procmail-3.03/SmartList/etc/rc.init'\"
else
echo shar: Extracting \"'procmail-3.03/SmartList/etc/rc.init'\" \(9559 characters\)
sed "s/^X//" >'procmail-3.03/SmartList/etc/rc.init' <<'END_OF_FILE'
X#
X# IMPORTANT variables to check/change: PATH domain listmaster
X#
X
X# BEFORE editing this file or any rc.* file in the .etc directory
X# you should create the .etc/rc.lock file. As long as this file
X# exists, mail delivery to any list will stall (flist checks this file).
X#
X# Delivery can be temporarily stalled on a per list basis by creating
X# the file rc.lock in the respective list's subdirectory.
X
X# ENVIRONMENT:
X# list contains the submitting address of the list (sans domain)
X# domain should contain the domain for the list, so that $list@$domain
X# can be used to submit to the list
X# maintainer should contain the fully qualified address of the maintainer
X# of $list; maintainter can be left empty
X# listmaster should contain the fully qualified address of the supervising
X# list maintainer; listmaster can be left empty
X# X_ENVELOPE_TO contains the address that the incoming mail was addressed to
X
X# FILES:
X# log optional logfile (uncomment the LOGFILE assignment to enable
X# it)
X# dist the subscriber list, one address per line
X# accept the list of people allowed to submit messages (usually a
X# link to dist, only checked if $foreign_submit != yes)
X# reject list of people you definitely do not want to subscribe
X# subscreen program (e.g. shell script) to screen prospective subscribers
X# (see in the examples directory for a sample script)
X# request all the messages to request that could not be handled
X# automatically (only if maintainer is empty)
X# help.txt file sent to help & info requests
X# info.txt optional file sent to help & info requests as well,
X# it should contain a concise description of what the
X# list is all about
X# the various info.txt files are optionally gathered in
X# order to advertise the availability of the mailinglists
X# subscribe.txt file sent to new subscribers
X# subscribe.file file containing an arbitrary number of archive server commands
X# to be executed on behalf of new subscribers
X# unsubscribe.txt file sent to unsubscribers
X# accept.txt file sent to people not on the accept list
X# archive.txt file sent to people requesting help from the archive server
X# archive (link to a) directory below which files can be accessed through
X# the archive server
X# bounces directory containing the bounce history files
X# rc.submit rcfile used when distributing submissions
X# rc.request rcfile used when processing requests
X# rc.custom rcfile that contains all the customisations per list
X# rc.local.* optional rcfiles for any local extensions (to be used in
X# conjunction with the RC_LOCAL_* variables which can be set
X# in rc.init or rc.custom files)
X
X#$Id: rc.init,v 1.37 1994/06/30 16:30:32 berg Exp $
X
XDELIVERED=yes # we're in control of the mail now, tell sendmail to go away
X
XPATH=.:$PATH:../.bin:/bin:/usr/bin:/usr/local/bin # setup a decent path
XSHELL=/bin/sh # to prevent surprises
X
Xdefaults=.etc
X
XLOCKTIMEOUT=3660 # set these values this high (1 hour)
XTIMEOUT=3600 # to give sendmail the time to
X # resolve big aliases
X
X###############################################################################
X# You have to setup the following two assignments, make sure that the address
X# mentioned in listmaster is *not* the address this script runs under; if
X# you would end up doing that, then assign listmaster to ""
X# The same applies to the maintainer addresses used for every list, if you
X# would like to alias them back to this script or to the respective -request
X# addresses, then assign maintainer to "" instead.
X#
X# The mail-domain you have to insert below, must be the fully qualified
X# mail-domain for this list; e.g. if the preferred mail address for this
X# account would be: list@somemachine.somewhere.universe
X# Then you should assign the following:
X# domain=somemachine.somewhere.universe
X###############################################################################
X
Xdomain=INSERT.YOUR.MAIL.DOMAIN.HERE # the common domain for all the lists
Xlistmaster=
X
X#UMASK=077 # group can not touch the files
X#UMASK=027 # group can read
X UMASK=007 # group can write as well
X
Xdefaults=.etc # the name of the defaults directory
XLOGFILE=log
XLOGABSTRACT=no
X
X#LOGABSTRACT=yes # uncomment in case of emergency
X#VERBOSE=yes # uncomment in case of real emergency
X#LOGFILE=../$defaults/log # uncomment if you want centralised
X # logging
X
XRC_INIT # clear this one from the environment
X # so that we include this file only
X # once
X
Xlistaddr=$list@$domain
Xlistreq=$list-request@$domain
Xlistdist=$list-dist@$domain
X
X # the following constants determine the
X # behaviour of choplist, the dist-file
X # expander (zero means: no limit) which
X # calls sendmail
Xminnames = 32 # minimum number of names per call
Xmindiffnames = 8 # minimum for maxnames-minnames
Xmaxnames = 64 # maximum number of names per call
Xmaxsplits = 0 # maximum number of parts to split dist in
Xmaxsize = 200000 # maximal disk space to be taken up per mail
Xmaxconcur = 4 # maximum number of concurrent sendmail calls
X
Xalt_sendmail="\
Xchoplist $minnames $mindiffnames $maxnames $maxsplits $maxsize $maxconcur dist"
Xminnames mindiffnames maxnames maxsplits maxsize maxconcur
X#alt_sendmail # uncomment if you'd prefer sendmail
X # to handle the $listdist expansion
X
XsendmailOPT="-oem -odb -oi -om -f$listreq"
XsendmailOPTp=-oep
XsendmailOPTq=-odq
XsendmailQflush="$SENDMAIL -q"
X#sendmailQflush # uncomment if you don't want the
X # queue to be flushed after all archive
X # retrieval files have been queued
X########################
X# sendmail options used:
X#
X# -t scan the header of the mail for recipients
X# -f specify the sender envelope address (requires T entry in sendmail.cf)
X# -oi do not regard a single dot on an otherwise empty line as EOF
X# -om include myself in any alias expansions
X# -odb background deliverymode command returns immediately
X# -odq queued deliverymode (put messages in the queue only)
X# -q flush the queue
X# -oem mail back error messages
X# -oep print error messages
X# -onF do not check aliases while expanding them (use it, if available)
X########################
X#
X# If you only have /bin/mail and not some sendmail compatible mailer that
X# understands the -t option of sendmail, then you have to uncomment the
X# following two lines:
X#
X#sendmailOPT sendmailOPTp sendmailOPTq sendmailQflush
X#SENDMAIL=../SedBinDir/sendmails
X#
X########################
X
Xsize_limit = 524288 # sanity cutoff value for submissions
X
Xidcache_size = 8192 # duplicate-msgid cache size in bytes
X
Xarchive_hist = 2 # number of messages left archived
Xarchive_log = $LOGFILE # log file for archive retrievals
Xsubscribe_log = $LOGFILE # log file for administrivia
X
Xmaxhist = 16 # bounce history limit
Xminbounce = 4 # no. of bounces before removal
Xcutoff_bounce = 256 # lines to keep in bounce processing
X
Xmatch_threshold = 30730 # for close matches to the list
Xmedium_threshold= 28672 # for not so close matches to the list
Xloose_threshold = 24476 # for loosely finding your name
X
Xauto_off_threshold= $medium_threshold # for auto-unsubscribing bouncers
Xoff_threshold = $loose_threshold # for unsubscribing
Xreject_threshold= $match_threshold # for rejecting subscriptions
Xsubmit_threshold= $medium_threshold # for permitting submissions
X
Xunsub_assist
X#unsub_assist = 8 # uncomment (and change perhaps) this
X # line to enable unsubscription
X # assistance; it specifies the no. of
X # multigram matches an unsuccessful
X # unsubscriber will receive back
Xforeign_submit = yes
X#foreign_submit # uncomment this line if you
X # want to restrict submitting to
X # people on the accept list
Xforce_subscribe
X#force_subscribe= yes # uncomment to cause people to
X # be autosubscribed upon first
X # submission to the list
Xauto_subscribe = yes
X#auto_subscribe # uncomment to disable unattended
X # subscription handling
Xauto_help
X#auto_help = yes # uncomment to enable default help
X # responses to all undecipherable
X # requests
Xmoderated_flag
X#moderated_flag = yes # uncomment this to make the list
X # moderated (you must create a
X # `moderators' file for this to work)
Xcc_requests
X#cc_requests = yes # uncomment if you want subscribe
X # and help requests to be Cc'd to
X # the maintainer
Xcc_unsubrequests
X#cc_unsubrequests= yes # uncomment if you want unsubscribe
X # requests to be Cc'd to the maintainer
Xreply_to
X#reply_to = "Resent-Reply-To: $listaddr" # uncomment (and perhaps change
X # it to "Reply-To") to force replies
X # to go to the list (discouraged)
Xdigest_flag
X#digest_flag = yes # uncomment this if you want digests
Xdigest_age = 262144 # maximum age of a digest in seconds
Xdigest_size = 32768 # maximum size of a digest in bytes
X
X
XX_COMMAND = X-Command
XX_COMMAND_PASSWORD = password # put the global password for
X # X-Command mails here
X # this password can of course be changed/
X # customised in the per list rc.custom file
X
X#daemon_bias='100^0 ^From:.*daemon@ok' # You could set "daemon_bias" to
X # positively discriminate some
X # mail address not to be from a daemon. Either with a regexp as demonstrated
X # or with more complicated recipes that simply set it to '100^0' or nothing.
X
X#RC_LOCAL_SUBMIT_00 = rc.local.s00 # Uncomment (and change) these to
X#RC_LOCAL_SUBMIT_10 = rc.local.s10 # call up customised local scripts
X#RC_LOCAL_SUBMIT_20 = rc.local.s20 # at predefined points.
X#RC_LOCAL_REQUEST_00 = rc.local.r00
X#RC_LOCAL_REQUEST_10 = rc.local.r10
X#RC_LOCAL_REQUEST_20 = rc.local.r20
X#RC_LOCAL_REQUEST_30 = rc.local.r30
X
XRC_CUSTOM=rc.custom
END_OF_FILE
if test 9559 -ne `wc -c <'procmail-3.03/SmartList/etc/rc.init'`; then
echo shar: \"'procmail-3.03/SmartList/etc/rc.init'\" unpacked with wrong size!
fi
# end of 'procmail-3.03/SmartList/etc/rc.init'
fi
if test ! -d 'procmail-3.03/SmartList/examples' ; then
echo shar: Creating directory \"'procmail-3.03/SmartList/examples'\"
mkdir 'procmail-3.03/SmartList/examples'
fi
if test ! -d 'procmail-3.03/src' ; then
echo shar: Creating directory \"'procmail-3.03/src'\"
mkdir 'procmail-3.03/src'
fi
if test -f 'procmail-3.03/src/hsort.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'procmail-3.03/src/hsort.h'\"
else
echo shar: Extracting \"'procmail-3.03/src/hsort.h'\" \(146 characters\)
sed "s/^X//" >'procmail-3.03/src/hsort.h' <<'END_OF_FILE'
X/*$Id: hsort.h,v 1.1 1994/04/05 15:34:44 berg Exp $*/
X
Xvoid hsort Q((void*base,size_t nelem,size_t width,
X int(*fcmp)(const void*,const void*)));
END_OF_FILE
if test 146 -ne `wc -c <'procmail-3.03/src/hsort.h'`; then
echo shar: \"'procmail-3.03/src/hsort.h'\" unpacked with wrong size!
fi
# end of 'procmail-3.03/src/hsort.h'
fi
if test -f 'procmail-3.03/src/multigram.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'procmail-3.03/src/multigram.c'\"
else
echo shar: Extracting \"'procmail-3.03/src/multigram.c'\" \(27219 characters\)
sed "s/^X//" >'procmail-3.03/src/multigram.c' <<'END_OF_FILE'
X/************************************************************************
X * multigram - The human mail address reader *
X * *
X * It uses multigrams to intelligently filter out mail addresses *
X * from the garbage in any arbitrary mail. *
X * Multigram is currently unable to pick out addresses that *
X * contain embedded whitespace. *
X * This program also contains some swiss-army-knife mailinglist *
X * support features. *
X * *
X * Most notably: flist A program that should be setuid root. *
X * *
X * Seems to be relatively bug free. *
X * *
X * Copyright (c) 1992-1994, S.R. van den Berg, The Netherlands *
X * #include "../README" *
X ************************************************************************/
X#ifdef RCS
Xstatic /*const*/char rcsid[]=
X "$Id: multigram.c,v 1.57 1994/06/28 16:56:34 berg Exp $";
X#endif
Xstatic /*const*/char rcsdate[]="$Date: 1994/06/28 16:56:34 $";
X#include "includes.h"
X#include "sublib.h"
X#include "hsort.h"
X#include "shell.h"
X#include "ecommon.h"
X#include "mcommon.h"
X
X#include "targetdir.h" /* see ../SmartList/install.sh2 for more details */
X
X#define BUFSTEP 16
X#define ADDR_INCR 128
X#define COPYBUF 16384
X/*#define SPEEDBUF COPYBUF /* uncomment to get a speed increase? */
X#define SCALE_WEIGHT 0x7fff
X#define EXCL_THRESHOLD 30730
X
X#define DEFmaxgram 4
X#define DEFminweight (SCALE_WEIGHT/4) /* sanity cutoff value */
X#define DEFbest_matches 2
X
X#define TMPMAILFILE "/tmp/choplist.%ld"
X
X#define DEFAULTS_DIR ".etc" /* some configurable paths */
X#define GLOCKFILE "../.etc/rc.lock"
X#define RCMAIN "./../.etc/rc.main"
X#define LLOCKFILE "rc.lock"
X#define LINKMOVED "../.etc/Moved"
X#define REQUEST "-request"
X#define RCSUBMIT "./rc.submit"
X#define RCREQUEST "./rc.request"
X#define RCPOST "./../.etc/rc.post"
X#define RCINIT "RC_INIT=rc.init"
X#define XENVELOPETO "X_ENVELOPE_TO="
X#define LIST "list="
X
X#define metoo_SENDMAIL "-om"
X#define nometoo_SENDMAIL "-omF"
X#define REMOV1_DELIM "(Only"
X#define REMOV2_DELIM "addresses below this line can be automatically removed)"
X#define NOT_METOO "(-n)"
X
Xstruct string{char*text,*itext;size_t textlen,buflen;};
X
Xstatic remov_delim,maxgram;
X
Xint strnIcmp(a,b,l)const char*a,*b;size_t l; /* stub */
X{ return strncmp(a,b,l);
X}
X /* read a string from a file into a struct string buffer */
Xstatic size_t readstr(file,p,linewise)FILE*const file;struct string*p;
X const int linewise;
X{ size_t len;int i,firstspc;
X static const char rem1str[]=REMOV1_DELIM,rem2str[]=REMOV2_DELIM;
X for(len=firstspc=0;;)
X { switch(i=getc(file))
X { case ' ':case '\t':case '\n':
X if(!len) /* only skip leading space */
X continue;
X if(!linewise) /* do we need a complete line? */
X break; /* no, a word will do */
X if(!firstspc) /* already seen spaces? */
X { if(i=='\n') /* no, so check for EOL */
X { p->text[len]='\0'; /* terminate the first word, split */
X if(++len==p->buflen) /* still buffer space left? */
X p->text=realloc(p->text,p->buflen+=BUFSTEP);
X break;
X }
X i='\0';firstspc=1;
X } /* not the first word on the line, continue */
X if(i=='\n')
X break;
X default:p->text[len]=i; /* regular character, store it */
X if(++len==p->buflen) /* watch our buffer space */
X p->text=realloc(p->text,p->buflen+=BUFSTEP);
X continue; /* next character */
X case EOF:;
X }
X p->text[len]='\0'; /* terminate the buffer in any case */
X if(linewise&&len)
X { int i=0;
X for(i=0;!remov_delim&&!i;i=1)
X if(!strcmp(p->text+i,rem1str)&&
X !strcmp(p->text+sizeof rem1str+i,rem2str)) /* special delimiter? */
X remov_delim=1;
X }
X return len;
X }
X}
X
Xstatic char*tstrdup(p)const char*const p;
X{ return strcpy(malloc(strlen(p)+1),p);
X}
X
Xstatic const char*mailfile;
Xstatic int retval=EX_UNAVAILABLE;
X
Xstatic void sterminate P((void))
X{ unlink(mailfile);exit(retval);
X}
X
Xstatic int strIcmp(s1,s2)const char*const s1,*const s2;
X{ register unsigned i,j;register const char*a,*b;
X a=s1;b=s2;
X do
X { while(*a&&*a==*b)
X a++,b++;
X if((i= *a++)-'A'<='Z'-'A')
X i+='a'-'A';
X if((j= *b++)-'A'<='Z'-'A')
X j+='a'-'A';
X if(j!=i)
X return i>j?a-s1:s1-a;
X }
X while(i&&j);
X return 0;
X}
X
Xstatic int pstrIcmp(s1,s2)const void*const s1,*const s2;
X{ return strIcmp(*(const char*const*)s1,*(const char*const*)s2);
X}
X
Xstatic void revstr(p)register char*p; /* reverse the string */
X{ register char*q;
X for(q=strchr(p,'\0')-1;p<q;p++,q--)
X { unsigned i;
X i= *p;*p= *q;*q=i;
X }
X}
X
Xstatic void makelow(str)register char*str;
X{ for(;*str;str++)
X if((unsigned)*str-'A'<'Z'-'A')
X *str+='a'-'A';
X}
X
Xstatic void lowcase(str)struct string*const str; /* make lowercase */
X{ makelow(str->itext=tstrdup(str->text));
X}
X
Xstatic void elog(a)const char*const a;
X{ fputs(a,stderr);
X}
X /* the program names */
Xstatic const char idhash[]="idhash",flist[]="flist",senddigest[]="senddigest",
X choplist[]="choplist",dirsep[]=DIRSEP;
Xstatic const char*progname="multigram";
X
X#define ISPROGRAM(curname,refname) \
X (!strncmp(curname,refname,STRLEN(refname)))
X
Xvoid nlog(a)const char*const a; /* log error with identification */
X{ fprintf(stderr,"%s: %s",progname,a);
X}
X
Xvoid logqnl(a)const char*const a;
X{ fprintf(stderr," \"%s\"\n",a);
X}
X /* finds the next character */
Xstatic char*lastdirsep(filename)const char*filename;
X{ const char*p; /* following the last DIRSEP */
X while(p=strpbrk(filename,dirsep))
X filename=p+1;
X return (char*)filename;
X}
X /* check rc.lock file age */
Xstatic int rclock(file,stbuf)const char*const file;struct stat*const stbuf;
X{ int waited=0;
X while(!stat(file,stbuf)&&time((time_t*)0)-stbuf->st_mtime<DEFlocktimeout)
X waited=1,sleep(DEFlocksleep); /* wait, if appropriate */
X return waited;
X}
X
Xstatic char*argstr(first,last)const char*first,*last; /* construct */
X{ char*chp;size_t i; /* an argument assignment */
X strcpy(chp=malloc((i=strlen(first))+strlen(last)+1),first);
X strcpy(chp+i,last);
X return chp;
X}
X
Xstatic void checkparens(pleft,pright,str,echp)int pleft,pright;
X char*str,*const echp;
X{ int parens;char*chp;
X for(chp=str,parens=0;chp=strchr(chp,pleft);chp++,parens++);
X for(chp=str;chp=strchr(chp,pright);chp++,parens--);
X if(*(chp=str)==pleft) /* any opening paren? */
X { if(!parens&&*echp==pright) /* parens matched and enclosing? */
X { *echp='\0';
X goto shftleft;
X }
X if(parens>0) /* more opening than closing parens? */
Xshftleft:
X tmemmove(chp,chp+1,echp-chp+1); /* delete left paren */
X }
X else if(parens<0&&*echp==pright) /* more closing than opening parens? */
X *echp='\0'; /* delete right paren */
X}
X
Xstatic PROGID;
X
Xstatic int matchgram(fuzzstr,hardstr)
Xconst struct string*const fuzzstr;struct string*const hardstr;
X{ size_t minlen,maxlen;unsigned maxweight;int meter;
X register size_t gramsize;
X if((minlen=hardstr->textlen=strlen(hardstr->text))>(maxlen=fuzzstr->textlen))
X minlen=fuzzstr->textlen,maxlen=hardstr->textlen;
X if((gramsize=minlen-1)>maxgram)
X gramsize=maxgram;
X maxweight=SCALE_WEIGHT/(gramsize+1);
X meter=(int)((unsigned long)SCALE_WEIGHT/2*minlen/maxlen)-SCALE_WEIGHT/2;
X do /* reset local multigram counter */
X { register lmeter=0;size_t cmaxlen=maxlen;
X ;{ register const char*fzz,*hrd;
X fzz=fuzzstr->itext;
X do
X { for(hrd=fzz+1;hrd=strchr(hrd,*fzz);) /* is it present in */
X if(!strncmp(++hrd,fzz+1,gramsize)) /* own string? */
X { if(cmaxlen>gramsize+1)
X cmaxlen--;
X goto dble_gram; /* skip until it's last */
X }
X for(hrd=hardstr->itext;hrd=strchr(hrd,*fzz);) /* otherwise */
X if(!strncmp(++hrd,fzz+1,gramsize)) /* search it in the */
X { lmeter++; /* dist entry */
X break;
X }
Xdble_gram:;
X }
X while(*(++fzz+gramsize)); /* next gram */
X }
X if(lmeter)
X { unsigned weight;
X if(cmaxlen>minlen)
X cmaxlen=minlen;
X meter+=lmeter*(weight=maxweight/(unsigned)(cmaxlen-gramsize));
X meter-=weight*
X (unsigned long)((lmeter+=gramsize-cmaxlen)<0?-lmeter:lmeter)/cmaxlen;
X }
X }
X while(gramsize--); /* search all gramsizes down to one */
X return meter;
X}
X
Xmain(argc,argv)int argc;char*argv[];
X{ struct string fuzzstr,hardstr,excstr,exc2str;FILE*hardfile;
X const char*addit=0;
X struct match{char*fuzz,*hard;int metric;long lentry;off_t offs1,offs2;}
X **best,*curmatch=0;
X unsigned best_matches,charoffs=0,remov=0,renam=0,incomplete=0,
X chkmetoo=(char*)progid-(char*)progid;
X int lastfrom,minweight;
X static const char cldntopen[]="Couldn't open";
X static const char usage[]=
X"Usage: multigram [-cdimr] [-b nnn] [-l nnn] [-w nnn] [-ax address] filename\n"
X ;
X if(argc) /* sanity check, any arguments at all? */
X { char*chp; /* suid flist prog? */
X if(ISPROGRAM(chp=lastdirsep(argv[0]),flist))
X { struct stat stbuf;struct passwd*pass;char*arg;
X static const char request[]=REQUEST,listid[]=LISTID,
X rcrequest[]=RCREQUEST,rcpost[]=RCPOST,list[]=LIST,
X defdir[]=DEFAULTS_DIR,targetdir[]=TARGETDIR,
X *pmexec[]={PROCMAIL,RCSUBMIT,RCINIT,0,0,0,rcrequest,rcpost,0};
X#define Endpmexec(i) (pmexec[maxindex(pmexec)-(i)])
X progname=flist;*chp='\0';
X if(argc!=2) /* wrong number of arguments? */
X { elog("\
XUsage: flist listname[-request]\n\
X Or: flist -v\n");
X return EX_USAGE;
X }
X if(!strcmp(arg=argv[1],"-v"))
X { fprintf(stderr,"%s\nUser: %s\nDirectory: %s\n",SLVERSION,listid,
X targetdir);
X return EX_OK;
X }
X ;{ uid_t euid;
X if((euid=geteuid())==ROOT_uid)
X { if(!(pass=getpwnam(listid)))
X { nlog("User \"");elog(listid);elog("\"");
X goto bailout;
X }
X /*
X * continue as the compile-time-determined list maintainer
X */
X setgid(pass->pw_gid);initgroups(listid,pass->pw_gid);
X setuid(pass->pw_uid);
X }
X else if(!(pass=getpwuid(euid)))
X { nlog("Euid");
Xbailout: elog(" unknown\n");
X return EX_NOUSER;
X }
X else
X /*
X * we weren't root, so try to get the uid and gid belonging to
X * the euid we started under
X */
X { int error;
X setrgid(pass->pw_gid);error=setgid(pass->pw_gid);setruid(euid);
X if(setuid(pass->pw_uid)&&error)
X nlog("Insufficient privileges\n");
X }
X endpwent();
X if(chdir(chp=pass->pw_dir))
X goto nochdir;
X }
X if(*(chp=(char*)targetdir)&&chdir(chp))
Xnochdir: { nlog("Couldn't chdir to");logqnl(targetdir);
X return EX_NOPERM;
X }
X if(stat(defdir,&stbuf))
X { nlog("Can't find \"");elog(defdir);elog("\" in");logqnl(targetdir);
X return EX_NOINPUT;
X }
X if(pass->pw_uid!=stbuf.st_uid||pass->pw_gid!=stbuf.st_gid)
X nlog("Strange group or user id\n"); /* check for -request */
X if((chp=strchr(arg,'\0'))-arg>STRLEN(request)&&
X !strcmp(chp-=STRLEN(request),request))
X *chp='\0',pmexec[1]=rcrequest,Endpmexec(1)=0,Endpmexec(2)=rcpost;
X else
X chp=0;
X if(!strcmp(arg,chPARDIR)||strpbrk(arg,dirsep))
X { nlog("Bogus listname\n");
X return EX_NOPERM;
X }
X ;{ int foundlock;
X do
X { foundlock=0;
X if(chdir(arg)) /* goto the list's subdirectory */
X pmexec[1]=RCMAIN,Endpmexec(2)=0,chdir(defdir);
X while(rclock(GLOCKFILE,&stbuf)||rclock(LLOCKFILE,&stbuf))
X foundlock=1; /* stall */
X }
X while(foundlock&&!chdir(LINKMOVED)); /* did the lists move? */
X }
X Endpmexec(5)=INIT_PATH;
X Endpmexec(4)=argstr(list,arg); /* pass on the list name */
X if(chp) /* was it a -request list? */
X *chp= *request; /* then restore the leading '-' */
X Endpmexec(3)=argstr(XENVELOPETO,arg);
X execve(pmexec[0],(char*const*)pmexec,environ);nlog("Couldn't exec");
X logqnl(pmexec[0]);
X return EX_UNAVAILABLE; /* panic */
X }
X /*
X * revoke any suid permissions now, since we're not flist
X */
X setgid(getgid());setuid(getuid());
X if(ISPROGRAM(chp,idhash)) /* idhash program? */
X { unsigned long hash=0;int i;
X progname=idhash;
X if(argc!=1)
X { elog("Usage: idhash\n");
X return EX_USAGE;
X }
X while(i=fgetc(stdin),!feof(stdin)) /* hash away! */
X hash=hash*67067L+i;
X printf("%lx",hash);
X return EX_OK;
X }
X if(ISPROGRAM(chp,senddigest)) /* senddigest program? */
X { struct stat stbuf;
X progname=senddigest;
X if(argc<5)
X { elog(
X "Usage: senddigest maxage maxsize bodyfile trailerfile [file] ...\n");
X return EX_USAGE;
X }
X if(!stat(argv[3],&stbuf))
X { time_t newt;off_t size;
X newt=stbuf.st_mtime;size=stbuf.st_size;
X if(!stat(argv[argc=4],&stbuf))
X { off_t maxsize;
X if(stbuf.st_mtime+strtol(argv[1],(char**)0,10)<newt)
X return EX_OK; /* digest too old */
X maxsize=strtol(argv[2],(char**)0,10);
X goto statd;
X do
X { if(!stat(argv[argc],&stbuf))
Xstatd: if((size+=stbuf.st_size)>maxsize) /* digest too big? */
X return EX_OK;
X }
X while(argv[++argc]);
X }
X }
X return 1;
X }
X hardstr.text=malloc(hardstr.buflen=BUFSTEP);
X if(ISPROGRAM(chp,choplist))
X { unsigned long minnames,mindiffnames,maxnames,maxsplits,maxsize,
X maxconcur;
X char*distfile,**nargv,**revarr;int mailfd;size_t revfilled;
X static const char tmpmailfile[]=TMPMAILFILE;
X char lmailfile[STRLEN(TMPMAILFILE)+8*sizeof(pid_t)*4/10+1+1];
X progname=choplist;
X if(argc<9)
X { elog(
X"Usage: choplist minnames mindiffnames maxnames maxsplits maxsize maxconcur\n\
X\tdistfile sendmail [flags ...]\n");
X return EX_USAGE;
X }
X minnames=strtol(argv[1],(char**)0,10);
X mindiffnames=strtol(argv[2],(char**)0,10);
X maxnames=strtol(argv[3],(char**)0,10);
X maxsplits=strtol(argv[4],(char**)0,10);
X maxsize=strtol(argv[5],(char**)0,10);
X maxconcur=strtol(argv[6],(char**)0,10);distfile=argv[7];
X nargv=argv+8;argc-=8;setbuf(stdin,(char*)0);setbuf(stdout,(char*)0);
X sprintf((char*)(mailfile=lmailfile),tmpmailfile,(long)getpid());
X qsignal(SIGTERM,sterminate);qsignal(SIGINT,sterminate);
X qsignal(SIGHUP,sterminate);qsignal(SIGQUIT,sterminate);
X unlink(mailfile);
X#ifndef O_CREAT
X if(0>(mailfd=creat(mailfile,NORMperm)))
X#else
X if(0>(mailfd=open(mailfile,O_RDWR|O_CREAT|O_EXCL,NORMperm)))
X#endif
X { nlog("Can't create temporary file");logqnl(mailfile);
X return EX_CANTCREAT;
X }
X ;{ char*buf;int i;unsigned long totsize=0;
X buf=malloc(COPYBUF);
X goto jin;
X do
X { char*a=buf;size_t len;
X totsize+=(len=i);
X do
X { while(0>(i=write(mailfd,buf,(size_t)len))&&errno==EINTR);
X if(i<0)
X { nlog("Can't write temporary file");logqnl(mailfile);
X retval=EX_IOERR;sterminate();
X }
X a+=i;
X }
X while(i>0&&(len-=i));
Xjin: while(0>(i=read(STDIN,buf,(size_t)COPYBUF))&&errno==EINTR);
X }
X while(i>0);
X if(!totsize)
X nlog("Can't find the mail\n"),retval=EX_NOINPUT,sterminate();
X free(buf);totsize=(maxsize+totsize-1)/totsize;
X if(maxsize&&(!maxsplits||totsize<maxsplits))
X maxsplits=totsize?totsize:1;
X }
X fclose(stdin);close(STDIN);
X if(!(hardfile=fopen(chp=distfile,"r")))
X nlog(cldntopen),logqnl(distfile),retval=EX_IOERR,sterminate();
X ;{ size_t revlen;
X revarr=malloc((revlen=ADDR_INCR)*sizeof*revarr);revfilled=0;
X while(readstr(hardfile,&hardstr,1))
X { int i=strchr((chp=strchr(hardstr.text,'\0'))+1,'\0')[-1];
X if(*hardstr.text!='(')
X switch(i)
X { default:
X goto invaddr;
X case ')':case '\0':;
X }
X else /* comment line */
X switch(i)
Xinvaddr: { default:nlog("Skipping invalid address entry:");*chp=' ';
X logqnl(hardstr.text);
X case ')':case '\0':
X continue;
X }
X if(revfilled==revlen) /* watch our space */
X revarr=realloc(revarr,(revlen+=ADDR_INCR)*sizeof*revarr);
X revstr(hardstr.text);revarr[revfilled++]=tstrdup(hardstr.text);
X }
X }
X free(hardstr.text);fclose(hardfile);
X if(!revfilled)
X retval=EX_OK,sterminate(); /* oops, no recipients, finished */
X if(fork()>0) /* lose our tail */
X return EX_OK; /* causes procmail to release the lockfile */
X revarr=realloc(revarr,revfilled*sizeof*revarr); /* be modest */
X hsort(revarr,revfilled,sizeof*revarr,pstrIcmp); /* sort'em */
X if(maxsplits)
X { maxsplits=(revfilled+maxsplits-1)/maxsplits;
X if(!minnames||minnames<maxsplits)
X { minnames=maxsplits;
X if(maxnames&&maxnames<minnames)
X maxnames=minnames+mindiffnames;
X }
X }
X if(!maxnames||(maxnames+argc>MAX_argc))
X maxnames=MAX_argc-argc;
X if(minnames>maxnames)
X minnames=maxnames;
X if(!minnames)
X minnames=1;
X ;{ int*rdist,*ip;char**nam;size_t n;
X ip=rdist=malloc((n=revfilled)*sizeof*rdist);nam=revarr;
X while(--n)
X { int i,j;char*left,*right;
X left= *nam;
X if(!(i=strIcmp(right= *++nam,left)))
X j=SCALE_WEIGHT; /* identical! don't split them up */
X else
X for(j=0;--i;)
X switch(*right++)
X { case '@':j=SCALE_WEIGHT/2; /* domains match! */
X case '.':j++; /* domain borders */
X }
X revstr(left);*ip++=j;
X }
X revstr(*nam);*ip=0;nam=malloc(++argc*sizeof*argv);
X tmemmove(nam,nargv,argc*sizeof*argv);nargv=nam;
X ;{ unsigned long cnames,cnsize,cconcur,maxnsize;
X char**first,**best;
X for(maxnsize=MAX_argc*16L;*nam;maxnsize-=strlen(*nam++));
X n=cconcur=0;
X do
X { int bestval;
X cnsize=strlen(*(first=nam=revarr+n));cnames=0;
X do
X { if(first-nam<minnames||rdist[n]<=bestval)
X bestval=rdist[n],best=nam;
X cnames++;
X }
X while(++n<revfilled&&
X maxnsize>=(cnsize+=strlen(*++nam)+1)&&
X maxnames>cnames);
X nam=(nargv=realloc(nargv,
X ((bestval=best-first+1)+argc)*sizeof*argv))+argc-1;
X if(maxconcur&&maxconcur<++cconcur)
X wait((int*)0);
X tmemmove(nam,first,bestval*sizeof*argv);nam[bestval]=0;
X if(STDIN!=open(mailfile,O_RDONLY))
X { nlog("Lost");logqnl(mailfile);retval=EX_NOINPUT;
X sterminate();
X }
X for(;;)
X { switch(fork())
X { case -1:nlog("Couldn't fork, retrying\n");
X if(wait((int*)0)==-1)
X sleep(DEFsuspend);
X continue;
X case 0:
X execve(nargv[0],nargv,environ);
X kill(getppid(),SIGTERM);nlog("Couldn't exec");
X logqnl(nargv[0]);
X return EX_UNAVAILABLE;
X }
X break;
X }
X close(STDIN);
X }
X while((n=best-revarr+1)<revfilled);
X }
X }
X retval=EX_OK;sterminate();
X }
X minweight=SCALE_WEIGHT;best_matches=maxgram=0;exc2str.text=excstr.text=0;
X while((chp= *++argv)&&*chp=='-')
X for(chp++;;)
X { int c;
X switch(c= *chp++)
X { case 'c':charoffs=1;
X continue;
X case 'd':remov=1;
X continue;
X case 'i':incomplete=1;
X continue;
X case 'r':renam=1;
X continue;
X case 'm':chkmetoo=1;
X continue;
X case 'a':
X if(!*chp&&!(chp= *++argv))
X goto usg;
X addit=chp;
X break;
X case 'x':
X if(!*chp&&!(chp= *++argv))
X goto usg;
X if(excstr.text)
X exc2str.text=chp;
X else
X excstr.text=chp;
X break;
X case 'b':case 'l':case 'w':
X { int i;
X ;{ const char*ochp;
X if(!*chp&&!(chp= *++argv)||
X (i=strtol(ochp=chp,(char**)&chp,10),chp==ochp))
X goto usg;
X }
X switch(c)
X { case 'b':best_matches=i;
X continue;
X case 'l':minweight=i;
X continue;
X case 'w':maxgram=i;
X continue;
X }
X }
X case HELPOPT1:case HELPOPT2:elog(usage);
X elog(
X "\t-a address\tadd this address to the list\
X\n\t-b nnn\t\tmaximum no. of best matches shown\
X\n\t-c\t\tdisplay offsets in characters\
X\n\t-d\t\tdelete address from list\
X\n\t-i\t\tcheck for incomplete addresses too\
X\n\t-m\t\tcheck for metoo\
X\n\t-l nnn\t\tlower bound metric\
X\n\t-r\t\trename address on list\
X\n\t-x address\texclude this address from the search (max. 2)\
X\n\t-w nnn\t\twindow width used when matching\n");
X return EX_USAGE;
X case '-':
X if(!*chp)
X { chp= *++argv;
X goto lastopt;
X }
X default:
X goto usg;
X case '\0':;
X }
X break;
X }
Xlastopt:
X if(!chp||*++argv||renam+remov+!!addit>1)
X goto usg;
X if(excstr.text)
X { excstr.textlen=strlen(excstr.text);lowcase(&excstr);
X if(exc2str.text)
X exc2str.textlen=strlen(exc2str.text),lowcase(&exc2str);
X }
X if(!(hardfile=fopen(chp,remov||renam||addit?"r+":"r")))
X { nlog(cldntopen);logqnl(chp);
X return EX_IOERR;
X }
X#ifdef SPEEDBUF /* allocate a bigger stdio buffer */
X setvbuf(hardfile,malloc(SPEEDBUF),_IOFBF,(size_t)SPEEDBUF);
X#endif
X }
X else
Xusg:
X { elog(usage);
X return EX_USAGE;
X }
X if(addit) /* special subfunction, to add entries */
X { int lnl;off_t lasttell; /* to the dist file */
X for(lnl=1,lasttell=0;;)
X { switch(getc(hardfile)) /* step through the file */
X { case '\n':
X if(!lnl) /* looking for trailing newlines */
X lnl=1,lasttell=ftell(hardfile);
X continue;
X default:lnl=0;
X continue;
X case EOF:; /* or the end of the file */
X }
X break;
X } /* go back there, and add the new entry */
X fseek(hardfile,lasttell,SEEK_SET);fprintf(hardfile,"%s\n",addit);
X printf("Added: %s\n",addit);fclose(hardfile);
X return EX_OK;
X }
X if(!maxgram)
X maxgram=DEFmaxgram;
X maxgram--;
X if(minweight==SCALE_WEIGHT)
X minweight=DEFminweight;
X if(!best_matches)
X best_matches=DEFbest_matches;
X fuzzstr.text=malloc(fuzzstr.buflen=BUFSTEP);
X ;{ int i;
X best=malloc(best_matches--*sizeof*best);i=best_matches;
X do
X { best[i]=malloc(sizeof**best);best[i]->hard=malloc(1);
X best[i]->fuzz=malloc(1);best[i]->metric= -SCALE_WEIGHT;
X }
X while(i--);
X }
X for(lastfrom= -1;readstr(stdin,&fuzzstr,0);)
X { int meter,maxmetric;long linentry;off_t offs1,offs2;
X ;{ char*chp,*echp;
X const static char tpunctuation[]="@\\/!#$%^&*-_=+|~`';:,.?{}";
X#define punctuation (tpunctuation+3)
X echp=strchr(chp=fuzzstr.text,'\0')-1;
X while(*chp&&strchr(punctuation,*chp)) /* strip leading punctuation */
X chp++;
X if(*chp=='"'&&!strchr(chp+1,'"')) /* strip leading unbalanced " */
X chp++;
X while(*chp&&strchr(punctuation,*chp)) /* strip leading punctuation */
X chp++;
X while(echp>=chp&&strchr(tpunctuation,*echp))
X *echp--='\0'; /* strip trailing punctuation */
X if(echp>=chp&&*echp=='"'&&strchr(chp,'"')==echp)
X *echp--='\0'; /* strip trailing unbalanced " */
X while(echp>=chp&&strchr(tpunctuation,*echp))
X *echp--='\0'; /* strip trailing punctuation */
X if(echp<chp)
X continue;
X if(lastfrom<=0&& /* roughly check if it could be a mail address */
X !strpbrk(chp,"@/")&& /* RFC-822 or X-400 address */
X (!strchr(chp,'!')|| /* UUCP bang path address */
X strchr(chp,'|')||
X strchr(chp,',')||
X strstr(chp,".."))&&
X !(*chp=='<'&&*echp=='>')&& /* RFC-822 machine literal */
X !(incomplete&&strchr(chp,'.'))) /* domain name */
X { if(lastfrom<0)
X lastfrom=!strcmp(SHFROM,chp);
X continue; /* apparently not an email address */
X }
X lastfrom=0;tmemmove(fuzzstr.text,chp,echp-chp+1);
X checkparens('(',')',fuzzstr.text,echp);
X checkparens('[',']',fuzzstr.text,strchr(fuzzstr.text,'\0'));
X if(*(chp=fuzzstr.text)=='<'&&*(echp=strchr(chp,'\0')-1)=='>')
X { if(chp=strstr(chp,">,<")) /* take the first of a dense */
X (echp=chp)[1]='\0'; /* list of addresses */
X if(!strchr(chp=fuzzstr.text,',')) /* strip '<' and '>' ? */
X *echp='\0',tmemmove(chp,chp+1,echp-chp);
X }
X if(!(fuzzstr.textlen=strlen(chp))) /* still something left? */
X continue; /* it's gone, next word please */
X lowcase(&fuzzstr); /* cast it into lowercase */
X if(excstr.text&&matchgram(&fuzzstr,&excstr)>=EXCL_THRESHOLD||
X exc2str.text&&matchgram(&fuzzstr,&exc2str)>=EXCL_THRESHOLD)
X { free(fuzzstr.itext);
X continue;
X }
X ;{ int i=0;
X do
X { if(best[i]->metric==-SCALE_WEIGHT&&!strcmp(best[i]->fuzz,chp))
X break;
X if(!strcmp(best[i]->fuzz,chp)) /* already matched this one? */
X goto dupl_addr;
X }
X while(++i<=best_matches);
X }
X if(!curmatch)
X curmatch=malloc(sizeof*curmatch);
X curmatch->fuzz=tstrdup(chp);curmatch->hard=malloc(1);
X curmatch->metric= -SCALE_WEIGHT;
X }
X fseek(hardfile,(off_t)0,SEEK_SET);maxmetric=best[best_matches]->metric;
X for(remov_delim=offs2=linentry=0;
X offs1=offs2,readstr(hardfile,&hardstr,1);)
X { offs2=ftell(hardfile);linentry++;
X if(*hardstr.text=='(')
X continue; /* unsuitable for matches */
X lowcase(&hardstr);meter=matchgram(&fuzzstr,&hardstr);
X free(hardstr.itext); /* check if we had any luck */
X if(meter>maxmetric&&(remov_delim||!renam&&!remov))
X { size_t hardlen;
X curmatch->metric=maxmetric=meter;curmatch->lentry=linentry;
X free(curmatch->hard);hardlen=hardstr.textlen+1;
X hardlen+=strlen(hardstr.text+hardlen)+1;
X curmatch->hard=malloc(hardlen+=strlen(hardstr.text+hardlen)+1);
X tmemmove(curmatch->hard,hardstr.text,hardlen);
X curmatch->offs1=offs1;curmatch->offs2=offs2;
X }
X }
X free(fuzzstr.itext); /* maybe this match can be put in the array */
X if(curmatch->metric>-SCALE_WEIGHT) /* of best matches so far */
X { struct match*mp,**mmp;
X free((mp= *(mmp=best+best_matches))->fuzz);free(mp->hard);free(mp);
X while(--mmp>=best&&(mp= *mmp)->metric<curmatch->metric)
X mmp[1]=mp; /* keep it sorted */
X mmp[1]=curmatch;curmatch=0;
X }
X else
X free(curmatch->fuzz),free(curmatch->hard);
Xdupl_addr:;
X }
X ;{ int i;struct match*mp;
X for(i=0;i<=best_matches&&(mp=best[i++])->metric>=minweight;)
X if(chkmetoo)
X printf("%s\n",strcmp(mp->hard+strlen(mp->hard)+1,NOT_METOO)
X ?metoo_SENDMAIL:nometoo_SENDMAIL);
X else
X printf("%3ld %-34s %5d %s\n",
X charoffs?mp->offs1:mp->lentry,mp->hard,mp->metric,mp->fuzz);
X if((mp= *best)->metric>=minweight)
X { struct match*worse;
X if(renam)
X { long line;int i,w1;unsigned maxweight;
X maxweight=SCALE_WEIGHT/(maxgram+1)>>1;;
X for(i=1,line=mp->lentry,w1=mp->metric,worse=0;
X i<=best_matches&&(mp=best[i++])->metric>=minweight;)
X if(mp->lentry==line&&mp->metric+maxweight<w1)
X goto remv1;
X for(i=1;i<=best_matches&&(mp=best[i++])->metric>=minweight;)
X if(mp->metric+maxweight<w1)
Xremv1: { worse=mp;mp= *best;
X goto remv;
X }
X nlog("Couldn't find a proper address pair\n");
X goto norenam;
X }
X if(remov)
Xremv: { char*buf;off_t offs1,offs2;size_t readin;
X buf=malloc(COPYBUF);offs1=mp->offs1;offs2=mp->offs2;
X while(fseek(hardfile,offs2,SEEK_SET),
X readin=fread(buf,1,COPYBUF,hardfile))
X { offs2=ftell(hardfile);fseek(hardfile,offs1,SEEK_SET);
X if(buf[readin-1]=='\n') /* try and remove some empty lines */
X while(readin>1&&buf[readin-2]=='\n') /* at the end, since */
X readin--; /* every time could be the last */
X fwrite(buf,1,readin,hardfile);offs1=ftell(hardfile);
X }
X free(buf);fseek(hardfile,offs1,SEEK_SET);
X printf("Removed: %s\n",mp->hard);
X if(renam)
X fputs(worse->fuzz,hardfile),printf("Added: %s\n",worse->fuzz);
X do putc('\n',hardfile); /* erase the tail */
X while(ftell(hardfile)<offs2);
X fclose(hardfile);
X }
X return EX_OK;
X }
X }
X if(remov||renam)
X { nlog("Couldn't even find a single address\n");
X }
Xnorenam:
X return 1;
X}
END_OF_FILE
if test 27219 -ne `wc -c <'procmail-3.03/src/multigram.c'`; then
echo shar: \"'procmail-3.03/src/multigram.c'\" unpacked with wrong size!
fi
# end of 'procmail-3.03/src/multigram.c'
fi
echo shar: End of archive 1 \(of 5\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 5 archives.
rm -f ark[1-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...