[comp.sources.misc] v09i006: pc-mail over nfs

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (11/27/89)

Posting-number: Volume 9, Issue 6
Submitted-by: wietse@wzv.win.tue.nl (Wietse Z. Venema)
Archive-name: pc-mail-nfs

This is an extension to the pc-mail package (uucp mail for pc's) that
appeared in comp.sources.misc, april 1988.  It is intended for an
environment where pc-mail users mount their personal mail directories
from a file server.  The programs in the present package run on the file
server.  They directly access the per-user pc-mail directories and thus
replace the UUCP file transfer functions of the pc-mail software.  The
programs were tested with SunOS 4.0.3 and Microport System-V/AT 2.3.
This software is in the public domain.

	Wietse Venema (wswietse@lso.win.tue.nl)

#! /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:  README pc-mail.c pc-maild.c Makefile sysexits.h syslog.h
#   syslog.c util.c util.h mtime.c mtime.h dosunix.c dosunix.h
#   percentm.h percentm.c pc-mail.8 pc-maild.8
# Wrapped by wietse@wzv on Sun Nov 19 14:01:07 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(6589 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X@(#) README 1.6 11/19/89 14:00:51
X
XThis is an extension to the pc-mail package (uucp mail for pc's) that
Xappeared in comp.sources.misc, april 1988.  It is intended for an
Xenvironment where pc-mail users mount their personal mail directories
Xfrom a file server.  The programs in the present package run on the file
Xserver.  They directly access the per-user pc-mail directories and thus
Xreplace the UUCP file transfer functions of the pc-mail software.  The
Xprograms were tested with SunOS 4.0.3 and Microport System-V/AT 2.3.
XThis software is in the public domain.
X
XPlease report any problems etc.  to the author (Wietse Venema) via one
Xof the following e-mail addresses:
X
X	wswietse@lso.win.tue.nl
X	wswietse@heitue5.bitnet
X
XThe remainder of this document describes the operation of the software,
Xhow to install the software, how to add new users, and how to migrate
Xusers from pc-mail over UUCP to pc-mail over PC-NFS.
X
XOperation
X=========
X
XThe UUCP file transfer functions of the pc-mail "cico.exe" program are
Xtaken over by the following two programs that run on the file server:
X
Xpc-mail:	deliver mail to a user's mail directory (the receiving
X		function of the "cico.exe" program). This program is 
X		intended to be called by sendmail.
X
Xpc-maild:	scan user mail directories for unsent mail, and pipe it 
X		through the UNIX rmail command (the sending function of 
X		the "cico.exe" program).
X
XInstallation on the server
X==========================
X
XBuild the pc-mail and pc-maild programs. In the Makefile, you can
Xdefine the location of the executable programs and the pc-mail spool
Xarea, and how often the daemon program will scan user directories for
Xunsent mail. You will probably have to do `make depend' before you
Xcan compile the programs.
X
XExecute the following command to create a pc-mail spool area, and
Xinstall the pc-mail and pc-maild programs.  You must be root.
X
X    % make install
X
XThe output from the "make" command will depend on how you specified the
Xpath names in the Makefile:
X
X    mkdir /var/spool/pc-mail
X    chmod 755 /var/spool/pc-mail
X    cp pc-mail pc-maild /usr/local/lib
X    chown root /usr/local/lib/pc-mail
X    chmod u+s /usr/local/lib/pc-mail
X
XExecute the following command to install the manual pages, if you want
Xto. 
X
X    % make installman
X
XAgain, output from make will depend on what you specified in the
XMakefile:
X
X    cp pc-mail.8 pc-maild.8 /usr/local/man/man8
X
XAdd a line with the command
X
X    /usr/local/lib/pc-maild
X
Xto the file /etc/rc.local (the exact name of the rc script depends on
Xyour version of unix, and the exact path name of the pc-maild program
Xdepends on where you installed it).
X
XFor now, you will have to start the pc-maild program by hand (unless
Xyou wish to reboot the machine).
X
XAdd to the sendmail.cf file a line that looks like:
X
X    Mpc,	P=/usr/local/lib/pc-mail, F=lsDFMn, S=xxx, R=yyy, A=pc-mail $u
X
XWhere xxx and yyy may be the same rewriting rules as used for the local
Xmailer (usually defined with the "Mlocal" line).
X
XIn sendmail.cf, at the end of ruleset S0, just before the local mailer
Xwill be invoked (something like "R$*	$#local $:$1"), add a line with
X
X    R $=X			$#pc $:$1
X
XUse a different letter if X is already in use.  A later section
Xdescribes how to convince sendmail that X is a list of login names of
Xpc-mail users.
X
XAdding users (server side)
X==========================
X
XAdd the user to the password data base.  In the spool area on the
Xserver, create a subdirectory for the pc-mail user.  The directory must
Xbe owned by that user; for reasons of privacy, mode 0700 is recommended.
XIn the following example, replace username by the actual login name of
Xthe user.
X
X    % mkdir /var/spool/pc-mail/username
X    % chown username /var/spool/pc-mail/username
X    % chmod 700 /var/spool/pc-mail/username
X
XAdding users (pc side)
X======================
X
XOn the pc, adjust the AUTOEXEC.BAT, NETWORK.BAT or DRIVES.BAT files so
Xthat they contain the following commands (replacing server by the name
Xof the NFS server host, and replacing username by the login name of the
Xactual user):
X
X    net name username *
X    net use m: \\server\var\spool\pc-mail\username
X    set MAILDIR=m:\
X
XThe trailing \ is needed on the last command, or the mail program will
Xcomplain that it "cannot access some essential data files".
X
XIf the user had a UUCP-based pc-mail link, you can now remove the -p
Xoption from any CMAIL commands that may appear in batch files.
X
XReboot the pc.
X
XIf the user had a UUCP-based pc-mail link, copy the contents of the
Xuser's LOCAL mail directory to the REMOTE mail directory on the file
Xserver.  From now on the local mail directory will no longer be needed.
X
XTest if the mail program works by creating a small mail message. Since
Xthe message will automatically be picked up by the pc-maild program the
Xfiles may disappear before you had a chance to type a DIR command!
X
XAdding users (server side again)
X================================
X
XAdd the user to the list of NFS pc-mail users.  There are two ways to
Xaccomplish the same result. The list of users can be hardcoded in the
Xsendmail.cf file, e.g.:
X
X    CXjohn marsha
X
XMultiple usernames on a line, and multiple CX lines are allowed.  A
Xbetter way is to have sendmail read the list from an external file,
Xby putting the following line into the sendmail.cf file:
X
X    FX/etc/pc-mail-users %s
X
XThe /etc/pc-mail-users file should contain only a single login name per
Xline.
X
XKill the sendmail daemon and restart it.
X
XIf the user had a UUCP-based pc-mail connection, you can now get rid of
Xaliases that were needed for UUCP support.
X
XNote that the sendmail ON THE NFS SERVER will not read the user's
X.forward file.  The file will still be useful, however, if the user's
Xhome directory is exported to OTHER hosts running sendmail.  In that
Xcase you will want to create a .forward file in the user's home
Xdirectory containing
X
X	username@fully-qualified-hostname
X
XAdding users (pc side again)
X============================
X
XThis step can be skipped if the user had no UUCP-based pc-mail connection.
X
XIf the user used to have a UUCP connection, pick up any mail that still
Xresides in the UUCP spool area on the file server (the mail will now be
Xstored in the user's private remote mail directory through the miracles
Xof NFS). 
X
XAt this point the cico.exe program has become obsolete. You may consider
Xto replace it by a small C program that does nothing.
X
XAdding users (server side again)
X================================
X
XThis step can be skipped if the user had no UUCP-based pc-mail connection.
X
XThe user's uucp login can be removed from the password file.
END_OF_FILE
if test 6589 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'pc-mail.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pc-mail.c'\"
else
echo shar: Extracting \"'pc-mail.c'\" \(10884 characters\)
sed "s/^X//" >'pc-mail.c' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	pc-mail 8
X/* SUMMARY
X/*	deliver mail to nfs-based pc-mail users
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	pc-mail user
X/* DESCRIPTION
X/*	This program is to be run on the nfs server that exports mail
X/*	directories to MS-DOS pc-mail users. The program replaces the
X/*	UNIX -> MS-DOS file transfer function of the MS-DOS \fIcico\fR
X/*	program.
X/*
X/*	Normally, the pc-mail delivery program is invoked by sendmail(8).
X/*	Its purpose is to deliver new mail in the mail directory of the
X/*	specified \fIuser\fR (default /var/spool/pc-mail/\fIuser\fR).
X/*	Any error conditions detected by the pc-mail delivery program
X/*	are reported back in a sendmail-compatible manner.
X/*
X/*	This program must be run with root privileges. It will assume
X/*	the (uid, gid) of the specified user before delivering mail.
X/*
X/*	The program attempts to create any missing directories, and to
X/*	correct ownerships or protections where needed.
X/* FILES
X/*	/usr/spool/pc-mail/\fIuser\fR/nNNNNN, mail message.
X/*	/usr/spool/pc-mail/\fIuser\fR/hNNNNN, sender of message.
X/*	(NNNNN is the pc-mail "message id").
X/* SEE ALSO
X/*	pc-maild(1)
X/* DIAGNOSTICS
X/*	All conceivable error conditions cause the program to terminate
X/*	with a non-zero exit status, after printing an error message on
X/*	the standard error stream, and appending an entry to the system log.
X/*	See <sysexits.h> for details.
X/* BUGS
X/*	There is no way to notify a pc-mail user of the arrival of new mail.
X/* AUTHOR(S)
X/*	W.Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 22 18:00:53 MED 1989
X/* LAST MODIFICATION
X/*	11/19/89 13:46:04
X/* VERSION/RELEASE
X/*	1.2
X/*--*/
X
X#ifndef lint
Xstatic char sccsid[] = "@(#) pc-mail.c 1.2 11/19/89 13:46:04";
X
X#endif
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <pwd.h>
X#include <varargs.h>
X
X#ifdef SYSLOG
X#include <syslog.h>
X#else
X#include "syslog.h"
X#endif
X
X#ifdef SYSV
X#include <ndir.h>
X#else
X#include <sys/dir.h>
X#endif
X
X#ifdef	SYSEXITS
X#include <sysexits.h>
X#else
X#include "sysexits.h"
X#endif
X
X#include "dosunix.h"
X#include "percentm.h"
X
X/* Stuff related to failed system calls */
X
Xextern int errno;
X
X/* External functions */
X
Xextern struct passwd *getpwnam();
Xextern long time();
Xextern char *mktemp();
Xextern void exit();
Xextern unsigned sleep();
X
X/* Local declarations */
X
X#ifndef	MAILDIR
X#define	MAILDIR	"/usr/spool/pc-mail"	/* pc-mail directory tree */
X#endif
X
X#define	LOCK	"pc-mail.lck"		/* the lock file */
X#define	STALE	1800			/* max age of lock file */
X#define	MAXTRY	60			/* max retry count for lock creation */
X#define	MSGFIL_FMT	"n%05d"		/* message file name format */
X#define	SNDFIL_FMT	"h%05d"		/* sender file name format */
X
Xchar    template[] = "pc.XXXXXX";	/* template lock file */
X
X/* local functions */
X
Xvoid    sender();
Xvoid    message();
Xvoid    error();
X
Xchar   *progname;
X
Xmain(argc, argv)
Xint     argc;
Xchar  **argv;
X{
X    struct passwd *pwd;
X    static char userdir[BUFSIZ];
X    int     seqno;
X
X    progname = argv[0];
X
X    /* Garbage in, garbage out */
X
X    if (argc != 2)
X	error(EX_USAGE, "usage: %s user", *argv);
X
X#ifndef DEBUG
X    if (geteuid() != 0)
X	error(EX_USAGE, "must run with root privileges");
X
X    /* need this for SYSVR2 or mkdir(1) fails */
X#ifdef SYSV
X    if (setuid(0) != 0)
X	error(EX_OSERR, "cannot setuid(0)");
X#endif
X#endif
X
X    if ((pwd = getpwnam(argv[1])) == 0)
X	error(EX_NOUSER, "unknown user: %s", argv[1]);
X
X    /* Setup a somewhat safe environment */
X
X    if (putenv("PATH=/bin:/usr/bin:/usr/ucb")
X	|| putenv("IFS= \t\n"))
X	error(EX_TEMPFAIL, "putenv() failed");
X
X    /* Check the necessary directories exist */
X
X    (void) sprintf(userdir, "%s/%s", MAILDIR, argv[1]);
X    checkdir(userdir, pwd->pw_uid, pwd->pw_gid, 0700);
X
X    /* Now with that out of the way, try to deliver the message */
X
X    if (setgid(pwd->pw_gid))
X	error(EX_USAGE, "setgid(%s) failed: %m", argv[1]);
X    if (setuid(pwd->pw_uid))
X	error(EX_USAGE, "setuid(%s) failed: %m", argv[1]);
X
X    /* make sure the user mail directory is accessible */
X
X    if (chdir(userdir))
X	error(EX_TEMPFAIL, "can't access mail directory %s", userdir);
X
X    /* deliver mail */
X
X    seqno = newseqno(userdir);			/* Allocate sequence number */
X    message(pwd, seqno);			/* Create message file */
X    sender(seqno);				/* Create metafile (sender) */
X    exit(EX_OK);				/* Done. */
X    /* NOTREACHED */
X}
X
X/* message - write message file */
X
Xvoid    message(pwd, seqno)
Xstruct passwd *pwd;
Xint     seqno;
X{
X    static char buf[BUFSIZ];
X    register FILE *fp;
X
X    /* Create the message file */
X
X    (void) sprintf(buf, MSGFIL_FMT, seqno);
X    if ((fp = fopen(buf, "w")) == 0)
X	error(EX_CANTCREAT, "create error for file %s/%s: %m",
X	      pwd->pw_name, buf);
X    if (unix2dos(stdin, fp)) {
X	(void) unlink(buf);
X	error(EX_CANTCREAT, "write error for file %s/%s: %m",
X	      pwd->pw_name, buf);
X    }
X    (void) fclose(fp);
X    (void) chmod(buf, 0400);			/* Avoid tampering */
X}
X
X/* sender - extract sender from message */
X
Xvoid    sender(seqno)
Xint     seqno;
X{
X    register FILE *ifp;
X    register FILE *ofp;
X    static char fname[BUFSIZ];		/* file names */
X    static char line[BUFSIZ];		/* read buffer */
X    static char from[BUFSIZ] = "unknown";	/* sender */
X
X    /*
X     * Try to open the message file; if that fails, let the pc software scan
X     * for the sender at a later time.
X     * 
X     * We recognize the following From line formats:
X     *
X     * From name
X     * 
X     * >From name
X     * 
X     * From: address (full name)
X     * 
X     * From: full name <address>
X     * 
X     * From: full name
X     */
X
X    (void) sprintf(fname, MSGFIL_FMT, seqno);
X    if ((ifp = fopen(fname, "r")) == 0)
X	return;
X
X    /* Extract sender from message */
X
X    while (dosgets(line, sizeof(line), ifp) && *line) {
X	if (sscanf(line, "From: %*s ( %[^)] )", from) == 1)
X	    break;
X	if (sscanf(line, "From: %[^<]", from) == 1)
X	    break;
X	sscanf(line, "%*[>] From %s", from) || sscanf(line, "From %s", from);
X    }
X    (void) fclose(ifp);
X
X    /*
X     * Try to create the meta file; if that fails, let the pc software try
X     * again at a later time.
X     */
X
X    (void) sprintf(fname, SNDFIL_FMT, seqno);
X    if (ofp = fopen(fname, "w")) {
X	(void) fprintf(ofp, "%s\r\n", from);
X	if (fflush(ofp) || ferror(ofp) || feof(ofp) || fclose(ofp)) {
X	    (void) unlink(fname);
X	} else {
X	    (void) chmod(fname, 0400);		/* avoid tampering */
X	}
X    }
X}
X
X/* newseqno - allocate new message sequence number */
X
Xint     newseqno(userdir)
Xchar   *userdir;
X{
X    register DIR *dd;
X    register struct direct *p;
X    struct stat st;
X    register int seqno = 0;
X    int     tmp = 0;
X    int     i;
X    char    junk;
X
X    /*
X     * When the pc adds a file to the "mail data base", the file name is
X     * composed of a single letter and a unique sequence number. The pc
X     * chooses a new sequence number by adding one to the highest existing
X     * sequence number.
X     * 
X     * Now that the pc mounts its mail directory from the nfs server we must
X     * avoid possible concurrency conflicts when both pc and file server try
X     * to update the "mail data base".
X     * 
X     * Since the pc does not know about concurrent access from the nfs server,
X     * the server has to add 2 to the highest existing message sequence
X     * number, in order to avoid conflicts. Fortunately, only one pc at a
X     * time will be accessing a mail directory of a particular user.
X     * 
X     * Further concurrency conflicts are be avoided on the server side by using
X     * lock files.
X     * 
X     * If we cannot create a lock file right now, we back off and let sendmail
X     * try again later.
X     */
X
X    /* Get rid of stale lock files */
X
X    if (stat(LOCK, &st) == 0 && st.st_mtime < time((long *) 0) - STALE)
X	(void) unlink(LOCK);
X
X    /* Wait until we can create the lock file */
X
X    if (creat(mktemp(template), 0400) < 0)
X	error(EX_TEMPFAIL, "cannot set lock in directory %s: check ownership",
X	      userdir);
X    for (i = 0; link(template, LOCK) && i < MAXTRY; i++)
X	(void) sleep(1);
X    (void) unlink(template);
X    if (i >= MAXTRY)
X	error(EX_TEMPFAIL, "locked: %s", userdir);
X
X    /* Scan the user mail directory for the highest existing message number */
X
X    if ((dd = opendir(userdir)) == 0) {
X	(void) unlink(LOCK);
X	error(EX_TEMPFAIL, "opendir(\"%s\") failed: %m", userdir);
X    }
X    while (p = readdir(dd)) {
X	if (sscanf(p->d_name + 1, "%d%c", &tmp, &junk) == 1 && tmp > seqno)
X	    seqno = tmp;
X    }
X
X    /* clean up and terminate */
X
X    closedir(dd);
X    (void) unlink(LOCK);
X    return (seqno + 2);
X}
X
X/* checkdir - check/update presence/ownership/protection of directory */
X
Xcheckdir(path, uid, gid, mode)
Xchar   *path;
Xint     uid;
Xint     gid;
Xint     mode;
X{
X    struct stat st;
X
X    /*
X     * If a user mail directory does not exist, try to create it. Otherwise,
X     * make sure it has sane permissions
X     */
X
X    if (stat(path, &st) == -1) {		/* no directory */
X	if (mkdir(path, mode))			/* try to create it */
X	    error(EX_TEMPFAIL, "cannot create directory %s: %m", path);
X	if (chown(path, uid, gid))		/* set owner, group */
X	    error(EX_TEMPFAIL, "cannot chown directory %s: %m", path);
X    } else {					/* directory exists */
X	if ((st.st_mode & S_IFMT) != S_IFDIR)	/* must be directory! */
X	    error(EX_TEMPFAIL, "%s should be a directory", path);
X	if ((st.st_uid != uid || st.st_gid != gid)	/* check owner/group */
X	    &&chown(path, uid, gid))		/* correct owner, group */
X	    error(EX_TEMPFAIL, "cannot chown directory %s: %m", path);
X	if ((st.st_mode & 0777) != mode		/* check permissions */
X	    && chmod(path, mode))		/* correct permissions */
X	    error(EX_TEMPFAIL, "cannot chmod %o directory %s: %m", mode, path);
X    }
X}
X
X/* error - print diagnostic and terminate */
X
X/* VARARGS */
X
Xvoid    error(va_alist) va_dcl
X{
X    va_list ap;
X    register int exstat;
X    register char *fmt;
X    char    buf[BUFSIZ];
X    int     err = errno;
X
X    /* Format the error message */
X
X    va_start(ap);
X    exstat = va_arg(ap, int);			/* exit status */
X    fmt = va_arg(ap, char *);			/* format string */
X    (void) vsprintf(buf, percentm(fmt, err), ap);
X    va_end(ap);
X
X    /* Write message to standard error stream */
X
X    (void) fprintf(stderr, "%s: %s\n", progname, buf);
X
X    /* Append the same message to system log */
X
X    (void) openlog("pc-mail", LOG_PID, LOG_MAIL);
X    (void) syslog(LOG_WARNING, "%s", buf);
X    (void) closelog();
X
X    /* Notify sendmail of the nature of the problem */
X
X    exit(exstat);
X}
X
X#ifdef SYSV
X
X/* mkdir - create directory */
X
Xint     mkdir(dir, mode)
Xchar   *dir;
Xint     mode;
X{
X    char    cmd[BUFSIZ];
X
X    sprintf(cmd, "mkdir %s 2>&1 >/dev/null 2>&1 && chmod %o %s",
X	    dir, mode, dir);
X    return (system(cmd));			/* does not set errno */
X}
X
X#endif
END_OF_FILE
if test 10884 -ne `wc -c <'pc-mail.c'`; then
    echo shar: \"'pc-mail.c'\" unpacked with wrong size!
fi
# end of 'pc-mail.c'
fi
if test -f 'pc-maild.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pc-maild.c'\"
else
echo shar: Extracting \"'pc-maild.c'\" \(13746 characters\)
sed "s/^X//" >'pc-maild.c' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	pc-maild 8
X/* SUMMARY
X/*	deliver unsent mail
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	pc-maild [delay]
X/* DESCRIPTION
X/*	This program should be run on the nfs file server that exports
X/*	mail directories to MS-DOS pc-mail users. It replaces the
X/*	(MS-DOS -> UNIX) transmission function of the MS-DOS \fIcico\fR
X/*	program.
X/*
X/*	The per-user mail directories (default: /var/spool/pc-mail/\fIuser\fR)
X/*	are scanned for outgoing mail every \fIdelay\fR seconds (default: 300).
X/*	When outgoing mail is found, it is sent through the UNIX rmail program
X/*	(uucp mail interface) and the corresponding files are removed from the
X/*	user\'s mail directory.
X/*
X/*	The program should run with root privileges. It will assume
X/*	the (uid, gid) of the sending user before accessing mail files.
X/* COMMANDS
X/*	rmail(1), uucp mail interface program
X/* FILES
X/*	/usr/spool/pc-mail/\fIuser\fR/dNNNNN, mail message
X/*	/usr/spool/pc-mail/\fIuser\fR/xNNNNN, recipients
X/*	(NNNNN is the pc-mail "message id").
X/* SEE ALSO
X/*	pc-mail(1)
X/* DIAGNOSTICS
X/*	Errors found during initialization cause the program to
X/*	terminate with a diagnostic on the standard error stream.
X/*	All other errors are considered transient, i.e. if something
X/*	fails, it is tried again at a later time.  Where possible,
X/*	diagnostics are logged through the syslog facility.
X/* BUGS
X/*	Scanning mail directories is an inefficient way to detect
X/*	unsent mail.
X/* AUTHOR(S)
X/*	W.Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 22 22:12:15 MED 1989
X/* LAST MODIFICATION
X/*	10/31/89 15:44:54
X/* VERSION/RELEASE
X/*	1.3
X/*--*/
X
X#ifndef lint
Xstatic char sccsid[] = "@(#) pc-maild.c 1.3 10/31/89 15:44:54";
X
X#endif
X
X /*
X  * General return-value conventions:
X  * 
X  * int func():		0 means OK
X  * 
X  * stuff *func():	0 means error
X  * 
X  */
X
X#include <stdio.h>
X#include <pwd.h>
X#include <time.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#ifdef SYSLOG
X#include <syslog.h>
X#else
X#include "syslog.h"
X#endif
X
X#ifdef SYSV
X#include <sys/utsname.h>
X#include <ndir.h>
X#else
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <sgtty.h>
X#endif
X
X#include "dosunix.h"
X#include "util.h"
X#include "mtime.h"
X
X/* Library functions */
X
Xextern char *strtok();
Xextern char *strncpy();
Xextern struct passwd *getpwnam();
Xextern unsigned sleep();
Xextern void exit();
Xextern void _exit();
Xextern struct tm *localtime();
Xextern char *asctime();
Xextern long time();
X
X/* Local defines, declarations */
X
X#ifndef	DELAY
X#define	DELAY	300			/* default: scan every 5 minutes */
X#endif
X
X#ifndef	MAILDIR
X#define	MAILDIR	"/usr/spool/pc-mail"	/* default pc-mail directory tree */
X#endif
X
X
Xvoid    catchsig();
Xvoid    finduser();
Xchar   *getrcpt();
Xchar   *fullname();
X
Xint     delay = DELAY;			/* the default delay */
Xchar   *progname;			/* my process name */
X
X
Xint     main(argc, argv)
Xint     argc;
Xchar  **argv;
X{
X    progname = *argv;
X
X    /* Sanity checks */
X
X#ifndef DEBUG
X
X    if (geteuid() != 0) {
X	fprintf(stderr, "%s: must be run as root\n", progname);
X	exit(1);
X    }
X#endif
X
X    /* Check for command-line delay argument */
X
X    if (argc > 1 && (delay = atoi(argv[1])) < 1)
X	delay = DELAY;
X
X    /* Become a daemon process */
X
X#ifndef DEBUG
X    disconnect();
X#endif
X
X    /* Set up signal handling */
X
X    catchsig();
X
X    /* Enable syslogging */
X
X    (void) openlog(progname, LOG_PID, LOG_MAIL);
X    syslog(LOG_WARNING, "daemon restarted");
X
X    /* Setup a decent environment */
X
X    if (putenv("PATH=/bin:/usr/bin:/usr/ucb") || putenv("IFS= \t\n")) {
X	syslog(LOG_WARNING, "initialization failed (insufficient resources)");
X	exit(1);
X    }
X    /* Enter the main loop */
X
X    finduser();
X    /* NOTREACHED */
X}
X
X/* finduser - repeatedly iterate over all pc-mail user directories */
X
Xvoid    finduser()
X{
X    register DIR *maildp;
X    register struct direct *dp;
X    register struct passwd *uinfo;
X    MTIME  *dirtime;
X    char    userdir[BUFSIZ];
X    struct stat st;
X
X    /*
X     * Ignore names that start with a period.
X     *
X     * Ignore names that do not correspond to a directory.
X     * 
X     * Ignore directories that did not change since the last time they were
X     * known to hold no unsent mail.
X     * 
X     * Ignore directories that do not have a name equal to the login name of a
X     * user.
X     */
X
X    for (;;) {
X	if ((e_chdir(MAILDIR) == 0) && (maildp = e_opendir(MAILDIR))) {
X	    while (dp = readdir(maildp)) {
X		if ((dp->d_name[0] != '.')
X		    && (stat(dp->d_name, &st) == 0)
X		    && ((st.st_mode & S_IFMT) == S_IFDIR)
X		    && (st.st_mtime > (dirtime = mtime(dp->d_name))->time)
X		    && ((uinfo = getpwnam(dp->d_name)) != 0)) {
X		    (void) sprintf(userdir, "%s/%s", MAILDIR, dp->d_name);
X		    if (findmail(uinfo, userdir) == 0)
X			dirtime->time = st.st_mtime;	/* say it was empty */
X		}
X	    }
X	    closedir(maildp);			/* done with this user */
X	    (void) chdir("/");			/* be friendly */
X	}
X	(void) sleep(delay);			/* try again later */
X    }
X}
X/* findmail - enter a user\'s mail directory and scan for unsent mail */
X
Xint     findmail(uinfo, userdir)
Xstruct passwd *uinfo;
Xchar   *userdir;
X{
X    register DIR *dd;
X    register struct direct *p;
X    int     seqno;
X    static char xfile[BUFSIZ];		/* file with recipients */
X    static char dfile[BUFSIZ];		/* file with mail message */
X    int     found = 0;			/* no mail found yet */
X
X    /*
X     * Use the fact that 'x' files (recipient addresses) are created later
X     * than 'd' files (message body) when a pc user generates a message.
X     * Extract the pc-mail message id from the file name and try to pipe the
X     * message through the UNIX rmail command. All knowledge about pc-mail
X     * file names resides in this function. Return zero if no unsent mail was
X     * found.
X     */
X
X    if ((e_chdir(userdir) == 0) && (dd = e_opendir(userdir))) {
X	while (p = readdir(dd)) {
X	    if (*p->d_name == 'x' && sscanf(p->d_name + 1, "%d", &seqno) == 1) {
X		(void) sprintf(xfile, "x%05d", seqno);	/* recipients */
X		if (strcmp(p->d_name, xfile) == 0) {	/* ignore junk */
X		    (void) sprintf(dfile, "d%05d", seqno);
X		    pickup(uinfo, xfile, dfile);
X		    found = 1;			/* found unsent mail */
X		}
X	    }
X	}
X	closedir(dd);
X	(void) chdir(MAILDIR);
X    }
X    return (found);
X}
X
X/* pickup - pick up one message from a user\'s mail directory */
X
Xpickup(uinfo, xfile, dfile)
Xstruct passwd *uinfo;
Xchar   *xfile;
Xchar   *dfile;
X
X{
X
X    /*
X     * Actual delivery must be done with the (uid, gid) of the sender, or the
X     * From: lines will not be correct. Therefore, we do delivery in a child
X     * process. This also avoid all kinds of nasty security problems. All
X     * errors are considered non-fatal.
X     */
X
X#ifdef DEBUG
X    sendasuser(uinfo, xfile, dfile);		/* don't fork */
X#else
X    switch (e_fork()) {
X    case -1:					/* failure */
X	break;
X    case 0:					/* child */
X	sendasuser(uinfo, xfile, dfile);
X	_exit(0);
X	/* NOTREACHED */
X    default:					/* parent */
X	(void) wait((int *) 0);
X	break;
X    }
X#endif
X}
X
X/* sendasuser - send mail through rmail(1), having (uid, gid) of sender */
X
Xsendasuser(uinfo, xfile, dfile)
Xstruct passwd *uinfo;
Xchar   *xfile;
Xchar   *dfile;
X{
X    char   *dest;			/* recipient address(es) */
X
X    /*
X     * User-specific mail files must be opened AFTER we have assumed the
X     * (uid, gid) of the pc-mail user; this in order to avoid nasty security
X     * holes.
X     */
X
X    if ((setugid(uinfo) == 0)			/* assume proper (uid, gid) */
X	&&(dest = getrcpt(uinfo, xfile))	/* extract recipients */
X	&&(rmail(uinfo, dfile, dest) == 0)) {	/* pipe message through rmail */
X	(void) u_unlink(uinfo, xfile);		/* recipients file */
X	(void) u_unlink(uinfo, dfile);		/* message body file */
X    }
X}
X
X/* setugid - assume (uid, gid) of user */
X
Xint     setugid(uinfo)
Xstruct passwd *uinfo;
X{
X    if (setgid(uinfo->pw_gid)) {
X	syslog(LOG_WARNING, "setgid(%s) failed: %m", uinfo->pw_name);
X	return (1);
X    }
X    if (setuid(uinfo->pw_uid)) {
X	syslog(LOG_WARNING, "setuid(%s) failed: %m", uinfo->pw_name);
X	return (1);
X    } else {
X	return (0);
X    }
X}
X
X/* getrcpt - extract recipient from user mail file */
X
Xchar   *getrcpt(uinfo, xfile)
Xstruct passwd *uinfo;
Xchar   *xfile;
X{
X    FILE   *xfp;			/* recipient file pointer */
X    static char dest[2 * BUFSIZ];	/* recipient names */
X    register char *ret;
X
X    if ((xfp = u_fopen(uinfo, xfile, "r")) == 0) {
X	return (0);
X    } else {
X	pc_wait(fileno(xfp));		/* let pc finish writing */
X	ret = dosgets(dest, sizeof(dest), xfp);
X	(void) fclose(xfp);
X	if (ret == 0)
X	    syslog(LOG_WARNING, "no recipients specified in %s/%s",
X		   uinfo->pw_name, xfile);
X	return (ret);
X    }
X}
X
X/* rmail - pipe a pc mail message through the UNIX rmail program */
X
Xint     rmail(uinfo, dfile, dest)
Xstruct passwd *uinfo;			/* originator */
Xchar   *dfile;				/* message file */
Xchar   *dest;				/* recipients */
X{
X    static char cmd[BUFSIZ * 2];	/* command + arguments */
X    FILE   *dfp;			/* source stream */
X    FILE   *pfp;			/* output stream */
X    int     ret;			/* return value, 0 if OK */
X    long    secs;			/* absolute UNIX time */
X    static char hostname[BUFSIZ];	/* our host name */
X
X    /*
X     * The UNIX rmail command needs a UUCP-style From_ line.
X     * 
X     * The To: and From: lines can be added for esthetical porposes.
X     * 
X     * Report communication failures with the rmail command. Error returns from
X     * rmail are ignored; they should be handled in sendmail.
X     */
X
X    if (dfp = u_fopen(uinfo, dfile, "r")) {	/* open message file */
X	sprintf(cmd, "rmail %s", dest);
X	if ((pfp = popen(cmd, "w")) == 0) {	/* invoke rmail... */
X	    syslog(LOG_WARNING, "cannot invoke %.20s...: %m", rmail);
X	    ret = 1;
X	} else {
X	    secs = time((long *) 0);
X	    (void) gethostname(hostname, sizeof(hostname));
X	    fprintf(pfp, "From %s %.24s remote from %s\n", uinfo->pw_name,
X		    asctime(localtime(&secs)),
X		    hostname);			/* add UUCP From_ line */
X#ifdef	RFC822
X	    rfc822hdr(uinfo, dest, pfp);	/* do RFC822 stuff */
X#endif
X	    if (ret = dos2unix(dfp, pfp))	/* append message body */
X		syslog(LOG_WARNING, "write to rmail failed: %m");
X	    (void) pclose(pfp);
X	}
X	(void) fclose(dfp);
X    }
X    return (ret);
X}
X
X/* rfc822hdr - generate subset of RFC822 header lines */
X
Xrfc822hdr(uinfo, dest, pfp)
Xregister struct passwd *uinfo;
Xchar   *dest;
Xregister FILE *pfp;
X{
X    char   *sep = " ,\t\r\n";
X    char   *name;
X
X    /*
X     * There are a few problems with this function. First of all, it destroys
X     * the dest argument. In the second place, putting each recipient on a
X     * separate To: header line is ugly.
X     */
X
X    fprintf(pfp, "From: %s (%s)\n", uinfo->pw_name,
X	    fullname(uinfo));			/* add From: header line */
X    for (name = strtok(dest, sep); name; name = strtok((char *) 0, sep))
X	fprintf(pfp, "To: %s\n", name);		/* add To: header line */
X}
X
X/* fullname - extract full name from gecos field */
X
Xchar   *fullname(uinfo)
Xstruct passwd *uinfo;
X{
X    static char name[BUFSIZ];
X
X    /* This code assumes BSD-style gecos fields (name,stuff,stuff...) */
X
X    if (sscanf(uinfo->pw_gecos, "%[^,]", name) == 0)
X	name[0] = '\0';
X    return (name);
X}
X
X/* gotsig - caught a signal; terminate with diagnostic */
X
Xvoid    gotsig(sig)
Xint     sig;
X{
X    syslog(LOG_WARNING, "going down on signal %d", sig);
X    closelog();
X    exit(sig);
X}
X
X/* catchsig - catch some signals */
X
Xvoid    catchsig()
X{
X#ifdef	DEBUG
X    (void) signal(SIGHUP, gotsig);
X    (void) signal(SIGINT, gotsig);
X    (void) signal(SIGQUIT, gotsig);
X#else
X    (void) signal(SIGHUP, SIG_IGN);
X    (void) signal(SIGINT, SIG_IGN);
X    (void) signal(SIGQUIT, SIG_IGN);
X#endif
X    (void) signal(SIGBUS, gotsig);
X    (void) signal(SIGSEGV, gotsig);
X    (void) signal(SIGTERM, gotsig);
X}
X
X/* disconnect - become a daemon process */
X
Xdisconnect()
X{
X#ifndef	SYSV
X    int     fd;
X
X#endif
X
X    /* Get rid of the parent process */
X
X    switch (e_fork()) {
X    case -1:					/* failure */
X	exit(1);
X	/* NOTREACHED */
X    default:
X	_exit(0);				/* parent */
X	/* NOTREACHED */
X    case 0:					/* child */
X	break;
X    }
X
X    /* Get rid of the controlling terminal */
X
X    (void) close(0);
X    (void) close(1);
X    (void) close(2);
X#ifdef SYSV
X    (void) setpgrp();
X#else
X    if ((fd = open("/dev/tty", 0)) >= 0) {
X	(void) ioctl(fd, TIOCNOTTY, 0);
X	(void) close(fd);
X    }
X#endif
X}
X
X/* pc_wait - wait till the pc has finished writing a file */
X
Xpc_wait(fd)
Xint     fd;
X{
X    struct stat st;
X    long    oldsize = 0;
X
X    /*
X     * Repeatedly sleep one second until the file size does not change
X     * anymore.
X     * 
X     * At first sight, this does not seem to be a very robust algorithm. It is,
X     * however, sufficient. The pc sofware will first create a message file,
X     * then the file with recipient addresses. The pc-maild program, on the
X     * other hand, will read the recipient-address file first. If that file
X     * turns out to be empty, it will try again at a later time. So, the only
X     * time we may produce an incorrect result is under the following
X     * conditions:
X     * 
X     * (1) the file with recipient names is longer than the PC/NFS packet size
X     * or the pc\'s stdio buffer size.
X     * 
X     * (2) the network connection goes down for > 1 second after part of the
X     * data has arrived in the file with recipient addresses.
X     */
X
X    while (fstat(fd, &st) == 0 && oldsize != st.st_size) {
X	oldsize = st.st_size;
X	sleep(1);
X    }
X}
X
X#ifdef SYSV
X
X/* gethostname - BSD compatibility routine */
X
Xgethostname(name, len)
Xchar   *name;
Xint     len;
X{
X    struct utsname ut;
X
X    uname(&ut);
X    (void) strncpy(name, ut.nodename, len);
X    return (0);
X}
X
X#endif
END_OF_FILE
if test 13746 -ne `wc -c <'pc-maild.c'`; then
    echo shar: \"'pc-maild.c'\" unpacked with wrong size!
fi
# end of 'pc-maild.c'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(4401 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# @(#) Makefile 1.5 11/19/89 13:53:47
X
X###############################
X# Start of configurable options. You will also have to do a `make depend'.
X
X# Compiler options.
X# -DSYSV is needed for system 5 release 2
X# -DRFC822 if you want the daemon to produce To: and From: header lines
X# -DSYSEXITS if your system has <sysexits.h>
X# -DSYSLOG if your system has a BSD 4.3-like syslog facility
X# -DSYSLOGFILE=\"/usr/spool/mqueue/syslog\" if you don't have BSD4.3-like syslog
X#	You will also have to create that file, with mode 666.
X#
X#BSD4.X: DEFS = -DRFC822 -DSYSEXITS -DSYSLOG
X#SYSVR2: DEFS = -DRFC822 -DSYSV -DSYSLOGFILE=\"/usr/spool/mqueue/syslog\" 
X
XDEFS	= -DRFC822 -DSYSEXITS -DSYSLOG
X
X# Location of pc-mail spool area
X
XMAILDIR	= /var/spool/pc-mail
X
X# How often the daeman will scan the pc-mail spool area for unsent mail.
X# This time interval can also be changed via the command line.
X
XDELAY	= 30
X
X# Some system-5 implementations have a separate library with BSD-compatible
X# directory access routines.
X#
X#LIBS	= -lndir
X
XLIBS	= 
X
X# Location of the pc-mail en pc-maild binaries
X
XEXEDIR	= /usr/local/lib
X
X# If you want to, where to install the manual pages
X
XMANDIR	= /usr/local/man/man8
X
X# End of configurable options
X#############################
X
XSHELL	= /bin/sh
XCFLAGS	= $(DEFS) -DDELAY=$(DELAY) -DMAILDIR=\"$(MAILDIR)\"
XARCHIVE	= sarch
XSOURCES	= README pc-mail.c pc-maild.c Makefile sysexits.h syslog.h \
X	syslog.c util.c util.h mtime.c mtime.h dosunix.c dosunix.h \
X	percentm.h percentm.c 
X
XPCMOBJ	= pc-mail.o syslog.o percentm.o dosunix.o
XPCMSRC	= pc-mail.c syslog.c percentm.c dosunix.c
X
XPCMDOBJ	= pc-maild.o syslog.o percentm.o dosunix.o util.o mtime.o
XPCMDSRC	= pc-maild.c syslog.c percentm.c dosunix.c util.c mtime.c
X
Xall:	pc-mail pc-maild
X
Xinstall: all
X	-mkdir $(MAILDIR)
X	chmod 755 $(MAILDIR)
X	cp pc-mail pc-maild $(EXEDIR)
X	chown root $(EXEDIR)/pc-mail
X	chmod 4755 $(EXEDIR)/pc-mail
X
Xinstallman: 
X	cp pc-mail.8 pc-maild.8 $(MANDIR)
X
Xpc-mail: $(PCMOBJ)
X	$(CC) $(CFLAGS) -o $@ $(PCMOBJ) $(LIBS)
X
Xpc-maild: $(PCMDOBJ)
X	$(CC) $(CFLAGS) -o $@ $(PCMDOBJ) $(LIBS)
X
Xlint:	lint1 lint2
X
Xlint1:	$(PCMSRC)
X	lint $(CFLAGS) $(PCMSRC)
X
Xlint2:	$(PCMDSRC)
X	lint $(CFLAGS) $(PCMDSRC)
X
Xshar:	$(SOURCES) pc-mail.8 pc-maild.8
X	@shar $(SOURCES) pc-mail.8 pc-maild.8
X
Xclean:
X	rm -f *.o core nohup.out
X
Xclobber: clean
X	rm -f pc-maild pc-mail *.8
X
Xarchive: $(SOURCES)
X	$(ARCHIVE) $?;
X	touch archive
X
Xdepend:	
X	(sed '1,/^# do not edit/!d' Makefile; \
X	for i in [a-z][a-z]*.c; do \
X	    $(CC) -E $(CFLAGS) $$i | sed -n '/^# *1 *"\([^"]*\)".*/{;s//'`echo $$i|sed 's/c$$/o/'`':	\1/;p;}'; \
X	done)>$$$$ && mv $$$$ Makefile
X
X# do not edit below this line - it was create with `make depend'
Xdosunix.o:	dosunix.c
Xdosunix.o:	/usr/include/stdio.h
Xdosunix.o:	./dosunix.h
Xmtime.o:	mtime.c
Xmtime.o:	/usr/include/syslog.h
Xmtime.o:	./mtime.h
Xpc-mail.o:	pc-mail.c
Xpc-mail.o:	/usr/include/stdio.h
Xpc-mail.o:	/usr/include/sys/types.h
Xpc-mail.o:	/usr/include/sys/sysmacros.h
Xpc-mail.o:	/usr/include/sys/stat.h
Xpc-mail.o:	/usr/include/pwd.h
Xpc-mail.o:	/usr/include/varargs.h
Xpc-mail.o:	/usr/include/syslog.h
Xpc-mail.o:	/usr/include/sys/dir.h
Xpc-mail.o:	/usr/include/sysexits.h
Xpc-mail.o:	./dosunix.h
Xpc-mail.o:	./percentm.h
Xpc-maild.o:	pc-maild.c
Xpc-maild.o:	/usr/include/stdio.h
Xpc-maild.o:	/usr/include/pwd.h
Xpc-maild.o:	/usr/include/time.h
Xpc-maild.o:	/usr/include/signal.h
Xpc-maild.o:	/usr/include/vm/faultcode.h
Xpc-maild.o:	/usr/include/sys/types.h
Xpc-maild.o:	/usr/include/sys/sysmacros.h
Xpc-maild.o:	/usr/include/sys/stat.h
Xpc-maild.o:	/usr/include/syslog.h
Xpc-maild.o:	/usr/include/sys/types.h
Xpc-maild.o:	/usr/include/sys/dir.h
Xpc-maild.o:	/usr/include/sgtty.h
Xpc-maild.o:	/usr/include/sys/ioctl.h
Xpc-maild.o:	/usr/include/sys/ttychars.h
Xpc-maild.o:	/usr/include/sys/ttydev.h
Xpc-maild.o:	/usr/include/sys/ttold.h
Xpc-maild.o:	/usr/include/sys/ioccom.h
Xpc-maild.o:	/usr/include/sys/ttycom.h
Xpc-maild.o:	/usr/include/sys/filio.h
Xpc-maild.o:	/usr/include/sys/ioccom.h
Xpc-maild.o:	/usr/include/sys/sockio.h
Xpc-maild.o:	/usr/include/sys/ioccom.h
Xpc-maild.o:	./dosunix.h
Xpc-maild.o:	./util.h
Xpc-maild.o:	./mtime.h
Xpercentm.o:	percentm.c
Xpercentm.o:	/usr/include/stdio.h
Xpercentm.o:	./percentm.h
Xsyslog.o:	syslog.c
Xutil.o:	util.c
Xutil.o:	/usr/include/stdio.h
Xutil.o:	/usr/include/pwd.h
Xutil.o:	/usr/include/sys/types.h
Xutil.o:	/usr/include/sys/sysmacros.h
Xutil.o:	/usr/include/sys/dir.h
Xutil.o:	/usr/include/syslog.h
Xutil.o:	./util.h
END_OF_FILE
if test 4401 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'sysexits.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sysexits.h'\"
else
echo shar: Extracting \"'sysexits.h'\" \(972 characters\)
sed "s/^X//" >'sysexits.h' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	sysexits 5
X/* SUMMARY
X/*	exit status codes for programs called by sendmail
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	#include "sysexits.h"
X/* DESCRIPTION
X/* .nf
X
X /* sendmail-compatible exit status codes */
X
X#define	EX_OK		0
X#define EX_USAGE	64
X#define EX_DATAERR	65
X#define EX_NOINPUT	66
X#define EX_NOUSER	67
X#define EX_NOHOST	68
X#define EX_UNAVAILABLE	69
X#define EX_SOFTWARE	70
X#define EX_OSERR	71
X#define EX_OSFILE	72
X#define EX_CANTCREAT	73
X#define EX_IOERR	74
X#define EX_TEMPFAIL	75
X#define EX_PROTOCOL	76
X#define EX_NOPERM	77
X/* AUTHOR(S)
X/*	Wietse Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/*
X/*	These codes were actually defined by Eric Allman, the originator
X/*	of the sendmail program.
X/* CREATION DATE
X/*	Sun Oct 29 16:03:19 MET 1989
X/* LAST MODIFICATION
X/*	10/29/89 22:29:47
X/* VERSION/RELEASE
X/*	1.1
X/*--*/
X
END_OF_FILE
if test 972 -ne `wc -c <'sysexits.h'`; then
    echo shar: \"'sysexits.h'\" unpacked with wrong size!
fi
# end of 'sysexits.h'
fi
if test -f 'syslog.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'syslog.h'\"
else
echo shar: Extracting \"'syslog.h'\" \(698 characters\)
sed "s/^X//" >'syslog.h' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	syslog 5
X/* SUMMARY
X/*	surrogate BSD4.3 syslog facility
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	include "syslog.h"
X/* DESCRIPTION
X/* .nf
X
X /* Do nothing if we already have <syslog.h> */
X
X#ifndef SYSLOG
X
X /* various constants */
X
X#define	LOG_PID		1
X#define	LOG_MAIL	1
X#define	LOG_WARNING	1
X
Xextern  openlog();
Xextern  syslog();
Xextern  closelog();
X
X#endif
X/* AUTHOR(S)
X/*	Wietse Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 29 15:12:57 MET 1989
X/* LAST MODIFICATION
X/*	10/29/89 22:29:50
X/* VERSION/RELEASE
X/*	1.1
X/*--*/
X
END_OF_FILE
if test 698 -ne `wc -c <'syslog.h'`; then
    echo shar: \"'syslog.h'\" unpacked with wrong size!
fi
# end of 'syslog.h'
fi
if test -f 'syslog.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'syslog.c'\"
else
echo shar: Extracting \"'syslog.c'\" \(2657 characters\)
sed "s/^X//" >'syslog.c' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	syslog 3
X/* SUMMARY
X/*	surrogate BSD4.3 syslog facility
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	include "syslog.h"
X/*
X/*	openlog(name, logopt, facility)
X/*	char *name;
X/*	int logopt;
X/*	int facility;
X/*
X/*	syslog(priority, format, arguments)
X/*	int priority;
X/*	char *format;
X/*
X/*	closelog()
X/* DESCRIPTION
X/*	These functions emulate the BSD4.3 syslog(3) facility. Output is
X/*	written to a system logfile (default /usr/spool/mqueue/syslog).
X/*	That file should have mode 666 (i.e. read/write access permitted
X/*	for everyone).
X/*
X/*	syslog() tries to output the log entry as one big chunk.
X/* FILES
X/*	/usr/spool/mqueue/syslog, system logfile
X/* SEE ALSO
X/*	percentm(3), interprets "%m" sequences in syslog format strings.
X/* BUGS
X/*	The functions use the stdio package. This may cause the program to
X/*	grow unexpectedly.
X/* AUTHOR(S)
X/*	Wietse Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 29 15:12:57 MET 1989
X/* LAST MODIFICATION
X/*	10/29/89 22:58:33
X/* VERSION/RELEASE
X/*	1.2
X/*--*/
X
X#ifndef SYSLOG
X
X#ifndef lint
Xstatic char sccsid[] = "@(#) syslog.c 1.2 10/29/89 22:58:33";
X
X#endif
X
X#include <stdio.h>
X#include <varargs.h>
X#include <time.h>
X#include "percentm.h"
X
Xextern struct tm *localtime();
Xextern char *asctime();
Xextern long time();
Xextern int errno;
X
X#ifndef SYSLOGFILE
X#define	SYSLOGFILE	"/usr/spool/mqueue/syslog"
X#endif
X
Xstatic char *logname;
X
X/* openlog - initialize syslog facility; ignores all but the "name" argument */
X
X/* ARGSUSED */
X
Xopenlog(name, logopt, facility)
Xchar   *name;
Xint     logopt;
Xint     facility;
X{
X    logname = name;				/* ignore rest */
X}
X
X/* syslog - append entry to system log */
X
X/* VARARGS */
X
Xsyslog(va_alist)
Xva_dcl
X{
X    va_list ap;
X    char   *fmt;
X    char   *percentm();
X    long    secs;
X    char   *date;
X    FILE   *fp;
X    int     err = errno;
X    static char buf[BUFSIZ];
X
X    if (fp = fopen(SYSLOGFILE, "a")) {
X
X	/* Format the time stamp */
X
X	secs = time((long *) 0);
X	date = asctime(localtime(&secs));
X	(void) sprintf(buf, "%2.2s-%3.3s-%2.2s %8.8s %s: ",
X		       date + 8, date + 4, date + 22, date + 11, logname);
X
X	/* Format the actual message */
X
X	va_start(ap);
X	(void) va_arg(ap, int);			/* skip priority */
X	fmt = va_arg(ap, char *);
X	(void) vsprintf(buf + strlen(buf), percentm(fmt, err), ap);
X	va_end(ap);
X
X	/* Try to ouput the log entry as one big chunk */
X
X	(void) fprintf(fp, "%s\n", buf);
X	(void) fclose(fp);
X    }
X}
X
X/* closelog - a real dummy */
X
Xcloselog()
X{
X    /* no-op */
X}
X
X#endif					/* SYSLOG */
X
END_OF_FILE
if test 2657 -ne `wc -c <'syslog.c'`; then
    echo shar: \"'syslog.c'\" unpacked with wrong size!
fi
# end of 'syslog.c'
fi
if test -f 'util.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util.c'\"
else
echo shar: Extracting \"'util.c'\" \(2780 characters\)
sed "s/^X//" >'util.c' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	util 3
X/* SUMMARY
X/*	wrappers around standard library functions
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	#include <stdio.h>
X/*	#include <pwd.h>
X/*	#include <directory_access_stuff.h>
X/*
X/*	FILE *u_fopen(uinfo,path,mode)
X/*	struct passwd *uinfo;
X/*	char *path;
X/*	char *mode;
X/*
X/*	int u_unlink(uinfo, path)
X/*	struct passwd *uinfo;
X/*	char *path;
X/*
X/*	DIR *e_opendir(path)
X/*	char *path;
X/*
X/*	int e_chdir(path)
X/*	char *path;
X/*
X/*	int e_fork()
X/* DESCRIPTION
X/*	These functions are wrappers around some standard library functions.
X/*	In case of problems, they append an entry to the system log (with
X/*	priority LOG_WARNING). The \fIuinfo\fR argument specifies the owner
X/*	of the mail subdirectory in which the problem occurred.
X/* SEE ALSO
X/*	syslog(3)
X/* DIAGNOSTICS
X/*	Diagnostics are logged via the syslog package; error return values
X/*	are identical to those of the underlying library functions.
X/* AUTHOR(S)
X/*	Wietse Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 29 16:21:02 MET 1989
X/* LAST MODIFICATION
X/*	10/29/89 22:29:53
X/* VERSION/RELEASE
X/*	1.1
X/*--*/
X
X#ifndef lint
Xstatic char sccsid[] = "@(#) util.c 1.1 10/29/89 22:29:53";
X
X#endif
X
X#include <stdio.h>
X#include <pwd.h>
X
X#ifdef SYSV
X#include <ndir.h>
X#else
X#include <sys/types.h>
X#include <sys/dir.h>
X#endif
X
X#ifdef SYSLOG
X#include <syslog.h>
X#else
X#include "syslog.h"
X#endif
X
X#include "util.h"			/* consistency check */
X
X/* u_fopen - open file in user directory, log any errors */
X
XFILE   *u_fopen(uinfo, file, mode)
Xstruct passwd *uinfo;
Xchar   *file;
Xchar   *mode;
X{
X    register FILE *fp;
X
X    if ((fp = fopen(file, mode)) == 0)
X	syslog(LOG_WARNING, "cannot open %s/%s: %m", uinfo->pw_name, file);
X    return (fp);
X}
X
X/* u_unlink - unlink file in user directory, log any errors */
X
Xint     u_unlink(uinfo, file)
Xstruct passwd *uinfo;
Xchar   *file;
X{
X    register int stat;
X
X    if (stat = unlink(file))
X	syslog(LOG_WARNING, "cannot unlink %s/%s: %m", uinfo->pw_name, file);
X    return (stat);
X}
X
X/* e_opendir - open directory, log any errors */
X
XDIR    *e_opendir(path)
Xchar   *path;
X{
X    register DIR *dd;
X
X    if ((dd = opendir(path)) == 0)
X	syslog(LOG_WARNING, "cannot open directory %s: %m", path);
X    return (dd);
X}
X
X/* e_chdir - change directory, log any errors */
X
Xint     e_chdir(path)
Xchar   *path;
X{
X    register int ret;
X
X    if (ret = chdir(path))
X	syslog(LOG_WARNING, "cannot chdir to directory %s: %m", path);
X    return (ret);
X}
X
X/* e_fork - do a fork(), log any errors */
X
Xint     e_fork()
X{
X    register int stat;
X
X    if ((stat = fork()) == -1)
X	syslog(LOG_WARNING, "fork() failed: %m");
X    return (stat);
X}
X
END_OF_FILE
if test 2780 -ne `wc -c <'util.c'`; then
    echo shar: \"'util.c'\" unpacked with wrong size!
fi
# end of 'util.c'
fi
if test -f 'util.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util.h'\"
else
echo shar: Extracting \"'util.h'\" \(1060 characters\)
sed "s/^X//" >'util.h' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	util 3
X/* SUMMARY
X/*	wrappers around standard library functions
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	#include <stdio.h>
X/*	#include <pwd.h>
X/*	#include "util.h"
X/* DESCRIPTION
X/* .nf
X
X /* Anticipate on ANSI-compatible compilers */
X
X#ifdef __STDC__
XFILE   *u_fopen(struct passwd * user, char *file, char *mode);
Xint     u_unlink(char *file);
XDIR    *e_opendir(char *path);
Xint     e_chdir(char *path);
Xint     e_fork(void);
X
X#else
XFILE   *u_fopen();			/* open file, log any errors */
Xint     u_unlink();			/* unlink file, log any errors */
XDIR    *e_opendir();			/* open directory, log any errors */
Xint     e_chdir();			/* change directory, log any errors */
Xint     e_fork();			/* fork, log any errors */
X
X#endif
X/* AUTHOR(S)
X/*	Wietse Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 29 16:21:02 MET 1989
X/* LAST MODIFICATION
X/*	10/29/89 22:29:55
X/* VERSION/RELEASE
X/*	1.1
X/*--*/
X
END_OF_FILE
if test 1060 -ne `wc -c <'util.h'`; then
    echo shar: \"'util.h'\" unpacked with wrong size!
fi
# end of 'util.h'
fi
if test -f 'mtime.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mtime.c'\"
else
echo shar: Extracting \"'mtime.c'\" \(2331 characters\)
sed "s/^X//" >'mtime.c' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	mtime 3
X/* SUMMARY
X/*	maintain modification times of files
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	#include "mtime.h"
X/*
X/*	MTIME *mtime(path)
X/*	char *path;
X/* DESCRIPTION
X/*	mtime() maintains a table of modification times of files.
X/*	If a new file name is given, a modification time of 0 is
X/*	assumed (the UNIX equivalent of "a very long time ago").
X/*
X/*	If, for whatever reason, no memory can be allocated to update the
X/*	symbol table, a dummy entry is returned with modification time of 0.
X/* DIAGNOSTICS
X/*	Diagnostics are logged with the syslog(3) facility. The program
X/*	tries to continue to run as long as possible.
X/* BUGS
X/*	The dummy entry is stored in static memory; its value may be
X/*	overwritten an any time.
X/* AUTHOR(S)
X/*	Wietse Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 29 15:48:01 MET 1989
X/* LAST MODIFICATION DATE
X/*	10/29/89 22:29:56
X/* VERSION/RELEASE
X/*	1.1
X/*--*/
X
X#ifndef lint
Xstatic char sccsid[] = "@(#) mtime.c 1.1 10/29/89 22:29:56";
X
X#endif
X
X#ifdef SYSLOG
X#include <syslog.h>
X#else
X#include "syslog.h"
X#endif
X
X#include "mtime.h"
X
Xextern char *malloc();
Xextern char *strcpy();
X
XMTIME  *mtime_tree;			/* head of symbol table */
X
X/* findtime - actual symbol-table access routine */
X
XMTIME  *findtime(path, tree)
Xregister char *path;
Xregister MTIME *tree;
X{
X    register int direct;
X    static MTIME dummy;
X
X    /*
X     * We use a trivial binary-tree storage scheme. If we cannot get memory
X     * for whatever reason, produce a dummy result. This means we will always
X     * believe that a file has changed. My first excercise in "graceful
X     * degradation".
X     */
X
X    if (tree == 0) {				/* new file */
X	if ((tree = (MTIME *) malloc(sizeof(MTIME))) == 0
X	    || (tree->path = malloc(strlen(path) + 1)) == 0) {
X	    syslog(LOG_WARNING, "memory allocation failed");
X	    dummy.time = 0;
X	    tree = &dummy;
X	} else {
X	    (void) strcpy(tree->path, path);
X	    tree->time = 0;
X	    tree->left = tree->rite = 0;
X	}
X    } else if ((direct = strcmp(path, tree->path)) < 0) {
X	tree->left = findtime(path, tree->left);
X    } else if (direct > 0) {
X	tree->rite = findtime(path, tree->rite);
X    }
X    return (tree);
X}
X
END_OF_FILE
if test 2331 -ne `wc -c <'mtime.c'`; then
    echo shar: \"'mtime.c'\" unpacked with wrong size!
fi
# end of 'mtime.c'
fi
if test -f 'mtime.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mtime.h'\"
else
echo shar: Extracting \"'mtime.h'\" \(943 characters\)
sed "s/^X//" >'mtime.h' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	mtime 5
X/* SUMMARY
X/*	maintain modification times of files
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	#include "mtime.h"
X/* DESCRIPTION
X/* .nf
X
X /* structure of one symbol-table entry */
X
Xtypedef struct MTIME {
X    char   *path;			/* key */
X    long    time;			/* value */
X    struct MTIME *left;			/* left subtree */
X    struct MTIME *rite;			/* right subtree */
X}       MTIME;
X
X /* client interface */
X
X#define mtime(path)	(mtime_tree = findtime(path,mtime_tree))
X
X /* actual interface */
X
Xextern MTIME *mtime_tree;		/* head of symbol table */
XMTIME  *findtime();			/* actual access function */
X
X/* AUTHOR(S)
X/*	Wietse Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 29 15:48:01 MET 1989
X/* LAST MODIFICATION DATE
X/*	10/29/89 22:29:58
X/* VERSION/RELEASE
X/*	1.1
X/*--*/
X
END_OF_FILE
if test 943 -ne `wc -c <'mtime.h'`; then
    echo shar: \"'mtime.h'\" unpacked with wrong size!
fi
# end of 'mtime.h'
fi
if test -f 'dosunix.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dosunix.c'\"
else
echo shar: Extracting \"'dosunix.c'\" \(2720 characters\)
sed "s/^X//" >'dosunix.c' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	dosunix 3
X/* SUMMARY
X/*	UNIX <-> MS-DOS text format conversion
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	#include <stdio.h>
X/*	#include "dosunix.h"
X/*
X/*	int dos2unix(ifp, ofp)
X/*	FILE *ifp;
X/*	FILE *ofp;
X/*
X/*	int unix2dos(ifp, ofp)
X/*	FILE *ifp;
X/*	FILE *ofp;
X/*
X/*	char *dosgets(buf, len, fp)
X/*	char *buf;
X/*	unsigned len;
X/*	FILE *fp;
X/* DESCRIPTION
X/*	dos2unix() converts an MS-DOS text stream (with cr/lf-delimited
X/*	lines) to a UNIX style stream (with lf-delimited lines).
X/*
X/*	unix2dos() performs the opposite function as dos2unix().
X/*
X/*	dosgets() reads one line from the designated stream and strips
X/*	off any cr of lf characters.
X/* DIAGNOSTICS
X/*	dos2unix(), unix2dos() return a nonzero value if an error was detected.
X/*
X/*	dosgets() returns (char *) 0 if it could not read any data.
X/* BUGS
X/*	Very long lines will be broken; Ctrl-Z in MS-DOS files is not
X/*	given special treatment, nor will it be added to the end of
X/*	MS-DOS files.
X/* AUTHOR(S)
X/*	Wietse Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 29 16:41:50 MET 1989
X/* LAST MODIFICATION
X/*	10/29/89 22:30:00
X/* VERSION/RELEASE
X/*	1.1
X/*--*/
X
X#ifndef lint
Xstatic char sccsid[] = "@(#) dosunix.c 1.1 10/29/89 22:30:00";
X
X#endif
X
X#include <stdio.h>
X#include "dosunix.h"			/* consistency check */
X
Xextern char *strchr();
Xextern char *fgets();
X
X/* unix2dos - copy UNIX-format stream to MS-DOS-format stream */
X
Xint     unix2dos(ifp, ofp)
XFILE   *ifp;
XFILE   *ofp;
X{
X    static char buf[BUFSIZ];
X    register int end;
X
X    while (fgets(buf, sizeof(buf), ifp)) {
X	if (buf[end = strlen(buf) - 1] == '\n') {
X	    buf[end] = '\r';
X	    (void) fputs(buf, ofp);
X	    (void) putc('\n', ofp);
X	} else {
X	    (void) fputs(buf, ofp);
X	}
X    }
X    return (fflush(ofp) || ferror(ofp) || feof(ofp));
X}
X
X/* dos2unix - copy MS-DOS-format text stream to UNIX-format text stream */
X
Xint     dos2unix(dfp, pfp)
Xregister FILE *dfp;
Xregister FILE *pfp;
X{
X    static char msgbuf[BUFSIZ];		/* copy buffer */
X
X    while (dosgets(msgbuf, sizeof(msgbuf), dfp)) {
X	(void) fputs(msgbuf, pfp);
X	(void) putc('\n', pfp);
X    }
X    return (fflush(pfp) || ferror(pfp) || feof(pfp));
X}
X
X/* dosgets - read one line from DOS-format text stream; strip cr and lf */
X
Xchar   *dosgets(buf, len, fp)
Xregister char *buf;
Xunsigned len;
Xregister FILE *fp;
X{
X    register char *cp;
X    register char *ret;
X
X    /* Lines with >= len characters will be broken */
X
X    if ((ret = fgets(buf, len, fp))
X	&& ((cp = strchr(buf, '\r')) || (cp = strchr(buf, '\n'))))
X	*cp = '\0';				/* strip cr or lf */
X    return (ret);
X}
X
END_OF_FILE
if test 2720 -ne `wc -c <'dosunix.c'`; then
    echo shar: \"'dosunix.c'\" unpacked with wrong size!
fi
# end of 'dosunix.c'
fi
if test -f 'dosunix.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dosunix.h'\"
else
echo shar: Extracting \"'dosunix.h'\" \(779 characters\)
sed "s/^X//" >'dosunix.h' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	dosunix 5
X/* SUMMARY
X/*	UNIX <-> MS-DOS text format conversion
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	#include <stdio.h>
X/*	#include "dosunix.h"
X/* DESCRIPTION
X/* .nf
X
X /* Anticipate ANSI-compatible compilers */
X
X#ifdef __STDC__
Xint     unix2dos(FILE * ifp, FILE * ofp);
Xint     dos2unix(FILE * dfp, FILE * pfp);
Xchar   *dosgets(char *buf, int len, FILE * fp);
X
X#else
Xint     unix2dos();
Xint     dos2unix();
Xchar   *dosgets();
X
X#endif
X/* AUTHOR(S)
X/*	Wietse Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 29 16:41:50 MET 1989
X/* LAST MODIFICATION
X/*	10/29/89 22:30:05
X/* VERSION/RELEASE
X/*	1.1
X/*--*/
X
END_OF_FILE
if test 779 -ne `wc -c <'dosunix.h'`; then
    echo shar: \"'dosunix.h'\" unpacked with wrong size!
fi
# end of 'dosunix.h'
fi
if test -f 'percentm.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'percentm.h'\"
else
echo shar: Extracting \"'percentm.h'\" \(562 characters\)
sed "s/^X//" >'percentm.h' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	percentm 5
X/* SUMMARY
X/*	convert %m to system error message
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	#include percentm.h
X/* DESCRIPTION
X/* .nf
X
X /* external interface of the percentm module */
X
Xextern char *percentm();
X
X/* AUTHOR(S)
X/*	Wietse Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 29 15:29:37 MET 1989
X/* LAST MODIFICATION
X/*	10/29/89 22:31:53
X/* VERSION/RELEASE
X/*	1.1
X/*--*/
X
END_OF_FILE
if test 562 -ne `wc -c <'percentm.h'`; then
    echo shar: \"'percentm.h'\" unpacked with wrong size!
fi
# end of 'percentm.h'
fi
if test -f 'percentm.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'percentm.c'\"
else
echo shar: Extracting \"'percentm.c'\" \(1694 characters\)
sed "s/^X//" >'percentm.c' <<'END_OF_FILE'
X/*++
X/* NAME
X/*	percentm 3
X/* SUMMARY
X/*	convert %m to system error message
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	nfs
X/* SYNOPSIS
X/*	#include percentm.h
X/*
X/*	char *percentm(string, err)
X/*	char *string;
X/*	int err;
X/* DESCRIPTION
X/*	percentm() interprets %m format specificiers in \fIstring\fR
X/*	In the output, %m will be replaced by the error message that
X/*	corresponds with the error value \fIerr\fR (see <errno.h>.
X/* BUGS
X/*	The result is stored in static memory that is overwritten with
X/*	each call.
X/* AUTHOR(S)
X/*	Wietse Z. Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Sun Oct 29 15:29:37 MET 1989
X/* LAST MODIFICATION
X/*	10/29/89 22:30:06
X/* VERSION/RELEASE
X/*	1.1
X/*--*/
X
X#ifndef lint
Xstatic char sccsid[] = "@(#) percentm.c 1.1 10/29/89 22:30:06";
X
X#endif
X
X#include <stdio.h>
X#include "percentm.h"
X
Xextern int errno;
Xextern char *sys_errlist[];
Xextern int sys_nerr;
Xextern char *strcpy();
X
X/* percentm - replace %m by error message associated with value in err */
X
Xchar   *percentm(str, err)
Xchar   *str;
Xint     err;
X{
X    static char buf[BUFSIZ];
X    register char *ip = str;
X    register char *op = buf;
X
X    while (*ip) {
X	switch (*ip) {
X	case '%':
X	    switch (ip[1]) {
X	    case '\0':				/* don't fall off end */
X		*op++ = *ip++;
X		break;
X	    case 'm':				/* replace %m */
X		(void) strcpy(op,
X			sys_errlist[(err < sys_nerr && err > 0) ? err : 0]);
X		op += strlen(op);
X		ip += 2;
X		break;
X	    default:				/* leave %<any> alone */
X		*op++ = *ip++, *op++ = *ip++;
X		break;
X	    }
X	default:
X	    *op++ = *ip++;
X	}
X    }
X    return (buf);
X}
X
END_OF_FILE
if test 1694 -ne `wc -c <'percentm.c'`; then
    echo shar: \"'percentm.c'\" unpacked with wrong size!
fi
# end of 'percentm.c'
fi
if test -f 'pc-mail.8' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pc-mail.8'\"
else
echo shar: Extracting \"'pc-mail.8'\" \(1779 characters\)
sed "s/^X//" >'pc-mail.8' <<'END_OF_FILE'
X.TH PC-MAIL 8 
X.ad
X.fi
X.SH NAME
Xpc-mail
X\-
Xdeliver mail to nfs-based pc-mail users
X.SH PROJECT
X.na
X.nf
Xpc-mail
X.SH PACKAGE
X.na
X.nf
Xnfs
X.SH SYNOPSIS
X.na
X.nf
Xpc-mail user
X.SH DESCRIPTION
X.ad
X.fi
XThis program is to be run on the nfs server that exports mail
Xdirectories to MS-DOS pc-mail users. The program replaces the
XUNIX -> MS-DOS file transfer function of the MS-DOS \fIcico\fR
Xprogram.
X
XNormally, the pc-mail delivery program is invoked by sendmail(8).
XIts purpose is to deliver new mail in the mail directory of the
Xspecified \fIuser\fR (default /var/spool/pc-mail/\fIuser\fR).
XAny error conditions detected by the pc-mail delivery program
Xare reported back in a sendmail-compatible manner.
X
XThis program must be run with root privileges. It will assume
Xthe (uid, gid) of the specified user before delivering mail.
X
XThe program attempts to create any missing directories, and to
Xcorrect ownerships or protections where needed.
X.SH FILES
X.na
X.nf
X/usr/spool/pc-mail/\fIuser\fR/nNNNNN, mail message.
X/usr/spool/pc-mail/\fIuser\fR/hNNNNN, sender of message.
X(NNNNN is the pc-mail "message id").
X.SH SEE ALSO
X.na
X.nf
Xpc-maild(1)
X.SH DIAGNOSTICS
X.ad
X.fi
XAll conceivable error conditions cause the program to terminate
Xwith a non-zero exit status, after printing an error message on
Xthe standard error stream, and appending an entry to the system log.
XSee <sysexits.h> for details.
X.SH BUGS
X.ad
X.fi
XThere is no way to notify a pc-mail user of the arrival of new mail.
X.SH AUTHOR(S)
X.na
X.nf
XW.Z. Venema
XEindhoven University of Technology
XDepartment of Mathematics and Computer Science
XDen Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X.SH CREATION DATE
X.na
X.nf
XSun Oct 22 18:00:53 MED 1989
X.SH LAST MODIFICATION
X.na
X.nf
X11/19/89 13:46:04
X.SH VERSION/RELEASE
X.na
X.nf
X1.2
END_OF_FILE
if test 1779 -ne `wc -c <'pc-mail.8'`; then
    echo shar: \"'pc-mail.8'\" unpacked with wrong size!
fi
# end of 'pc-mail.8'
fi
if test -f 'pc-maild.8' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pc-maild.8'\"
else
echo shar: Extracting \"'pc-maild.8'\" \(1766 characters\)
sed "s/^X//" >'pc-maild.8' <<'END_OF_FILE'
X.TH PC-MAILD 8 
X.ad
X.fi
X.SH NAME
Xpc-maild
X\-
Xdeliver unsent mail
X.SH PROJECT
X.na
X.nf
Xpc-mail
X.SH PACKAGE
X.na
X.nf
Xnfs
X.SH SYNOPSIS
X.na
X.nf
Xpc-maild [delay]
X.SH DESCRIPTION
X.ad
X.fi
XThis program should be run on the nfs file server that exports
Xmail directories to MS-DOS pc-mail users. It replaces the
X(MS-DOS -> UNIX) transmission function of the MS-DOS \fIcico\fR
Xprogram.
X
XThe per-user mail directories (default: /var/spool/pc-mail/\fIuser\fR)
Xare scanned for outgoing mail every \fIdelay\fR seconds (default: 300).
XWhen outgoing mail is found, it is sent through the UNIX rmail program
X(uucp mail interface) and the corresponding files are removed from the
Xuser\'s mail directory.
X
XThe program should run with root privileges. It will assume
Xthe (uid, gid) of the sending user before accessing mail files.
X.SH COMMANDS
X.na
X.nf
Xrmail(1), uucp mail interface program
X.SH FILES
X.na
X.nf
X/usr/spool/pc-mail/\fIuser\fR/dNNNNN, mail message
X/usr/spool/pc-mail/\fIuser\fR/xNNNNN, recipients
X(NNNNN is the pc-mail "message id").
X.SH SEE ALSO
X.na
X.nf
Xpc-mail(1)
X.SH DIAGNOSTICS
X.ad
X.fi
XErrors found during initialization cause the program to
Xterminate with a diagnostic on the standard error stream.
XAll other errors are considered transient, i.e. if something
Xfails, it is tried again at a later time.  Where possible,
Xdiagnostics are logged through the syslog facility.
X.SH BUGS
X.ad
X.fi
XScanning mail directories is an inefficient way to detect
Xunsent mail.
X.SH AUTHOR(S)
X.na
X.nf
XW.Z. Venema
XEindhoven University of Technology
XDepartment of Mathematics and Computer Science
XDen Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X.SH CREATION DATE
X.na
X.nf
XSun Oct 22 22:12:15 MED 1989
X.SH LAST MODIFICATION
X.na
X.nf
X10/31/89 15:44:54
X.SH VERSION/RELEASE
X.na
X.nf
X1.3
END_OF_FILE
if test 1766 -ne `wc -c <'pc-maild.8'`; then
    echo shar: \"'pc-maild.8'\" unpacked with wrong size!
fi
# end of 'pc-maild.8'
fi
echo shar: End of shell archive.
exit 0