riscy
[Top] [All Lists]

(fwd) MailServ 1.1.0

To: riscy@pyramid.com
Subject: (fwd) MailServ 1.1.0
From: Bill Broadley <broadley@neurocog.lrdc.pitt.edu>
Date: Wed, 30 Jun 93 22:33:09 -0400
Newsgroups: alt.sources
Organization: Learning Research and Development Center at University of Pittsburgh

FYI, get lots of work done.  The mailing list we be there on your return ;-)

Version 1.1.0 -- Changes
Wed Jun 30 15:03:04 MDT 1993

- Now checks for relevant info in Info file.  If anything is missing
        that it needs, it announces it (to stderr and the logfile, if
        possible) and dies.  This fixes most of the segfault problems.
- Fixed a couple of memory allocation bugs in utils.c and info.c.
- Made the "usage" function a little more helpful.
- Tracked down a couple of other segfault bugs.

----------------------------------------------------------------------

        MailServ  --  by Dave DeBry <debry@peruvian.cs.utah.edu>
        Version 1.1.0

        A mailing list, mail request server, digest server, etc., all
in one tiny little program.  Wheee!

----------------------------------------------------------------------

        This is a mailing list program that I wrote, because I wasn't
to excited about all the other packages that I found floating on the
net.  I'm currently using it to run two digests, five self-running
reflector mailing lists, and two invitation-only mailing lists
(there's no request address for those, they're private).

        MailServ:

        o allows for as many users as you want per list,

        o users can be mailed to "quietly" (ie: their name won't
                be found anywhere in the mailing... good for 
                nosy sysadmins at other sites),

        o has a request server so users can get any files you make
                available for them,

        o handles subscribes and unsubscribes without bothering you,

        o can archive off reflector mailing list posts,

        o can announce to all list readers when someone subscribes
                or unsubscribes,

        o can be set to let people request a list of readers,

        o does all the digest handling work for you,

        o can upload (via ftp) each days digest to a given site for
                archiving,

        o can backup the userlist to a different disk/area/whatever,

        o can post a FAQ to USENET periodically,

        o announces when a message has been taken from USENET, so
                people don't get that horrible deja vu feeling
                while reading their mail,

        o sends you a log of all the day's activities every night,

        o lets you toggle all of these things for complete 
                customization,

        o and much, much more!  (I should be an announcer for those
                Remco ads, I know it.)

----------------------------------------------------------------------

        MailServ isn't for the weak at heart.  It's not pretty, and
I'm releasing it to the net because several people have asked for
copies, and I'd like to know what changes are made to it.  If you
don't know much about UNIX or mail, I wouldn't suggest using MailServ
until it gets a little bit nicer.

----------------------------------------------------------------------

        A lot of the digest code was vulture coded from David A.
Curry's (davy@intrepid.ecn.purdue.edu) digest program.  I've included
his code in here as well so you can put back in the stuff that I've
ripped out if you wish.

----------------------------------------------------------------------

        Feel free to distribute and edit this code as you want.  My
only requests are:

        1] Keep my name and Mr. Curry's name intact -- credit where
credit is due, and all that jazz.

        2] Let me know of any modifications you make.  Chances are
I'll want to incorporate them into my working copy.  Not only that,
but it would be nice if we had one "real" version of the program out
there that people could grab.

----------------------------------------------------------------------

        I don't guarantee anything about this code.  I've only truly
tested it well on a MIPS based box.  However, it builds well under
GCC, and executes only the most standard of UNIX programs (cp, rm,
sendmail, etc.).  It should be fine, but don't blame me for any
problems.  (That should be enough disclaimer to ward off the lawyers,
don't you think?)

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#               "End of shell archive."
# Contents:  MailServ MailServ/Changes MailServ/InfoDir
#   MailServ/Install MailServ/Readme MailServ/aliases MailServ/backup
#   MailServ/bin MailServ/crontab MailServ/fakedigest
#   MailServ/fakelist MailServ/src MailServ/backup/fakedigest
#   MailServ/backup/fakelist MailServ/bin/GenInfo MailServ/bin/fndusr
#   MailServ/bin/nightly MailServ/bin/rarely MailServ/fakedigest/Info
#   MailServ/fakedigest/counter MailServ/fakedigest/files
#   MailServ/fakedigest/head MailServ/fakedigest/help
#   MailServ/fakedigest/index MailServ/fakedigest/input
#   MailServ/fakedigest/netrc MailServ/fakedigest/nounsub
#   MailServ/fakedigest/output MailServ/fakedigest/sub
#   MailServ/fakedigest/tail MailServ/fakedigest/unsub
#   MailServ/fakedigest/users MailServ/fakelist/Info
#   MailServ/fakelist/archive MailServ/fakelist/help
#   MailServ/fakelist/nounsub MailServ/fakelist/sub
#   MailServ/fakelist/unsub MailServ/fakelist/users
#   MailServ/src/Makefile MailServ/src/digest.c MailServ/src/info.c
#   MailServ/src/inmsg.c MailServ/src/mailserv.c
#   MailServ/src/mailserv.h MailServ/src/orig-dig
#   MailServ/src/outmsg.c MailServ/src/request.c MailServ/src/utils.c
#   MailServ/fakedigest/files/UNDIGEST.C
#   MailServ/src/orig-dig/Makefile MailServ/src/orig-dig/digest.c
#   MailServ/src/orig-dig/undigest.c
# Wrapped by ddebry@ren on Wed Jun 30 15:52:49 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test ! -d 'MailServ' ; then
    echo shar: Creating directory \"'MailServ'\"
    mkdir 'MailServ'
fi
if test -f 'MailServ/Changes' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/Changes'\"
else
echo shar: Extracting \"'MailServ/Changes'\" \(405 characters\)
sed "s/^X//" >'MailServ/Changes' <<'END_OF_FILE'
XVersion 1.1.0
XWed Jun 30 15:03:04 MDT 1993
X
X- Now checks for relevant info in Info file.  If anything is missing
X       that it needs, it announces it (to stderr and the logfile, if
X       possible) and dies.  This fixes most of the segfault problems.
X- Fixed a couple of memory allocation bugs in utils.c and info.c.
X- Made the "usage" function a little more helpful.
X- Tracked down a couple of other segfault bugs.
END_OF_FILE
if test 405 -ne `wc -c <'MailServ/Changes'`; then
    echo shar: \"'MailServ/Changes'\" unpacked with wrong size!
fi
# end of 'MailServ/Changes'
fi
if test -f 'MailServ/InfoDir' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/InfoDir'\"
else
echo shar: Extracting \"'MailServ/InfoDir'\" \(4163 characters\)
sed "s/^X//" >'MailServ/InfoDir' <<'END_OF_FILE'
XHere's a rundown of the elements of the Info file:
X
Xerrorsto       Where the mail bounces will go to. (1)
Xreplyto                Where user replies will go to. (1)
Xuserfile       List of users.  (3)
Xlogfile                Log file, cleared daily. (2)
Xdelay          Delay between messagesm in seconds.  Even on very
X               fast machines, it's easy to overload them with mail
X               (especially if you've got a slower link to the net).
X               I'd suggest *at least* a 5 second delay.  8-10 is
X               probably optimal.
Xfrom           Address for the request line.  Also will be on the
X               "From" line for messages.
Xsubscribefile  The file that users will be sent when they subscribe. (2) 
Xunsubscribefile        The file that users will be sent when they 
X               unsubscribe. (2)
Xnounsubfile    The file that users will be sent when they can't be
X               unsubscribed. (2)
Xhelpfile       The file that users will be sent when MailServ can't
X               figure out what they want. (2)
Xfiles          Set if you have files that can be requested. (4)
Xindexfile      Index file for requestable files.  Will not be mailed
X               out, for MailServ use only. (2)
Xkeep           Set if you want reflector posts archived. (4)
Xarchivefile    File where reflector posts will be archived. (2)
Xannounce       Set if you want all users told when someone subscribes
X               or unsubscribes. (4)
Xdigest         Set if this list is a digest (as opposed to a
X               reflector).  (4)
Xdigestinput    File where input to digest will go.  (2)
Xdigestoutput   File for latest digest. (2)
Xdigestcounterfile      File to keep track of which issue and volume
X                       of digest you are on.  On the first day of
X                       every month, MailServ will increment the
X                       volume counter and set the issue counter
X                       back to 1.  (Unlike Mr. Curry's version
X                       of 'digest', the counter sets the issue
X                       to be tomorrow's digest number, instead
X                       of yesterday's.  That way, restarting a
X                       digest means setting the issue to 1, not
X                       0). (2)
Xdigestname     Name of the digest.
Xdigesthead     File to be prepended to the digest. (2)
Xdigesttail     File to be appended to the digest. (2)
Xftp            Set if the digest is to be uploaded to an ftp site.
Xftpdir         Directory on the ftp site where the digest should go.
X               MailServ will go to that directory and write to the
X               file 'vol-X/Y', where X is the volume number and Y
X               is the issue number.  It will then ALSO write the same
X               digest into the file 'daily'.  That way people can 
X               always download the latest issue with ease.
Xftpsite                Site to ftp to.
Xnetrcfile      A netrc file.  Must be read/writeable ONLY by mailserv.
X               Put the account name and password of the account to
X               ftp to on ftpsite here.  This file will be copied to
X               ~MailServ/.netrc when the ftp is started.  As soon as
X               it is over, ~MailServ/.netrc will be deleted.  It will
X               only work if the permissions are correct.  For the
X               netrc format, see the man page on ftp. (2)
Xbackup         Set if you want your userlist backed up somewhere. (4)
Xbackupdir      Directory to back up the userlist to.  MailServ will
X               keep the past 7 days worth of backups in this directory.
X               The name of the files will be the date of the backup. 
X               I currently have this pointing to ~MailServ/backup/list,
X               but if you want it to do any good I'd suggest pointing
X               it to a different physical disk.  (2)
Xfaq            Set if the list has a FAQ that is to be posted to 
X               USENET. (4)
Xfaqfile                The FAQ in question.  All the USENET headers must 
already
X               be in place in this file. (2)
X
X       Here's what the footnotes mean:
X
X       (1) This is a mail address.  Treat it as such.
X
X       (2) This is a file or directory.  If the file doesn't start
Xwith '/' or '.', then MailServ will assume that you mean
X'~Mailserv/*list*/*file*', where *list* is the name of the list (like
Xfakelist or fakedigest), and *file* is the string you have entered.
X
X       (3) This is a userlist.  One address to a line, one line to
Xan address.  If you start a line with an asterisk ("*"), then that
Xuser will be mailed to "quietly".  This means that their name will not
Xbe found anywhere in the mailing.
X
X       (4) This is a boolean variable.  Proper settings are "yes" and
X"no".
X
X       Any line starting with a "#" will be considered a comment and
Xignored.  This goes for any file MailServ reads as a data file
X(userlist, indexlist, Info, etc.), but not files that are going to be
Xmailed to a user.
END_OF_FILE
if test 4163 -ne `wc -c <'MailServ/InfoDir'`; then
    echo shar: \"'MailServ/InfoDir'\" unpacked with wrong size!
fi
# end of 'MailServ/InfoDir'
fi
if test -f 'MailServ/Install' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/Install'\"
else
echo shar: Extracting \"'MailServ/Install'\" \(5447 characters\)
sed "s/^X//" >'MailServ/Install' <<'END_OF_FILE'
X
X       First priority is to get an account for this program.  Yes,
XMailServ needs its own account and directory.  I'm assuming the
Xusername is 'mailserv', and the directory is '/usr/people/MailServ'.
XYou're also going to need to edit the /usr/lib/aliases (or
X/etc/aliases, depending on your system), so if you don't have root
Xaccess, or a good friend with root access, you're probably out of
Xluck.
X
X       Anyway, the account.  Go make it.  Now, unshar or untar this
Xpackage into that area.  (Do it from /usr/people, the package assumes
Xdirectory 'MailServ' is in the current working directory.)  Now become
Xmailserv.
X
X       Make a .forward file, and point it to YOUR account.  Not
Xmailserv (we don't want mail loops), YOU.  In real life.
X
X       Now go into the src directory.  With that in mind, edit the
Xmailserv.h file to fit your system.  As you add new lists, you
Xshouldn't have to rebuild the program; there are no references to the
Xlists in the executable.  Go ahead and 'make' it.
X
X       Ok, that's done.  Now you'll want to create your lists.  I've
Xmade a couple of demo lists: fakelist and fakedigest.  Follow the lead
Xof the files in there.  Most important is the Info file.  THIS FILE
XMUST BE THERE.  There's a list of elements for the Info file in a file
Xcalled "InfoDir" which you should have received with this release.
X
X       Now edit the ~MailServ/aliases file to reflect your new list.
XExamples of how to do this are already in the file.  NOTE:  There is a
X"notreal" alias in the file.  LEAVE IT THERE.  This must be there for
Xquiet mailing to work correctly.
X
X       Edit the ~Mailserv/bin/GenInfo file to show what lists exist,
Xwhere they are, etc.  GenInfo and aliases are the only files to need
Xto edit when you add or remove lists (besides the list's files, of
Xcourse).
X
X       Using your root powers, insert the ~MailServ/aliases file into
Xthe /usr/lib/aliases (or /etc/aliases) file.  Do a 'newaliases' to
Xrebuild the hash table.  You need to do this everytime you edit your
Xaliases file.
X
X       Edit the crontab to set when you want the nightly maintenance
Xand bi-weekly maintenance to occur.  Here's what happens at each time:
X
X       Nightly:
X
X       o Mailserv will sort the userlist and eliminate duplicate
X               entries.        
X       o If the list is supposed to have its userlist backed
X               up, MailServ will do that.
X       o If the list is a digest, MailServ builds the digest,
X               and mails it out to the readers.  It will also
X               upload the digest to an FTP site if necessary.
X       o Mailserv will dump the daily log into a tempfile.  When
X               all the lists have dumped their logs (ewww), Mailserv
X               will mail this meta-log to itself.  Since its forward
X               file is pointing at you, you will get it.
X
X       Biweekly ("rarely"):
X
X       o If your list has a FAQ that is to be posted to USENET,
X               MailServ will do that.
X
X       The crontab is currently set to run nightly maintenance at
X12:07am everyday.  Rare maintenance happens at 12:01am on the 5th and
X20th of every month.
X
X       Make sure you are still using the mailserv account, and do a
X'crontab crontab'.
X
X       The two shell scripts in the bin directory are the ones that
Xare run by the crontab.  I wanted to not use any shell scripts at all,
Xbut then I would have had to let the mailserv program know about every
Xlist, and I didn't want to do that.  Maybe that should change; at
Xleast then you wouldn't need a GenInfo file.  Comments?
X
X       There seems to be a little confusion over where you should
Xtell the users to mail their requests and messages to:
X
X       Requests to a list: listname-request@site
X       Messages to a list: listname@site
X       Human owner of list: listname-owner@site
X
X       There have also been some problems in running the program.
XThe correct way to run mailserv (as now explained if you do it wrong)
Xis like this:
X
X% mailserv listname command < mailfile
X
X       Where...
X
X       - "listname" is the name of the directory in the ~Mailserv
Xarea of a given list.  With the example lists, this would either be
Xfakedigest or fakelist.
X
X       - "command" tells mailserv what kind of a message is coming
Xin, and what you want to do with it.  Generally, "request" should only
Xbe used on request addresses, "message" should only be used on normal
Xaddresses, and "nightly" and "rare" should only be run by cron.
XHere's the list of commands:
X               request         mail from request address
X               message         mail from message address
X               nightly         do nightly maintenance
X               rare            do infrequent maintenance
X
X       - "mailfile" is the mail that mailserv is to process.
XObviously, this can be done like this as well:
X
X       % cat mailfile | mailserv listname command
X
X       In fact, that's how you *have* to do it in the aliases file.    
X
X       One last thing: MAKE SURE EVERY FILE (except the netrc files)
XAND DIRECTORY IN THE MailServ DIRECTORY IS READABLE AND WRITABLE BY
XEVERYONE!!!  This is *very* important.  When the aliases file invokes
Xthe 'mailserv' program, it won't run it as mailserv.  It will run it
Xas a user named 'halt', probably.  (Hmm... maybe we should setuid the
Xmailserv program... comments?)
X
X       BTW:  The fndusr program in the bin directory is very helpful
Xwhen you are running a lot of lists, and you have the same people on
Xmultiple lists.  It will list all the lists that a given user is on.
XMake the string it's searching for long enough that it doesn't throw
Xfits, though.  For instance:
X
XThis is good:
X% fndusr debry
X
XThis is not:
X% fndusr edu
X
X       That should do it.  Enjoy... I hope this program doesn't give
Xyou too many headaches.
X
X                                       - Dave DeBry
X                                         debry@peruvian.cs.utah.edu
END_OF_FILE
if test 5447 -ne `wc -c <'MailServ/Install'`; then
    echo shar: \"'MailServ/Install'\" unpacked with wrong size!
fi
# end of 'MailServ/Install'
fi
if test -f 'MailServ/Readme' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/Readme'\"
else
echo shar: Extracting \"'MailServ/Readme'\" \(3248 characters\)
sed "s/^X//" >'MailServ/Readme' <<'END_OF_FILE'
X
X       MailServ  --  by Dave DeBry <debry@peruvian.cs.utah.edu>
X       Version 1.1.0
X
X       A mailing list, mail request server, digest server, etc., all
Xin one tiny little program.  Wheee!
X
X----------------------------------------------------------------------
X
X       This is a mailing list program that I wrote, because I wasn't
Xto excited about all the other packages that I found floating on the
Xnet.  I'm currently using it to run two digests, five self-running
Xreflector mailing lists, and two invitation-only mailing lists
X(there's no request address for those, they're private).
X
X       MailServ:
X
X       o allows for as many users as you want per list,
X
X       o users can be mailed to "quietly" (ie: their name won't
X               be found anywhere in the mailing... good for 
X               nosy sysadmins at other sites),
X
X       o has a request server so users can get any files you make
X               available for them,
X
X       o handles subscribes and unsubscribes without bothering you,
X
X       o can archive off reflector mailing list posts,
X
X       o can announce to all list readers when someone subscribes
X               or unsubscribes,
X
X       o can be set to let people request a list of readers,
X
X       o does all the digest handling work for you,
X
X       o can upload (via ftp) each days digest to a given site for
X               archiving,
X
X       o can backup the userlist to a different disk/area/whatever,
X
X       o can post a FAQ to USENET periodically,
X
X       o announces when a message has been taken from USENET, so
X               people don't get that horrible deja vu feeling
X               while reading their mail,
X
X       o sends you a log of all the day's activities every night,
X
X       o lets you toggle all of these things for complete 
X               customization,
X
X       o and much, much more!  (I should be an announcer for those
X               Remco ads, I know it.)
X
X----------------------------------------------------------------------
X
X       MailServ isn't for the weak at heart.  It's not pretty, and
XI'm releasing it to the net because several people have asked for
Xcopies, and I'd like to know what changes are made to it.  If you
Xdon't know much about UNIX or mail, I wouldn't suggest using MailServ
Xuntil it gets a little bit nicer.
X
X----------------------------------------------------------------------
X
X       A lot of the digest code was vulture coded from David A.
XCurry's (davy@intrepid.ecn.purdue.edu) digest program.  I've included
Xhis code in here as well so you can put back in the stuff that I've
Xripped out if you wish.
X
X----------------------------------------------------------------------
X
X       Feel free to distribute and edit this code as you want.  My
Xonly requests are:
X
X       1] Keep my name and Mr. Curry's name intact -- credit where
Xcredit is due, and all that jazz.
X
X       2] Let me know of any modifications you make.  Chances are
XI'll want to incorporate them into my working copy.  Not only that,
Xbut it would be nice if we had one "real" version of the program out
Xthere that people could grab.
X
X----------------------------------------------------------------------
X
X       I don't guarantee anything about this code.  I've only truly
Xtested it well on a MIPS based box.  However, it builds well under
XGCC, and executes only the most standard of UNIX programs (cp, rm,
Xsendmail, etc.).  It should be fine, but don't blame me for any
Xproblems.  (That should be enough disclaimer to ward off the lawyers,
Xdon't you think?)
X
END_OF_FILE
if test 3248 -ne `wc -c <'MailServ/Readme'`; then
    echo shar: \"'MailServ/Readme'\" unpacked with wrong size!
fi
# end of 'MailServ/Readme'
fi
if test -f 'MailServ/aliases' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/aliases'\"
else
echo shar: Extracting \"'MailServ/aliases'\" \(367 characters\)
sed "s/^X//" >'MailServ/aliases' <<'END_OF_FILE'
Xnotreal: "| cat > /dev/null"
X
Xfakelist: "| /usr/people/MailServ/bin/mailserv fakelist message"
Xfakelist-request: "| /usr/people/MailServ/bin/mailserv fakelist request"
Xfakelist-owner: mailserv
X
Xfakedigest: "| /usr/people/MailServ/bin/mailserv fakedigest message"
Xfakedigest-request: "| /usr/people/MailServ/bin/mailserv fakedigest request"
Xfakedigest-owner: mailserv
END_OF_FILE
if test 367 -ne `wc -c <'MailServ/aliases'`; then
    echo shar: \"'MailServ/aliases'\" unpacked with wrong size!
fi
# end of 'MailServ/aliases'
fi
if test ! -d 'MailServ/backup' ; then
    echo shar: Creating directory \"'MailServ/backup'\"
    mkdir 'MailServ/backup'
fi
if test ! -d 'MailServ/bin' ; then
    echo shar: Creating directory \"'MailServ/bin'\"
    mkdir 'MailServ/bin'
fi
if test -f 'MailServ/crontab' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/crontab'\"
else
echo shar: Extracting \"'MailServ/crontab'\" \(88 characters\)
sed "s/^X//" >'MailServ/crontab' <<'END_OF_FILE'
X7 0 * * * /usr/people/MailServ/bin/nightly
X1 0 5,20 * * /usr/people/MailServ/bin/rarely
END_OF_FILE
if test 88 -ne `wc -c <'MailServ/crontab'`; then
    echo shar: \"'MailServ/crontab'\" unpacked with wrong size!
fi
# end of 'MailServ/crontab'
fi
if test ! -d 'MailServ/fakedigest' ; then
    echo shar: Creating directory \"'MailServ/fakedigest'\"
    mkdir 'MailServ/fakedigest'
fi
if test ! -d 'MailServ/fakelist' ; then
    echo shar: Creating directory \"'MailServ/fakelist'\"
    mkdir 'MailServ/fakelist'
fi
if test ! -d 'MailServ/src' ; then
    echo shar: Creating directory \"'MailServ/src'\"
    mkdir 'MailServ/src'
fi
if test ! -d 'MailServ/backup/fakedigest' ; then
    echo shar: Creating directory \"'MailServ/backup/fakedigest'\"
    mkdir 'MailServ/backup/fakedigest'
fi
if test ! -d 'MailServ/backup/fakelist' ; then
    echo shar: Creating directory \"'MailServ/backup/fakelist'\"
    mkdir 'MailServ/backup/fakelist'
fi
if test -f 'MailServ/bin/GenInfo' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/bin/GenInfo'\"
else
echo shar: Extracting \"'MailServ/bin/GenInfo'\" \(153 characters\)
sed "s/^X//" >'MailServ/bin/GenInfo' <<'END_OF_FILE'
X
Xset lhome = /usr/people/MailServ
Xset path = ( $lhome/bin /usr/ucb /bin /usr/lib /usr/new /usr/local/bin )
X
Xumask 000
X
Xset lists = "fakedigest fakelist"
END_OF_FILE
if test 153 -ne `wc -c <'MailServ/bin/GenInfo'`; then
    echo shar: \"'MailServ/bin/GenInfo'\" unpacked with wrong size!
fi
# end of 'MailServ/bin/GenInfo'
fi
if test -f 'MailServ/bin/fndusr' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/bin/fndusr'\"
else
echo shar: Extracting \"'MailServ/bin/fndusr'\" \(280 characters\)
sed "s/^X//" >'MailServ/bin/fndusr' <<'END_OF_FILE'
X#!/bin/csh
X
Xsource ~mailserv/bin/GenInfo
X
Xforeach h ($lists)
X       set file = `grep userfile $lhome/$h/Info | awk '{print $3}'`
X       set foo = `grep -i $argv[1] $lhome/$h/$file`
X       if ("$foo" != "") then
X               echo "*** $h : $file ***"
X               grep -n -i $argv[1] $lhome/$h/$file
X               echo ""
X       endif
Xend
END_OF_FILE
if test 280 -ne `wc -c <'MailServ/bin/fndusr'`; then
    echo shar: \"'MailServ/bin/fndusr'\" unpacked with wrong size!
fi
chmod +x 'MailServ/bin/fndusr'
# end of 'MailServ/bin/fndusr'
fi
if test -f 'MailServ/bin/nightly' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/bin/nightly'\"
else
echo shar: Extracting \"'MailServ/bin/nightly'\" \(191 characters\)
sed "s/^X//" >'MailServ/bin/nightly' <<'END_OF_FILE'
X#!/bin/csh -f
X
Xsource ~mailserv/bin/GenInfo
X
Xforeach h ($lists)
X       mailserv $h nightly >> /tmp/daily.log
Xend
X
Xcat /tmp/daily.log | mail -s "Mail Server Daily Log" mailserv
Xrm -f /tmp/daily.log
END_OF_FILE
if test 191 -ne `wc -c <'MailServ/bin/nightly'`; then
    echo shar: \"'MailServ/bin/nightly'\" unpacked with wrong size!
fi
chmod +x 'MailServ/bin/nightly'
# end of 'MailServ/bin/nightly'
fi
if test -f 'MailServ/bin/rarely' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/bin/rarely'\"
else
echo shar: Extracting \"'MailServ/bin/rarely'\" \(86 characters\)
sed "s/^X//" >'MailServ/bin/rarely' <<'END_OF_FILE'
X#!/bin/csh -f
X
Xsource ~mailserv/bin/GenInfo
X
Xforeach h ($lists)
X       mailserv $h rare
Xend
END_OF_FILE
if test 86 -ne `wc -c <'MailServ/bin/rarely'`; then
    echo shar: \"'MailServ/bin/rarely'\" unpacked with wrong size!
fi
chmod +x 'MailServ/bin/rarely'
# end of 'MailServ/bin/rarely'
fi
if test -f 'MailServ/fakedigest/Info' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/Info'\"
else
echo shar: Extracting \"'MailServ/fakedigest/Info'\" \(1952 characters\)
sed "s/^X//" >'MailServ/fakedigest/Info' <<'END_OF_FILE'
X#
X# Addresses for list that MUST be defined.
X#
Xreplyto = fakedigest@fakesite.org (Fake Mailing List)
Xerrorsto = fakedigest-owner@fakesite.org (Fake List Owner)
X
X#
X# Files that MUST be defined for the list.
X#
Xuserfile = users
Xlogfile = log
Xdelay = 8
X
X#
X# Files and addresses that need only be defined if this list has a
X# request line.
X#
Xfrom = fakedigest-request@fakesite.org (Fake List Server)
Xsubscribefile = sub
Xunsubscribefile = unsub
Xnounsubfile = nounsub
Xhelpfile = help
X
X#
X# If the request line allows you to request files, set 'files' to 'yes',
X# otherwise to 'no'.  If 'files' is 'yes', 'indexfile' must be defined.
X# 
Xfiles = yes
Xindexfile = index
X
X#
X# Set 'keep' to 'yes' if you want reflector posts archived, 'no'
X# otherwise.  'archivefile' must be defined if 'keep' is yes.
X#
Xkeep = no
X# archivefile = archive
X
X#
X# Set 'announce' to 'yes' if you want all users notified when someone
X# (un)subscribes.  Otherwise, set it to 'no'.
X#
Xannounce = no
X
X#
X# Set 'digest' to 'yes' if the list is a digest, not a reflector.  All
X# other 'digest*' variables must be defined if 'digest' is set to 'yes'.
X#
Xdigest = yes
Xdigestinput = input
Xdigestoutput = output
Xdigestcounterfile = counter
Xdigestname = Fake List Daily
Xdigesthead = head
Xdigesttail = tail
X
X#
X# If the list is a digest, and you'd like the digest to be FTP'ed to an
X# archive site every night, set 'ftp' to 'yes'.  All 'ftp*' variables
X# and 'netrcfile' must be defined if 'ftp' is 'yes'.
X#
Xftp = yes
Xftpdir = /pub/fakedigest/digest
Xftpsite = ftp.fakesite.org
Xnetrcfile = netrc
X
X#
X# Set 'backup' to yes if you want the userlist backed up every night to
X# a different area.  7 days worth of backups are kept. 'backupdir' must
X# be defined if 'backup' is set to 'yes'.
X#
Xbackup = yes
Xbackupdir = /usr/people/MailServ/backup/fakedigest
X
X#
X# If there is a FAQ that is to be posted to news, set 'faq' to 'yes'.
X# 'faqfile' must be defined if 'faq' is 'yes'.
X#
Xfaq = no
X# faqfile = files/FAQ
X
END_OF_FILE
if test 1952 -ne `wc -c <'MailServ/fakedigest/Info'`; then
    echo shar: \"'MailServ/fakedigest/Info'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/Info'
fi
if test -f 'MailServ/fakedigest/counter' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/counter'\"
else
echo shar: Extracting \"'MailServ/fakedigest/counter'\" \(4 characters\)
sed "s/^X//" >'MailServ/fakedigest/counter' <<'END_OF_FILE'
X1 1
END_OF_FILE
if test 4 -ne `wc -c <'MailServ/fakedigest/counter'`; then
    echo shar: \"'MailServ/fakedigest/counter'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/counter'
fi
if test ! -d 'MailServ/fakedigest/files' ; then
    echo shar: Creating directory \"'MailServ/fakedigest/files'\"
    mkdir 'MailServ/fakedigest/files'
fi
if test -f 'MailServ/fakedigest/head' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/head'\"
else
echo shar: Extracting \"'MailServ/fakedigest/head'\" \(110 characters\)
sed "s/^X//" >'MailServ/fakedigest/head' <<'END_OF_FILE'
X
X       This file will be inserted at the head of a digest, between
Xthe table of contents and the actual messages.
X
END_OF_FILE
if test 110 -ne `wc -c <'MailServ/fakedigest/head'`; then
    echo shar: \"'MailServ/fakedigest/head'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/head'
fi
if test -f 'MailServ/fakedigest/help' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/help'\"
else
echo shar: Extracting \"'MailServ/fakedigest/help'\" \(966 characters\)
sed "s/^X//" >'MailServ/fakedigest/help' <<'END_OF_FILE'
X
X       This is the help file that MailServe will send to a user when
Xit can't understand the user's command.  You should explain how to use
Xthe server, and what options are available.  For instance:
X
X------------------------------------------------------------------------
X
XUsage:
X
X       To use the server, just put your command in the subject line of
Xyour message.  Don't put anything else in your message, and only one
Xcommand per mail request.  Here's an example:
X
X> From: Joe User <joe-user@ceili.com>
X> To: fakelist-request@fakesite.org
X> Subject: subscribe
X>
X>
X
X       That's all you need in your mail to be subscribed to the list!
X
X------------------------------------------------------------------------
X
XCommands:      
X
X       subscribe               Add your name to the mailing list.
X
X       unsubscribe             Remove your name from the mailing list.
X
X       (other files as listed in the index file)
X
X------------------------------------------------------------------------
X
XAddresses:
X
X       blah blah blah...
X
END_OF_FILE
if test 966 -ne `wc -c <'MailServ/fakedigest/help'`; then
    echo shar: \"'MailServ/fakedigest/help'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/help'
fi
if test -f 'MailServ/fakedigest/index' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/index'\"
else
echo shar: Extracting \"'MailServ/fakedigest/index'\" \(60 characters\)
sed "s/^X//" >'MailServ/fakedigest/index' <<'END_OF_FILE'
X#
X# command              file to be sent
X#
Xundigest.c             files/UNDIGEST.C
END_OF_FILE
if test 60 -ne `wc -c <'MailServ/fakedigest/index'`; then
    echo shar: \"'MailServ/fakedigest/index'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/index'
fi
if test -f 'MailServ/fakedigest/input' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/input'\"
else
echo shar: Extracting \"'MailServ/fakedigest/input'\" \(0 characters\)
sed "s/^X//" >'MailServ/fakedigest/input' <<'END_OF_FILE'
END_OF_FILE
if test 0 -ne `wc -c <'MailServ/fakedigest/input'`; then
    echo shar: \"'MailServ/fakedigest/input'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/input'
fi
if test -f 'MailServ/fakedigest/netrc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/netrc'\"
else
echo shar: Extracting \"'MailServ/fakedigest/netrc'\" \(159 characters\)
sed "s/^X//" >'MailServ/fakedigest/netrc' <<'END_OF_FILE'
XSee the man page for the format for .netrc files.  This netrc file
Xwill be copied to ~MailServ/.netrc for the FTP, and deleted when the
Xtransfer has finished.
END_OF_FILE
if test 159 -ne `wc -c <'MailServ/fakedigest/netrc'`; then
    echo shar: \"'MailServ/fakedigest/netrc'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/netrc'
fi
if test -f 'MailServ/fakedigest/nounsub' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/nounsub'\"
else
echo shar: Extracting \"'MailServ/fakedigest/nounsub'\" \(317 characters\)
sed "s/^X//" >'MailServ/fakedigest/nounsub' <<'END_OF_FILE'
X
X       This file will be sent to the user if they tried to
Xunsubscribe, but MailServe couldn't find their name in the list.  This
Xcan happen for several reasons:
X
X       1] They weren't subscribed in the first place.
X
X       2] They are unsubscribing from a different machine than they
Xsubscribed from or their sitename has changed.
X
END_OF_FILE
if test 317 -ne `wc -c <'MailServ/fakedigest/nounsub'`; then
    echo shar: \"'MailServ/fakedigest/nounsub'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/nounsub'
fi
if test -f 'MailServ/fakedigest/output' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/output'\"
else
echo shar: Extracting \"'MailServ/fakedigest/output'\" \(0 characters\)
sed "s/^X//" >'MailServ/fakedigest/output' <<'END_OF_FILE'
END_OF_FILE
if test 0 -ne `wc -c <'MailServ/fakedigest/output'`; then
    echo shar: \"'MailServ/fakedigest/output'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/output'
fi
if test -f 'MailServ/fakedigest/sub' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/sub'\"
else
echo shar: Extracting \"'MailServ/fakedigest/sub'\" \(89 characters\)
sed "s/^X//" >'MailServ/fakedigest/sub' <<'END_OF_FILE'
X
X       This file will be sent to the user when they have sucessfully
Xsubscribed to the list.
X
END_OF_FILE
if test 89 -ne `wc -c <'MailServ/fakedigest/sub'`; then
    echo shar: \"'MailServ/fakedigest/sub'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/sub'
fi
if test -f 'MailServ/fakedigest/tail' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/tail'\"
else
echo shar: Extracting \"'MailServ/fakedigest/tail'\" \(54 characters\)
sed "s/^X//" >'MailServ/fakedigest/tail' <<'END_OF_FILE'
X
X       This file will be appended to the end of a digest.
X
END_OF_FILE
if test 54 -ne `wc -c <'MailServ/fakedigest/tail'`; then
    echo shar: \"'MailServ/fakedigest/tail'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/tail'
fi
if test -f 'MailServ/fakedigest/unsub' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/unsub'\"
else
echo shar: Extracting \"'MailServ/fakedigest/unsub'\" \(91 characters\)
sed "s/^X//" >'MailServ/fakedigest/unsub' <<'END_OF_FILE'
X
X       This file will be sent to a user when they have sucessfully
Xunsubscribed from the list.
X
END_OF_FILE
if test 91 -ne `wc -c <'MailServ/fakedigest/unsub'`; then
    echo shar: \"'MailServ/fakedigest/unsub'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/unsub'
fi
if test -f 'MailServ/fakedigest/users' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakedigest/users'\"
else
echo shar: Extracting \"'MailServ/fakedigest/users'\" \(87 characters\)
sed "s/^X//" >'MailServ/fakedigest/users' <<'END_OF_FILE'
Xfakeguy@fakesite.org
Xfakegirl@fakesite.org
X* hideme@fakesite.org
Xmorefake@fakesite.org
END_OF_FILE
if test 87 -ne `wc -c <'MailServ/fakedigest/users'`; then
    echo shar: \"'MailServ/fakedigest/users'\" unpacked with wrong size!
fi
# end of 'MailServ/fakedigest/users'
fi
if test -f 'MailServ/fakelist/Info' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakelist/Info'\"
else
echo shar: Extracting \"'MailServ/fakelist/Info'\" \(1958 characters\)
sed "s/^X//" >'MailServ/fakelist/Info' <<'END_OF_FILE'
X#
X# Addresses for list that MUST be defined.
X#
Xerrorsto = fakelist-owner@fakesite.org (Fake List Owner)
Xreplyto = fakelist@fakesite.org (Fake Mailing List)
X
X#
X# Files that MUST be defined for the list.
X#
Xuserfile = users
Xlogfile = log
Xdelay = 8
X
X#
X# Files and addresses that need only be defined if this list has a
X# request line.
X#
Xfrom = fakelist-request@fakesite.org (Fake List Server)
Xsubscribefile = sub
Xunsubscribefile = unsub
Xnounsubfile = nounsub
Xhelpfile = help
X
X#
X# If the request line allows you to request files, set 'files' to 'yes',
X# otherwise to 'no'.  If 'files' is 'yes', 'indexfile' must be defined.
X# 
Xfiles = no
X# indexfile = index
X
X#
X# Set 'keep' to 'yes' if you want reflector posts archived, 'no'
X# otherwise.  'archivefile' must be defined if 'keep' is yes.
X#
Xkeep = yes
Xarchivefile = archive
X
X#
X# Set 'announce' to 'yes' if you want all users notified when someone
X# (un)subscribes.  Otherwise, set it to 'no'.
X#
Xannounce = no
X
X#
X# Set 'digest' to 'yes' if the list is a digest, not a reflector.  All
X# other 'digest*' variables must be defined if 'digest' is set to 'yes'.
X#
Xdigest = no
X# digestinput = input
X# digestoutput = output
X# digestcounterfile = counter
X# digestname = Fake List Daily
X# digesthead = head
X# digesttail = tail
X
X#
X# If the list is a digest, and you'd like the digest to be FTP'ed to an
X# archive site every night, set 'ftp' to 'yes'.  All 'ftp*' variables
X# and 'netrcfile' must be defined if 'ftp' is 'yes'.
X#
Xftp = no
X# ftpdir = /pub/fakelist/digest
X# ftpsite = ftp.fakesite.org
X# netrcfile = netrc
X
X#
X# Set 'backup' to yes if you want the userlist backed up every night to
X# a different area.  7 days worth of backups are kept. 'backupdir' must
X# be defined if 'backup' is set to 'yes'.
X#
Xbackup = yes
Xbackupdir = /usr/people/MailServ/backups/fakelist
X
X#
X# If there is a FAQ that is to be posted to news, set 'faq' to 'yes'.
X# 'faqfile' must be defined if 'faq' is 'yes'.
X#
Xfaq = no
X# faqfile = files/FAQ
END_OF_FILE
if test 1958 -ne `wc -c <'MailServ/fakelist/Info'`; then
    echo shar: \"'MailServ/fakelist/Info'\" unpacked with wrong size!
fi
# end of 'MailServ/fakelist/Info'
fi
if test -f 'MailServ/fakelist/archive' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakelist/archive'\"
else
echo shar: Extracting \"'MailServ/fakelist/archive'\" \(0 characters\)
sed "s/^X//" >'MailServ/fakelist/archive' <<'END_OF_FILE'
END_OF_FILE
if test 0 -ne `wc -c <'MailServ/fakelist/archive'`; then
    echo shar: \"'MailServ/fakelist/archive'\" unpacked with wrong size!
fi
# end of 'MailServ/fakelist/archive'
fi
if test -f 'MailServ/fakelist/help' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakelist/help'\"
else
echo shar: Extracting \"'MailServ/fakelist/help'\" \(966 characters\)
sed "s/^X//" >'MailServ/fakelist/help' <<'END_OF_FILE'
X
X       This is the help file that MailServe will send to a user when
Xit can't understand the user's command.  You should explain how to use
Xthe server, and what options are available.  For instance:
X
X------------------------------------------------------------------------
X
XUsage:
X
X       To use the server, just put your command in the subject line of
Xyour message.  Don't put anything else in your message, and only one
Xcommand per mail request.  Here's an example:
X
X> From: Joe User <joe-user@ceili.com>
X> To: fakelist-request@fakesite.org
X> Subject: subscribe
X>
X>
X
X       That's all you need in your mail to be subscribed to the list!
X
X------------------------------------------------------------------------
X
XCommands:      
X
X       subscribe               Add your name to the mailing list.
X
X       unsubscribe             Remove your name from the mailing list.
X
X       (other files as listed in the index file)
X
X------------------------------------------------------------------------
X
XAddresses:
X
X       blah blah blah...
X
END_OF_FILE
if test 966 -ne `wc -c <'MailServ/fakelist/help'`; then
    echo shar: \"'MailServ/fakelist/help'\" unpacked with wrong size!
fi
# end of 'MailServ/fakelist/help'
fi
if test -f 'MailServ/fakelist/nounsub' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakelist/nounsub'\"
else
echo shar: Extracting \"'MailServ/fakelist/nounsub'\" \(317 characters\)
sed "s/^X//" >'MailServ/fakelist/nounsub' <<'END_OF_FILE'
X
X       This file will be sent to the user if they tried to
Xunsubscribe, but MailServe couldn't find their name in the list.  This
Xcan happen for several reasons:
X
X       1] They weren't subscribed in the first place.
X
X       2] They are unsubscribing from a different machine than they
Xsubscribed from or their sitename has changed.
X
END_OF_FILE
if test 317 -ne `wc -c <'MailServ/fakelist/nounsub'`; then
    echo shar: \"'MailServ/fakelist/nounsub'\" unpacked with wrong size!
fi
# end of 'MailServ/fakelist/nounsub'
fi
if test -f 'MailServ/fakelist/sub' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakelist/sub'\"
else
echo shar: Extracting \"'MailServ/fakelist/sub'\" \(89 characters\)
sed "s/^X//" >'MailServ/fakelist/sub' <<'END_OF_FILE'
X
X       This file will be sent to the user when they have sucessfully
Xsubscribed to the list.
X
END_OF_FILE
if test 89 -ne `wc -c <'MailServ/fakelist/sub'`; then
    echo shar: \"'MailServ/fakelist/sub'\" unpacked with wrong size!
fi
# end of 'MailServ/fakelist/sub'
fi
if test -f 'MailServ/fakelist/unsub' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakelist/unsub'\"
else
echo shar: Extracting \"'MailServ/fakelist/unsub'\" \(91 characters\)
sed "s/^X//" >'MailServ/fakelist/unsub' <<'END_OF_FILE'
X
X       This file will be sent to a user when they have sucessfully
Xunsubscribed from the list.
X
END_OF_FILE
if test 91 -ne `wc -c <'MailServ/fakelist/unsub'`; then
    echo shar: \"'MailServ/fakelist/unsub'\" unpacked with wrong size!
fi
# end of 'MailServ/fakelist/unsub'
fi
if test -f 'MailServ/fakelist/users' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/fakelist/users'\"
else
echo shar: Extracting \"'MailServ/fakelist/users'\" \(87 characters\)
sed "s/^X//" >'MailServ/fakelist/users' <<'END_OF_FILE'
Xfakeguy@fakesite.org
Xfakegirl@fakesite.org
X* hideme@fakesite.org
Xmorefake@fakesite.org
END_OF_FILE
if test 87 -ne `wc -c <'MailServ/fakelist/users'`; then
    echo shar: \"'MailServ/fakelist/users'\" unpacked with wrong size!
fi
# end of 'MailServ/fakelist/users'
fi
if test -f 'MailServ/src/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/src/Makefile'\"
else
echo shar: Extracting \"'MailServ/src/Makefile'\" \(424 characters\)
sed "s/^X//" >'MailServ/src/Makefile' <<'END_OF_FILE'
X
XCC     = gcc
XCFLAGS = -g
X
XHDRS    = mailserv.h
XSRC     = digest.c info.c inmsg.c mailserv.c outmsg.c request.c utils.c
XOBJ     = $(SRC:.c=.o)
XFIN     = mailserv
X
XMHOME  = ..
XINSTDIR        = $(MHOME)/bin
X
X# ----------------------------------------------------------------------
X
Xall:   $(FIN)
X
X$(FIN):        $(OBJ)
X       $(CC) $(OBJ) $(CFLAGS) -o $(FIN)
X       cp $(FIN) ../bin
X
Xclean: 
X       @ rm -f $(OBJ) *~ core
X
Xpristine:
X       @ rm -f $(OBJ) *~ core $(FIN)
END_OF_FILE
if test 424 -ne `wc -c <'MailServ/src/Makefile'`; then
    echo shar: \"'MailServ/src/Makefile'\" unpacked with wrong size!
fi
# end of 'MailServ/src/Makefile'
fi
if test -f 'MailServ/src/digest.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/src/digest.c'\"
else
echo shar: Extracting \"'MailServ/src/digest.c'\" \(15383 characters\)
sed "s/^X//" >'MailServ/src/digest.c' <<'END_OF_FILE'
X
X#include "mailserv.h"
X
X#define HEAD1          27              /* Field width of first third   */
X#define HEAD2          20              /* Field width of second third  */
X#define HEAD3          21              /* Field width of last third    */
X#define DATELEN                16              /* Amount of date to put in hdr 
*/
X#define LINELEN                70              /* Length of an average line    
*/
X#define MAXMSGS                64              /* Maximum number of 
msgs/digest*/
X#define LINESIZE       256             /* Maximum line size            */
X
Xstruct message 
X{
X    char *Date;
X    char *From;
X    char *Subject;
X    char *MessageID;
X    char *ReprintFrom;
X    char *sortstring;
X    long messageaddr;
X    long messagelength;
X    int  use_re;
X} messages[MAXMSGS];
X
XFILE *input;
XFILE *output;
X
Xint digestsize = 0;
Xint nmessages = 0;
X
Xchar *safter(), *nospace(), *getline();
Xchar digestsubject[100];
X
X/*****************************************************************************
X * vol_issue_out
X */
Xvoid
X    vol_issue_out ()
X{
X    FILE *voliss;
X
X    voliss = fopen (listinfo.digestcounterfile, "w");
X    fprintf (voliss, "%d %d\n", listinfo.volume, (listinfo.issue)+1);
X    fclose (voliss);
X}
X
X/*****************************************************************************
X * vol_issue_info
X */
Xvoid
X    vol_issue_info()
X{
X    char templine[100];
X    FILE *voliss;
X    
X    voliss = fopen (listinfo.digestcounterfile, "r");
X    fscanf (voliss, "%d %d\n", &listinfo.volume, &listinfo.issue);
X    fclose (voliss);
X
X    if ((listinfo.datestr[8] == '1') &&
X       (listinfo.datestr[9] == ' '))
X    {
X       listinfo.volume += 1;
X       listinfo.issue = 1;
X    }
X
X    sprintf (templine, "Volume %d: Issue %3d",
X            listinfo.volume, listinfo.issue);
X    listinfo.volline = strdup (templine);
X}
X
X/*****************************************************************************
X * distribute_digest
X */
Xvoid
X    distribute_digest()
X{
X    char cmdstr[120];
X    int i;
X
X    for (i=0; i<readercount; i++)
X    {
X       sprintf (cmdstr, "%s %s < %s",
X                SendMail, readers[i], listinfo.digestoutput);
X       system (cmdstr);
X       sleep (listinfo.delay);
X    }
X}
X
X/*****************************************************************************
X * make_digest
X */
Xvoid
X    make_digest()
X{
X    char cmdline[200];
X
X    sprintf (cmdline, "%s %s %s.prev", Copy,
X            listinfo.digestinput, listinfo.digestinput);
X    system (cmdline);
X
X    vol_issue_info();
X    vol_issue_out();
X    
X    fprintf(thelogfile, 
X           "Assembling %s Digest %s (%.*s)\n", 
X           listinfo.digestname, listinfo.volline, DATELEN, 
X           listinfo.datestr);
X    fprintf(thelogfile, "Scanning and sorting messages for topic lines.\n");
X
X    scan_messages();
X
X    if (nmessages == 0)
X    {
X       listinfo.issue -= 1;
X       vol_issue_out();
X       fprintf (thelogfile, "Zero length digest, not mailing.\n");
X       listinfo.ftp = False;
X       listinfo.keep = False;
X       return;
X    }
X
X    sort_messages();
X    
X    fprintf (thelogfile, "Writing %s Digest to \"%s\"\n",
X            listinfo.digestname, listinfo.digestoutput);
X    
X    do_digest_header();
X    read_messages();
X    
X    fprintf (thelogfile, "The digest is %d characters long in %d messages.\n",
X            digestsize, nmessages);
X
X    distribute_digest();
X}
X
X/*****************************************************************************
X * getline
X */
Xchar *getline(fp)
XFILE *fp;
X{
X    register int c;
X    register char *str, *str_begin;
X    
X    if ((str = malloc(LINESIZE)) == NULL) 
X    {
X       fprintf (thelogfile, "digest: out of memory.\n");
X       Exit(1);
X    }
X    
X    str_begin = str;
X    
X    while (((str - str_begin) < (LINESIZE - 1)) &&
X          ((c = getc(fp)) != '\n') && (c != EOF))
X       *str++ = c;
X
X    *str++ = NULL;
X    
X    if (c == EOF)
X       return(NULL);
X    
X    return(str_begin);
X}
X
X/*****************************************************************************
X * scan_messages
X */
Xscan_messages()
X{
X    register long n;
X    register char *s;
X    
X    if ((input = fopen(listinfo.digestinput, "r")) == NULL) 
X    {
X       fprintf (thelogfile, "digest: cannot open \"%s\" for reading.\n",
X                listinfo.digestinput);
X       Exit(1);
X    }
X    
X    /*
X     * We break out of this from inside.
X     */
X    for (;;) 
X    {
X       if (nmessages >= MAXMSGS) 
X       {
X           fprintf (thelogfile, "digest: too many messages.\n");
X           Exit(1);
X       }
X       
X       /*
X        * Find the start of the next message.
X        */
X       do {
X           /*
X            * If we hit EOF, mark the length of the
X            * previous message and go back.
X            */
X           if ((s = getline(input)) == NULL) {
X               n = ftell(input);
X               n = n - messages[nmessages - 1].messageaddr;
X               messages[nmessages - 1].messagelength = n;
X               return;
X           }
X       } while (strncmp(s, "From ", 5) != 0);
X       
X       /*
X        * If we have found another message, mark the
X        * length of the previous message.
X        */
X       if (nmessages) {
X           n = ftell(input);
X           n = n - (strlen(s) + 1);
X           n = n - messages[nmessages - 1].messageaddr;
X           messages[nmessages - 1].messagelength = n;
X       }
X       
X       /*
X        * Read in the headers.
X        */
X       for (;;) {
X           /*
X            * We shouldn't hit EOF here, we should
X            * at least finish the headers first.
X            */
X           if ((s = getline(input)) == NULL) {
X               fprintf (thelogfile, "digest: \"%s\": unexpected EOF.\n",
X                        listinfo.digestinput);
X               Exit(1);
X           }
X           
X           /*
X            * Blank line terminates headers.
X            */
X           if (*s == NULL)
X               break;
X           
X           /*
X            * Save certain headers.  We strip the
X            * header name and leading whitespace.
X            */
X           if (strncmp(s, "Message-ID:", 11) == 0) {
X               messages[nmessages].MessageID = 
X                   nospace(safter(s, "Message-ID:"));
X           }
X           else if (strncmp(s, "Message-Id:", 11) == 0) {
X               messages[nmessages].MessageID = 
X                   nospace(safter(s, "Message-Id:"));
X           }
X           else if (strncmp(s, "From:", 5) == 0) {
X               messages[nmessages].From = 
X                   nospace(safter(s, "From:"));
X           }
X           else if (strncmp(s, "Newsgroups:", 11) == 0) {
X               messages[nmessages].ReprintFrom = 
X                   nospace(safter(s, "Newsgroups:"));
X           }
X           else if (strncmp(s, "Date:", 5) == 0) {
X               messages[nmessages].Date = 
X                   nospace(safter(s, "Date:"));
X           }
X           else if (strncmp(s, "Subject:", 8) == 0) {
X               s = nospace(safter(s, "Subject:"));
X               
X               /*
X                * We don't need the "Re:" stuff.
X                */
X               messages[nmessages].use_re = 0;
X               while ((strncmp(s, "re:", 3) == 0) || 
X                      (strncmp(s, "Re:", 3) == 0) ||
X                      (strncmp(s, "RE:", 3) == 0) || 
X                      (strncmp(s, "rE:", 3) == 0)) 
X               {
X                   messages[nmessages].use_re = 1;
X                   s += 3;
X                   s = nospace(s);
X               }
X               
X               messages[nmessages].Subject = s;
X           }
X           else {
X               /*
X                * If we aren't saving this line,
X                * give the memory back.
X                */
X               free(s);
X           }
X       }
X       
X       /*
X        * The message starts after the header.
X        */
X       messages[nmessages].messageaddr = ftell(input);
X       nmessages++;
X    }
X}
X
X/*****************************************************************************
X * sort_messages
X */
Xsort_messages()
X{
X    register int i;
X    extern int comp();
X    register char *s, *t;
X    
X    for (i=0; i < nmessages; i++) {
X       /*
X        * Skip messages with no subject.
X        */
X       if (messages[i].Subject == NULL)
X           continue;
X       
X       s = messages[i].Subject;
X       
X       if ((t = malloc(strlen(s)+1)) == NULL) {
X           fprintf (thelogfile, "digest: out of memory.\n");
X           Exit(1);
X       }
X       
X       messages[i].sortstring = t;
X       
X       /*
X        * Zap leading whitespace.
X        */
X       s = nospace(s);
X       
X       /*
X        * Copy the subject string into sortstring
X        * converting upper case to lower case and
X        * ignoring whitespace.
X        */
X       while (*s) {
X           if ((*s == ' ') || (*s == '\t')) {
X               s++;
X               continue;
X           }
X           
X           if (isupper(*s))
X               *t++ = tolower(*s);
X           else
X               *t++ = *s;
X           
X           s++;
X       }
X       
X       *t = NULL;
X    }
X    
X    /*
X     * Sort 'em.
X     */
X    qsort(messages, nmessages, sizeof(struct message), comp);
X}
X
X/*****************************************************************************
X * comp
X */
Xcomp(m1, m2)
Xregister struct message *m1, *m2;
X{
X    int admin1, admin2;
X    
X    if (m1->sortstring == NULL) {
X       if (m2->sortstring == NULL)
X           return(0);
X       return(1);              /* no subject messages to end */
X    }
X    
X    if (m2->sortstring == NULL)
X       return(-1);             /* no subject messages to end */
X    
X    admin1 = strncmp(m1->sortstring, "administrivia", 13);
X    admin2 = strncmp(m2->sortstring, "administrivia", 13);
X    
X    if (admin1 == 0) {
X       if (admin2 == 0)
X           return(0);
X       return(-1);             /* administrivia to beginning */
X    }
X    
X    if (admin2 == 0)
X       return(1);              /* administrivia to beginning */
X    
X    return(strcmp(m1->sortstring, m2->sortstring));
X}
X
X/*****************************************************************************
X * do_digest_header
X */
Xdo_digest_header()
X{
X    FILE *fp;
X    char *laststr;
X    char buf[BUFSIZ];
X    char tmp[LINESIZE];
X    extern int comp2();
X    register int i, j, length;
X    char *c;
X    
X    if ((output = fopen(listinfo.digestoutput, "w")) == NULL) {
X       fprintf (thelogfile, "digest: cannot create \"%s\"\n",
X                listinfo.digestoutput);
X       Exit(1);
X    }
X    
X    digestsize = 0;
X    
X    /*
X     * Mailer headers.
X     */
X    sprintf (buf, "Precedence: Bulk\n", listinfo.datestr);
X    digestsize += strlen (buf);
X    fputs(buf, output);
X
X    sprintf(buf, "Date: %s\n", listinfo.datestr);
X    digestsize += strlen(buf);
X    fputs(buf, output);
X    
X    sprintf(buf, "Errors-To: %s\n", listinfo.errorsto);
X    digestsize += strlen(buf);
X    fputs(buf, output);
X    
X    sprintf(buf, "From: %s\n", listinfo.from);
X    digestsize += strlen(buf);
X    fputs(buf, output);
X    
X    sprintf(buf, "Reply-To: %s\n", listinfo.replyto);
X    digestsize += strlen(buf);
X    fputs(buf, output);
X    
X    strcpy (tmp, listinfo.volline);
X    for (c = tmp; *c != 0 && *c != ':'; c++) ;
X
X    do 
X    { *c-- = 0; } 
X    while (c >= tmp && *c == ' ');
X    
X    do 
X    { c--; } 
X    while (c >= tmp && *c != ' ');
X
X    c++;
X    digestsize += 9; fputs ("Subject: ", output);
X    sprintf(digestsubject, "%s Digest V%s #%d",
X           listinfo.digestname, c, listinfo.issue);
X    digestsize += strlen(digestsubject);
X    fputs(digestsubject, output);
X    digestsize++, putc ('\n', output);
X    
X    /*
X     * The digest header.
X     */
X    sprintf(tmp, "%s Digest", listinfo.digestname);
X    sprintf(buf, "\n\n%-*.*s %-*.*s %-*.*s\n\n",
X           HEAD1, HEAD1, tmp,
X           HEAD2, DATELEN, listinfo.datestr,
X           HEAD3, HEAD3, listinfo.volline);
X    digestsize += strlen(buf);
X    fputs(buf, output);
X    
X    sprintf(buf, "Today's Topics:\n");
X    digestsize += strlen(buf);
X    fputs(buf, output);
X    
X    /*
X     * Do today's topics lines.
X     */
X    laststr = "";
X    for (i=0; i < nmessages; i++) {
X       /*
X        * No topic.
X        */
X       if (messages[i].Subject == NULL)
X           continue;
X       
X       laststr = messages[i].sortstring;
X       
X       /*
X        * Count the number of messages with this topic.
X        */
X       j = 1;
X       while (((i + j) < nmessages)
X              && (messages[i+j].sortstring != NULL)
X              && (strcmp(laststr, messages[i+j].sortstring) == 0))
X           j++;
X       
X       /*
X        * Print the topic centered on the line.
X        */
X       if (j > 1) {
X           sprintf(tmp, "%s (%d msgs)", messages[i].Subject, j);
X           length = (LINELEN / 2) + (strlen(tmp) / 2);
X           sprintf(buf, "%*s\n", length, tmp);
X           
X           /*
X            * Sort messages with same topic into their
X            * original arrival order.
X            */
X           qsort(&messages[i], j, sizeof(struct message), comp2);
X           i += (j - 1);
X       }
X       else {
X           length = (LINELEN / 2) + (strlen(messages[i].Subject) / 2);
X           sprintf(buf, "%*s\n", length, messages[i].Subject);
X       }
X       
X       digestsize += strlen(buf);
X       fputs(buf, output);
X    }
X    
X    /*
X     * Read the listinfo.digesthead file, if there is one.
X     */
X    if ((fp = fopen(listinfo.digesthead, "r")) != NULL) {
X       putc('\n', output);
X       digestsize++;
X       
X       while (fgets(buf, BUFSIZ, fp) != NULL) {
X           digestsize += strlen(buf);
X           fputs(buf, output);
X       }
X       
X       fclose(fp);
X       putc('\n', output);
X    }
X    
X    /*
X     * Print a line of dashes.
X     */
X    for (i=0; i < LINELEN; i++) {
X       putc('-', output);
X       digestsize++;
X    }
X    
X    fputs("\n\n", output);
X    digestsize += 2;
X}
X
X/*****************************************************************************
X * comp2
X */
Xcomp2(m1, m2)
Xregister struct message *m1, *m2;
X{
X    return(m1->messageaddr - m2->messageaddr);
X}
X
X/*****************************************************************************
X * read_messages
X */
Xread_messages()
X{
X    FILE *fp;
X    char buf[BUFSIZ];
X    register char *s, *t;
X    register int i, length;
X    int linestart;
X    
X    for (i=0; i < nmessages; i++) {
X       /*
X        * Just in case.
X        */
X       clearerr(input);
X       
X       /*
X        * Put the message's headers back in.
X        */
X       sprintf(buf, "Date: %s\n", messages[i].Date);
X       digestsize += strlen(buf);
X       fputs(buf, output);
X       
X       sprintf(buf, "From: %s\n", messages[i].From);
X       digestsize += strlen(buf);
X       fputs(buf, output);
X       
X       if (messages[i].Subject != NULL) {
X           sprintf(buf, "Subject: %s%s\n",
X                   (messages[i].use_re ? "Re: " : ""),
X                   messages[i].Subject);
X           digestsize += strlen(buf);
X           fputs(buf, output);
X       }
X       
X       if (messages[i].MessageID != NULL) {
X           sprintf(buf, "Message-ID: %s\n", messages[i].MessageID);
X           digestsize += strlen(buf);
X           fputs(buf, output);
X       }
X       
X       if (messages[i].ReprintFrom != NULL) {
X           sprintf (buf, "\nReprintFrom: %s\n", messages[i].ReprintFrom);
X           digestsize += strlen(buf);
X           fputs (buf, output);
X       }
X       
X       putc ('\n', output); digestsize++;
X       
X       /*
X        * Read the message into memory.  This is
X        * so we can zap extra blank lines.
X        */
X       fseek(input, messages[i].messageaddr, 0);
X       length = messages[i].messagelength;
X       
X       if ((s = malloc(length+1)) == NULL) {
X           fprintf (thelogfile, "digest: out of memory.\n");
X           Exit(1);
X       }
X       
X       fread(s, 1, length, input);
X       
X       /*
X        * Zap trailing newlines.
X        */
X       t = s + length;
X       while (length > 0 && *--t == '\n')
X           length--;
X       *++t = NULL;
X       
X       /*
X        * Zap leading newlines.
X        */
X       t = s;
X       while (*t++ == '\n')
X           length--;
X       t--;
X       
X       /*
X        * Write the message.
X        *
X        * In any line which begins with 30 or more hyphens,
X        * change the first hyphen to a space, to avoid a clash
X        * with the message separator string.
X        */
X       digestsize += length;
X       /* fwrite(t, 1, length, output); */
X       linestart = 1;
X       while (length-- > 0) {
X           if (linestart &&
X               strncmp(t,"------------------------------",30) == 0)
X               linestart = 0, t++, putc (' ', output);
X           else {
X               linestart = (*t == '\n');
X               putc (*t++, output);
X           }
X       }
X       
X       sprintf(buf, "\n\n------------------------------\n\n");
X       digestsize += strlen(buf);
X       fputs(buf, output);
X       free(s);
X    }
X    
X    /*
X     * All done.
X     */
X    sprintf(buf, "End of %s\n******************************",
X           digestsubject);
X    digestsize += strlen(buf);
X    fputs(buf, output);
X    for (i = strlen (digestsubject) + 7; i > 30; i--)
X       digestsize++, putc ('*', output);
X    digestsize++, putc ('\n', output);
X
X    if ((fp = fopen(listinfo.digesttail, "r")) != NULL) {
X       putc('\n', output);
X       digestsize++;
X       
X       while (fgets(buf, BUFSIZ, fp) != NULL) {
X           digestsize += strlen(buf);
X           fputs(buf, output);
X       }
X       
X       fclose(fp);
X       putc('\n', output);
X    }
X
X    fclose(output);
X    fclose(input);
X
X    input = fopen (listinfo.digestinput, "w");
X    fclose (input);
X}
X
X/*
X * safter - return a pointer to the position in str which follows pat.
X */
Xchar *safter(str, pat)
Xregister char *str, *pat;
X{
X    register int len;
X    
X    len = strlen(pat);
X    
X    while (*str) {
X       if (strncmp(str, pat, len) == 0) {
X           str += len;
X           return(str);
X       }
X       
X       str++;
X    }
X    
X    return(NULL);
X}
X
X/*
X * nospace - advance s over leading whitespace, return new value.
X */
Xchar *nospace(s)
Xregister char *s;
X{
X    while ((*s != NULL) && ((*s == ' ') || (*s == '\t')))
X       s++;
X    
X    return(s);
X}
X
END_OF_FILE
if test 15383 -ne `wc -c <'MailServ/src/digest.c'`; then
    echo shar: \"'MailServ/src/digest.c'\" unpacked with wrong size!
fi
# end of 'MailServ/src/digest.c'
fi
if test -f 'MailServ/src/info.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/src/info.c'\"
else
echo shar: Extracting \"'MailServ/src/info.c'\" \(8664 characters\)
sed "s/^X//" >'MailServ/src/info.c' <<'END_OF_FILE'
X
X#include "mailserv.h"
X
X/*****************************************************************************
X * expand_path
X */
Xchar
X    *expand_path (fname)
Xchar *fname;
X{
X    char *carp;
X
X    if ((fname[0] != '/') && (fname[0] != '.'))
X    {
X       carp = (char *) malloc (strlen (ListHome) + strlen (listinfo.name) +
X                               strlen (fname) + 5);
X       sprintf (carp, "%s/%s/%s", ListHome, listinfo.name, fname);
X       return (carp);
X    }
X
X    return (strdup (fname));
X}
X
X/*****************************************************************************
X * boolean_info_line
X */
Xint
X    boolean_info_line (chptr)
Xchar *chptr;
X{
X    char cmdword[20], flag[5], *carp;
X
X    sscanf (chptr, "%s = %s", &cmdword, &flag);
X    if (carp = strstr (flag, "y"))
X       return (True);
X    else
X       return (False);
X}
X
X/*****************************************************************************
X * val_info_line
X */
Xint
X    val_info_line (chptr)
Xchar *chptr;
X{
X    char cmdword[20], value[5];
X
X    sscanf (chptr, "%s = %s", &cmdword, &value);
X    return (atoi (value));
X}
X
X/*****************************************************************************
X * str_info_line
X */
Xchar
X    *str_info_line (chptr)
Xchar *chptr;
X{
X    return (cleanup_string (strstr (chptr, "=") + 1));
X}
X
X/*****************************************************************************
X * file_info_line
X */
Xchar
X    *file_info_line (chptr)
Xchar *chptr;
X{
X    char *carp1, *carp2;
X
X    carp1 = str_info_line (chptr);
X    carp2 = expand_path (carp1);
X    free (carp1);
X    return (carp2);
X}
X
X/*****************************************************************************
X * get_list_info
X */
Xvoid
X    get_list_info (argc, argv)
Xint argc;
Xchar **argv;
X{
X    char filepath[100], templine[100], *carp;
X    int lnum = 0;
X    FILE *infofile;
X
X    if (argc != 3)
X    {
X       usage ();
X    }
X
X    listinfo.name = strdup (argv[1]);
X    listinfo.sub = strdup (argv[2]);
X
X    sprintf (filepath, "%s/%s/%s", ListHome, listinfo.name, InfoFile);
X
X    infofile = fopen (filepath, "r");
X
X    while (fgets (templine, 100, infofile) != NULL)
X    {
X       lnum ++;
X       if ((templine[0] != '#') && (strlen (templine)) > 3)
X       {
X           /*
X            * Booleans
X            */
X           if ((carp = strstr (templine, "keep ")) && (carp == templine))
X               listinfo.keep = boolean_info_line (carp);
X
X           else if ((carp = strstr (templine, "announce ")) && (carp == 
templine))
X               listinfo.announce = boolean_info_line (carp);
X
X           else if ((carp = strstr (templine, "files ")) && (carp == templine))
X               listinfo.files = boolean_info_line (carp);
X
X           else if ((carp = strstr (templine, "digest ")) && (carp == 
templine))
X               listinfo.digest = boolean_info_line (carp);
X
X           else if ((carp = strstr (templine, "backup ")) && (carp == 
templine))
X               listinfo.backup = boolean_info_line (carp);
X
X           else if ((carp = strstr (templine, "faq ")) && (carp == templine))
X               listinfo.faq = boolean_info_line (carp);
X
X           else if ((carp = strstr (templine, "ftp ")) && (carp == templine))
X               listinfo.ftp = boolean_info_line (carp);
X
X           /* 
X            * Values
X            */
X           else if ((carp = strstr (templine, "delay ")) && (carp == templine))
X               listinfo.delay = val_info_line (carp);
X
X           /* 
X            * Strings - general
X            */
X           else if ((carp = strstr (templine, "replyto ")) && (carp == 
templine))
X               listinfo.replyto = (char *) str_info_line (carp);
X
X           else if ((carp = strstr (templine, "errorsto ")) && (carp == 
templine))
X               listinfo.errorsto = (char *) str_info_line (carp);
X
X           else if ((carp = strstr (templine, "from ")) && (carp == templine))
X               listinfo.from = (char *) str_info_line (carp);
X
X           else if ((carp = strstr (templine, "ftpsite ")) && (carp == 
templine))
X               listinfo.ftpsite = (char *) str_info_line (carp);
X
X           else if ((carp = strstr (templine, "ftpdir ")) && (carp == 
templine))
X               listinfo.ftpdir = (char *) str_info_line (carp);
X
X           else if ((carp = strstr (templine, "digestname ")) && (carp == 
templine))
X               listinfo.digestname = (char *) str_info_line (carp);
X
X           /* 
X            * Strings - filenames/paths
X            */
X           else if ((carp = strstr (templine, "archivefile ")) && (carp == 
templine))
X               listinfo.archivefile = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "userfile ")) && (carp == 
templine))
X               listinfo.userfile = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "logfile ")) && (carp == 
templine))
X               listinfo.logfile = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "indexfile ")) && (carp == 
templine))
X               listinfo.indexfile = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "backupdir")) && (carp == 
templine))
X               listinfo.backupdir = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "subscribefile ")) && (carp == 
templine))
X               listinfo.subscribefile = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "unsubscribefile ")) && (carp == 
templine))
X               listinfo.unsubscribefile = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "nounsubfile ")) && (carp == 
templine))
X               listinfo.nounsubfile = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "helpfile ")) && (carp == 
templine))
X               listinfo.helpfile = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "faqfile ")) && (carp == 
templine))
X               listinfo.faqfile = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "netrcfile ")) && (carp == 
templine))
X               listinfo.netrcfile = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "digestinput ")) && (carp == 
templine))
X               listinfo.digestinput = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "digestoutput ")) && (carp == 
templine))
X               listinfo.digestoutput = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "digestcounterfile ")) && (carp 
== templine))
X               listinfo.digestcounterfile = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "digesthead ")) && (carp == 
templine))
X               listinfo.digesthead = (char *) file_info_line (carp);
X
X           else if ((carp = strstr (templine, "digesttail ")) && (carp == 
templine))
X               listinfo.digesttail = (char *) file_info_line (carp);
X
X           else
X           {
X               fprintf (stderr, "Error on line %d of %s\n",
X                        lnum, filepath);
X               fprintf (thelogfile, "Error on line %d of %s @ %s\n",
X                        lnum, filepath, listinfo.datestr);
X               Exit (1);
X           }
X       }
X    }
X
X    fclose (infofile);
X}
X
Xint okinfo;
X
X/*****************************************************************************
X * badinfo
X */
Xvoid
X    badinfo (carp)
Xchar *carp;
X{
X    fprintf (stderr, "Error in Info file: %s not defined\n", carp);
X    fprintf (thelogfile, "Error in Info file: %s not defined\n", carp);
X    okinfo = False;
X}
X
X/*****************************************************************************
X * verify_info
X */
Xvoid
X    verify_info ()
X{
X    okinfo = True;
X
X    if (listinfo.logfile == NULL)
X    {
X       fprintf (stderr, "Error in Info file: logfile not defined\n");
X       fflush (stderr);
X       exit (1);
X    }
X    thelogfile = fopen (listinfo.logfile, "a");
X
X    if (listinfo.replyto == NULL)
X       badinfo ("replyto");
X    if (listinfo.errorsto == NULL)
X       badinfo ("errorsto");
X    if (listinfo.userfile == NULL)
X       badinfo ("userfile");
X    if (listinfo.delay == NULL)
X       badinfo ("delay");
X
X    if (listinfo.from != NULL)
X    {
X       if (listinfo.subscribefile == NULL)
X           badinfo ("subscribefile");
X       if (listinfo.unsubscribefile == NULL)
X           badinfo ("unsubscribefile");
X       if (listinfo.nounsubfile == NULL)
X           badinfo ("nounsubfile");
X       if (listinfo.helpfile == NULL)
X           badinfo ("helpfile");
X    }
X
X    if (listinfo.files)
X    {
X       if (listinfo.indexfile == NULL)
X           badinfo ("indexfile");
X    }
X
X    if (listinfo.keep)
X    {
X       if (listinfo.archivefile == NULL)
X           badinfo ("archivefile");
X    }
X
X    if (listinfo.digest)
X    {
X       if (listinfo.digestinput == NULL)
X           badinfo ("digestinput");
X       if (listinfo.digestoutput == NULL)
X           badinfo ("digestoutput");
X       if (listinfo.digestcounterfile == NULL)
X           badinfo ("digestcounterfile");
X       if (listinfo.digestname == NULL)
X           badinfo ("digestname");
X       if (listinfo.digesthead == NULL)
X           badinfo ("digesthead");
X       if (listinfo.digesttail == NULL)
X           badinfo ("digesttail");
X
X       if (listinfo.ftp)
X       {
X           if (listinfo.ftpdir == NULL)
X               badinfo ("ftpdir");
X           if (listinfo.ftpsite == NULL)
X               badinfo ("ftpsite");
X           if (listinfo.netrcfile == NULL)
X               badinfo ("netrcfile");
X       }
X    }
X
X    if (listinfo.backup)
X    {
X       if (listinfo.backupdir == NULL)
X           badinfo ("backupdir");
X    }
X
X    if (listinfo.faq)
X    {
X       if (listinfo.faqfile == NULL)
X           badinfo ("backupdir");
X    }
X
X    if (!okinfo)
X       Exit (1);
X}
X
END_OF_FILE
if test 8664 -ne `wc -c <'MailServ/src/info.c'`; then
    echo shar: \"'MailServ/src/info.c'\" unpacked with wrong size!
fi
# end of 'MailServ/src/info.c'
fi
if test -f 'MailServ/src/inmsg.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/src/inmsg.c'\"
else
echo shar: Extracting \"'MailServ/src/inmsg.c'\" \(3900 characters\)
sed "s/^X//" >'MailServ/src/inmsg.c' <<'END_OF_FILE'
X
X#include "mailserv.h"
X
X/*****************************************************************************
X * get_raw_msg
X */
Xvoid
X    get_raw_msg()
X{
X    char templine[1000];
X    
X    msglines = 0;
X    while (fgets (templine, 1000, stdin))
X    {
X       if (msglines >= MAXLINES)
X           fprintf (thelogfile, "WARNING: message truncated @ %s\n",
X                    listinfo.datestr);
X       else
X           rawmsg[msglines] = strdup(templine);
X
X       msglines ++;
X    }
X}
X
X/*****************************************************************************
X * handle_alt_hdr
X */
Xint
X    handle_alt_hdr (line)
Xchar *line;
X{
X    if (outmsg.ahlcnt >= MAXALTHDR)
X    {
X       fprintf (thelogfile, 
X                "Warning: Alternate header buffer overflowed @ %s\n",
X                listinfo.datestr);
X       return (False);
X    }
X
X    outmsg.althdr[outmsg.ahlcnt++] = rm_tail_cr (line);
X    return (True);
X}
X
X/*****************************************************************************
X * process_raw_msg
X */
Xvoid
X    process_raw_msg()
X{
X    int hdrflag = True;
X    int pls = True;
X    char *carp;
X    int i;
X
X    for (i=0; i<msglines; i++)
X    {
X       if (!(hdrflag))
X       {
X           outmsg.msgbody[outmsg.mblcnt] = strdup (rawmsg[i]);
X           outmsg.mblcnt ++;
X           pls = True;
X           continue;
X       }
X
X       if (strlen (rawmsg[i]) == 1)
X       {
X           hdrflag = False;
X           pls = True;
X           continue;
X       }
X
X       if (isspace (rawmsg[i][0]))
X       {
X           if (pls)
X           {
X               pls = handle_alt_hdr (rawmsg[i]);
X               continue;
X           }
X           else
X           {
X               pls = False;
X               continue;
X           }
X       }
X
X       if ((carp = strstr (rawmsg[i], "Reply-To:")) &&
X           (!(strstr (rawmsg[i], "In-Reply-To:"))) &&
X           (carp == rawmsg[i]))
X       {
X           char *tlfrom;
X
X           outmsg.from = get_return_address (rawmsg[i]);
X           tlfrom = get_long_return_address (rawmsg[i]);
X
X           if (outmsg.longfrom)
X           {
X               if (strlen (outmsg.longfrom) <= strlen (tlfrom))
X               {
X                   free (outmsg.longfrom);
X                   outmsg.longfrom = tlfrom;
X               }
X           }
X           else
X           {
X               outmsg.longfrom = tlfrom;
X           }
X
X           pls = True;
X           continue;
X       }
X
X       if ((carp = strstr (rawmsg[i], "From:")) &&
X           (carp == rawmsg[i]))
X       {
X           char *tlfrom;
X
X           tlfrom = get_long_return_address (rawmsg[i]);
X           if (!(outmsg.from))
X               outmsg.from = get_return_address (rawmsg[i]);
X
X           if (outmsg.longfrom)
X           {
X               if (strlen (outmsg.longfrom) <= strlen (tlfrom))
X               {
X                   free (outmsg.longfrom);
X                   outmsg.longfrom = tlfrom;
X               }
X           }
X           else
X           {
X               outmsg.longfrom = tlfrom;
X           }
X           
X           pls = True;
X           continue;
X       }
X
X       if ((carp = strstr (rawmsg[i], "Subject:")) &&
X           (carp == rawmsg[i]))
X       {
X           outmsg.subj = cleanup_string (carp + 9);
X           pls = True;
X           continue;
X       }
X
X       if ((carp = strstr (rawmsg[i], "Newsgroups:")) &&
X           (carp == rawmsg[i]))
X       {
X           outmsg.newsgroup = cleanup_string (carp + 12);
X           pls = True;
X           continue;
X       }
X
X       if ((carp = strstr (rawmsg[i], "Apparently")) ||
X           (carp = strstr (rawmsg[i], "Cc")) ||
X           (carp = strstr (rawmsg[i], "Content")) ||
X           (carp = strstr (rawmsg[i], "Date")) ||
X           (carp = strstr (rawmsg[i], "Errors")) ||
X           (carp = strstr (rawmsg[i], "From ")) ||
X           (carp = strstr (rawmsg[i], "In-Reply-To")) ||
X           (carp = strstr (rawmsg[i], "Message-Id")) ||
X           (carp = strstr (rawmsg[i], "Mime")) ||
X           (carp = strstr (rawmsg[i], "Nntp")) ||
X           (carp = strstr (rawmsg[i], "Path")) ||
X           (carp = strstr (rawmsg[i], "Precedence")) ||
X           (carp = strstr (rawmsg[i], "Received")) ||
X           (carp = strstr (rawmsg[i], "References")) ||
X           (carp = strstr (rawmsg[i], "Reply-To")) ||
X           (carp = strstr (rawmsg[i], "Return-Path")) ||
X           (carp = strstr (rawmsg[i], "Sender")) ||
X           (carp = strstr (rawmsg[i], "Status")) ||
X           (carp = strstr (rawmsg[i], "To:")) ||
X           (carp = strstr (rawmsg[i], "X-")))
X       {
X           if (carp == rawmsg[i])
X           {
X               pls = False;
X               continue;
X           }
X       }
X
X       pls = handle_alt_hdr (rawmsg[i]);
X    }
X
X    outmsg.replyto = strdup (listinfo.replyto);
X    outmsg.errorsto = strdup (listinfo.errorsto);
X}
X
END_OF_FILE
if test 3900 -ne `wc -c <'MailServ/src/inmsg.c'`; then
    echo shar: \"'MailServ/src/inmsg.c'\" unpacked with wrong size!
fi
# end of 'MailServ/src/inmsg.c'
fi
if test -f 'MailServ/src/mailserv.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/src/mailserv.c'\"
else
echo shar: Extracting \"'MailServ/src/mailserv.c'\" \(2081 characters\)
sed "s/^X//" >'MailServ/src/mailserv.c' <<'END_OF_FILE'
X
X#define MAIN
X#include "mailserv.h"
X
X/*****************************************************************************
X * usage
X */
Xvoid
X    usage()
X{
X    fprintf (stderr, "Usage: mailserv listname command < mailfile\n\n");
X    fprintf (stderr, "Commands:\n");
X    fprintf (stderr, "\trequest\t\tmail from request address\n");
X    fprintf (stderr, "\tmessage\t\tmail from message address\n");
X    fprintf (stderr, "\tnightly\t\tdo nightly maintenance\n");
X    fprintf (stderr, "\trare\t\tdo infrequent maintenance\n");
X    Exit (1);
X}
X
X/*****************************************************************************
X * msgdate
X */
Xchar *msgdate()
X{
X    long t;
X
X    t = time(0);
X    return (cleanup_string (ctime (&t)));
X}
X
X/*****************************************************************************
X * init_globals
X */
Xvoid
X    init_globals ()
X{
X    listinfo.datestr = msgdate();
X
X    listinfo.delay = 5;
X
X    listinfo.replyto = NULL;
X    listinfo.errorsto = NULL;
X
X    listinfo.keep = False;
X    listinfo.announce = False;
X    listinfo.files = False;
X    listinfo.digest = False;
X    listinfo.backup = True;
X    listinfo.faq = False;
X    listinfo.ftp = False;
X
X    outmsg.longfrom = NULL;
X}
X
X/*****************************************************************************
X * main
X */
Xint
X    main (argc, argv)
Xint argc;
Xchar **argv;
X{
X    init_globals ();
X    get_list_info (argc, argv);
X    verify_info ();
X    get_user_list ();
X
X    if (strstr (listinfo.sub, "request"))
X    {
X       get_raw_msg ();
X       process_raw_msg ();
X       handle_request ();
X    }
X    else if (strstr (listinfo.sub, "message"))
X    {
X       get_raw_msg ();
X       process_raw_msg ();
X       distribute_message ();
X    }
X    else if (strstr (listinfo.sub, "nightly"))
X    {
X       if (listinfo.backup)
X           backup_user_list ();
X
X       if (listinfo.digest)
X       {
X           make_digest ();
X
X           if (listinfo.ftp)
X               ftp_digest ();
X       }
X
X       dump_log ();
X    }
X    else if (strstr (listinfo.sub, "rare"))
X    {
X       if (listinfo.faq)
X           post_faq ();
X    }
X    else
X    {
X       fprintf (stderr, "Illegal sublist type: %s\n", listinfo.sub);
X       Exit(1);
X    }
X
X    Exit (0);
X}
END_OF_FILE
if test 2081 -ne `wc -c <'MailServ/src/mailserv.c'`; then
    echo shar: \"'MailServ/src/mailserv.c'\" unpacked with wrong size!
fi
# end of 'MailServ/src/mailserv.c'
fi
if test -f 'MailServ/src/mailserv.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/src/mailserv.h'\"
else
echo shar: Extracting \"'MailServ/src/mailserv.h'\" \(2781 characters\)
sed "s/^X//" >'MailServ/src/mailserv.h' <<'END_OF_FILE'
X
X#ifndef MAILSERV
X#define MAILSERV
X
X/*****************************************************************************
X * Header files
X */
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <time.h>
X#include <sys/types.h>
X#include <ctype.h>
X
X/*****************************************************************************
X * Constants
X */
X#define True       1
X#define False      0
X#define MAXLINES   10000
X#define MAXALTHDR  10
X#define BADADDR    "Bad_Address"
X
X/* File names & locations */
X#define ListHome   "/itchy1/MailServ/"
X#define InfoFile   "Info"
X
X/* Shell Commands */
X#define SendMail   "/usr/lib/sendmail"
X#define Sort       "/bin/sort"
X#define Copy       "/bin/cp"
X#define Rm         "/bin/rm -f"
X#define Inews      "/usr/local/bin/inews"
X#define Ftp        "/usr/ucb/ftp"
X
X/* Fake address for Quiet mailings */
X#define FakeAddr   "notreal%itchy@dsd.es.com"
X
X/*****************************************************************************
X * Type definitions
X */
Xtypedef struct
X{
X    char *name, *sub;
X    char *replyto, *errorsto, *from;
X    char *archivefile, *userfile, *logfile, *indexfile, *backupdir;
X    char *subscribefile, *unsubscribefile, *nounsubfile, *helpfile;
X    char *digestinput, *digestoutput, *digestcounterfile;
X    char *digestname, *digesthead, *digesttail;
X    char *datestr, *volline;
X    char *faqfile;
X    char *ftpdir, *ftpsite, *netrcfile;
X
X    int volume, issue;
X    int delay;
X
X    unsigned announce : 1;
X    unsigned backup : 1;
X    unsigned digest : 1;
X    unsigned faq : 1;
X    unsigned files : 1;
X    unsigned ftp : 1;
X    unsigned keep : 1;
X}
XListInfo;
X
Xtypedef struct
X{
X    char *replyto;
X    char *errorsto;
X    char *from, *longfrom;
X    char *subj;
X    char *newsgroup;
X
X    char *althdr[MAXALTHDR];
X    int ahlcnt;
X
X    char *msgbody[MAXLINES];
X    int mblcnt;
X}
XMessage;
X
Xtypedef struct
X{
X    char *request;
X    char *filename;
X}
XReqFile;
X       
X
X/*****************************************************************************
X * Global variables
X */
X#ifdef MAIN
X#define SCOPE
X#else
X#define SCOPE extern
X#endif
X
XSCOPE char *rawmsg[MAXLINES];
XSCOPE int msglines;
X
XSCOPE ListInfo listinfo;
XSCOPE Message outmsg;
X
XSCOPE char *readers[MAXLINES];
XSCOPE int readercount;
X
XSCOPE ReqFile reqtable[MAXLINES];
XSCOPE int reqcount;
X
XSCOPE FILE *thelogfile;
X
X#endif /* #ifndef MAILSERV... */
X
X/*****************************************************************************
X * Functions predefs, for utils
X */
Xchar *first_word (char *);
Xchar *rest_of_line (char *);
Xchar *rm_tail_cr (char *);
Xchar *rm_head_space (char *);
Xchar *cleanup_string (char *);
Xchar *get_return_address (char *);
Xchar *get_long_return_address (char *);
Xvoid send_file (char *, char *, char *);
Xvoid get_user_list ();
Xvoid backup_user_list ();
Xvoid post_faq ();
END_OF_FILE
if test 2781 -ne `wc -c <'MailServ/src/mailserv.h'`; then
    echo shar: \"'MailServ/src/mailserv.h'\" unpacked with wrong size!
fi
# end of 'MailServ/src/mailserv.h'
fi
if test ! -d 'MailServ/src/orig-dig' ; then
    echo shar: Creating directory \"'MailServ/src/orig-dig'\"
    mkdir 'MailServ/src/orig-dig'
fi
if test -f 'MailServ/src/outmsg.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/src/outmsg.c'\"
else
echo shar: Extracting \"'MailServ/src/outmsg.c'\" \(5758 characters\)
sed "s/^X//" >'MailServ/src/outmsg.c' <<'END_OF_FILE'
X
X#include "mailserv.h"
X
X/*****************************************************************************
X * dump_clean_message
X */
Xvoid
X    dump_clean_message(fileid)
XFILE *fileid;
X{
X    int i;
X
X    if (fileid)
X    {
X       fprintf (fileid, "Errors-To: %s\n", outmsg.errorsto);
X       fprintf (fileid, "Reply-To: %s\n", outmsg.replyto);
X       fflush (fileid);
X    }
X    else
X    {
X       printf ("Errors-To: %s\n", outmsg.errorsto);
X       printf ("Reply-To: %s\n", outmsg.replyto);
X       fflush (stdout);
X    }
X
X    if (outmsg.longfrom)
X    {
X       if (fileid)
X       {
X           fprintf (fileid, "From: %s\n", outmsg.longfrom);
X           fflush (fileid);
X       }
X       else
X       {
X           printf ("From: %s\n", outmsg.longfrom);
X           fflush (stdout);
X       }
X    }
X
X    if (outmsg.subj)
X    {
X       if (fileid)
X       {
X           fprintf (fileid, "Subject: %s\n", outmsg.subj);
X           fflush (fileid);
X       }
X       else
X       {
X           printf ("Subject: %s\n", outmsg.subj);
X           fflush (stdout);
X       }
X    }
X
X    for (i=0; i<outmsg.ahlcnt; i++)
X    {
X       if (fileid)
X       {
X           fprintf (fileid, "%s\n", outmsg.althdr[i]);
X           fflush (fileid);
X       }
X       else
X       {
X           printf ("%s\n", outmsg.althdr[i]);
X           fflush (stdout);
X       }
X    }
X
X    if (fileid)
X    {
X       fprintf (fileid, "List-Name: %s\n", listinfo.name);
X       fprintf (fileid, "Precedence: Bulk\n");
X       fprintf (fileid, "\n");
X       fflush (fileid);
X    }
X    else
X    {
X       printf ("List-name: %s\n", listinfo.name);
X       printf ("Precedence: Bulk\n");
X       printf ("\n");
X       fflush (stdout);
X    }
X
X    if (outmsg.newsgroup)
X    {
X       if (fileid)
X       {
X           fprintf (fileid, "Newsgroups: %s\n", outmsg.newsgroup);
X           fflush (fileid);
X       }
X       else
X       {
X           printf ("Newsgroups: %s\n", outmsg.newsgroup);
X           fflush (stdout);
X       }
X    }
X
X    for (i=0; i<outmsg.mblcnt; i++)
X    {
X       if (fileid)
X       {
X           fprintf (fileid, "%s", outmsg.msgbody[i]);
X           fflush (fileid);
X       }
X       else
X       {
X           printf ("%s", outmsg.msgbody[i]);
X           fflush (stdout);
X       }
X    }
X}
X
X/*****************************************************************************
X * dump_quiet_clean_message
X */
Xvoid
X    dump_quiet_clean_message(fileid, qto)
XFILE *fileid;
Xchar *qto;
X{
X    int i;
X
X    if (fileid)
X    {
X       fprintf (fileid, "Errors-To: %s\n", outmsg.errorsto);
X       fprintf (fileid, "Reply-To: %s\n", outmsg.replyto);
X       fprintf (fileid, "Bcc: %s\n", qto);
X       fflush (fileid);
X    }
X    else
X    {
X       printf ("Errors-To: %s\n", outmsg.errorsto);
X       printf ("Reply-To: %s\n", outmsg.replyto);
X       printf ("Bcc: %s\n", qto);
X       fflush (stdout);
X    }
X
X    if (outmsg.longfrom)
X    {
X       if (fileid)
X       {
X           fprintf (fileid, "From: %s\n", outmsg.longfrom);
X           fflush (fileid);
X       }
X       else
X       {
X           printf ("From: %s\n", outmsg.longfrom);
X           fflush (stdout);
X       }
X    }
X
X    if (outmsg.subj)
X    {
X       if (fileid)
X       {
X           fprintf (fileid, "Subject: %s\n", outmsg.subj);
X           fflush (fileid);
X       }
X       else
X       {
X           printf ("Subject: %s\n", outmsg.subj);
X           fflush (stdout);
X       }
X    }
X
X    for (i=0; i<outmsg.ahlcnt; i++)
X    {
X       if (fileid)
X       {
X           fprintf (fileid, "%s\n", outmsg.althdr[i]);
X           fflush (fileid);
X       }
X       else
X       {
X           printf ("%s\n", outmsg.althdr[i]);
X           fflush (stdout);
X       }
X    }
X
X    if (fileid)
X    {
X       fprintf (fileid, "List-Name: %s\n", listinfo.name);
X       fprintf (fileid, "Precedence: Bulk\n");
X       fprintf (fileid, "\n");
X       fflush (fileid);
X    }
X    else
X    {
X       printf ("List-name: %s\n", listinfo.name);
X       printf ("Precedence: Bulk\n");
X       printf ("\n");
X       fflush (stdout);
X    }
X
X    if (outmsg.newsgroup)
X    {
X       if (fileid)
X       {
X           fprintf (fileid, "Newsgroups: %s\n", outmsg.newsgroup);
X           fflush (fileid);
X       }
X       else
X       {
X           printf ("Newsgroups: %s\n", outmsg.newsgroup);
X           fflush (stdout);
X       }
X    }
X
X    for (i=0; i<outmsg.mblcnt; i++)
X    {
X       if (fileid)
X       {
X           fprintf (fileid, "%s", outmsg.msgbody[i]);
X           fflush (fileid);
X       }
X       else
X       {
X           printf ("%s", outmsg.msgbody[i]);
X           fflush (stdout);
X       }
X    }
X}
X
X/*****************************************************************************
X * dump_raw_msg
X */
Xvoid
X    dump_raw_msg(fileid)
XFILE *fileid;
X{
X    int i;
X
X    for (i=0; i<msglines; i++)
X    {
X       if (fileid)
X       {
X           fputs (rawmsg[i], fileid);
X           fflush (fileid);
X       }
X       else
X       {
X           fputs (rawmsg[i], stdin);
X           fflush (stdout);
X       }
X    }
X}   
X
X/*****************************************************************************
X * send_to_digest
X */
Xvoid
X    send_to_digest()
X{
X    FILE *digestfile;
X
X    digestfile = fopen (listinfo.digestinput, "a");
X    dump_raw_msg (digestfile);
X    fclose (digestfile);
X}
X
X/*****************************************************************************
X * send_to_users
X */
Xvoid
X    send_to_users()
X{
X    FILE *outfile;
X    char cmdstr[120], *carp;
X    int i;
X
X    for (i=0; i<readercount; i++)
X    {
X       if (readers[i][0] == '*')
X       {
X           sprintf (cmdstr, "%s %s", SendMail, FakeAddr);
X           outfile = popen (cmdstr, "w");
X           carp = rest_of_line (readers[i]);
X           dump_quiet_clean_message (outfile, carp);
X       }
X       else
X       {
X           sprintf (cmdstr, "%s %s", SendMail, readers[i]);
X           outfile = popen (cmdstr, "w");
X           dump_clean_message (outfile);
X       }
X
X       pclose (outfile);
X       sleep (listinfo.delay);
X    }
X}
X
X/*****************************************************************************
X * archive_message
X */
Xvoid
X    archive_message()
X{
X    FILE *outfile;
X
X    outfile = fopen (listinfo.archivefile, "a");
X    dump_clean_message (outfile);
X    fclose (outfile);
X}
X
X/*****************************************************************************
X * distribute_message
X */
Xvoid
X    distribute_message()
X{
X    fprintf (thelogfile, "Message: %s @ %s\n",
X            outmsg.from, listinfo.datestr);
X    fprintf (thelogfile, "     Subj: %s\n",
X            outmsg.subj);
X
X    if (outmsg.newsgroup)
X       fprintf (thelogfile, "     News: %s\n", outmsg.newsgroup);
X
X    if (listinfo.digest)
X    {
X       send_to_digest();
X       return;
X    }
X
X    send_to_users();
X
X    if (listinfo.keep)
X       archive_message();
X
X}
END_OF_FILE
if test 5758 -ne `wc -c <'MailServ/src/outmsg.c'`; then
    echo shar: \"'MailServ/src/outmsg.c'\" unpacked with wrong size!
fi
# end of 'MailServ/src/outmsg.c'
fi
if test -f 'MailServ/src/request.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/src/request.c'\"
else
echo shar: Extracting \"'MailServ/src/request.c'\" \(7555 characters\)
sed "s/^X//" >'MailServ/src/request.c' <<'END_OF_FILE'
X
X#include "mailserv.h"
X
X/*****************************************************************************
X * std_req_hdr
X */
Xvoid
X    std_req_hdr (fileid)
XFILE *fileid;
X{
X    if (fileid)
X    {
X        fprintf (fileid, "Errors-To: %s\n", outmsg.errorsto);
X        fprintf (fileid, "Reply-To: %s\n", listinfo.from);
X       fprintf (fileid, "From: %s\n", listinfo.from);
X        fprintf (fileid, "List-Name: %s\n", listinfo.name);
X        fprintf (fileid, "Precedence: Bulk\n\n");
X       fflush (fileid);
X    }
X    else
X    {
X        printf ("Errors-To: %s\n", outmsg.errorsto);
X        printf ("Reply-To: %s\n", listinfo.from);
X       printf ("From: %s\n", listinfo.from);
X       printf ("List-name: %s\n", listinfo.name);
X        printf ("Precedence: Bulk\n\n");
X       fflush (stdout);
X    }
X}
X
X/*****************************************************************************
X * quiet_req_hdr
X */
Xvoid
X    quiet_req_hdr (fileid, qto)
XFILE *fileid;
Xchar *qto;
X{
X    if (fileid)
X    {
X        fprintf (fileid, "Errors-To: %s\n", outmsg.errorsto);
X        fprintf (fileid, "Reply-To: %s\n", listinfo.from);
X       fprintf (fileid, "From: %s\n", listinfo.from);
X       fprintf (fileid, "Bcc: %s\n", qto);
X        fprintf (fileid, "Precedence: Bulk\n\n");
X       fflush (fileid);
X    }
X    else
X    {
X        printf ("Errors-To: %s\n", outmsg.errorsto);
X        printf ("Reply-To: %s\n", listinfo.from);
X       printf ("From: %s\n", listinfo.from);
X       printf ("Bcc: %s\n", qto);
X        printf ("Precedence: Bulk\n\n");
X       fflush (stdout);
X    }
X}
X
X/*****************************************************************************
X * handle_bad_address
X */
Xvoid
X    handle_bad_address()
X{
X    FILE *cmdstream;
X    char cmdstr[100];
X
X    sprintf (cmdstr, "%s %s-owner", SendMail, listinfo.name);
X    cmdstream = popen (cmdstr, "w");
X
X    sprintf (cmdstr, "Subject: BAD ADDRESS in %s\n", listinfo.name);
X    fputs (cmdstream, cmdstr);
X    std_req_hdr (cmdstream);
X
X    dump_raw_msg (cmdstream);
X    pclose (cmdstream);
X}
X
X/*****************************************************************************
X * make_request_table
X */
Xvoid
X    make_request_table ()
X{
X    char templine[100], *carp;
X    char request[40], thefile[40];
X    FILE *reqfile;
X    
X    reqfile = fopen (listinfo.indexfile, "r");
X
X    while (fgets (templine, 100, reqfile) != NULL)
X    {
X       carp = cleanup_string (templine);
X
X        if (carp[0] != '#')
X       {
X           int i;
X
X           reqtable[reqcount].request = (char *)
X               cleanup_string (first_word (carp));
X           reqtable[reqcount].filename = (char *)
X               cleanup_string (rest_of_line (carp));
X           for (i=0; i<strlen(reqtable[reqcount].request); i++)
X               if (isupper (reqtable[reqcount].request[i]))
X                   request[i] = tolower(reqtable[reqcount].request[i]);
X           reqcount++;
X       }
X    }
X
X    fclose (reqfile);
X}
X
X/*****************************************************************************
X * announce
X */
Xvoid
X    announce (annstring)
Xchar *annstring;
X{
X    FILE *cmdstream;
X    char cmdstr[100];
X
X    sprintf (cmdstr, "%s %s", SendMail, listinfo.name);
X    cmdstream = popen (cmdstr, "w");
X
X    fprintf (cmdstream, "Subject: %s", annstring);
X    std_req_hdr (cmdstream);
X    fprintf (cmdstream, "%s\n", annstring);
X       
X    pclose (cmdstream);
X}
X
X/*****************************************************************************
X * handle_subscribe
X */
Xvoid
X    handle_subscribe ()
X{
X    char filepath[100];
X    FILE *fileptr;
X
X    fileptr = fopen (listinfo.userfile, "a");
X    fprintf (fileptr, "%s\n", outmsg.from);
X    fclose (fileptr);
X
X    send_file (outmsg.from, listinfo.subscribefile, "Subscribed");
X
X    fprintf (thelogfile, "Subscribed: %s @ %s\n",
X            outmsg.from, listinfo.datestr);
X    fprintf (thelogfile, "     Subj: %s\n", outmsg.subj);
X
X    if (listinfo.announce)
X    {
X       sprintf (filepath, "Adding %s to the %s list.\n",
X                outmsg.from, listinfo.name);
X       announce (filepath);
X    }
X
X    if (listinfo.digest)
X       send_file (outmsg.from, listinfo.digestoutput, "Previous Digest");
X}
X
X/*****************************************************************************
X * handle_unsubscribe
X */
Xvoid
X    handle_unsubscribe ()
X{
X    int i, ok = False, thisuser=0;
X    char filepath[100], *carp;
X    FILE *fileptr;
X
X    for (i=0; i<readercount; i++)
X    {
X       if ((carp = strstr (readers[i], outmsg.from)) &&
X           (carp == readers[i]))
X       {
X           thisuser = i;
X           ok = True;
X           break;
X       }
X       else if ((carp = strstr (readers[i], outmsg.from)) &&
X                (carp == (readers[i]) + 2) &&
X                (readers[i][0] == '*'))
X       {
X           thisuser = i;
X           ok = True;
X           break;
X       }
X
X    }
X
X    if (ok)
X    {
X       fileptr = fopen (listinfo.userfile, "w");
X
X       for (i=0; i<readercount; i++)
X       {
X           if (i != thisuser)
X               fprintf (fileptr, "%s\n", readers[i]);
X           fflush (fileptr);
X       }
X       fclose (fileptr);
X
X       send_file (outmsg.from, listinfo.unsubscribefile, "Unsubscribed");
X
X       fprintf (thelogfile, "Unsubscribed: %s @ %s\n",
X                outmsg.from, listinfo.datestr);
X       fprintf (thelogfile, "     Subj: %s\n", outmsg.subj);
X
X       if (listinfo.announce)
X       {
X           sprintf (filepath, "Removing %s from the %s list.\n",
X                    outmsg.from, listinfo.name);
X           announce (filepath);
X       }
X    }
X    else
X    {
X       send_file (outmsg.from, listinfo.nounsubfile, "Unsubscribe FAILED");
X
X       fprintf (thelogfile, "Didn't unsub %s @ %s\n", 
X                outmsg.from, listinfo.datestr);
X       fprintf (thelogfile, "     Subj: %s\n", outmsg.subj);
X    }
X}                  
X
X/*****************************************************************************
X * handle_show_list
X */
Xvoid
X    handle_show_list ()
X{
X    char filepath[100];
X
X    send_file (outmsg.from, listinfo.userfile, "User List");
X
X    fprintf (thelogfile, "Sent userlist to: %s @ %s\n", 
X            outmsg.from, listinfo.datestr);
X    fprintf (thelogfile, "     Subj: %s\n", outmsg.subj);
X}
X
X/*****************************************************************************
X * handle_file_request
X */
Xvoid
X    handle_file_request (filenum)
Xint filenum;
X{
X    send_file (outmsg.from, reqtable[filenum].filename,
X              reqtable[filenum].request);
X
X    fprintf (thelogfile, "Sent %s to: %s @ %s\n", 
X            reqtable[filenum].filename, outmsg.from, listinfo.datestr);
X    fprintf (thelogfile, "     Subj: %s\n", outmsg.subj);
X}
X
X/*****************************************************************************
X * handle_help
X */
Xvoid
X    handle_help ()
X{
X    send_file (outmsg.from, listinfo.helpfile, "Help");
X
X    fprintf (thelogfile, "Helping: %s @ %s\n", 
X            outmsg.from, listinfo.datestr);
X    fprintf (thelogfile, "     Subj: %s\n", outmsg.subj);
X}
X
X/*****************************************************************************
X * handle_request
X */
Xvoid
X    handle_request()
X{
X    char *request, *carp;
X    int i;
X
X    if (strstr (outmsg.from, BADADDR))
X       handle_bad_address();
X
X    if (listinfo.files)
X       make_request_table();
X
X    if (outmsg.subj == NULL)
X    {
X       handle_help();
X       return;
X    }
X
X    request = strdup (outmsg.subj);
X    for (i=0; i<strlen(request); i++)
X       if (isupper (request[i]))
X           request[i] = tolower(request[i]);
X
X    if ((carp = strstr (request, "unsubscribe")) &&
X       (carp == request))
X    {
X       handle_unsubscribe();
X       return;
X    }
X
X    if ((carp = strstr (request, "subscribe")) &&
X       (carp == request))
X    {
X       handle_subscribe();
X       return;
X    }
X
X    if ((carp = strstr (request, "show-list")) &&
X       (carp == request))
X    {
X       if (listinfo.announce)
X           handle_show_list ();
X       else
X           handle_help ();
X
X       return;
X    }
X
X    if (listinfo.files)
X    {
X       for (i=0; i<reqcount; i++)
X       {
X           if ((carp = strstr (request, reqtable[i].request)) &&
X               (carp == request))
X           {
X               handle_file_request (i);
X               return;
X           }
X       }
X    }
X
X    handle_help ();
X
X}
END_OF_FILE
if test 7555 -ne `wc -c <'MailServ/src/request.c'`; then
    echo shar: \"'MailServ/src/request.c'\" unpacked with wrong size!
fi
# end of 'MailServ/src/request.c'
fi
if test -f 'MailServ/src/utils.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/src/utils.c'\"
else
echo shar: Extracting \"'MailServ/src/utils.c'\" \(6921 characters\)
sed "s/^X//" >'MailServ/src/utils.c' <<'END_OF_FILE'
X
X#include "mailserv.h"
X
X/*****************************************************************************
X * first_word
X */
Xchar
X    *first_word (line)
Xchar *line;
X{
X    char *tcp, tc;
X    int i=0;
X
X    while (i < strlen(line))
X    {
X       if (isspace (line[i]))
X       {
X           tc = line[i];
X           line[i] = '\0';
X           tcp = strdup (line);
X           line[i] = tc;
X           return (tcp);
X       }
X       i++;
X    }
X
X    return (strdup (line));
X}
X
X/*****************************************************************************
X * rest_of_line
X */
Xchar
X    *rest_of_line (line)
Xchar *line;
X{
X    int i=0;
X
X    while (i < strlen(line))
X    {
X       if (isspace (line[i]))
X       {
X           return (strdup ( &(line[i+1]) ));
X           break;
X       }
X       i++;
X    }
X
X    return (NULL);
X}
X
X
X/*****************************************************************************
X * rm_tail_cr
X */
Xchar
X    *rm_tail_cr (line)
Xchar *line;
X{
X    char *carp, *tcp;
X    char cr[2];
X
X    sprintf (cr, "\n");
X
X    tcp = strdup (line);
X    if (carp = strstr (tcp, cr))
X       *carp = '\0';
X
X    return (tcp);
X}
X
X/*****************************************************************************
X * rm_head_space
X */
Xchar
X    *rm_head_space (line)
Xchar *line;
X{
X    int flag = True;
X    char *tcp, *carp1, *carp2;
X
X    carp1 = tcp = strdup (line);
X
X    while (flag)
X    {
X       if (isspace (*carp1))
X           carp1++;
X       else
X           flag = False;
X    }
X
X    carp2 = strdup (carp1);
X    free (tcp);
X
X    return (carp2);
X}
X
X/*****************************************************************************
X * cleanup_string
X */
Xchar
X    *cleanup_string (line)
Xchar *line;
X{
X    char *tc1, *tc2;
X
X    tc1 = rm_tail_cr (line);
X    tc2 = rm_head_space (tc1);
X    free (tc1);
X    return (tc2);
X}
X
X/*****************************************************************************
X * get_return_address
X */
Xchar
X    *get_return_address (line)
Xchar *line;
X{
X    char *first, *rest, *full;
X    char *carp, *tcp;
X    int cleanloop = True, i, m;
X
X    full = strdup (line);
X
X    while (full)
X    {
X       first = first_word (full);
X       rest = rest_of_line (full);
X       free (full);
X
X       if (strstr (first, "@"))
X       {
X           free (rest);
X           break;
X       }
X
X       full = rest;
X       free (first);
X       first = NULL;
X    }
X
X    if (first == NULL)
X       return (strdup (BADADDR));
X
X    carp = first;
X
X    while (cleanloop)
X    {
X       if (carp[0] == '[')
X       {
X           carp++;
X           tcp = strstr(carp, "]");
X           *tcp = '\0';
X           continue;
X       }
X
X       if (carp[0] == '(')
X       {
X           carp++;
X           tcp = strstr(carp, ")");
X           *tcp = '\0';
X           continue;
X       }
X
X       if (carp[0] == '<')
X       {
X           carp++;
X           tcp = strstr(carp, ">");
X           *tcp = '\0';
X           continue;
X       }
X
X       cleanloop = False;
X    }
X
X    m = strlen (carp);
X
X    for (i=0; i<m; i++)
X    {
X       if (isupper (carp[i]))
X           carp[i] = tolower (carp[i]);
X    }
X
X    tcp = cleanup_string (carp);
X    free (first);
X    return (tcp);
X}
X
X/*****************************************************************************
X * get_long_return_address
X */
Xchar
X    *get_long_return_address (line)
Xchar *line;
X{
X    char *tc1, *tc2;
X
X    tc1 = rest_of_line (line);
X    tc2 = cleanup_string (tc1);
X    free (tc1);
X    return (tc2);
X}
X
X/*****************************************************************************
X * send_file
X */
Xvoid
X    send_file (name, filepath, subj)
Xchar *name, *filepath, *subj;
X{
X    FILE *cmdstream, *datafile;
X    char cmdstr[100];
X
X    if (filepath[0] == '/')
X       sprintf (cmdstr, "%s", filepath);
X    else
X       sprintf (cmdstr, "%s/%s/%s", ListHome, listinfo.name, filepath);
X
X    if ((datafile = fopen (cmdstr, "r")) == NULL)
X    {
X       fprintf (thelogfile, "Error sending file %s: %s @ %s\n", 
X                filepath, outmsg.from, listinfo.datestr);
X       fprintf (thelogfile, "     Subj: %s\n", outmsg.subj);
X       return;
X    }
X
X    sprintf (cmdstr, "%s %s", SendMail, name);
X    cmdstream = popen (cmdstr, "w");
X
X    fprintf (cmdstream, "Subject: %s\n", subj);
X    std_req_hdr (cmdstream);
X
X    while (fgets (cmdstr, 100, datafile) != NULL)
X    {
X       fputs (cmdstr, cmdstream);
X       fflush (cmdstream);
X    }
X
X    pclose (cmdstream);
X    fclose (datafile);
X}
X
X/*****************************************************************************
X * get_user_list
X */
Xvoid
X    get_user_list()
X{
X    char templine[100], *carp;
X    FILE *userfile;
X
X    readercount = 0;
X    userfile = fopen (listinfo.userfile, "r");
X    while (fgets (templine, 100, userfile) != NULL)
X    {
X       if (templine[0] != '#')
X       {
X           if (readercount > MAXLINES)
X           {
X               fprintf (stderr, "Warning: User list overflow.\n");
X               fprintf (thelogfile, "Warning: User list overflow @ %s\n",
X                        listinfo.datestr);
X               break;
X           }
X
X           readers[readercount++] = cleanup_string (templine);
X       }
X    }
X}
X
X/*****************************************************************************
X * backup_user_list
X */
Xvoid
X    backup_user_list()
X{
X    char tl[200];
X    int d;
X
X    d = atoi (&(listinfo.datestr[8]));
X
X    if (listinfo.backup)
X    {
X       sprintf (tl, "%s -u -o %s %s", Sort,
X                listinfo.userfile, listinfo.userfile);
X       system (tl);
X
X       sprintf (tl, "%s %s %s/%d", Copy, listinfo.userfile,
X                listinfo.backupdir, d);
X       system (tl);
X
X       d = (d + 31 - 7) % 31;
X       sprintf (tl, "%s -f %s/%d", Rm, listinfo.backupdir, d);
X       system (tl);
X    }
X}
X
X/*****************************************************************************
X * dump_log
X */
Xvoid
X    dump_log ()
X{
X    char templine[200];
X
X    fclose (thelogfile);
X    thelogfile = fopen (listinfo.logfile, "r");
X
X    printf ("==================================\n");
X    printf ("List Log: %s    (%d users)\n\n", listinfo.name, readercount);
X
X    while (fgets (templine, 200, thelogfile))
X       fputs (templine, stdout);
X
X    fclose (thelogfile);
X    printf ("\n");
X    thelogfile = fopen (listinfo.logfile, "w");
X}
X
X/*****************************************************************************
X * post_faq
X */
Xvoid
X    post_faq ()
X{
X    char cmdstr[100];
X
X    sprintf (cmdstr, "%s %s", Inews, listinfo.faqfile);
X    system (cmdstr);
X}
X
X/*****************************************************************************
X * ftp_digest
X */
Xvoid
X    ftp_digest ()
X{
X    char cmd[200];
X    FILE *cmdstream;
X
X    sprintf (cmd, "%s %s %s/.netrc", Copy, listinfo.netrcfile, ListHome);
X    system (cmd);
X
X    sprintf (cmd, "%s %s", Ftp, listinfo.ftpsite);
X    cmdstream = popen (cmd, "w");
X    sleep (15);
X
X    fprintf (cmdstream, "bin\n");
X    sleep (10);
X
X    fprintf (cmdstream, "prompt\n");
X    sleep (10);
X
X    fprintf (cmdstream, "put %s  %s/daily\n", 
X            listinfo.digestoutput, listinfo.ftpdir);
X    sleep (10);
X
X    fprintf (cmdstream, "put %s  %s/vol-%d/%d\n",
X            listinfo.digestoutput, listinfo.ftpdir, 
X            listinfo.volume, listinfo.issue);
X    sleep (10);
X    
X    fprintf (cmdstream, "quit\n");
X    sleep (100);
X
X    sprintf (cmd, "%s %s/.netrc", Rm, ListHome);
X    system (cmd);
X
X    pclose (cmdstream);
X}
X
X/*****************************************************************************
X * Exit
X */
Xvoid
X    Exit (state)
Xint state;
X{
X    fflush (stderr);
X    fclose (thelogfile);
X    exit (state);
X}
END_OF_FILE
if test 6921 -ne `wc -c <'MailServ/src/utils.c'`; then
    echo shar: \"'MailServ/src/utils.c'\" unpacked with wrong size!
fi
# end of 'MailServ/src/utils.c'
fi
if test -f 'MailServ/fakedigest/files/UNDIGEST.C' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file 
\"'MailServ/fakedigest/files/UNDIGEST.C'\"
else
echo shar: Extracting \"'MailServ/fakedigest/files/UNDIGEST.C'\" \(5155 
characters\)
sed "s/^X//" >'MailServ/fakedigest/files/UNDIGEST.C' <<'END_OF_FILE'
X/*
X       Modified 11/16/90 to fix use of an uninitialized variable
X       (could cause a run time error on some machines)
X       and a variable set but not used to eliminate the warnings
X       from the Apollo c compiler.  jdb
X
X       Modified 1/27/88 to handle more types of digests and
X       a compile-time option added (LONGNAME) which will cause
X       the default output file name to be <digest-name>.VOL.NUM
X       rather than the VOL.NUM form described below.
X
X       This has been tested with the Info-IBM, Info-Kermit, and
X       Info-CPM Digest formats.
X
X       This program should be called 'UNDIGEST' rather than 'DIGEST'
X       as it is below since there is a companion program in the
X       Simtel20 PD2:<UNIX.MAIL> directory (digest.c) that
X       creates a Digest file from individual messages.
X
X       The original documentation below has NOT been modified to
X       reflect these changes.
X
X                                       David Brown
X                                       jdb@email.ncsc.navy.mil
X*/
X/*
XDIGEST:  (version 3) November, 1984
X
XNAME: 
X       Digest  - reformats the ailist digest for use with "mail -f"
X
XSYNOPSIS:
X       digest file [file] 
X
XDESCRIPTION:
X
Xdigest takes the file name  given  in  first  argument  and  places  the
Xreformatted  file  in  the  second argument, if given. If no output file
X(2nd argument) is given, the output will be placed into a  default  file
Xwhose  name  is of the form VOL.NUM where VOL and NUM are the volume and
Xnumber of the ailist digest fed in (e.g. 2.144,etc.).
X
XA few notes:
X       (1) if only one argument is given, it is assumed to be the
X           input file.  If no args are given, you get prompted for
X           for the input file, and the output is sent to the default
X           file construction.
X
X       (2) This has been tested only for use with the specific ailist/human-
X           nets format now in use.  I will soon get around to adding
X           code to this program to handle other formats.  When I do,
X           I will send it along.
X
X       (3) The input to this program must be A SINGLE AILIST 
X           OR HUMAN-NETS DIGEST.  If you have been stuffing all 
X           your ailist digests into a single file, running this pgm 
X           on that file will yield  incorrect and unpredictable results.  
X           The pgm is best  used to manage the incoming stuff.
X
X       (4) the input file is left untouched (i.e. is not removed)
X
X       (5) digest does not work with piped input (a bug, sorry).
X           This has meant for me that I stick the day's ailist digest
X           into a temp file when I receive it over "mail", and then
X           later "digest" this temp file to get it into a suitable
X           form for "mail -f".
X
XBUGS:
X       If there are ailist sub-entries which do not have a DATE:
X       field in the header, they will be appended to the entry
X       prior.  
X
XAny questions, suggestions or problems, etc. should be sent to 
X
Xdouglas stumberger
Xdepartment of computer science
X111 Cumington Street
Xboston, ma. 02215
X
Xcsnet: des@bostonu
Xbitnet: csc10304@bostonu
X
X*/
X
X#include <stdio.h>
X
Xmain(argc,argv)
X       int argc; char *argv[] ;
X{
X       FILE *fpr, *fpw ;
X       char *lead, *fromline, temp[81], fname[81] ,
X               digest[81],vol[50],num[5] ;
X       register int done=0, gl ;
X       
X       if (argc > 3) {
X               printf("Usage: %s file [file]\n",argv[0]) ;
X               exit(0);
X       }
X       if (argc == 1) { 
X               printf("What file is the digest in? > ") ;
X               scanf("%s",fname) ;
X       }
X       else 
X               strcpy(fname,argv[1]) ;
X       
X       if ((fpr = fopen(fname,"r")) == NULL) {
X               printf("%s: No such file\n",fname) ;
X               exit(0) ;
X       }
X
X#ifdef DEBUG
X       printf(" input file name is <%s>\n",fname) ;
X#endif
X
X       lead = (char *) calloc(90,sizeof(char)) ;  
X
X       get_line(fpr,lead) ;            /* get the first line of file */
X
X       fromline = (char *) malloc(strlen(lead)+1) ;
X       strcpy(fromline,lead) ;
X
X       if (argc != 3) {   /* no output file given - 
X                               find out vol/num for filename */
X
X               while ((lead[0] != '-') && (!done)) {
X#ifdef DEBUG
Xprintf("Scanning:%s",lead);
X#endif
X                       sscanf(lead,"%s %s",digest,temp) ;
X                       if (!strcmp(temp,"Digest")) {
X#ifdef DEBUG
Xprintf("\nFound a match\n");
X#endif
X                      sscanf(lead,"%*s %*s %*s %*s %*s %*s %*s %s %*c %*s %s",
X                               vol,num) ;
X                       done++ ;
X                       }
X                       get_line(fpr,lead) ;
X               }
X
X               strcat(digest,".") ;            
X#ifndef LONGNAME
X               digest[0]='\0';
X#endif
X               strcat(digest,vol) ;
X               strcat(digest,".") ;
X               strcat(digest,num) ;
X       }
X       else 
X               strcpy(digest,argv[2]) ;        /* output filename is third 
argument */
X
X
X#ifdef DEBUG
X               printf("output file is <%s>",digest) ;
X#endif
X
X       fclose(fpr) ;                   
X
X#ifdef DEBUG
X               printf(" input file is <%s>\n",fname) ;
X#endif
X
X       if ((fpr = fopen(fname,"r")) == NULL) {
X               printf("\nERROR: File will not rewind\n") ;
X               exit(0) ;
X       }
X
X       if ((fpw = fopen(digest,"w")) == NULL) {
X               printf("\nERROR: Output File will not open\n") ;
X               exit(0) ;
X       }
X
X       get_line(fpr,lead) ;            /* copy the ailist header */
X
X       while (lead[0] != '-') {        /* i.e.  Law's message of the topics */
X               fprintf(fpw,"%s",lead) ;
X               get_line(fpr,lead) ;
X       }
X
X       gl = get_line(fpr,lead) ;       /* do the body of the digest */
X       while (gl != EOF) {
X               sscanf(lead,"%s",temp) ;
X               if (!strcmp (temp,"Date:"))
X                       fprintf(fpw,"%s",fromline) ;
X               fprintf(fpw,"%s",lead) ;
X               gl = get_line(fpr,lead) ;
X       }
X
X       printf("Re-formatted digest now in file <%s>\n",digest) ;
X       }       
X
X
Xget_line (fp,s)
X       FILE *fp;       char *s;
X{
X       register int c=0,i=0 ;
X
X       while ((c != '\n') && (c != EOF)) {
X               c = getc(fp) ;
X               *(s+i++) = c ;
X       }
X       *(s+i) = '\0' ;
X       return(c) ;
X}
X
END_OF_FILE
if test 5155 -ne `wc -c <'MailServ/fakedigest/files/UNDIGEST.C'`; then
    echo shar: \"'MailServ/fakedigest/files/UNDIGEST.C'\" unpacked with wrong 
size!
fi
chmod +x 'MailServ/fakedigest/files/UNDIGEST.C'
# end of 'MailServ/fakedigest/files/UNDIGEST.C'
fi
if test -f 'MailServ/src/orig-dig/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/src/orig-dig/Makefile'\"
else
echo shar: Extracting \"'MailServ/src/orig-dig/Makefile'\" \(204 characters\)
sed "s/^X//" >'MailServ/src/orig-dig/Makefile' <<'END_OF_FILE'
X
XSRC =  digest.c
X
XOBJ =  digest.o
X
Xdigest-test:
X       cc -c digest.o -g $(SRC)
X       cc -o digestify-test -g $(OBJ)
X       rm digest.o
X
Xdigest-final:
X       cc -c digest.o -O -s $(SRC)
X       cc -o digestify -O -s $(OBJ)
X       rm digest.o
END_OF_FILE
if test 204 -ne `wc -c <'MailServ/src/orig-dig/Makefile'`; then
    echo shar: \"'MailServ/src/orig-dig/Makefile'\" unpacked with wrong size!
fi
# end of 'MailServ/src/orig-dig/Makefile'
fi
if test -f 'MailServ/src/orig-dig/digest.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MailServ/src/orig-dig/digest.c'\"
else
echo shar: Extracting \"'MailServ/src/orig-dig/digest.c'\" \(20528 characters\)
sed "s/^X//" >'MailServ/src/orig-dig/digest.c' <<'END_OF_FILE'
X/*
X * digest - create digests of mail messages
X *
X * This program uses the file "digest.info" to figure out what issue
X * of the digest it is making.  The format of this file is:
X *
X *     Name of the List                # leave out the word "digest"
X *     Host                            # the host where the digest lives
X *     From                            # who sends the digest out
X *     To                              # who the list is sent to
X *     Volume                          # Volume XX : Issue XXX
X *     Date                            # Day, dd Mon yy hh:mm:ss ZZZ
X *
X * As an example:
X *
X *     Foobar
X *     intrepid.ecn.purdue.edu
X *     Dave Curry (The Moderator) <Foobar-Digest@intrepid.ecn.purdue.edu>
X *     Foobar-List@intrepid.ecn.purdue.edu
X *     Volume 1 : Issue 0
X *     Mon,  4 Jan 88 20:15:33 EST
X *
X * Make sure the "From" line includes a legitimate RFC 822 mail address.
X * Make sure the issue number starts at zero; it gets incremented BEFORE
X * generating each digest.  Volume numbers must be incremented by hand.
X * The "digest.info" file gets modified by the program after generation
X * of each digest.
X *
X * The contents of the file "digest.head", if it exists, will be placed
X * between the list of today's topics and the top of the digest.  This
X * can be used to put information about where to FTP archives from, etc.
X *
X * The file "digest.input" should contain a set of mail messages in the
X * format of a UNIX mailbox.  These messages will be read into memory,
X * and a list of "Today's Topics" generated from the subject lines.  The
X * messages will then be sorted so that all the messages on the same topic
X * come out together in the digest.  Any message whost first word in the
X * subject line is "Administrivia" will be guaranteed to come out first
X * in the digest.
X *
X * The digest will be left in the file "digest.output".  You can send it
X * using the command "/usr/lib/sendmail -t < digest.output".
X *
X * I suggest creating the following mail aliases in /usr/lib/aliases:
X *
X *     1. Foobar-Digest:/path/to/the/digest.input/file
X *             This file must be world-writable for sendmail to modify it.
X *             This is the address to publish for people to send digest
X *             submissions to.
X *     2. Foobar-Digest-Request:yourlogin
X *             This is the address for people to use to ask to be added
X *             or deleted from the list.
X *     3. Foobar-List: :include:/path/to/list/of/recipients
X *             This is the list of people who receive the digest.  It should
X *             be a list of addresses of the format:
X *
X *                     name, name, name, name,
X *                             name, name, name
X *
X *             Continuation lines should start with whitespace.
X *
X * There is one problem with the sorting of messages by subject line to get
X * all the same topic together.  The code handles elimination of "Re:"
X * strings, but if someone changes the subject on you, then things get ugly.
X * This shouldn't happen too often, though.
X *
X * Special thanks to Jon Solomon who sent me his TELECOM digest generating
X * program.  I swiped a lot of ideas from it in writing this one.
X *
X * David A. Curry
X * davy@intrepid.ecn.purdue.edu
X */
X#include <sys/types.h>
X#include <sys/timeb.h>
X#include <sys/time.h>
X#include <ctype.h>
X#include <stdio.h>
X
X#define HEAD1          27              /* Field width of first third   */
X#define HEAD2          20              /* Field width of second third  */
X#define HEAD3          21              /* Field width of last third    */
X#define DATELEN                16              /* Amount of date to put in hdr 
*/
X#define LINELEN                70              /* Length of an average line    
*/
X#define MAXMSGS                64              /* Maximum number of 
msgs/digest*/
X#define LINESIZE       256             /* Maximum line size            */
X#define LISTINFO       "digest.info"   /* Information file name        */
X#define LISTHEAD       "digest.head"   /* Header for top of digest     */
X#define LISTINPUT      "digest.input"  /* Input file name              */
X#define LISTOUTPUT     "digest.output" /* Output file name             */
X
X/*
X * Message structure.  We read through the input file and fill one of
X * these in for each message.  The To, Cc, From, Date, and Subject
X * point to the fields of the same names from the message.  The
X * "sortstring" is a copy of the subject string with all whitespace
X * deleted and all letters in lower case.  The messageaddr is the
X * seek position in the file where the message body starts, and
X * messagelength is how long the message is.
X */
Xstruct message {
X       char *Date;
X       char *From;
X       char *Subject;
X       char *MessageID;
X       char *ReprintFrom;
X       char *sortstring;
X       long messageaddr;
X       long messagelength;
X       int  use_re;
X} messages[MAXMSGS];
X
X/*
X * List structure.  Contains the information from the LISTINFO file.
X */
Xstruct listinfo {
X       char *Title;
X       char *Host;
X       char *From;
X       char *To;
X       char *Volline;
X       char *Dateline;
X} listinfo;
X
XFILE *input;
XFILE *output;
X
Xint issue_number;                      /* The number of this issue     */
Xint nmessages = 0;                     /* Number of messages           */
Xint digestsize = 0;                    /* Size of digest in bytes      */
X
Xchar digestsubject[100];
X
Xchar *index(), *malloc(), *safter(), *nospace(), *getline();
X
Xmain()
X{
X       /*
X        * Read the list information file and update the
X        * issue number and date strings.
X        */
X       get_list_info();
X       inc_volume_and_date();
X
X       printf("Assembling %s Digest %s (%.*s)\n", listinfo.Title, 
listinfo.Volline, DATELEN, listinfo.Dateline);
X       printf("Scanning and sorting messages for topic lines.\n");
X
X       /*
X        * Scan the message file for subject strings and
X        * sort the messages to get all the messages for
X        * each topic next to each other.
X        */
X       scan_messages();
X       sort_messages();
X
X       printf("Writing %s Digest to \"%s\"\n", listinfo.Title, LISTOUTPUT);
X
X       /*
X        * Print the digest header, put the messages
X        * in the digest.
X        */
X       do_digest_header();
X       read_messages();
X
X       printf("The digest is %d characters long in %d messages.\n", 
digestsize, nmessages);
X
X       /*
X        * Put out the new list information.
X        */
X       put_list_info();
X}
X
X/*
X * get_list_info - reads in the LISTINFO file.
X */
Xget_list_info()
X{
X       FILE *fp;
X       int incomplete;
X
X       if ((fp = fopen(LISTINFO, "r")) == NULL) {
X               printf("digest: cannot open \"%s\" for reading.\n", LISTINFO);
X               exit(1);
X       }
X
X       incomplete = 0;
X
X       if ((listinfo.Title = getline(fp)) == NULL)
X               incomplete++;
X       if ((listinfo.Host = getline(fp)) == NULL)
X               incomplete++;
X       if ((listinfo.From = getline(fp)) == NULL)
X               incomplete++;
X       if ((listinfo.To = getline(fp)) == NULL)
X               incomplete++;
X       if ((listinfo.Volline = getline(fp)) == NULL)
X               incomplete++;
X       if ((listinfo.Dateline = getline(fp)) == NULL)
X               incomplete++;
X
X       fclose(fp);
X
X       /*
X        * Error-check.  Not too sophisicated, but then you're
X        * supposed to know what you're doing anyway.
X        */
X       if (incomplete) {
X               printf("digest: incomplete or badly formatted \"%s\" file.\n", 
LISTINFO);
X               printf("Proper format:\n");
X               
printf("\tTitle\n\tHost\n\tFrom\n\tTo\n\tVolline\n\tDateline\n");
X               exit(1);
X       }
X}
X
X/*
X * inc_volume_and_date - update the volume/issue string and get a new date.
X */
Xinc_volume_and_date()
X{
X       char *msgdate();
X       register char *volline, *colon;
X
X       if ((volline = malloc(strlen(listinfo.Volline)+5)) == NULL) {
X               printf("digest: out of memory.\n");
X               exit(1);
X       }
X
X       /*
X        * Volume numbers get changed by hand.
X        */
X       issue_number = atoi(safter(listinfo.Volline, " Issue ")) + 1;
X
X       if ((colon = index(listinfo.Volline, ':')) != NULL)
X               *colon = NULL;
X
X       sprintf(volline, "%s: Issue %3d", listinfo.Volline, issue_number);
X       strcpy(listinfo.Volline, volline);
X
X       /*
X        * Get a new date.
X        */
X       listinfo.Dateline = msgdate();
X
X       free(volline);
X}
X
X/*
X * msgdate - produce a new date string.  Format is
X *
X *             Day, dd Mon yy hh:mm:ss tzn
X */
Xchar *msgdate()
X{
X       char *timezone();
X       struct timeb tbuf;
X       register struct tm *t;
X       struct tm *localtime();
X       static char datebuf[64];
X       char *days = "SunMonTueWedThuFriSat";
X       char *months = "JanFebMarAprMayJunJulAugSepOctNovDec";
X       int n; char tzsign; int tzhours, tzmins;
X
X       ftime(&tbuf);
X       t = localtime(&(tbuf.time));
X
X       n = tbuf.timezone; if (t->tm_isdst) n -= 60;
X       if (n > 0) tzsign = '-';
X       else       tzsign = '+', n = -n;
X       tzhours = n / 60; tzmins  = n % 60;
X
X       sprintf(datebuf,
X               "%3.3s, %2d %3.3s %04d %02d:%02d:%02d %c%02d%02d (%3.3s)",
X               &days[3 * t->tm_wday], t->tm_mday,
X               &months[3 * t->tm_mon], t->tm_year + 1900,
X               t->tm_hour, t->tm_min, t->tm_sec,
X               tzsign, tzhours, tzmins,
X               timezone(tbuf.timezone, t->tm_isdst));
X
X       /* remove space if day of the month is between 1 and 9 */
X       if (datebuf[5] == ' ')
X           strcpy (datebuf+5, datebuf+6);
X
X       return(datebuf);
X}
X
X/*
X * getline - read a line into a dynamically allocated buffer.
X */
Xchar *getline(fp)
XFILE *fp;
X{
X       register int c;
X       register char *str, *str_begin;
X
X       if ((str = malloc(LINESIZE)) == NULL) {
X               printf("digest: out of memory.\n");
X               exit(1);
X       }
X
X       str_begin = str;
X
X       while (((str - str_begin) < (LINESIZE - 1)) &&
X              ((c = getc(fp)) != '\n') && (c != EOF))
X               *str++ = c;
X       *str++ = NULL;
X
X       if (c == EOF)
X               return(NULL);
X
X       return(str_begin);
X}
X
X/*
X * scan_messages - scans through LISTINPUT reading in header fields
X *                and marking the beginning and ending of messages.
X *
X * NOTE: some of the code here depends on the UNIX mail header format.
X *       This format simply guarantees that the first line of a message's
X *      header will be "From blah-blah-blah".  Note there is no colon
X *      (`:') on the "From", the real "From:" line is farther down in
X *      the headers.
X */
Xscan_messages()
X{
X       register long n;
X       register char *s;
X
X       if ((input = fopen(LISTINPUT, "r")) == NULL) {
X               printf("digest: cannot open \"%s\" for reading.\n", LISTINPUT);
X               exit(1);
X       }
X
X       /*
X        * We break out of this from inside.
X        */
X       for (;;) {
X               if (nmessages >= MAXMSGS) {
X                       printf("digest: too many messages.\n");
X                       exit(1);
X               }
X
X               /*
X                * Find the start of the next message.
X                */
X               do {
X                       /*
X                        * If we hit EOF, mark the length of the
X                        * previous message and go back.
X                        */
X                       if ((s = getline(input)) == NULL) {
X                               n = ftell(input);
X                               n = n - messages[nmessages - 1].messageaddr;
X                               messages[nmessages - 1].messagelength = n;
X                               return;
X                       }
X               } while (strncmp(s, "From ", 5) != 0);
X
X               /*
X                * If we have found another message, mark the
X                * length of the previous message.
X                */
X               if (nmessages) {
X                       n = ftell(input);
X                       n = n - (strlen(s) + 1);
X                       n = n - messages[nmessages - 1].messageaddr;
X                       messages[nmessages - 1].messagelength = n;
X               }
X
X               /*
X                * Read in the headers.
X                */
X               for (;;) {
X                       /*
X                        * We shouldn't hit EOF here, we should
X                        * at least finish the headers first.
X                        */
X                       if ((s = getline(input)) == NULL) {
X                               printf("digest: \"%s\": unexpected EOF.\n", 
LISTINPUT);
X                               exit(1);
X                       }
X
X                       /*
X                        * Blank line terminates headers.
X                        */
X                       if (*s == NULL)
X                               break;
X
X                       /*
X                        * Save certain headers.  We strip the
X                        * header name and leading whitespace.
X                        */
X                       if (strncmp(s, "Message-ID:", 11) == 0) {
X                               messages[nmessages].MessageID = 
nospace(safter(s, "Message-ID:"));
X                       }
X                       else if (strncmp(s, "Message-Id:", 11) == 0) {
X                               messages[nmessages].MessageID = 
nospace(safter(s, "Message-Id:"));
X                       }
X                       else if (strncmp(s, "From:", 5) == 0) {
X                               messages[nmessages].From = nospace(safter(s, 
"From:"));
X                       }
X                       else if (strncmp(s, "Newsgroups:", 11) == 0) {
X                               messages[nmessages].ReprintFrom = 
nospace(safter(s, "Newsgroups:"));
X                       }
X                       else if (strncmp(s, "Date:", 5) == 0) {
X                               messages[nmessages].Date = nospace(safter(s, 
"Date:"));
X                       }
X                       else if (strncmp(s, "Subject:", 8) == 0) {
X                               s = nospace(safter(s, "Subject:"));
X
X                               /*
X                                * We don't need the "Re:" stuff.
X                                */
X                               messages[nmessages].use_re = 0;
X                               while ((strncmp(s, "re:", 3) == 0) || 
(strncmp(s, "Re:", 3) == 0) ||
X                                      (strncmp(s, "RE:", 3) == 0) || 
(strncmp(s, "rE:", 3) == 0)) {
X                                       messages[nmessages].use_re = 1;
X                                       s += 3;
X                                       s = nospace(s);
X                               }
X
X                               messages[nmessages].Subject = s;
X                       }
X                       else {
X                               /*
X                                * If we aren't saving this line,
X                                * give the memory back.
X                                */
X                               free(s);
X                       }
X               }
X
X               /*
X                * The message starts after the header.
X                */
X               messages[nmessages].messageaddr = ftell(input);
X               nmessages++;
X       }
X}
X
X/*
X * sort_messages - convert each message's subject line to a string
X *                all in lower case with no whitespace.  Then sort
X *                the messages on this string.  This will group
X *                all the messages on the same subject together.
X */
Xsort_messages()
X{
X       register int i;
X       extern int comp();
X       register char *s, *t;
X
X       for (i=0; i < nmessages; i++) {
X               /*
X                * Skip messages with no subject.
X                */
X               if (messages[i].Subject == NULL)
X                       continue;
X
X               s = messages[i].Subject;
X
X               if ((t = malloc(strlen(s)+1)) == NULL) {
X                       printf("digest: out of memory.\n");
X                       exit(1);
X               }
X
X               messages[i].sortstring = t;
X
X               /*
X                * Zap leading whitespace.
X                */
X               s = nospace(s);
X
X               /*
X                * Copy the subject string into sortstring
X                * converting upper case to lower case and
X                * ignoring whitespace.
X                */
X               while (*s) {
X                       if ((*s == ' ') || (*s == '\t')) {
X                               s++;
X                               continue;
X                       }
X
X                       if (isupper(*s))
X                               *t++ = tolower(*s);
X                       else
X                               *t++ = *s;
X
X                       s++;
X               }
X
X               *t = NULL;
X       }
X
X       /*
X        * Sort 'em.
X        */
X       qsort(messages, nmessages, sizeof(struct message), comp);
X}
X
X/*
X * comp - comparison routine for qsort.  Meassges with no subject go
X *       at the end of the digest, messages with "administrivia" as
X *       the subject go to the top of the digest.
X */
Xcomp(m1, m2)
Xregister struct message *m1, *m2;
X{
X       int admin1, admin2;
X
X       if (m1->sortstring == NULL) {
X               if (m2->sortstring == NULL)
X                       return(0);
X               return(1);              /* no subject messages to end */
X       }
X
X       if (m2->sortstring == NULL)
X               return(-1);             /* no subject messages to end */
X
X       admin1 = strncmp(m1->sortstring, "administrivia", 13);
X       admin2 = strncmp(m2->sortstring, "administrivia", 13);
X
X       if (admin1 == 0) {
X               if (admin2 == 0)
X                       return(0);
X               return(-1);             /* administrivia to beginning */
X       }
X
X       if (admin2 == 0)
X               return(1);              /* administrivia to beginning */
X
X       return(strcmp(m1->sortstring, m2->sortstring));
X}
X
X/*
X * do_digest_header - prints the digest header and mailer headers.
X */
Xdo_digest_header()
X{
X       FILE *fp;
X       char *laststr;
X       char buf[BUFSIZ];
X       char tmp[LINESIZE];
X       extern int comp2();
X       register int i, j, length;
X       char *c;
X
X       if ((output = fopen(LISTOUTPUT, "w")) == NULL) {
X               printf("digest: cannot create \"%s\"\n", LISTOUTPUT);
X               exit(1);
X       }
X
X       digestsize = 0;
X
X       /*
X        * Mailer headers.
X        */
X       sprintf(buf, "Date: %s\n", listinfo.Dateline);
X       digestsize += strlen(buf);
X       fputs(buf, output);
X
X       sprintf(buf, "From: %s\n", listinfo.From);
X       digestsize += strlen(buf);
X       fputs(buf, output);
X
X       sprintf(buf, "Reply-To: %s@%s\n", listinfo.Title, listinfo.Host);
X       digestsize += strlen(buf);
X       fputs(buf, output);
X
X       strcpy (tmp, listinfo.Volline);
X       for (c = tmp; *c != 0 && *c != ':'; c++) ;
X       do { *c-- = 0; } while (c >= tmp && *c == ' ');
X       do { c--; } while (c >= tmp && *c != ' ');
X       c++;
X       digestsize += 9; fputs ("Subject: ", output);
X       sprintf(digestsubject, "%s Digest V%s #%d",
X               listinfo.Title, c, issue_number);
X       digestsize += strlen(digestsubject);
X       fputs(digestsubject, output);
X       digestsize++, putc ('\n', output);
X
X       sprintf(buf, "To: %s\n", listinfo.To);
X       digestsize += strlen(buf);
X       fputs(buf, output);
X
X       /*
X        * The digest header.
X        */
X       sprintf(tmp, "%s Digest", listinfo.Title);
X       sprintf(buf, "\n\n%-*.*s %-*.*s %-*.*s\n\n",
X                               HEAD1, HEAD1, tmp,
X                               HEAD2, DATELEN, listinfo.Dateline,
X                               HEAD3, HEAD3, listinfo.Volline);
X       digestsize += strlen(buf);
X       fputs(buf, output);
X
X       sprintf(buf, "Today's Topics:\n");
X       digestsize += strlen(buf);
X       fputs(buf, output);
X
X       /*
X        * Do today's topics lines.
X        */
X       laststr = "";
X       for (i=0; i < nmessages; i++) {
X               /*
X                * No topic.
X                */
X               if (messages[i].Subject == NULL)
X                       continue;
X
X               laststr = messages[i].sortstring;
X
X               /*
X                * Count the number of messages with this topic.
X                */
X               j = 1;
X               while (((i + j) < nmessages)
X                       && (messages[i+j].sortstring != NULL)
X                       && (strcmp(laststr, messages[i+j].sortstring) == 0))
X                       j++;
X
X               /*
X                * Print the topic centered on the line.
X                */
X               if (j > 1) {
X                       sprintf(tmp, "%s (%d msgs)", messages[i].Subject, j);
X                       length = (LINELEN / 2) + (strlen(tmp) / 2);
X                       sprintf(buf, "%*s\n", length, tmp);
X
X                       /*
X                        * Sort messages with same topic into their
X                        * original arrival order.
X                        */
X                       qsort(&messages[i], j, sizeof(struct message), comp2);
X                       i += (j - 1);
X               }
X               else {
X                       length = (LINELEN / 2) + (strlen(messages[i].Subject) / 
2);
X                       sprintf(buf, "%*s\n", length, messages[i].Subject);
X               }
X
X               digestsize += strlen(buf);
X               fputs(buf, output);
X       }
X
X       /*
X        * Read the LISTHEAD file, if there is one.
X        */
X       if ((fp = fopen(LISTHEAD, "r")) != NULL) {
X               putc('\n', output);
X               digestsize++;
X
X               while (fgets(buf, BUFSIZ, fp) != NULL) {
X                       digestsize += strlen(buf);
X                       fputs(buf, output);
X               }
X
X               fclose(fp);
X               putc('\n', output);
X       }
X
X       /*
X        * Print a line of dashes.
X        */
X       for (i=0; i < LINELEN; i++) {
X               putc('-', output);
X               digestsize++;
X       }
X
X       fputs("\n\n", output);
X       digestsize += 2;
X}
X
X/*
X * comp2 - comparison routine for second qsort.  This one simply compares
X *        messages addresses in the input file, so that we can sort the
X *        messages with the same topic back into the order they arrived.
X */
Xcomp2(m1, m2)
Xregister struct message *m1, *m2;
X{
X       return(m1->messageaddr - m2->messageaddr);
X}
X
X/*
X * read_messages - reads in the message texts and puts them in the
X *                digest with their headers.
X */
Xread_messages()
X{
X       char buf[BUFSIZ];
X       register char *s, *t;
X       register int i, length;
X       int linestart;
X
X       for (i=0; i < nmessages; i++) {
X               /*
X                * Just in case.
X                */
X               clearerr(input);
X
X               /*
X                * Put the message's headers back in.
X                */
X               sprintf(buf, "Date: %s\n", messages[i].Date);
X               digestsize += strlen(buf);
X               fputs(buf, output);
X
X               sprintf(buf, "From: %s\n", messages[i].From);
X               digestsize += strlen(buf);
X               fputs(buf, output);
X
X               if (messages[i].Subject != NULL) {
X                       sprintf(buf, "Subject: %s%s\n",
X                               (messages[i].use_re ? "Re: " : ""),
X                               messages[i].Subject);
X                       digestsize += strlen(buf);
X                       fputs(buf, output);
X               }
X
X               if (messages[i].MessageID != NULL) {
X                       sprintf(buf, "Message-ID: %s\n", messages[i].MessageID);
X                       digestsize += strlen(buf);
X                       fputs(buf, output);
X               }
X
X               if (messages[i].ReprintFrom != NULL) {
X                   sprintf (buf, "\nReprintFrom: %s\n", 
messages[i].ReprintFrom);
X                   digestsize += strlen(buf);
X                   fputs (buf, output);
X               }
X
X               putc ('\n', output); digestsize++;
X
X               /*
X                * Read the message into memory.  This is
X                * so we can zap extra blank lines.
X                */
X               fseek(input, messages[i].messageaddr, 0);
X               length = messages[i].messagelength;
X
X               if ((s = malloc(length+1)) == NULL) {
X                       printf("digest: out of memory.\n");
X                       exit(1);
X               }
X
X               fread(s, 1, length, input);
X
X               /*
X                * Zap trailing newlines.
X                */
X               t = s + length;
X               while (length > 0 && *--t == '\n')
X                       length--;
X               *++t = NULL;
X               
X               /*
X                * Zap leading newlines.
X                */
X               t = s;
X               while (*t++ == '\n')
X                       length--;
X               t--;
X
X               /*
X                * Write the message.
X                *
X                * In any line which begins with 30 or more hyphens,
X                * change the first hyphen to a space, to avoid a clash
X                * with the message separator string.
X                */
X               digestsize += length;
X               /* fwrite(t, 1, length, output); */
X               linestart = 1;
X               while (length-- > 0) {
X                       if (linestart &&
X                           strncmp(t,"------------------------------",30) == 0)
X                               linestart = 0, t++, putc (' ', output);
X                       else {
X                               linestart = (*t == '\n');
X                               putc (*t++, output);
X                       }
X               }
X
X               sprintf(buf, "\n\n------------------------------\n\n");
X               digestsize += strlen(buf);
X               fputs(buf, output);
X               free(s);
X       }
X
X       /*
X        * All done.
X        */
X       sprintf(buf, "End of %s\n******************************",
X               digestsubject);
X       digestsize += strlen(buf);
X       fputs(buf, output);
X       for (i = strlen (digestsubject) + 7; i > 30; i--)
X           digestsize++, putc ('*', output);
X       digestsize++, putc ('\n', output);
X       fclose(output);
X       fclose(input);
X}
X
X/*
X * put_list_info - rewrite the LISTINFO file with the new data.
X */
Xput_list_info()
X{
X       FILE *fp;
X       char tmp[LINESIZE];
X
X       sprintf(tmp, "%s.old", LISTINFO);
X
X       if (rename(LISTINFO, tmp) < 0) {
X               printf("digest: cannot move old \"%s\" file, today's data 
lost.\n", LISTINFO);
X               return;
X       }
X
X       if ((fp = fopen(LISTINFO, "w")) == NULL) {
X               printf("digest: cannot create \"%s\", today's data lost.\n", 
LISTINFO);
X               return;
X       }
X
X       fprintf(fp, "%s\n", listinfo.Title);
X       fprintf(fp, "%s\n", listinfo.Host);
X       fprintf(fp, "%s\n", listinfo.From);
X       fprintf(fp, "%s\n", listinfo.To);
X       fprintf(fp, "%s\n", listinfo.Volline);
X       fprintf(fp, "%s\n", listinfo.Dateline);
X
X       fclose(fp);
X       unlink(tmp);
X}
X
X/*
X * safter - return a pointer to the position in str which follows pat.
X */
Xchar *safter(str, pat)
Xregister char *str, *pat;
X{
X       register int len;
X
X       len = strlen(pat);
X
X       while (*str) {
X               if (strncmp(str, pat, len) == 0) {
X                       str += len;
X                       return(str);
X               }
X
X               str++;
X       }
X
X       return(NULL);
X}
X
X/*
X * nospace - advance s over leading whitespace, return new value.
X */
Xchar *nospace(s)
Xregister char *s;
X{
X       while ((*s != NULL) && ((*s == ' ') || (*s == '\t')))
X               s++;
X
X       return(s);
X}
X
END_OF_FILE
if test 20528 -ne `wc -c <'MailServ/src/orig-dig/digest.c'`; then
    echo shar: \"'MailServ/src/orig-dig/digest.c'\" unpacked with wrong size!
fi
# end of 'MailServ/src/orig-dig/digest.c'
fi
if test -f 'MailServ/src/orig-dig/undigest.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file 
\"'MailServ/src/orig-dig/undigest.c'\"
else
echo shar: Extracting \"'MailServ/src/orig-dig/undigest.c'\" \(10974 
characters\)
sed "s/^X//" >'MailServ/src/orig-dig/undigest.c' <<'END_OF_FILE'
X/*
X * UNDIGEST
X *
X *     A filter program to split "digest" messages (formatted according
X *     to the de-facto standard, RFC 1153) into their component parts.
X *
X *     (C) Copyright 1991, 1992 Richard B. Wales.  All Rights Reserved.
X *     Permission is granted to use this program for any purpose, so
X *     long as this copyright notice is retained intact, this original
X *     source code (or a modified source with the changes clearly indi-
X *     cated as such) is included as part of any distribution, and no
X *     fee (other than a nominal communications charge) is assessed.
X *
X * DESCRIPTION
X *
X *     This program reads the standard input and writes to the standard
X *     output.  Or, when invoked with a "-d" flag and a user name, it
X *     reads from the standard input and appends its output to the
X *     user's incoming mailbox file in /usr/spool/mail.
X *
X *     The input is expected to be in the UNIX-style mailbox format
X *     (with a "From " line at the start of every message).  Messages
X *     which are not in "digest" format are copied to the standard
X *     output without change.  Digests are split into their component
X *     messages on the standard output.
X *
X *     The "From " line delimiter from the original digest message is
X *     copied unchanged to the start of each component message.  Also,
X *     any "Status:" line in the original header is copied unchanged to
X *     each component message -- replacing any "Status:" line which may
X *     already exist in a component message.
X *
X *     The "To:" line from the original digest message is added to each
X *     component message.  No attempt is made to delete an existing
X *     "To:" line in a component (though ordinarily there will be none).
X *
X *     An "X-Digest:" header line is added to each component message.
X *     This line repeats the "Subject:" information from the digest
X *     header.
X *
X *     When invoked with the "-d" option, the standard UNIX mailbox
X *     locking and "comsat" (asynchronous mail notification) procedures
X *     are adhered to.  Thus, this program may safely be used as a mail
X *     filter in a user's ".forward" file.  For example, the author's
X *     ".forward" file looks like this:
X *
X *                 "| /valeria/wales/bin/undigest -d wales"
X *
X *     This program has been successfully compiled and tested under the
X *     SunOS 4.1.1 operating system and "cc" compiler.  It may require
X *     modification to work in other environments.
X *
X * THINGS TO DO
X *
X *     Extra blank lines seem to get added to the ends of the component
X *     messages within a digest.  It would be nice to fix this.
X *
X *     The user interface could (should?) be changed to make delivery
X *     ("-d username") mode the default.
X */
X
X#include <stdio.h>
X#include <sys/file.h>
X#include <sys/errno.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X
X/*
X * Digest header info, to be inserted into component messages.
X */
X#define LINELEN 1024                   /* hopefully adequate */
Xchar   D_unixfrom[LINELEN];            /* "From " line */
Xchar   D_to[LINELEN];                  /* "To:" line */
Xchar   D_xdigest[LINELEN];             /* "X-Digest:" line */
Xchar   D_status[LINELEN];              /* "Status:" line */
X
X/*
X * Digest processing status flag.
X */
X#define FIRST_LINE     0               /* first line of input */
X#define NON_DIGEST_HDR 1               /* non-digest (header) */
X#define NON_DIGEST_BODY 2              /* non-digest (body) */
X#define DIGEST_PREAMBLE 3              /* digest (preamble) */
X#define END_PREAMBLE   4               /* end of preamble seen */
X#define COMPONENT_HDR  5               /* component message (header) */
X#define COMPONENT_BODY 6               /* component message (body) */
X#define END_COMPONENT  7               /* end of component seen */
Xint    state;
X
X
X/*
X * Read a line of up to "len-1" characters into a buffer.  The newline
X * character at the end of the line is discarded, and the line is ter-
X * minated by a null character.
X *
X * This routine will end up inserting extra newlines if the incoming
X * text contains null characters or overly long lines.
X */
Xint
Xgetline (buf, len)
X    register char *buf;
X    register int len;
X{   register int ch;
X
X    if ((ch = getchar ()) == EOF) return -1;
X    while (--len > 0 && ch != '\n' && ch != EOF && ch != 0)
X    {  *buf++ = ch;
X       ch = getchar ();
X    }
X    if (len <= 0) ungetc (ch, stdin);
X    *buf = 0;
X    return 0;
X}
X
X
X/*
X * Compare two strings in case-independent fashion.
X * Same as "strncasecmp", which doesn't seem to exist on the Suns.
X */
Xint
Xcstrncmp (s1, s2, len)
X    register char *s1, *s2;
X    register int len;
X{   register int n1, n2;
X
X    while (len-- > 0)
X    {  n1 = *s1++; n2 = *s2++;
X       if (n1 == 0 && n2 == 0) return 0;
X       if (n1 >= 'A' && n1 <= 'Z') n1 -= 'A' - 'a';
X       if (n2 >= 'A' && n2 <= 'Z') n2 -= 'A' - 'a';
X       if (n1 != n2) return n1 - n2;
X    }
X    return 0;
X}
X
X/*
X * Output a null-terminated line, plus a newline.
X */
Xputline (buf)
X    register char *buf;
X{   register int ch;
X
X    while ((ch = *buf++) != 0) putchar (ch);
X    putchar ('\n');
X}
X
X/*
X * Send a message to the "comsat" daemon (asynchronous notification of
X * new mail).  This routine was copied intact from /bin/mail.
X */
Xnotifybiff (msg)
X       register char *msg;
X{   static struct sockaddr_in addr;
X    static int f = -1;
X
X    if (addr.sin_family == 0)
X    {  addr.sin_family = AF_INET;
X       addr.sin_addr.s_addr = INADDR_ANY;
X       addr.sin_port = htons(IPPORT_BIFFUDP);
X    }
X    if (f < 0)
X       f = socket(AF_INET, SOCK_DGRAM, 0);
X    sendto (f, msg, strlen (msg)+1, 0, &addr, sizeof (addr));
X}
X
X
Xmain (argc, argv)
X    int argc;
X    char **argv;
X{   register int n;
X    register char *c;
X    static char buffer[LINELEN];
X    char biffinfo[20];
X    int delivery;
X
X    /* Initialization. */
X    state         = NON_DIGEST_HDR;
X    D_unixfrom[0] = 0;
X    D_to[0]       = 0;
X    D_xdigest[0]  = 0;
X    D_status[0]   = 0;
X    delivery      = 0;
X    biffinfo[0]   = 0;
X
X    /*
X     * See if there is a "-d" flag (delivery mode).
X     * An additional argument after "-d" gives the output file name;
X     * or, if it doesn't begin with a slash, the name of the recipient
X     * (with an output file in the directory "/usr/spool/mail").
X     */
X    if (argc >= 2 && strcmp (argv[1], "-d") == 0)
X    {  delivery = 1;
X       state = FIRST_LINE;
X       if (argc >= 3)
X       {   if (argv[2][0] != '/')
X           {   strcpy (buffer, "/usr/spool/mail/");
X               strcat (buffer, argv[2]);
X               strncpy (biffinfo, argv[2], 8);
X               biffinfo[8] = 0;
X               argv[2] = buffer;
X           }
X           freopen (argv[2], "a", stdout);
X           while (flock (1, LOCK_EX) == EWOULDBLOCK) sleep (5);
X           fseek (stdout, 0L, 2);
X    }  }
X
X    /*
X     * Save the necessary information so the user can be notified of
X     * the new mail's arrival later on via the "comsat" mechanism.
X     */
X    if (biffinfo[0] != 0)
X       sprintf (biffinfo + strlen (biffinfo),
X                "@%ld\n", ftell (stdout));
X
X    /* Process the input. */
X    while (getline (buffer, sizeof buffer) == 0)
X    {  /*
X        * A UNIX-style "From " line signals a new message.  Save a
X        * copy of the line for possible use before component messages
X        * of a digest.  In "delivery" mode, conceal a "From " line in
X        * the body of the message by prepending a ">" to the line.
X        */
X       if (strncmp (buffer, "From ", 5) == 0)
X       {   if (!delivery || state == FIRST_LINE)
X           {   strcpy (D_unixfrom, buffer);
X               putline (buffer);
X               D_to[0] = 0;
X               D_xdigest[0] = 0;
X               D_status[0] = 0;
X               state = NON_DIGEST_HDR;
X           }
X           else
X           {   putchar ('>');
X               putline (buffer);
X           }
X           continue;
X       }
X
X       /*
X        * In "delivery" mode, if a line begins with one or more ">"s
X        * followed by "From ", prepend another ">".
X        */
X       if (delivery && buffer[0] == '>')
X       {   for (c = buffer; *c == '>'; c++) ;
X           if (strncmp (c, "From ", 5) == 0)
X           {   putchar ('>');
X               putline (buffer);
X               continue;
X       }   }
X
X       /*
X        * An empty line -- or a line beginning with asterisks or the
X        * words "End of" -- is ignored at the end of a digest preamble
X        * or a component of a digest.  Any other kind of line signals
X        * the start of a new digest component.
X        */
X       if (state == END_PREAMBLE || state == END_COMPONENT)
X       {   if (buffer[0] == 0
X               || cstrncmp (buffer, "End of ", 7) == 0
X               || strncmp (buffer, "*******", 7) == 0)
X               continue;
X           state = COMPONENT_HDR;
X           putchar ('\n');
X           putline (D_unixfrom);
X           /* keep going -- no "continue;" here */
X       }
X
X       /*
X        * A "Subject:", "To:", or "Status:" line in the header is
X        * saved for possible future use in splitting up a digest.  In
X        * the case of the "Subject:" line, the keyword is replaced
X        * with the new keyword "X-Digest:".
X        *
X        * An empty line signals the end of the header; and the subject
X        * line is examined to see if this is a digest.
X        */
X       if (state == NON_DIGEST_HDR)
X       {   if (cstrncmp (buffer, "Subject:", 8) == 0)
X           {   for (c = buffer+8; *c == ' ' || *c == '\t'; c++) ;
X               /* note that new keyword is longer than old one */
X               buffer[sizeof buffer - 3] = 0;
X               strcpy (D_xdigest, "X-Digest: ");
X               strcpy (D_xdigest + 10, c);
X           }
X           else if (cstrncmp (buffer, "To:", 3) == 0)
X           {   strcpy (D_to, buffer);
X           }
X           else if (cstrncmp (buffer, "Status:", 7) == 0)
X           {   strcpy (D_status, buffer);
X           }
X           else if (buffer[0] == 0)
X           {   /* is the second word in the line "Digest"? */
X               c = D_xdigest + 10;
X               while (*c == ' ' || *c == '\t') c++;
X               while (*c != 0 && *c != ' ' && *c != '\t') c++;
X               while (*c == ' ' || *c == '\t') c++;
X               if (cstrncmp (c, "Digest ", 7) == 0)
X                    state = DIGEST_PREAMBLE;
X               else state = NON_DIGEST_BODY;
X           }
X           putline (buffer);
X           continue;
X       }
X
X       /*
X        * The body of a non-digest message is simply passed through.
X        */
X       if (state == NON_DIGEST_BODY)
X       {   putline (buffer);
X           continue;
X       }
X
X       /*
X        * The digest preamble is passed through, until it is ended by
X        * a line consisting of exactly 70 hyphens.
X        */
X       if (state == DIGEST_PREAMBLE)
X       {   for (n = 70, c = buffer; n > 0 && *c == '-'; n--, c++) ;
X           if (n != 0 || *c != 0) putline (buffer);
X           else                   state = END_PREAMBLE;
X           continue;
X       }
X
X       /*
X        * A header line in a digest component is passed through,
X        * except that any "Status:" line is deleted.  After the
X        * end of the component header, a "To:", "X-Digest:", and
X        * "Status:" line are added.
X        */
X       if (state == COMPONENT_HDR)
X       {   if (buffer[0] == 0)
X           {   if (D_to[0] != 0) putline (D_to);
X               putline (D_xdigest);
X               if (D_status[0] != 0) putline (D_status);
X               putchar ('\n');
X               state = COMPONENT_BODY;
X           }
X           else if (cstrncmp (buffer, "Status:", 7) != 0)
X               putline (buffer);
X           continue;
X       }
X
X       /*
X        * The component body is passed through, until it is ended by
X        * a line consisting of exactly 30 hyphens.
X        */
X       if (state == COMPONENT_BODY)
X       {   for (n = 30, c = buffer; n > 0 && *c == '-'; n--, c++) ;
X           if (n != 0 || *c != 0) putline (buffer);
X           else                   state = END_COMPONENT;
X           continue;
X       }
X
X       /*NOTREACHED*/
X    }
X
X    /* Windup. */
X    if (delivery) putchar ('\n');      /* just to be sure */
X
X    /* Use the "comsat" facility to notify the mail's recipient. */
X    notifybiff (biffinfo);
X
X    /* All done. */
X    exit (0);
X}
END_OF_FILE
if test 10974 -ne `wc -c <'MailServ/src/orig-dig/undigest.c'`; then
    echo shar: \"'MailServ/src/orig-dig/undigest.c'\" unpacked with wrong size!
fi
# end of 'MailServ/src/orig-dig/undigest.c'
fi
echo shar: End of shell archive.
exit 0

-- 
Dave  ddebry@ debry@   \ "All right.  I'll get your money for you.  But
DeBry dsd.    peruvian. | if you don't get the President of the United
      es.     cs.utah.  | States on the phone, you're going to have to
      com     edu      /  answer to the Coca-Cola company."

--
Bill                                    1st>    Broadley@neurocog.lrdc.pitt.edu
Broadley@schneider3.lrdc.pitt.edu <2nd  3rd>                 Broadley+@pitt.edu
Linux is great.         Bike to live, live to bike.                      PGP-ok


 

<Prev in Thread] Current Thread [Next in Thread>
  • (fwd) MailServ 1.1.0, Bill Broadley <=