rsalz@uunet.uu.net (Rich Salz) (10/16/89)
Submitted-by: Chip Salzenberg <chip@ateng.com> Posting-number: Volume 20, Issue 23 Archive-name: deliver2.0/part01 Deliver is a program which delivers electronic mail once it has arrived at a given machine. It is intended for use in three environments: 1. Any Xenix system. 2. Any Unix system with smail 2.x. 3. Any Unix system with either sendmail or smail 3.x. If you have been frustrated by inflexible E-Mail delivery, here is your salvation. Deliver permits complete control over mail delivery through the use of "delivery files." Delivery files are shell scripts which are executed during message delivery. These shell scripts -- written by you! -- control who, if anyone, gets each E-Mail message. Mostly, Deliver 2.0 is an incremental enhancement from Deliver 1.0.8. New features include: 1. Parsing of the From_ line. Badly formed From_ lines, including those with illegal dates, are rejected. Messages with invalid From_ lines are still delivered, but the contents the From_ line is put into an Invalid-UUCP-From: line. 2. The "header" program, which parses RFC822 headers. Besides its obvious utility in delivery files, header should prove quite useful for scanning Usenet directories. 3. Sample delivery files, including the often-requested vacation "answering machine". -- Chip Salzenberg <chip@ateng.com> or <uunet!ateng!chip> A T Engineering "Designed with your mind in mind." #! /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 deliver.8 Makefile uid.c header.c getopt.c samples # samples/README samples/p-aliases samples/s-aliases samples/u-chip # samples/u-vacation 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'\" \(2335 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' X$Header: README,v 2.1 89/06/09 12:25:10 network Exp $ X X X WHAT IS DELIVER? X X XDeliver is a program which delivers electronic mail once it has arrived Xat a given machine. X X X X WHO CAN USE IT? X X XDeliver is intended for use in three environments: X X X 1. Any Xenix system. X X Deliver was invented to be a direct replacement for the Xenix X program /usr/lib/mail/mail.local. In fact, on ateng, mail.local is X just another link to /usr/bin/deliver. X X X 2. Any Unix system with smail 2.x. X X You can use deliver for local mail by changing the local mailer X definition in config.h: X #define LMAIL(frm) "/usr/bin/deliver -r '%s'",frm X X X 3. Any Unix system with either sendmail or smail 3.x. X X Any user can let deliver handle all his mail by putting the X following line in his .forward file: X "|/usr/bin/deliver username" X Be sure to specify the correct username, or someone else will X get your mail! X X X X PORTABILITY X X XDeliver has been compiled and tested under SCO Xenix System V/286 and 4.3 XBSD. The configuration provides for System V, but I have not been able to Xtest it. (Patches for all environments are welcome; see below.) X X X X WARNINGS: BE CAREFUL! X X X 1. Deliver is intended to be run setuid root; otherwise it would not X be possible to execute a user delivery file in the context of its X owner. Any setuid root program is a potential security hole! Be X careful of the modes on the deliver binary and the directory where X it lives. X X 2. Deliver's flexibility makes it easy to lose lots of mail through X carelessness in configuration. Delivery files should be written X with extreme care. X X X X COMPILING AND INSTALLING X X XEdit the Makefile and config.h to taste. Type "make". To install, type X"make install". See the Makefile for further hints. X X X X HELP SAVE THE WORLD! X X XIf you run into a bug, you are probably not alone. Save your fellow human Xbeings from toil and trouble! Send mail to <bugs-deliver@ateng.uucp>. Bug Xreports accepted; patches greatly appreciated. I will coordinate patches. X XThank you, and good night. X X Chip Salzenberg X A T Engineering X X <chip@ateng.uucp> or X <chip@ateng.uu.net> or X <uunet!ateng!chip> END_OF_FILE if test 2335 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'deliver.8' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'deliver.8'\" else echo shar: Extracting \"'deliver.8'\" \(11359 characters\) sed "s/^X//" >'deliver.8' <<'END_OF_FILE' X.\" $Header: deliver.8,v 2.1 89/06/09 12:25:19 network Exp $ X.\" X.\" Man page for deliver. X.\" X.\" $Log: deliver.8,v $ X.\" Revision 2.1 89/06/09 12:25:19 network X.\" Update RCS revisions. X.\" X.\" Revision 1.8 89/06/09 12:23:42 network X.\" Baseline for 2.0 release. X.\" X.TH DELIVER 8 X.SH NAME Xdeliver \- deliver local mail X.SH SYNOPSIS X.B deliver X[ options ] address ... X.SH DESCRIPTION XThe X.I deliver Xprogram collects a mail message from the standard input and delivers it. XIt is intended to take over the delivery of all local mail, a job usually Xhandled by X.I /bin/mail X(System V), X.I /usr/lib/sendmail X(BSD), or X.I /usr/lib/mail/mail.local X(Xenix). X.PP X.I deliver Xintroduces flexibility in the handling of local mail delivery. All files Xused to control X.I deliver Xare Bourne shell scripts. Thus anything that can be called by a shell Xscript can be used to control mail delivery. X.SH OPTIONS X.TP X.B \-b XInterpret all arguments as mailbox filenames instead of addresses. Note Xthat the user running X.I deliver Xmust have write permissions on the given mailbox files. He may also need Xwrite permissions on their parent directories, depending on the existence Xof the mailbox file and the local locking protocol. X.TP X.B \-n XInterpret arguments as addresses, but do not run any delivery files; simply Xdeliver the message to the mailbox(es) of the given user(s). This option is Xmost useful when X.I deliver Xis executed recursively, since it prevents further recursion. X.TP X.B \-A XPrint resolved addresses; do not deliver the message. Note that X.I deliver Xstill collects a message from the standard input, since delivery files may Xdo different things depending on message content. For simple testing, Xredirect standard input from /dev/null. X.TP X.B \-d XBe verbose; don't deliver to any mailboxes or catch any signals. X.TP X.B \-v XBe verbose, but still deliver. X.TP X.B \-t XDo not remove temporary files before exiting. X.TP X.BI \-r " sender" XPut X.I sender Xon the generated From_ line. Default is to use the address on the From_ Xline in the input, or else the name corresponding to the real uid, or else X"unknown". X.TP X.BI \-h " hostname" XSet the host name. The default is configuration dependent. X.TP X.BI \-s " system delivery file" XSpecify an alternate system delivery file. The default is X.I /usr/local/lib/deliver.sys. XFor security reasons, this option disables setuid privileges. X.TP X.BI \-p " post-user delivery file" XSpecify an alternate post-user delivery file. The default is X.I /usr/local/lib/deliver.post. XFor security reasons, this option disables setuid privileges. X.TP X.BI \-u " user delivery file" XSpecify an alternate user delivery file. The default is X.I .deliver X(in each user's home directory). XFor security reasons, this option disables setuid privileges. X.PP XAll command line options are put into environment variables, examined by X.I deliver Xon startup; thus all flags are propagated when X.I deliver Xis invoked recursively. X.SH ENVIRONMENT XFor mail systems based on X.I smail X2.x, the LMAIL (local mailer) macro can be changed to call X.I deliver. XFor mail systems based on X.I smail X3.x or X.I sendmail, Xa similar arrangement may be made; or individual users can invoke X.I deliver Xby mentioning it in their X.I .forward Xfiles. X.PP XFor Xenix systems, X.I deliver Xmay be used as a direct replacement for X.IR /usr/lib/mail/mail.local. X.PP XFor stock Unix systems, it may be possible to make X.I /bin/rmail Xa link to X.I deliver; Xhowever, this configuration has not been tested and is not recommended. XAny postmaster motivated enough to install X.I deliver, Xand who wants something better than the standard X.I /bin/rmail, Xshould install X.I smail. X.SH OPERATION XBy default, X.I deliver Xdeposits mail in the system mailbox for the named user(s). Also, as a Xnecessity for use with X.I smail X2.x, X.I deliver Xalso understands UUCP-style bang addresses well enough to forward the Xmessage correctly, using X.I uux. X.PP XHowever, this basic behavior only scratches the surface: the usefulness of X.I deliver Xderives from its flexibility; its behavior can be made to depend on the Xrecipient(s), content or any other aspect of mail messages. X.PP XWhen X.I deliver Xstarts execution, it interprets its arguments in one of three ways. If the X.B \-b X(mailbox) option was specified, then all arguments are interpreted as Xmailbox pathnames. Otherwise, if a system delivery file exists and the X.B \-n X(no delivery files) option was not specified, X.I deliver Xexecutes the system delivery file with all of deliver's arguments Xas its arguments. X.I deliver Xinterprets the delivery file's output as described below. This procedure Xgives the postmaster control over delivery to non-existent hosts and users. XIf the X.B \-n Xoption is specified or if there is no system delivery file, X.I deliver Xinterprets all its arguments as mail addresses. X.PP XAfter possibly executing the system delivery file, X.I deliver Xlooks in its list of destinations for valid user names without explicitly Xnamed mailboxes. If any of these users have user delivery files in Xtheir home directories, and if the X.B \-n Xoption was not specified, X.I deliver Xexecutes each user delivery file with the name of the given user as its Xonly argument. X.PP XAfter executing any user delivery files, X.I deliver Xlooks in its list of destinations for simple user names and UUCP Xaddresses. If any are found, if the post-user delivery file exists, Xand if the X.B \-n Xoption was not specified, X.I deliver Xexecutes the post-user delivery file with these addresses as its arguments. X.SH "DELIVERY FILES" XDelivery files are shell scripts. They are executed by X.I deliver Xto control delivery to users. Note that delivery files do X.I not Xcontrol delivery to explicitly named mailboxes. X.PP XOn each system the postmaster may create a X.I system delivery file Xto controls delivery of all messages. XThe system delivery file, if it exists, is executed Xwith the name(s) specified on the X.I deliver Xcommand line as its arguments. X.PP XThe postmaster may also create a X.I post-user delivery file Xwhich is executed after any user delivery files, but before delivery of the Xmessage to any mailboxes. This file is particularly useful for implementing Xsystem-wide aliases, since it can deal with addresses generated by user Xdelivery files, whereas the system delivery file cannot. X.PP XFinally, each user may create a X.I user delivery file Xin his home directory. User delivery files are always executed with exactly Xone argument: the name of the user in whose home directory the file is Xfound. X.PP XRecursive execution of X.I deliver Xis useful, especially with the X.B \-b X(mailbox) and X.B \-n X(no delivery files) flags. For example, a user may wish to transform a Xmessage body before it is stored in a mailbox. This may be done with a user Xdelivery file and recursive execution of X.I deliver. XFor example, the following user delivery file translates all incoming Xmessage bodies to lower case, and stores them in the user's default mailbox: X.TP X(cat $HEADER; tr '[A-Z]' '[a-z]' <$BODY) | deliver -n "$1" X.PP XWhen X.I deliver Xexecutes a delivery file, it sets several environment variables, listed Xbelow. XNote that these environment variables are both set and used by X.I deliver; Xtherefore, all command line options automatically propagate when X.I deliver Xis run recursively (within a delivery file). The environment variable Xnames set and used by X.I deliver Xare: X.TP X.B DELFLAGS XThe command line flags, if any, specified on the X.I deliver Xcommand line. X.TP X.B SYSDELFILE XThe system delivery filename. X.TP X.B POSTDELFILE XThe post-user delivery filename. X.TP X.B USERDELFILE XThe user delivery filename, relative to the home directory of each user. X.TP X.B HOSTNAME XThe local host name, either the real hostname or a name specified with the X.B \-h Xoption to X.I deliver. X.TP X.B SENDER XThe sender, either an address specified with X.B \-r Xoption to X.I deliver, Xor the address given in the From_ line of the message, or the user who Xinvoked X.I deliver. X.TP X.B HEADER XThe name of the temporary file containing the message header. X.TP X.B BODY XThe name of the temporary file containing the message body. X.PP X.I deliver Xmonitors the standard output of delivery files for lines of two forms: Xeither "user" or "user:mailbox". Those users whose names appear in the Xoutput of a delivery file will receive the message. If a mailbox name Xappears after the user name, then that mailbox receives the message. If a Xmailbox name is not specified, the user's default mailbox is used. (The Xdefault mailbox for a user is configuration-dependent.) If a mailbox is not Xan absolute pathname, it is interpreted relative to the home directory of Xthe named user. X.PP X.B NOTE 1: XWhen X.I deliver Xexecutes a delivery file, it expects that delivery file to explicitly name Xall users (and, optionally, mailboxes) where the message should be Xdelivered. If a delivery file does not name any users in its output, then Xthe message will not be delivered to anyone whose mail delivery is Xcontrolled by that delivery file. X.PP XTherefore, a user delivery file containing only "exit" will keep the given Xuser from receiving any mail. A system delivery file containing only "exit" Xwill cause X.B all Xmail to disappear. So be careful! X.PP X.B NOTE 2: XIf X.I deliver Xis setuid root -- which it should be for normal operation -- then the system Xdelivery file is executed as root. Be X.I "very careful" Xabout its permissions and its contents! Carelessness here can easily Xcreate a security problem. X.PP X.B NOTE 3: XAll user delivery files are executed in the context of the user in whose Xhome directory they reside. A user's "context" includes the uid, gid, and Xhome directory as specified in /etc/passwd. X.PP X.B NOTE 4: XFor security reasons, if a user's home directory is writable to the world, X.I deliver Xwill ignore any delivery file that might be found there. X.PP X.B NOTE 5: XFor security reasons, X.I deliver Xrejects lines of the form "user:mailbox" when generated by a user delivery Xfile unless they are output by the given user's delivery file. In other Xwords, no user can request writing a mailbox as another user. X.SH LOCKING XSeveral preprocessor labels may be defined during compilation to control Xthe method(s) used by X.I deliver Xto lock mailboxes. These labels are: X.RS X.PP X.B ML_DOTLOCK XLock on exclusive creation of the mailbox name with ".lock" Xappended. (Version 7 and early BSD mailers use this method.) X.PP X.B ML_DOTMLK XLock on exclusive creation of X.I /tmp/basename.mlk, Xwhere X.I basename Xis the last component of the mailbox pathname. (Xenix mailers use this Xmethod.) X.PP X.B ML_LOCKF XExclusively lock mailbox with lockf(). X.PP X.B ML_FCNTL XExclusively lock mailbox with fcntl(). X.PP X.B ML_LOCKING XExclusively lock mailbox with locking(). X.PP X.RE XOne or both of ML_DOTLOCK and ML_DOTMLK may be specified. At most one of XML_LOCKF, ML_FCNTL or ML_LOCKING may be specified. X.SH FILES X/usr/local/lib/deliver.sys system delivery file X.br X/usr/local/lib/deliver.post post-user delivery file X.br X~user/.deliver user delivery file(s) X.br X/etc/systemid system name (Xenix only) X.SH SUPPORT XEnhancements, enhancement requests, trouble reports, etc., should be mailed Xto <bugs-deliver@ateng.com>; or for UUCP-only sites, X<uunet!ateng!bugs-deliver>. X.SH "SEE ALSO" X.IR mail (1), X.IR uux (1), X.IR smail (8), X.IR sendmail (8) END_OF_FILE if test 11359 -ne `wc -c <'deliver.8'`; then echo shar: \"'deliver.8'\" unpacked with wrong size! fi # end of 'deliver.8' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(4306 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# $Header: Makefile,v 2.2 89/06/09 13:19:53 network Exp $ X# X# Makefile for deliver X# X# +----------------+ X# | Things to make | X# +----------------+ X# X# deliver Compile and link the deliver program. X# header Compile and link the header program. X# install Install deliver and header. (You must be root.) X# lint Run lint on all sources, creating lint.out. X# shar Create distribution sharchives. X# clean Clean up. X# clobber Remove everything that can be regenerated. X# X# +---------------+ X# | Configuration | X# +---------------+ X# X# SHELL X# I don't have to tell you... X# X# COPY X# Your local copy program. SCO Xenix users may want to change this X# to "copy -m" which preserves file modification time. X# X# SHAR X# Your local sharchive generator. X# X# CFLAGS X# Compile-time flags to cc. X# For BSD systems, include "-DBSD". X# For USG (System III and System V) systems, include "-DUSG". X# X# LDFLAGS X# Link-time flags to cc. The -i flag creates pure (sharable) code. X# X# LIBS X# Depending on your environment, you may or may not need to link X# with "-lx". SCO Xenix System V needs it; Altos Xenix doesn't. X# X# BIN X# Target directory for installation; /usr/bin is recommended. X# You may use /usr/local/bin (or whatever), but you must be sure X# that the directory you choose is in your PATH during mail X# transmission and delivery. X# X# DELSHAR X# Basename of sharchives created by "make shar". X# X XSHELL = /bin/sh XCOPY = cp XSHAR = shar XCFLAGS = -O XLDFLAGS = -i XLIBS = -lx XBIN = /usr/bin XDELSHAR = deliver.sh X X# X# The files that make up the deliver distribution. X# X XDOCS = README deliver.8 XMF = Makefile X XHDRS = config.h context.h deliver.h dest.h patchlevel.h misc.h X XDELSRC1 = context.c copymsg.c XDELSRC2 = debug.c dest.c dfile.c lock.c main.c XDELSRC3 = mbox.c procs.c subs.c sysdep.c unctime.y uucp.c XDELSRCS = $(DELSRC1) $(DELSRC2) $(DELSRC3) XUIDSRCS = uid.c XHDRSRCS = header.c XCOMSRCS = getopt.c XSAMPLES = samples samples/* X XDELOBJS = context.o copymsg.o debug.o dest.o dfile.o lock.o \ X main.o mbox.o procs.o subs.o sysdep.o unctime.o uucp.o XUIDOBJS = uid.o XHDROBJS = header.o XCOMOBJS = getopt.o X X# X# For GNU Make. Sorry about the ugliness. X# X X.PHONY: all install lint shar clean clobber X X# X# The default target. X# X Xall: deliver header uid X X# X# "make clobber" implies "make clean". X# X Xclobber:: clean X X# X# How to install deliver and associated utilities. X# X Xinstall: deliver header uid X @if [ `./uid -uU | fgrep '(root)' | wc -l` -ne 2 ]; \ X then \ X echo "Sorry! You must be root to install deliver."; \ X exit 1; \ X fi X $(COPY) deliver $(BIN)/deliver X chgrp root $(BIN)/deliver X chown root $(BIN)/deliver X chmod 4711 $(BIN)/deliver X $(COPY) header $(BIN)/header X chmod 755 $(BIN)/header X X# X# How to compile and link the program. X# X Xdeliver: $(DELOBJS) $(COMOBJS) X $(CC) $(LDFLAGS) -o $@ $(DELOBJS) $(COMOBJS) $(LIBS) X$(DELOBJS): $(HDRS) X Xclean:: X rm -f $(DELOBJS) Xclobber:: X rm -f deliver X X# X# A header parsing program. X# X Xheader: $(HDRSRCS) $(COMOBJS) X $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(HDRSRCS) $(COMOBJS) $(LIBS) X rm -f $(HDROBJS) X Xclobber:: X rm -f header X X# X# A little program to check on user and group id's. X# (I wish that the System V "id" program were available everywhere.) X# X Xuid: $(UIDSRCS) $(COMOBJS) config.h X $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(UIDSRCS) $(COMOBJS) $(LIBS) X rm -f $(UIDOBJS) X Xclobber:: X rm -f uid X X# X# Common subroutines X# X X$(COMOBJS): config.h X Xclean:: X rm -f $(COMOBJS) X X# X# Look for fuzz. X# X Xlint: deliver.lint uid.lint X Xdeliver.lint: $(HDRS) $(DELSRCS) $(COMSRCS) X lint $(DELSRCS) $(COMSRCS) -lc $(LIBS) >$@ X Xuid.lint: config.h $(UIDSRCS) $(COMSRCS) X lint $(UIDSRCS) $(COMSRCS) -lc $(LIBS) >$@ X Xclean:: X rm -f *.lint X X# X# Make distribution sharchives. X# X Xshar: $(DELSHAR).01 $(DELSHAR).02 $(DELSHAR).03 $(DELSHAR).04 X$(DELSHAR).01: $(DOCS) $(MF) $(UIDSRCS) $(HDRSRCS) $(COMSRCS) $(SAMPLES) X $(SHAR) >$@ $(DOCS) $(MF) $(UIDSRCS) $(HDRSRCS) $(COMSRCS) $(SAMPLES) X$(DELSHAR).02: $(HDRS) $(DELSRC1) X $(SHAR) >$@ $(HDRS) $(DELSRC1) X$(DELSHAR).03: $(DELSRC2) X $(SHAR) >$@ $(DELSRC2) X$(DELSHAR).04: $(DELSRC3) X $(SHAR) >$@ $(DELSRC3) X Xclobber:: X rm -f $(DELSHAR).?? END_OF_FILE if test 4306 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'uid.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'uid.c'\" else echo shar: Extracting \"'uid.c'\" \(2772 characters\) sed "s/^X//" >'uid.c' <<'END_OF_FILE' X/* $Header: uid.c,v 2.1 89/06/09 12:25:41 network Exp $ X * X * I wish the System V "id" program were universally available; but it X * isn't, so I've written this replacement. X * X * usage: uid [-options] X * X * Default action is to print one line in the manner of "id": X * uid=201(chip) gid=50(group) euid=0(root) egid=0(root) X * (Note that the "euid" and "egid" entries are not output if they are X * the same as the "uid" and "gid" values.) X * X * If an option string is specified, it disables the normal behavior in X * favor of displaying id information, one per line, in the order that X * the options appear in the option string. Legal options are: X * u real uid X * g real gid X * U effective uid X * G effective gid X * X * NOTE: This program is not a paragon of good style. X * It's just something I needed for a Makefile. X * X * $Log: uid.c,v $ X * Revision 2.1 89/06/09 12:25:41 network X * Update RCS revisions. X * X * Revision 1.3 89/06/09 12:24:00 network X * Baseline for 2.0 release. X * X */ X X#include <stdio.h> X#include <pwd.h> X#include <grp.h> X#include "config.h" X X#ifdef NULL X#undef NULL X#endif X#define NULL 0 X Xextern struct passwd *getpwuid(); Xextern struct group *getgrgid(); X Xchar *progname = "uid"; X Xchar *uid_desc(); Xchar *gid_desc(); X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X int uid, gid, euid, egid; X int c, lines, errcount; X X uid = getuid(); X gid = getgid(); X euid = geteuid(); X egid = getegid(); X X errcount = 0; X lines = 0; X X while ((c = getopt(argc, argv, "ugUG")) != EOF) X { X switch (c) X { X case 'u': X (void) printf("%s\n", uid_desc(uid)); X ++lines; X break; X X case 'g': X (void) printf("%s\n", gid_desc(gid)); X ++lines; X break; X X case 'U': X (void) printf("%s\n", uid_desc(euid)); X ++lines; X break; X X case 'G': X (void) printf("%s\n", gid_desc(egid)); X ++lines; X break; X X case '?': X ++errcount; X break; X } X } X X if (errcount) X { X (void) fprintf(stderr, "usage: uid [-ugUG]\n"); X exit(1); X } X X if (lines == 0) X { X (void) printf("uid=%s", uid_desc(uid)); X (void) printf(" gid=%s", gid_desc(gid)); X X if (euid != uid) X (void) printf(" euid=%s", uid_desc(euid)); X if (egid != gid) X (void) printf(" egid=%s", gid_desc(egid)); X X (void) printf("\n"); X } X X exit(0); X /* NOTREACHED */ X} X Xchar * Xuid_desc(uid) Xint uid; X{ X struct passwd *pw; X static char buf[80]; X X (void) sprintf(buf, "%d", uid); X if ((pw = getpwuid(uid)) != NULL) X (void) sprintf(buf + strlen(buf), "(%s)", pw->pw_name); X X return buf; X} X Xchar * Xgid_desc(gid) Xint gid; X{ X struct group *gr; X static char buf[80]; X X (void) sprintf(buf, "%d", gid); X if ((gr = getgrgid(gid)) != NULL) X (void) sprintf(buf + strlen(buf), "(%s)", gr->gr_name); X X return buf; X} END_OF_FILE if test 2772 -ne `wc -c <'uid.c'`; then echo shar: \"'uid.c'\" unpacked with wrong size! fi # end of 'uid.c' fi if test -f 'header.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'header.c'\" else echo shar: Extracting \"'header.c'\" \(4796 characters\) sed "s/^X//" >'header.c' <<'END_OF_FILE' X/* $Header: header.c,v 2.2 89/06/09 13:08:07 network Exp $ X * X * A program to parse RFC 822 mail/news headers. X * X * usage: header [-c] [-n] [-f field] ... files X * X * Default action is to print entire header. If one or more -f options X * are given, only the specified fields are printed. The field names are X * not printed unless -n is specified. Field name comparisons are case X * insensitive unless -c is specified. X * X * Output lines are preceeded by the filename if more than one file is X * specified. X * X * This program is intended for use in delivery files, to extract multi- X * line header fields. X * X * $Log: header.c,v $ X * Revision 2.2 89/06/09 13:08:07 network X * Adapt to BSD quirks. X * X * Revision 2.1 89/06/09 12:25:29 network X * Update RCS revisions. X * X * Revision 1.5 89/06/09 12:23:51 network X * Baseline for 2.0 release. X * X */ X X#include <stdio.h> X#include <ctype.h> X X/* X * Manifest constants X */ X X#define TRUE 1 X#define FALSE 0 X X/* X * Other useful macros. X */ X X#define GETSIZE(buf) (sizeof(buf) - 1) X X#define ISFROM(p) ((p)[0] == 'F' && (p)[1] == 'r' && (p)[2] == 'o' \ X && (p)[3] == 'm' && (p)[4] == ' ') X X/* X * External data. X */ X X/* Variables set by getopt() [blech] */ X Xextern int optind, opterr; Xextern char *optarg; X X/* X * Library functions. X */ X Xextern char *malloc(); Xextern char *realloc(); Xextern void free(); X X/* X * Global data X */ X Xint field_count = 0; Xint field_alloc = 0; Xchar **field_names = NULL; X Xint nocasematch = TRUE; /* ignore case in header matches */ Xint printnames = FALSE; /* print field names with data */ X X/*---------------------------------------------------------------------- X * The Program. X */ X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X int c, errors; X X field_alloc = 8; X field_names = (char **) malloc(field_alloc * sizeof(char **)); X if (field_names == NULL) X nomem(); X X errors = FALSE; X while ((c = getopt(argc, argv, "cnf:")) != EOF) X { X switch (c) X { X case 'c': X nocasematch = FALSE; X break; X case 'n': X printnames = TRUE; X break; X case 'f': X if (field_count >= field_alloc) X { X field_alloc *= 2; X field_names = X (char **) realloc((char *)field_names, X field_alloc * sizeof(char **)); X if (field_names == NULL) X nomem(); X } X field_names[field_count++] = optarg; X break; X default: X errors = TRUE; X break; X } X } X X if (errors) X usage(); X X if (optind == argc) X header(stdin, (char *)NULL); X else X { X FILE *fp; X int a, filenames; X X filenames = ((argc - optind) > 1); X for (a = optind; a < argc; ++a) X { X if ((fp = fopen(argv[a], "r")) == NULL) X { X errors = TRUE; X perror(argv[a]); X continue; X } X X header(fp, (filenames ? argv[a] : (char *)NULL)); X fclose(fp); X } X } X X exit(errors ? 1 : 0); X} X Xusage() X{ X fprintf(stderr, "usage: header [-c] [-f fieldname] ... files\n"); X exit(1); X} X Xnomem() X{ X fprintf(stderr, "header: out of memory\n"); X exit(1); X} X Xheader(fp, filename) XFILE *fp; Xchar *filename; X{ X char buf[1024]; X X if (fgets(buf, GETSIZE(buf), fp) == NULL) X return; X X /* Ignore From_ line(s). */ X X while (ISFROM(buf) || buf[0] == '>') X { X if (fgets(buf, GETSIZE(buf), fp) == NULL) X return; X } X X while (buf[0] != '\n') X { X char *p; X int print_this; X X p = buf; X while (isupper(*p) || islower(*p) || isdigit(*p) || *p == '-') X ++p; X if (p == buf || *p != ':') X break; X print_this = field(buf, p - buf); X if (print_this) X { X if (filename) X { X fputs(filename, stdout); X putc(':', stdout); X } X ++p; X if (*p == ' ' || *p == '\t') X ++p; X if (field_count == 0 || printnames) X fputs(buf, stdout); X else X fputs(p, stdout); X } X X /* get the next input line */ X if (fgets(buf, GETSIZE(buf), fp) == NULL) X break; X X /* deal with continuation lines */ X while (buf[0] == ' ' || buf[0] == '\t') X { X if (print_this) X { X if (filename) X { X fputs(filename, stdout); X putc(':', stdout); X } X fputs(buf, stdout); X } X X if (fgets(buf, GETSIZE(buf), fp) == NULL) X { X buf[0] = '\n'; X break; X } X } X } X} X Xint Xfield(s, n) Xchar *s; Xint n; X{ X int i; X X if (field_count == 0) X return TRUE; X X for (i = 0; i < field_count; ++i) X { X char *f = field_names[i]; X X if (strlen(f) == n) X { X if (nocasematch) X { X if (ci_strncmp(f, s, n) == 0) X return TRUE; X } X else X { X if (strncmp(f, s, n) == 0) X return TRUE; X } X } X } X X return FALSE; X} X Xint Xci_strncmp(s, t, n) Xchar *s, *t; Xint n; X{ X char c, d; X X while (n-- > 0) X { X c = *s++; X d = *t++; X if ((c == 0) && (d == 0)) X break; X if (isupper(c)) X c = tolower(c); X if (isupper(d)) X d = tolower(d); X if (c > d) X return 1; X if (c < d) X return -1; X } X X return 0; X} END_OF_FILE if test 4796 -ne `wc -c <'header.c'`; then echo shar: \"'header.c'\" unpacked with wrong size! fi # end of 'header.c' fi if test -f 'getopt.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getopt.c'\" else echo shar: Extracting \"'getopt.c'\" \(1719 characters\) sed "s/^X//" >'getopt.c' <<'END_OF_FILE' X/* $Header: getopt.c,v 2.1 89/06/09 12:25:28 network Exp $ X * X * A version of the public-domain getopt() function, as found X * in the SVID and fine Unix manuals everywhere. X * X * $Log: getopt.c,v $ X * Revision 2.1 89/06/09 12:25:28 network X * Update RCS revisions. X * X * Revision 1.4 89/06/09 12:23:50 network X * Baseline for 2.0 release. X * X */ X X#include <stdio.h> X#include "config.h" X#include "misc.h" X X/*---------------------------------------------------------------------- X * Get command line options. X * This is essentially the public domain version, just reformatted to X * match the rest of the deliver program. X */ X X#ifndef HAS_GETOPT X Xint opterr = 1; Xint optind = 1; Xint optopt = 0; Xchar *optarg = NULL; X X#define ERR(what,c) \ X if (!opterr) {} else fprintf(stderr,"%s: %s -- %c\n", argv[0], what, c); X Xint Xgetopt(argc, argv, opts) Xint argc; Xchar **argv; Xchar *opts; X{ X static int sp = 1; X int c; X char *cp; X X if (sp == 1) X { X if (optind >= argc X || argv[optind][0] != '-' || argv[optind][1] == '\0') X return EOF; X X if (strcmp(argv[optind], "--") == NULL) X { X optind++; X return EOF; X } X } X X optopt = c = argv[optind][sp]; X X if (c == ':' || (cp = strchr(opts, c)) == NULL) X { X ERR("illegal option", c); X if (argv[optind][++sp] == '\0') X { X optind++; X sp = 1; X } X return '?'; X } X X if (*++cp == ':') X { X if (argv[optind][sp + 1] != '\0') X optarg = &argv[optind++][sp + 1]; X else if (++optind >= argc) X { X ERR("option requires an argument", c); X sp = 1; X return '?'; X } X else X optarg = argv[optind++]; X X sp = 1; X } X else X { X if (argv[optind][++sp] == '\0') X { X sp = 1; X optind++; X } X X optarg = NULL; X } X X return c; X} X X#endif /* !HAS_GETOPT */ END_OF_FILE if test 1719 -ne `wc -c <'getopt.c'`; then echo shar: \"'getopt.c'\" unpacked with wrong size! fi # end of 'getopt.c' fi if test ! -d 'samples' ; then echo shar: Creating directory \"'samples'\" mkdir 'samples' fi if test -f 'samples/README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'samples/README'\" else echo shar: Extracting \"'samples/README'\" \(229 characters\) sed "s/^X//" >'samples/README' <<'END_OF_FILE' XREADME for samples. X XThese sample delivery file are provides for your edification and amusement. XI've actually tested u-chip and u-vacation; the other samples are just off Xthe top of my head. Use at your own risk, and all that. END_OF_FILE if test 229 -ne `wc -c <'samples/README'`; then echo shar: \"'samples/README'\" unpacked with wrong size! fi # end of 'samples/README' fi if test -f 'samples/p-aliases' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'samples/p-aliases'\" else echo shar: Extracting \"'samples/p-aliases'\" \(445 characters\) sed "s/^X//" >'samples/p-aliases' <<'END_OF_FILE' X: p-aliases X# A sample post-user deliver file. X# X# This post-user delivery file provides system-wide aliases that are X# processed after user delivery files have had their say. X Xfor u Xdo X case $u in X root) echo buoc ;; # Big User On Computer :-) X uucp) echo buoc ;; X postmaster) echo buoc ;; X bug-alias) echo user1; echo user2 ;; # Both users get each message X *) echo $u ;; X esac Xdone END_OF_FILE if test 445 -ne `wc -c <'samples/p-aliases'`; then echo shar: \"'samples/p-aliases'\" unpacked with wrong size! fi # end of 'samples/p-aliases' fi if test -f 'samples/s-aliases' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'samples/s-aliases'\" else echo shar: Extracting \"'samples/s-aliases'\" \(653 characters\) sed "s/^X//" >'samples/s-aliases' <<'END_OF_FILE' X: s-aliases X# A sample system delivery file. X# X# While Joe is gone, send problem reports to Fred. X# Note that since user delivery files are processed after this one, X# Fred's user delivery file may direct all such mail back to joe X# if Fred wants to be difficult. :-) X# Note that a better solution is to use a bug report alias, X# but this method demonstrates variable delivery based X# on message headers. X XSUBJECT=`header -f subject $HEADER | tr '[A-Z]' '[a-z]'` X Xfor u Xdo X case $u in X joe) case $SUBJECT in X *bug*|*problem*) echo fred ;; X *) echo joe ;; X esac ;; X *) echo $u ;; X esac Xdone END_OF_FILE if test 653 -ne `wc -c <'samples/s-aliases'`; then echo shar: \"'samples/s-aliases'\" unpacked with wrong size! fi # end of 'samples/s-aliases' fi if test -f 'samples/u-chip' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'samples/u-chip'\" else echo shar: Extracting \"'samples/u-chip'\" \(247 characters\) sed "s/^X//" >'samples/u-chip' <<'END_OF_FILE' X: u-chip X# Chip's user delivery file. X Xuser="$1" XTO=`header -f To -f CC $HEADER` X Xcase "$SENDER" in X*zardoz*!sec*) echo $user:mbox.sec; exit ;; Xesac X Xcase "$TO" in X*ietf*|*ineng*) echo $user:mbox.ietf; exit ;; Xesac X X# Default case Xecho $user END_OF_FILE if test 247 -ne `wc -c <'samples/u-chip'`; then echo shar: \"'samples/u-chip'\" unpacked with wrong size! fi # end of 'samples/u-chip' fi if test -f 'samples/u-vacation' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'samples/u-vacation'\" else echo shar: Extracting \"'samples/u-vacation'\" \(1033 characters\) sed "s/^X//" >'samples/u-vacation' <<'END_OF_FILE' X: u-vacation X# A user delivery file for when you're on vacation. X# X# The ALREADY file remembers who you've already mailed vacation messages to. X# The BEBACK string is the date you will return. X XALREADY=vacation.list XBEBACK="on July 4, 1776" X Xecho "$1" # Keep the mail! X Xif grep '^'${SENDER}'$' $ALREADY >/dev/null 2>/dev/null Xthen X exit 0 # We already notified this person; reject Xfi X Xcase $SENDER in X*uucp) exit 0 ;; # Not a human; reject X*daemon) exit 0 ;; # Not a human; reject X*DAEMON) exit 0 ;; # Not a human; reject X*!*) ;; X*@*) ;; X## *) exit 0 ;; # Local user; reject (maybe) Xesac X X# Remember this person Xecho $SENDER >>$ALREADY X X# Send the vacation message XSUBJECT=`header -f subject $HEADER` Xmail -s "I'm on vacation" $SENDER <<!EOF! XYour message to me on the subject X "$SUBJECT" Xhas been delivered. However, I am on vacation, so I have not yet Xread your message. I will be back $BEBACK. X XThis is the only such message you will receive. X XThank you. X!EOF! END_OF_FILE if test 1033 -ne `wc -c <'samples/u-vacation'`; then echo shar: \"'samples/u-vacation'\" unpacked with wrong size! fi # end of 'samples/u-vacation' fi echo shar: End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.