[comp.os.minix] umail part 2 of 2

ast@cs.vu.nl (Andy Tanenbaum) (10/23/89)

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'Makefile'
sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile'
X#
X#       Makefile for UMAIL Mail Router (MINIX)
X#
X# Author:   Fred van Kempen, MicroWalt Corporation
X#
X# Define WMAILER if the local mailer is W-MAIL.
X# This mailer understands the "-i filename" option,
X# and this works much faster than stdIO redirecting.
X#
XCFLAGS  =	-DMINIX -DWMAILER
X
XBIN	=	/usr/bin
X
XOBJS    =	ummain.s umtime.s umheader.s umconvert.s \
X		umroute.s umsend.s umscanner.s
XSRCS    =	ummain.c umtime.c umheader.c umconvert.c \
X		umroute.c umsend.c umscanner.c
XOTHERS	=	README umail.doc umail.cf umail Makefile uucp.h umail.h
X
Xumail:	   	Makefile $(OBJS)
X	   	cc -i -o umail $(OBJS)
X		@chmem =16000 umail >/dev/null
X
Xinstall:	umail
X		@rm -f $(BIN)/umail $(BIN)/rmail
X		@echo 'Copying files...'
X		@cp umail $(BIN)/umail
X		@echo 'Setting up links...'
X		@ln $(BIN)/umail $(BIN)/rmail
X		@echo 'Setting up permissions:'
X		chown root.root $(BIN)/umail
X		chmod 6555 $(BIN)/umail
X
Xshar:
X		@shar -v -o umail.shar $(OTHERS) $(SRCS)
X
Xtar:
X		@tar c umail.tar $(OTHERS) $(SRCS)
X
Xummain.s:  	umail.h ummain.c
X	   	cc $(CFLAGS) -S ummain.c
X
Xumtime.s:  	umail.h umtime.c
X	   	cc $(CFLAGS) -S umtime.c
X
Xumheader.s:  	umail.h umheader.c
X		cc $(CFLAGS) -S umheader.c
X
Xumconvert.s:    umail.h umconvert.c
X	   	cc $(CFLAGS) -S umconvert.c
X
Xumroute.s:      umail.h umroute.c
X	   	cc $(CFLAGS) -S umroute.c
X
Xumsend.s:    	umail.h uucp.h umsend.c
X	   	cc $(CFLAGS) -S umsend.c
X
Xumscanner.s: 	umscanner.c
X	   	cc $(CFLAGS) -S umscanner.c
X
+ END-OF-FILE Makefile
chmod 'u=rw,g=r,o=r' 'Makefile'
set `wc -c 'Makefile'`
count=$1
case $count in
1429)	:;;
*)	echo 'Bad character count in ''Makefile' >&2
		echo 'Count should be 1429' >&2
esac
echo Extracting 'README'
sed 's/^X//' > 'README' << '+ END-OF-FILE ''README'
X	  U-MAIL Remote Mail Transport Agent (MINIX)
X
X		     MicroWalt U-MAIL V2.5
X		     =====================
X
X
XThis archive contains the sources of the UMAIL Network Mailer
Xfor the MINIX operating system. It runs on most UNIXes as well.
X
XThe file 'umail' is the executable program, and 'umail.doc' is
Xthe (preliminary) documentation of the program.
XSee 'umail.cf' for configuration information.
X
XOf course, this program needs the presence of either UUCP or
XRSMTP to run properly...
X
XEnjoy!
X+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
X| MINIX User Group (Holland)   UUCP: hp4nl!kyber!minixug!waltje	|
X| c/o Fred van Kempen,		 or: minixug!waltje@kyber.UUCP	|
X| Hoefbladhof  27						|
X| 2215 DV  VOORHOUT						|
X| The Netherlands	"A good programmer knows his Sources"	|
X+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
X
+ END-OF-FILE README
chmod 'u=rw,g=r,o=r' 'README'
set `wc -c 'README'`
count=$1
case $count in
852)	:;;
*)	echo 'Bad character count in ''README' >&2
		echo 'Count should be 852' >&2
esac
echo Extracting 'umail.cf'
sed 's/^X//' > 'umail.cf' << '+ END-OF-FILE ''umail.cf'
X#
X#   MicroWalt Corporation   --  UMAIL Configuration File
X#
X#   System: MINIX User Group Holland, minixug.nluug.nl
X#   OS:     MicroWalt Advanced MINIX 1.4B
X#
X#   Author: F. van Kempen, MicroWalt Corporation
X#
X
X# These are some configuration variables for the
X# mailer. They define the working environment.
XBEGIN
X    Organization    := "MINIX User Group Holland, Netherlands"
X    System          := "minixug"
X    Domain          := "nluug.nl"
X    TimeZone        := "MET +0100"
X    OldMailer       := TRUE	# We want V6 "From <user> <date>" lines
X    Escape          := TRUE	# We can send all undeliverable mail
X				# to another host.
XEND
X
X# The next table defines all the names under which
X# our system could possibly be adressed. It is used
X# to map domain adresses back to local adresses.
XNAMES BEGIN
X    minixug.nluug.nl				# Our official name
X    minixug.nl					# other possible names
X    minixug.uucp                                # old-style UUCP name
X    minixug					# local name
XEND
X
X# This table defines the systems that we know of, and
X# what networking software to use to get to it.
X# 'TRUE' means, that the specified host understands
X# route-adressing (and can thus do things itself).
X# FALSE means that we have to give that host a ready-
X# to-run UUCP adress in bang-style.
XHOSTS BEGIN
X    minixug := TRUE , $$ , "@"                    # Just local mail !
X    kyber   := FALSE , $$ , "@"                   # My UUCP host site
X    archvax := FALSE , "rsmtp" , "<%s archvax!"   # SMTP via Ethernet
XEND
X
X# This is the actual routing table.
X# It defines where mail for the various domains
X# should be sent to. Note, that domain "." is
X# the "default domain", which is used if no
X# matching domain can be found.
X# Format:
X#
X#   DOMAIN	:=  HOST  , ROUTE
X#
XDOMAINS BEGIN
X    aha.nl      :=  kyber , htsa	# Algemene Hogeschool Amsterdam
X    edu         :=  kyber , hp4nl	# Educational Institutes Network
X    nl          :=  kyber , hp4nl	# UUCP-Netherlands
X    nluug       :=  kyber , hp4nl	# Dutch UNIX User Group Network
X    nluug.nl    :=  kyber , hp4nl
X    uu.net      :=  kyber , hp4nl	# USA UUCP Network
X    uucp        :=  kyber , hp4nl	# Old-style UUCP Network
X    uunet       :=  kyber , hp4nl	# USA UUCP Network
X    .           :=  kyber , hp4nl	# Default host
XEND
+ END-OF-FILE umail.cf
chmod 'u=rw,g=r,o=r' 'umail.cf'
set `wc -c 'umail.cf'`
count=$1
case $count in
2282)	:;;
*)	echo 'Bad character count in ''umail.cf' >&2
		echo 'Count should be 2282' >&2
esac
echo Extracting 'umail.doc'
sed 's/^X//' > 'umail.doc' << '+ END-OF-FILE ''umail.doc'
XUMAIL(1)             MINIX User's Manual               UMAIL(1)
X
X
XNAME     
X     umail - electronic mail delivery agent.
X
XSYNOPSIS     
X     umail [-c <config> [-d] [-i <inputfile> [-n] <user>
X
XDESCRIPTION     
X     Umail is a  semi-intelligent  mail transporting  program
X     which  knows something  about Internet adresses and mail
X     adress routing to other systems.
X     It  is  used as  a back-end to  the Mailx program; which
X     is used  to  read or create  messages. Umail  only takes
X     care  of the transportation  of  the  message  to  other
X     MINIX (or UNIX) systems  through  the  available network
X     software like UUCP and RSMTP.
X
X     In  restricted mode ('rmail') it  functions as a message
X     delivery program for incoming network mail.
X     Networking programs like uucico(1)  and rsmtp(8) execute
X     the rmail(1)  command to  deliver a  received message to
X     the adressed user, or to forward  the message to another
X     system.
X
X     The  program  has  some  command-line options, which are
X     used  to alter  the "standard" behaviour of the program.
X     The options are:
X
X	-c <config>	Debug; use 'config' as the configura-
X			tion file  instead  of  the  standard
X			one. This is  sometimes  useful  when
X			debugging the package.
X
X	-d		Debug; generate  some  useful  output
X			while working.
X
X	-i <infile>	Input; use file 'infile' as  the mes-
X			sage file instead of  standard input.
X
X	-n		Now;  call  the  networking  delivery
X			software immediately  after  queueing
X			the message. Not recommended!
X
X     The 'user' string  identifies the  network-adress of the
X     user who is  to receive the message. It can be any legal
X     UUCP or Internet mail-adress.
X
XDELIVERY     
X     The Mailx program can serve as  both a  user agent and a
X     local  delivery  agent. If Mailx sees that the  adressed
X     user is  on the  local system, it  will do  the delivery
X     itself. No  header (except  for From, To and Subject) is
X     added, and  delivery  errors  will  cause the message to
X     be returned to the user as a file 'dead.letter'.
X
X     Otherwise,  if  the  specified  adress is not local, the
X     message  is sent  to  the  Remote Mailer  on the system.
X
X
X
X				-- 1 --
X
X
X
XUMAIL(1)             MINIX User's Manual               UMAIL(1)
X
X
X
X     Usually,  this is  the rmail(1)  command; programs  like
X     sendmail(8)  or  smail(1) (or links to them) are used as
X     well. On  MINIX systems, rmail(1) is a separate program.
X
X     This small remote mailer knows something about UUCP, and
X     how to interpret old-style UUCP (host!user) adresses.
X     This works fine for most users, but it is sometimes nice
X     to have a somewhat more intelligent mailer.
X     Therefore, one could install Umail as a link to rmail(1)
X     so that the mail(1) or Mailx(1) programs will never  see
X     the difference.
X
X     These (more or less)  intelligent mailers add a standard
X     (RFC-822) header to the message, and then send it to the
X     networking software. On MINIX  systems, messages will be
X     transported  using  either  the UUCP networking software
X     (serial lines) or the Amoeba RSMTP (Ethernet) software.
X
X     Because  it would  be too difficult to program all sorts
X     of  networks, system names  and  the lot  in  the mailer
X     software, a file exists which contains the Configuration
X     parameters  of  Umail: the  Config File. This is a plain
X     ASCII text file, containing a mixture  of comments, data
X     and instructions.
X
XAUTHOR     
X     Steve R. Sampson (first draft of rmail program)
X     Fred van Kempen, waltje@kyber.UUCP
X
XFILES     
X     /usr/spool/mail/user   	maildrop file
X     /usr/spool/mail/user.lock  lock for maildrop files
X     /tmp/um*      		temporary file
X     /usr/spool/uucp/*		UUCP networking files
X     /usr/spool/rsmtp/*         SMTP networking files
X     /usr/lib/uucp/umail.cf     configuration file
X
XSEE ALSO    
X     wmail.doc
X
XBUGS     
X     The routing algorithm could be improved a lot.
X     Also, the Config scanner should be more robust.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X				-- 2 --
X
X
+ END-OF-FILE umail.doc
chmod 'u=rw,g=r,o=r' 'umail.doc'
set `wc -c 'umail.doc'`
count=$1
case $count in
4082)	:;;
*)	echo 'Bad character count in ''umail.doc' >&2
		echo 'Count should be 4082' >&2
esac
echo Extracting 'umail.h'
sed 's/^X//' > 'umail.h' << '+ END-OF-FILE ''umail.h'
X/*
X * UMAIL -	MINIX Remote Domain-adressing Mail Router
X *
X *		This version of RMAIL handles message-headers in a much
X *		more "standard" way. It can handle bang-adresses, plus
X *		the new-style Internet adressing (user@host.domain).
X *		It is called by programs as "Mail" and "Uuxqt".
X *
X * 		D E F I N I T I O N S
X *
X * Author:	F. van Kempen, Jul-Oct '89 (waltje@minixug.nluug.nl)
X */
X
X#ifdef MINIX
X#	define VERSION         	  "2.5/MINIX"	/* 10/19/89 */
X#	define CONFIG		"/usr/lib/uucp/umail.cf"
X#endif
X
X#ifdef UNIX
X#	define VERSION             "2.5/UNIX"	/* 10/19/89 */
X#	define CONFIG		"/usr/lib/uucp/umail.cf"
X#endif
X
X#ifndef TRUE
X#	define FALSE	0
X#	define TRUE	1
X#endif
X
Xtypedef struct __name {
X    struct __name *next;
X    char *name;
X} NAME;
X
Xtypedef struct __var {
X    struct __var *next;
X    char *name;
X    char *value;
X} VAR;
X
Xtypedef struct __host {
X    struct __host *next;
X    char *name;
X    int smart;
X    char *command;
X    char *opts;
X} HOST;
X
Xtypedef struct __routemap {
X    struct __routemap *next;
X    char *domain;
X    char *host;
X    char *route;
X} ROUTE;
X
Xtypedef struct {
X    char user[256];			/* user name of adress */
X    char host[256];			/* host name of adress */
X    char domain[256];			/* domain name of adress */
X} BOX;
X
X#define NILNAME      ((NAME *)NULL)
X#define NILVAR        ((VAR *)NULL)
X#define NILHOST      ((HOST *)NULL)
X#define NILROUTE    ((ROUTE *)NULL)
X#define NILBOX	      ((BOX *)NULL)
X
X
X/* globals in ummain.c */
Xextern char *Version;			/* UMAIL version ID */
Xextern int immediate, debug;		/* commandline option flags */
Xextern int restrict;			/* restricted (UUCP) use only */
Xextern int aremote;			/* is adressee REMOTE or LOCAL ? */
Xextern char dfile[], infile[];		/* names of message temp-files */
Xextern char errmsg[];			/* global error message */
Xextern char mailsender[];		/* who sent the message? */
Xextern char mailaddr[];			/* final routed adress to use. */
Xextern char mailhost[];			/* which host to send to */
Xextern char mailcmd[];			/* command to use to send the mail */
Xextern char mailopts[];			/* which options the mailer uses */
Xextern NAME *namelist;			/* list of my network names */
Xextern VAR *varlist;			/* list of configuration variables */
Xextern HOST *hostlist;			/* list of reacheable host names */
Xextern ROUTE *routemap;			/* list of domain routes */
X
X/* configuration settings */
Xextern char *myname;			/* my UUCP site name */
Xextern char *mydomain;			/* my UUCP domain name */
Xextern char *myorg;			/* Name of my organization */
Xextern int oldmailer;			/* mailer uses old From-lines? */
Xextern int escape;			/* routing ESCAPE enable */
X
X/* external routines */
Xextern char *xtime(/* time_t *salt */);
Xextern BOX *convert(/* char *adr */);
Xextern int route(/* BOX *box */);
Xextern int header(/* FILE *infp, FILE *outfp */);
Xextern char *strupr(/* char *s */);
Xextern char *strlwr(/* char *s */);
Xextern void add_name(/* char *name */);
Xextern void add_host(/* char *name, int smart, char *cmd, char *opts */);
Xextern void add_route(/* char *domain, char *host, char *route */);
Xextern void add_var(/* char *name, char *val */);
Xextern char *lookup(/* char *what */);
Xextern int boolean(/* char *ascii */);
Xextern HOST *gethost(/* char *host */);
Xextern ROUTE *getdomain(/* char *domain */);
Xextern char *mfgets(/* char *s, int n, FILE *iop */);
Xextern char *whoami(/* void */);
Xextern char *full_id(/* char *user */);
Xextern char *realname(/* char *who */);
Xextern char *maketime(/* long *salt */);
Xextern void fcopy(/* FILE *inf, FILE *outf */);
Xextern int scanner(/* char *fname */);
Xextern int KnowHost(/* char *name */);
Xextern int islocal(/* char *name */);
Xextern char *genname(/* int prefix, int grade, char *sysname */);
Xextern int send_local(/* char *user, char *data */);
Xextern int send_remote(/* char *rmtname, char *rmtuser, char *data */);
Xextern void errmail(/* char *str, int mgronly */);
Xextern int sendit(/* char *who, char *host, char *cmd, char *opts, char *data */);
+ END-OF-FILE umail.h
chmod 'u=rw,g=r,o=r' 'umail.h'
set `wc -c 'umail.h'`
count=$1
case $count in
3965)	:;;
*)	echo 'Bad character count in ''umail.h' >&2
		echo 'Count should be 3965' >&2
esac
echo Extracting 'umconvert.c'
sed 's/^X//' > 'umconvert.c' << '+ END-OF-FILE ''umconvert.c'
X/*
X * UMAIL -	MINIX Remote Domain-adressing Mail Router
X *
X *		This version of RMAIL handles message-headers in a much
X *		more "standard" way. It can handle bang-adresses, plus
X *		the new-style Internet adressing (user@host.domain).
X *		It is called by programs as "Mail" and "Uuxqt".
X *
X *	    	A D R E S S   C O N V E R S I O N   M O D U L E
X *
X * 		Convert adresses into manageable chunks.
X *
X * 		We understand the following notations:
X *
X *		1. user@host.domain	--> waltje@minixug.UUCP
X *	
X *		2. host!user		--> minixug!waltje
X *	
X *		3. user			--> waltje
X *
X * Return TRUE (1) if OK, or FALSE (0) if an error was encountered.
X *
X * Author:	F. van Kempen, Jul-Oct '89 (waltje@minixug.nluug.nl)
X */
X#include <stdio.h>
X#include <alloc.h>
X#include <string.h>
X#include "umail.h"
X
X
X/*
X * Convert adress 'adr' into more manageable chunks.
X * Stuff the output into 'mailaddr' (the final user)
X * and 'mailcmd' (the mailer command to use).
X * Return NILBOX if an error ocurred.
X */
XBOX *convert(adr)
Xchar *adr;
X{
X  static BOX box;
X  char temp[1024];
X  register char *bp, *sp, *cp;
X  register ROUTE *rp;
X  register HOST *hp;
X
X  strcpy(mailaddr, adr);
X  box.domain[0] = box.host[0] = '\0';
X  box.user[0] = temp[0] = '\0';
X
X  /*
X   * Rule 1: Check for user@host.domain
X   */
X  sp = strrchr(mailaddr, '@');
X  if (sp != NULL) {
X	*sp++ = '\0';
X	strcpy(box.user, mailaddr);
X	strcpy(temp, sp);	
X	strlwr(temp);		/* convert domain to lower case: RFC822 */
X
X	/*
X	 * Rule 1A: Now check for "." in the domain part.
X	 * 	    This indicates that a host name was given.
X	 */
X	sp = strchr(temp, '.');		/* syntax host.domain ?? */
X	if (sp == NULL) {		/* no, onlky 'host' part */
X		hp = gethost(temp);	/* is this a local host? */
X		if (hp != NILHOST) {	/* yes! */
X			strcpy(box.host, temp);
X			box.domain[0] = '\0';
X			return(&box);
X		} else {		/* no, must be a domain.... */
X			strcpy(box.domain, temp);
X			box.host[0] = '\0';
X			return(&box);
X	  	  }
X	} else {			/* domain and host given! */
X		*sp++ = '\0';
X		strcpy(box.host, temp);
X		strcpy(box.domain, sp);
X		return(&box);
X	  }
X  }
X
X  /*
X   * Rule 2: Check for host!user
X   */
X  sp = strchr(mailaddr, '!');
X  if (sp != NULL) {
X	*sp++ = '\0';
X	strcpy(box.host, mailaddr);
X	strcpy(box.user, sp);
X	return(&box);
X  }
X
X  /*
X   * Rule 3: Must be local user.
X   */
X  strcpy(box.user, mailaddr);
X  box.host[0] = '\0';
X  box.domain[0] = '\0';
X  return(&box);
X}
X
+ END-OF-FILE umconvert.c
chmod 'u=rw,g=r,o=r' 'umconvert.c'
set `wc -c 'umconvert.c'`
count=$1
case $count in
2388)	:;;
*)	echo 'Bad character count in ''umconvert.c' >&2
		echo 'Count should be 2388' >&2
esac
echo Extracting 'umroute.c'
sed 's/^X//' > 'umroute.c' << '+ END-OF-FILE ''umroute.c'
X/*
X * UMAIL -	MINIX Remote Domain-adressing Mail Router
X *
X *		This version of RMAIL handles message-headers in a much
X *		more "standard" way. It can handle bang-adresses, plus
X *		the new-style Internet adressing (user@host.domain).
X *		It is called by programs as "Mail" and "Uuxqt".
X *
X *	    	M A I L   R O U T E R   M O D U L E
X *
X * 		Some rules exist for routing to other machines.
X *
X *		1. Check for local system names.
X *
X *		2. If we have a domain, check it for validity.
X *
X *		3. If we have a hostname, check it for validity.
X *
X *		4. Local user: check existence.
X *
X * 		Examples are:
X *
X *			user@host.domain@newdomain -
X *				-> ast@cs.vu@nluug.nl
X *			host!user@domain
X *				--> cs.vu!ast@nluug.nl
X *
X *		If we cannot find a matching domain or system name,
X *		then we get stuck. Fortunately, we can define the
X *		ESCAPE parameter, which allows us to send all mail
X *		for unknown hosts or domains to a "default" domain.
X *		This is the domain called "." in the tables.
X *		If the ESCAPE parameter is FALSE, we cannot deliver
X *		the message, so return it to the sender!
X *
X * Return TRUE (1) if OK, or FALSE (0) if an error was encountered.
X *
X * Author:	F. van Kempen, Jul-Oct '89 (waltje@minixug.nluug.nl)
X */
X#include <stdio.h>
X#include <alloc.h>
X#include <pwd.h>
X#include <string.h>
X#include "umail.h"
X
X
X/*
X * Route the adress in BOX into a ready-to-run
X * UUCP adress.
X */
Xint route(b)
XBOX *b;
X{
X  char temp[1024];
X  register char *bp, *sp;
X  register ROUTE *rp;
X  register HOST *hp;
X  struct passwd *pw;
X
X  /* 
X   * Rule 1: check for local system names.
X   *	     convert to LOCAL if possible.
X   */
X  if (b->domain[0] == '\0') strcpy(temp, b->host);
X    else sprintf(temp, "%s.%s", b->host, b->domain);
X  if (islocal(temp)) {
X	b->host[0] = '\0';
X	b->domain[0] = '\0';
X  }
X
X  /*
X   * Rule 2: Do we have a domain?
X   */
X  if (b->domain[0] != '\0') {			/* domain given? */
X	if (b->host[0]) sprintf(temp, "%s.%s", b->host, b->domain);
X	  else strcpy(temp, b->domain);
X	strcpy(b->host, temp);
X	bp = temp;
X	rp = NILROUTE;
X	while (TRUE) {			/* iterate on domain fragments */
X		sp = bp;
X		rp = getdomain(bp);
X		if (rp != NILROUTE) {		/* a matching domain! */
X			strcpy(b->domain, bp);
X			break;
X		}
X		bp = strchr(sp, '.');				
X		if (bp == NULL) break;
X		  else bp++;
X	}
X
X	/*
X 	 * We now have checked the DOMAIN table for a matching domain.
X	 * If we failed to find a match, there is a problem.
X	 * If the mailer was defined with the ESCAPE parameter, we can
X	 * try to route it to the default (".") domain.
X	 * Otherwise, we cannot deliver the message...
X	 */
X
X	/* check if we found a matching domain */
X	if (rp == NILROUTE) {	/* we did not. try to re-route it */
X		if (escape == FALSE) {
X			sprintf(errmsg, "%s ... domain unknown", b->domain);
X			return(FALSE);
X		}
X		rp = getdomain(".");	/* get default domain! */
X		if (rp == NILROUTE) {
X			sprintf(errmsg, "%s ... domain unknown", b->domain);
X			strcat(errmsg, "\n\nESCAPE domain not found.");
X			return(FALSE);
X		}
X	}
X
X	/*
X	 * At this point we have all the information we
X 	 * need to build an UUCP-adress.
X	 * We have a HOST as well.
X	 * Check if we can indeed reach that host.
X	 */
X	hp = gethost(rp->host);
X	if (hp == NILHOST) {
X		sprintf(errmsg, "%s ... host unreacheble", rp->host);
X		return(FALSE);
X	}
X
X	/* is the host smart enough to get "@"-adresses?? */
X	if (hp->smart == TRUE) {	/* yes, it is! */
X		if (*(rp->route) == '@') {
X			if (b->host[0] == '\0') sprintf(mailaddr,"%s@%s",
X				    	    		b->user, b->domain);
X  	  		  else sprintf(mailaddr, "%s@%s", b->user, b->host);
X		} else {
X			if (b->host[0] == '\0') sprintf(mailaddr,"%s!%s@%s",
X					rp->route, b->user, b->domain);
X  	  		  else sprintf(mailaddr, "%s!%s@%s.%s",
X				rp->route, b->user, b->host, b->domain);
X		  }
X	} else {
X		if (b->host[0] == '\0') sprintf(mailaddr,"%s!%s",
X							rp->route, b->user);
X		  else sprintf(mailaddr, "%s!%s!%s",
X				rp->route, b->host, b->user);
X	  }
X	strcpy(b->host, rp->host);
X
X	/*
X	 * We now have a HOST and an ADRESS.
X	 */
X	strcpy(mailcmd, hp->command);
X	strcpy(mailopts, hp->opts);
X	strcpy(mailhost, b->host);
X	aremote = TRUE;
X	return(TRUE);
X  }
X
X  /*
X   * Rule 3: Do we have a host name ?
X   */
X  if (b->host[0] != '\0') {			/* host name given? */
X	b->domain[0] = '\0';			/* signal 'no routing' */
X	hp = gethost(b->host);
X	if (hp == NILHOST) {
X		if (escape == FALSE) {
X			sprintf(errmsg, "%s ... host unknown", b->host);
X			return(FALSE);
X		}
X		rp = getdomain(".");	/* get default domain! */
X		if (rp == NILROUTE) {
X			sprintf(errmsg, "%s ... host unknown", b->host);
X			strcat(errmsg, "\n\nESCAPE domain not found.");
X			return(FALSE);
X		}
X
X		/*
X		 * We now have a HOST as well.
X		 * Check if we can indeed reach that host.
X		 */
X		strcpy(b->domain, rp->host);
X		hp = gethost(rp->host);
X		if (hp == NILHOST) {
X			sprintf(errmsg, "%s ... host unreacheble", rp->host);
X			return(FALSE);
X		}
X	}
X
X	/*
X	 * USER	contains the user-part
X	 * HOST contains the (old) host-part
X	 * DOMAIN now contains the new hostname
X	 */
X
X	/* is the host smart enough to get "@"-adresses?? */
X	if (b->domain[0] != '\0') {	/* are we routing? */
X		if (hp->smart == TRUE) sprintf(mailaddr, "%s@%s",
X							b->user, b->host);
X		  else sprintf(mailaddr, "%s!%s", b->host, b->user);
X		strcpy(b->host, b->domain);
X	} else {	/* no, ordinary case */
X		strcpy(mailaddr, b->user);
X	  }
X
X	strcpy(mailhost, b->host);
X	strcpy(mailcmd, hp->command);
X	strcpy(mailopts, hp->opts);
X	aremote = TRUE;
X	return(TRUE);
X  }
X
X  /*
X   * Rule 4: Check for local user.
X   */
X  if ((pw = getpwnam(b->user)) == (struct passwd *)NULL) {
X	sprintf(errmsg, "%s ... user unknown", b->user);
X	return(FALSE);
X  }
X  hp = gethost(myname);
X  strcpy(mailaddr, b->user);
X  mailhost[0] = '\0';
X  strcpy(mailcmd, hp->command);
X  strcpy(mailopts, hp->opts);
X  aremote = FALSE;
X  return(TRUE);
X}
+ END-OF-FILE umroute.c
chmod 'u=rw,g=r,o=r' 'umroute.c'
set `wc -c 'umroute.c'`
count=$1
case $count in
5809)	:;;
*)	echo 'Bad character count in ''umroute.c' >&2
		echo 'Count should be 5809' >&2
esac
echo Extracting 'umscanner.c'
sed 's/^X//' > 'umscanner.c' << '+ END-OF-FILE ''umscanner.c'
X/*
X * UMAIL -	MINIX Remote Domain-adressing Mail Router
X *
X *		This version of RMAIL handles message-headers in a much
X *		more "standard" way. It can handle bang-adresses, plus
X *		the new-style Internet adressing (user@host.domain).
X *		It is called by programs as "Mail" and "Uuxqt".
X *
X *          	C O N F I G U R A T I O N   F I L E   S C A N N E R
X *
X * Author:	F. van Kempen, Jul-Oct '89 (waltje@minixug.nluug.nl)
X */
X#include <stdio.h>
X
X
Xtypedef struct {
X    char *name;
X    int opcode;
X} WORD;
X
X
X/* operator opcodes */
X#define O_ASSIGN        1       /* ":="             */
X#define O_COMMA         2       /* ","              */
X#define O_BEGIN         3       /* "BEGIN"          */
X#define O_END           4       /* "END"            */
X#define O_DATA          5       /* "DATA"           */
X#define O_NAMES         6       /* "NAMES"          */
X#define O_DOMAIN        7       /* "DOMAINS"        */
X#define O_HOST          8       /* "HOST"           */
X
X
X/* main scanner states */
X#define S_LOOK          1       /* looking for a keyword */
X#define S_BEGIN         2       /* got O_BEGIN */
X#define S_END           3       /* got O_END */
X
X/* block classes */
X#define SC_DATA         1       /* DATA (variable) class */
X#define SC_NAMES        2       /* NAMES (my domains) class */
X#define SC_DOMAIN       3       /* DOMAIN TABLE class */
X#define SC_HOST         4       /* HOSTS class */
X
X#define SS_LOOK         1       /* looking for keyword or variable name */
X#define SS_IDENT        2       /* looking for identifier */
X#define SS_ASSIGN       3       /* got varname, looking for O_COMMA */
X#define SS_COMMA        4       /* got varname, looking for O_ASSIGN */
X#define SS_VALUE        5       /* got O_ASSIGN, looking for value */
X#define SS_DOMAIN1      6       /* got domain, looking for hostname */
X#define SS_DOMAIN2      7       /* got boolean, looking for domain descr. */
X#define SS_HOST1        8       /* got host, looking for boolean */
X#define SS_HOST2        9       /* got host, looking for host mailer name */
X#define SS_HOST3       10       /* got host, looking for host mailer opts */
X
X
Xstatic FILE *infp;                      /* input file pointer */
Xstatic char scbuf[1024];                /* input line buffer */
Xstatic char *scptr = NULL;              /* input line pointer */
Xstatic char *errptr = NULL;		/* error pointer */
Xstatic char sctemp1[128];               /* current identifier */
Xstatic char sctemp2[128];               /* current identifier */
Xstatic int scbool;			/* temp. boolean value */
Xstatic int lineno = 1;                  /* current line number */
Xstatic int sclass = SC_DATA;            /* temporary state */
Xstatic int state = S_LOOK;              /* state of scanner */
Xstatic int sstate = SS_LOOK;            /* secondairy state */
Xstatic int tstate = SS_LOOK;		/* triple state */
Xstatic WORD table[] = {                 /* language table */
X  { ":="    	,   O_ASSIGN    },
X  { ","     	,   O_COMMA     },
X  { "BEGIN" 	,   O_BEGIN     },
X  { "END"   	,   O_END       },
X  { "DATA"  	,   O_DATA      },
X  { "NAMES" 	,   O_NAMES     },
X  { "DOMAINS" 	,   O_DOMAIN    },
X  { "HOSTS" 	,   O_HOST      },
X};
X
X
Xextern int debug;
X
X
X/*
X * Return next character of input file;
X * also do some bookkeeping for error-recovery.
X */
Xstatic int nextch(void)
X{
X  register int ch;
X
X  ch = fgetc(infp);
X  if (ch == '\n') {
X	lineno++;
X	*scptr = '\0';
X	scptr = scbuf;
X  } else *scptr++ = ch;
X  return(ch);
X}
X
X
X/*
X * Handle a syntax error.
X * Also, perform some error recovery.
X */
Xstatic void syntax(s)
Xchar *s;
X{
X  register char *bp, *ep;
X  register int ch;
X
X  ep = errptr;
X  do {
X      ch = nextch();			/* read up to end of line */
X  } while (ch!='\n' && ch!=EOF);	/* and start over on next line */
X
X  sstate = SS_LOOK;     		/* reset state machine #2 */
X
X  fprintf(stderr, "%05.5d %s\n      ", lineno, scbuf);
X  bp = scbuf;
X  ep--;
X  while (bp < ep) {
X	fprintf(stderr, " ");
X	bp++;
X  }
X  fprintf(stderr, "^ %s\n", s);
X}
X
X
X/*
X * Check the text of a keyword.
X */
Xstatic int crunch(text)
Xchar *text;
X{
X  register WORD *wp;
X
X  wp = &table[0];
X  while (wp->opcode != 0) {
X	if (!strcmp(wp->name, text)) return(wp->opcode);
X	wp++;
X  }
X  return(0);
X}
X
X
X/*
X * Decode a word, and perform some action if necessary.
X * This routine holds all the syntax grammar.
X * It is far from perfect, but it works...
X */
Xstatic void do_word(name)
Xchar *name;
X{
X  int op;               /* decoded keyword code */
X  char *s = "expected END";
X
X  op = crunch(name);
X  if (sstate == SS_LOOK) switch(op) {
X	case O_DATA:
X        	if (state==S_LOOK || state==S_END) sclass = SC_DATA;
X		  else syntax(s);
X		break;
X        case O_NAMES:
X		if (state==S_LOOK || state==S_END) sclass = SC_NAMES;
X		  else syntax(s);
X		break;
X        case O_DOMAIN:
X		if (state==S_LOOK || state==S_END) sclass = SC_DOMAIN;
X		  else syntax(s);
X		break;
X        case O_HOST:
X            	if (state==S_LOOK || state==S_END) sclass = SC_HOST;
X              	  else syntax(s);
X		break;
X        case O_BEGIN:
X            	switch(sclass) {
X                	case SC_DATA:
X                	case SC_DOMAIN:
X                	case SC_HOST:
X			case SC_NAMES:
X                		sstate = SS_LOOK;
X                		state = S_BEGIN;
X                		break;
X                	default:
X                    		syntax("expected class prefix");
X                    		break;
X            	}
X            	break;
X        case O_END:
X            	if (state == S_BEGIN) {
X			state = S_LOOK;
X			sclass = 0;
X	    	} else syntax("expected BEGIN");
X            	break;
X        default:
X            	sstate = SS_IDENT;
X            	break;
X  }
X  switch(sstate) {
X    	case SS_LOOK:		/* propagated from the above switch() */
X        	break;
X	case SS_IDENT:      	/* looking for identifier */
X		switch(sclass) {
X			case SC_DATA:
X			case SC_HOST:
X			case SC_DOMAIN:
X    				strcpy(sctemp1, name);
X				sstate = SS_ASSIGN;
X		        	break;
X			case SC_NAMES:
X				add_name(name);
X				sstate = SS_LOOK;
X				break;
X			default:
X				syntax("expected BEGIN or CLASS");
X		}
X		break;
X    	case SS_ASSIGN:     	/* looking for O_ASSIGN */
X		op = crunch(name);
X        	if (op == O_ASSIGN) switch(sclass) {     /* found O_ASSIGN */
X            		case SC_DATA:
X                		sstate = SS_VALUE;
X                		break;
X            		case SC_DOMAIN:
X                		sstate = SS_DOMAIN1;
X                		break;
X            		case SC_HOST:
X                		sstate = SS_HOST1;
X                		break;
X            		default:
X                		break;
X       		 } else syntax("expected ASSIGN");
X        	break;
X	case SS_COMMA:		/* field separator */
X		op = crunch(name);
X		if (op == O_COMMA) switch(sclass) {
X			case SC_DOMAIN:
X				sstate = SS_DOMAIN2;
X				break;
X			case SC_HOST:
X				switch(tstate) {
X					case SS_HOST1:
X						sstate = SS_HOST2;
X						break;
X					case SS_HOST2:
X						sstate = SS_HOST3;
X						break;
X					default:
X						syntax("no comma here");
X						break;
X				}
X				break;
X			default:
X				syntax("no comma here");
X				break;
X		} else syntax("expected COMMA");
X		break;
X    	case SS_VALUE:      	/* looking for value */
X        	add_var(sctemp1, name);
X        	sstate = SS_LOOK;
X        	break;
X	case SS_DOMAIN1:		/* looking for route hostname */
X		strcpy(sctemp2, name);
X		sstate = SS_COMMA;
X		break;
X   	case SS_DOMAIN2:		/* looking for host route */
X        	add_route(sctemp1, sctemp2, name);
X        	sstate = SS_LOOK;
X        	break;
X    	case SS_HOST1:		/* looking for host 'smart' boolean */
X        	scbool = boolean(name);
X		sstate = SS_COMMA;
X		tstate = SS_HOST1;
X        	break;
X    	case SS_HOST2:		/* looking for host mailer name */
X		strcpy(sctemp2, name);	/* mailer name */
X        	sstate = SS_COMMA;	/* look for mailer opts */
X		tstate = SS_HOST2;
X        	break;
X    	case SS_HOST3:		/* looking for host mailer opts */
X		add_host(sctemp1, scbool, sctemp2, name);
X		sstate = SS_LOOK;
X        	break;
X    	default:		/* this can't be for real! */
X        	syntax("Huh? You must be joking!");
X        	break;
X  }
X}
X
X
X/*
X * This is the Configuration File Scanner.
X * It has *some* level of intelligence, but is must
X * be improved a lot.
X */
Xint scanner(fname)
Xchar *fname;
X{
X  char wordbuf[512];
X  register char *bp = wordbuf;
X  register int ch;
X  register int quote = 0;
X  register int stopped = 0;
X
X  infp = fopen(fname, "r");
X  if (infp == (FILE *)NULL) return(-1);
X
X  scptr = scbuf;
X  ch = nextch();
X  do {
X      switch(ch) {
X 	case '#':   /* comment, skip rest of line */
X        	do {
X                    ch = nextch();
X            	   } while (ch != '\n');
X            	break;
X        case ' ':   /* SPACE */
X        case '\t':
X            	if (quote == 0) {
X			errptr = scptr;
X                	do {    /* skip rest of leading space */
X                    	    ch = nextch();
X                	   } while (ch==' ' || ch=='\t');
X                	*bp = '\0';
X                	if (bp != wordbuf) {
X                    		do_word(wordbuf);
X                    		bp = wordbuf;
X                	}
X            	} else {
X                    	*bp++ = ch;
X                    	ch = nextch();
X              	  }
X            	break;
X        case EOF:   /* EOF, done! */
X            	stopped = 1;
X        case '\n':  /* end-of-word marker, handle word */
X            	*bp = '\0';
X            	if (wordbuf[0]) {
X                	do_word(wordbuf);
X                	bp = wordbuf;
X            	}
X            	if (ch != EOF) ch = nextch();
X            	break;
X        case '"':   /* quote, set/reset quoting flag */
X            	quote = 1 - quote;
X            	ch = nextch();
X            	break;
X        default:    /* anything else: text */
X            	*bp++ = ch;
X            	ch = nextch();
X            	break;
X      }
X  } while (!stopped);
X
X  fclose(infp);
X
X  return(0);
X}
+ END-OF-FILE umscanner.c
chmod 'u=rw,g=r,o=r' 'umscanner.c'
set `wc -c 'umscanner.c'`
count=$1
case $count in
9752)	:;;
*)	echo 'Bad character count in ''umscanner.c' >&2
		echo 'Count should be 9752' >&2
esac
echo Extracting 'umsend.c'
sed 's/^X//' > 'umsend.c' << '+ END-OF-FILE ''umsend.c'
X/*
X * UMAIL -	MINIX Remote Domain-adressing Mail Router
X *
X *		This version of RMAIL handles message-headers in a much
X *		more "standard" way. It can handle bang-adresses, plus
X *		the new-style Internet adressing (user@host.domain).
X *		It is called by programs as "Mail" and "Uuxqt".
X *
X * 		M A I L   T R A N S P O R T   M O D U L E
X *
X * Author:	F. van Kempen, Jul-Oct '89 (waltje@minixug.nluug.nl)
X */
X#include <stdio.h>
X#include <sys/types.h>
X#include <dirent.h>
X#include <errno.h>
X#include <string.h>
X#include <time.h>
X#include <uucp.h>
X#include "umail.h"
X
X
X/*
X * Check the host machine name.
X *
X * returns FALSE if not found, else TRUE
X */
Xint KnowHost(name)
Xchar *name;
X{
X  register HOST *hp;
X
X  hp = gethost(name);
X  return((hp==NILHOST) ? FALSE : TRUE);
X}		
X
X
X/*
X * Check if this is one of our local names.
X * Return 1 if TRUE, or 0 if FALSE.
X */
Xint islocal(name)
Xchar *name;
X{
X  register NAME *np;
X
X  np = namelist;
X  while (np != NILNAME) {
X	if (!strcmp(np->name, name)) return(TRUE);
X	np = np->next;
X  }
X  return(FALSE);
X}
X
X
X/*
X * Creates a unique UUCP file name, and returns a pointer
X * to it. The filename is a combination of prefix, grade, system name
X * and a sequential number taken from SPOOLSEQ.
X */
Xchar *genname(prefix, grade, sysname)
Xint prefix, grade;
Xchar *sysname;
X{
X  static char _gen_buf[128];
X  int i = 0;
X  char seqline[10];
X  char *seqname = SPOOLSEQ;		/* to save some string space */
X  char *lseqname = LSPOOLSEQ;		/* to save some string space */
X  FILE *spoolseq;
X
X  if (access(seqname, 0) != 0) close(creat(seqname, 0600));
X
X  while(link(seqname, lseqname) != 0) {
X  	sleep(5);
X  	if (++i > 5) return(NULL);
X  }
X
X  spoolseq = fopen(seqname, "r");
X  fgets(seqline, sizeof(seqline), spoolseq);
X  fclose(spoolseq);
X  unlink(lseqname);
X
X  i = (atoi(seqline) + 1);
X
X  if ((spoolseq = fopen(seqname, "w")) == (FILE *)NULL) return(NULL);
X  fprintf(spoolseq, "%d\n", i);
X  fclose(spoolseq);
X
X  if (grade == 0) sprintf(_gen_buf, "%c.%.7s%04.4x", prefix, sysname, i);
X    else sprintf(_gen_buf, "%c.%.7s%c%04.4x", prefix, sysname, grade, i);
X
X  return(_gen_buf);
X}
X
X
X/*
X * Deliver this message to a local user.
X * We do this by calling "LMAIL" (which is actually
X * a link to "Mail"; the Local Mail Agent.
X */
Xint send_local(user, data)
Xchar *user;
Xchar *data;
X{
X  struct passwd *pw;
X  char tmpbuf[128];
X
X  /* See if destination user name exists on this machine */
X  pw = (struct passwd *) getpwnam(user);
X  if (pw == (struct passwd *)NULL) {
X	sprintf(tmpbuf, "%s ... unknown user at %s", user, myname);
X	errmail(tmpbuf, FALSE);
X  }
X
X#ifdef WMAILER	/* faster than redirecting! */
X  sprintf(tmpbuf, "exec %s -i%s %s", LMAIL, data, user);
X#else
X  sprintf(tmpbuf, "exec %s <%s %s", LMAIL, data, user);
X#endif WMAILER
X
X  return(system(tmpbuf));
X}
X
X
X/*
X * Deliver this message to a remote user.
X * We do this by creating the spoolfiles needed by UUCICO.
X * Then we call that program daemon to do the real work.
X */
Xint send_remote(rmtname, rmtuser, data)
Xchar *rmtname;
Xchar *rmtuser;
Xchar *data;
X{
X  char tmpbuf[128];
X  char Bfile[128], Cfile[128], Dfile[128], Xfile[128];
X  FILE *fcfile, *fbfile, *fdfile, *fp;
X
X  if (KnowHost(rmtname) == FALSE) {
X	sprintf(tmpbuf, "%s ... unknown host machine", rmtname);
X	errmail(tmpbuf, FALSE);
X  }
X
X  /* make the spool files for uucico */
X  strcpy(Bfile, genname('B', 0, rmtname));
X  strcpy(Cfile, genname('C', 'N', rmtname));
X  strcpy(Dfile, genname('D', 0, myname));
X  strcpy(Xfile, genname('X', 'N', rmtname));
X
X  /* Copy the temp-file to the UUCP data file (D.???) */
X  if ((fdfile = fopen(Dfile, "w")) == (FILE *)NULL) {
X	perror("rmail 4");
X      	exit(1);
X  } else {
X	  fp = fopen(data, "r");	/* open temp-file */
X	  fcopy(fp, fdfile);
X	  fclose(fdfile);
X	  fclose(fp);
X    }
X    
X  if ((fbfile = fopen(Bfile, "w")) == (FILE *)NULL) {
X	perror("rmail 4");
X	exit(1);
X  } else {
X	  fprintf(fbfile, "U %s %s\nF %s\nI %s\nC rmail %s\n",
X    				UUCPUSER, myname, Dfile, Dfile, rmtuser);
X    	  fclose(fbfile);
X    }
X
X  if ((fcfile = fopen(Cfile, "w")) == (FILE *)NULL) {
X	perror("rmail 5");
X	exit(1);
X  } else {
X	  fprintf(fcfile,"S %s %s %s - %s 0666\nS %s %s %s - %s 0666\n",
X		Dfile, Dfile, UUCPUSER, Dfile, Bfile, Xfile, UUCPUSER, Bfile);
X          fclose(fcfile);
X    }
X
X  /* RMAIL is setUID root... UUCP cannot read these files! */
X  chown(Bfile, UUCPUID, UUCPGID);
X  chown(Cfile, UUCPUID, UUCPGID);
X  chown(Dfile, UUCPUID, UUCPGID);
X  chown(Xfile, UUCPUID, UUCPGID);
X
X  if (immediate == TRUE) {	/* call uucico now! */
X	strcpy(tmpbuf, UUCICO);
X	sprintf(tmpbuf, "exec %s -s%s -x1 >/dev/null &", UUCICO, rmtname);
X	system(tmpbuf);
X  }
X
X  return(FALSE);
X}
X
X
X/*
X * Perform the mail-transport.
X * We do this by calling the appropriate mailer.
X * If the name of the mailer is "$$" then we can use
X * this program to deliver. This saves a lot of memory.
X */
Xint sendit(who, host, cmd, opts, data)
Xchar *who;			/* who is the adressee? */
Xchar *host;			/* on which machine? */
Xchar *cmd;			/* what command should we use? */
Xchar *opts;			/* which options? */
Xchar *data;			/* name of data (message) file */
X{
X  char cmdline[512];
X  char tmpbuff[512];
X
X  chdir(SPOOLDIR); 			/* Change to UUCP directory */
X
X  if (!strcmp(cmd, "$$")) {		/* run our own mail routines */
X	if (*host == '\0') send_local(who, data);
X          else send_remote(host, who, data);
X  } else {
X	  sprintf(tmpbuff, "exec %s %s ", cmd, opts);
X	  sprintf(cmdline, tmpbuff, data);	/* create commandline */
X	  strcat(cmdline, who);			/* add user adress */
X	  system(cmdline);			/* execute command (mailer) */
X    }
X}
X
X
X/*
X * Send mail to system manager upon errors
X *
X * Mail is contained in a file referenced
X * by Global variable 'dfile'
X */
Xvoid errmail(str, mgronly)
Xchar *str;
Xint mgronly;
X{
X  FILE *fp, *tp;
X  long now;
X  char fname[32];
X  char tmp[128];
X
X  strcpy(fname, "/tmp/umeXXXXXX");
X  mktemp(fname);
X
X  tp = fopen(fname, "w");
X  fp = fopen(dfile, "r");
X
X  time(&now);
X
X  /* create header of the report-message */
X  fprintf(tp, "From %s %s\n", ERRUSER, xtime(&now));	
X  if (mailsender != NULL) fprintf(tp, "To: %s\n", mailsender);
X  fprintf(tp, "Subject: Returned mail\n\n");
X
X  /* create an error transcript */
X  fprintf(tp, "   ---- Transcript of session follows ----\n\n");
X  fprintf(tp, "%s\n", str);
X  fprintf(tp, "\n   ---- Unsent message follows ----\n");
X
X  /* copy the message */
X  while (mfgets(tmp, sizeof(tmp), fp) != (char *)NULL)
X				fprintf(tp, "> %s\n", tmp);
X
X  fclose(tp);	/* flush and close message file */
X  fclose(fp);	/* flush and close orig. file */
X
X  /* Return mail to system manager (and sender if mgronly == FALSE) */
X  if (mgronly == FALSE) sendit(mailsender, "", RMAIL, " <%s", fname);
X
X  /* send mail to UUCP administrator */
X  sendit(ERRUSER, "", "$$", "", fname);
X
X  unlink(fname);	/* remove data files */
X  unlink(dfile);
X
X  exit(1);		/* and exit! */
X}
+ END-OF-FILE umsend.c
chmod 'u=rw,g=r,o=r' 'umsend.c'
set `wc -c 'umsend.c'`
count=$1
case $count in
6827)	:;;
*)	echo 'Bad character count in ''umsend.c' >&2
		echo 'Count should be 6827' >&2
esac
echo Extracting 'umtime.c'
sed 's/^X//' > 'umtime.c' << '+ END-OF-FILE ''umtime.c'
X/*
X * XTIME	-	Create ASCII string of the given time.
X *			This file contains a modified version
X *			of the ctime(3) function from the MINIX
X *			C library. The format of the string is:
X *
X *				Sat, Oct 14 89 20:26:00\0
X *
X */
X#include <time.h>
X
X
Xstatic int days_per_month[] = {
X	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
X};
Xstatic char *months[] = { 
X	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
X	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
X};
Xstatic char *days[] = {
X	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
X};
X
X#define	MIN	60L		/* # seconds in a minute */
X#define	HOUR	(60 * MIN)	/* # seconds in an hour */
X#define	DAY	(24 * HOUR)	/* # seconds in a day */
X#define	YEAR	(365 * DAY)	/* # seconds in a year */
X
X
Xchar *xtime(pt)
Xlong *pt;
X{
X  static struct tm tm;
X  static char xtmbuf[30];
X
X  register long t = *pt;
X  long year;
X
X  tm.tm_year = 0;
X  tm.tm_mon = 0;
X  tm.tm_mday = 1;
X  tm.tm_hour = 0;
X  tm.tm_min = 0;
X  tm.tm_sec = 0;
X
X  /* t is elapsed time in seconds since Jan 1, 1970. */
X  tm.tm_wday = (int) (t/DAY + 4L) % 7;	/* Jan 1, 1970 is 4th wday */
X  while (t >= (year=((tm.tm_year%4)==2) ? YEAR+DAY : YEAR)) {
X	tm.tm_year += 1;
X	t -= year;
X  }
X  tm.tm_year += 1970;
X
X  /* t is now the offset into the current year, in seconds. */
X  tm.tm_yday = (t/DAY);		/* day # of the year, Jan 1 = 0 */
X
X  days_per_month[1] = 28;
X  if ((tm.tm_year % 4) == 0)	/* check for leap year */
X		days_per_month[1]++;
X
X  /* Compute month. */
X  while (t >= (days_per_month[tm.tm_mon] * DAY))
X		t -= days_per_month[tm.tm_mon++] * DAY;
X
X  /* Month established, now compute day of the month */
X  while (t >= DAY) {
X	t -= DAY;
X	tm.tm_mday++;
X  }
X
X  /* Day established, now do hour. */
X  while (t >= HOUR) {
X	t -= HOUR;
X	tm.tm_hour++;
X  }
X
X  /* Hour established, now do minute. */
X  while (t >= MIN) {
X	t -= MIN;
X	tm.tm_min++;
X  }
X
X  /* Residual time is # seconds. */
X  tm.tm_sec = (int) t;
X
X  /* Generate output in ASCII in _buf_. */
X  sprintf(xtmbuf, "%s, %2.2d %s %2.2d %02d:%02d:%02d",
X	days[tm.tm_wday], tm.tm_mday, months[tm.tm_mon], 
X	    tm.tm_year - 1900, tm.tm_hour, tm.tm_min, tm.tm_sec); 
X  return(xtmbuf);
X}
+ END-OF-FILE umtime.c
chmod 'u=rw,g=r,o=r' 'umtime.c'
set `wc -c 'umtime.c'`
count=$1
case $count in
2113)	:;;
*)	echo 'Bad character count in ''umtime.c' >&2
		echo 'Count should be 2113' >&2
esac
echo Extracting 'uucp.h'
sed 's/^X//' > 'uucp.h' << '+ END-OF-FILE ''uucp.h'
X/*
X * UUCP.H-	DCP: A UUCP clone.
X * 		Definitions for the UUCP package
X *
X * Copyright Richard H. Lamb 1985,1986,1987
X * Copyright S. R. Sampson, August 1989
X * Copyright F. N. G. van Kempen Jul-Oct '89
X */
X
X#ifndef TRUE
X#	define FALSE	0
X#	define TRUE	1
X#endif
X
X#define LSYS		         "/usr/lib/uucp/L.sys"
X#define LDEVICE		     "/usr/lib/uucp/L-devices"
X#define UUCICO			"/usr/lib/uucp/uucico"
X#define UUXQT			 "/usr/lib/uucp/uuxqt"
X#define RMAIL			      	       "rmail"	/* Remote Mailer */
X#define SMAIL			               "smail"	/* Internet Mailer */
X#define LMAIL			               "lmail"	/* Local Mailer */
X#define SYSLOG          "/usr/lib/uucp/Log/uucico.log"
X#define XQTLOG           "/usr/lib/uucp/Log/uuxqt.log" 
X#define PUBDIR		       "/usr/spool/uucppublic"
X#define SPOOLDIR	             "/usr/spool/uucp"
X#define SPOOLSEQ	      "/usr/lib/uucp/SPOOLSEQ"
X#define LSPOOLSEQ	  "/usr/lib/uucp/SPOOLSEQ.LCK"
X#define LOCKFILE            "/usr/spool/locks/LCK..%s"	/* terminal LOCKfile */ 
X#define GLOCKFILE         "/usr/spool/locks/GLOCK..%s"	/* terminal LOCKfile */ 
X#define NODENAME		       "/etc/uucpname"
X#define CALLFILE				"C.%s"
X#define XQTFILE					"X.%s"
X#define MAILFILE				"B.%s"
X
X#define UUCPUSER			  	"uucp"
X#define ERRUSER				  "postmaster"
X
X#define UUCPUID					    40	/* RMAIL needs these */
X#define UUCPGID					    40
X#define POSTUID					    41	/* RMAIL needs these */
X#define POSTGID					    40
X
X#define SITENAMELEN	 32
X#define PATHLEN		256
X
X#define MSGTIME          20
X#define MAXPACK         256
X
X/* L.sys field defines */
X#define	FLD_REMOTE	  0	/* remote system name */
X#define	FLD_CCTIME	  1	/* legal call times */
X#define	FLD_DEVICE	  2	/* device, or ACU for modem */
X#define	FLD_SPEED	  3	/* bit rate */
X#define FLD_PHONE	  4	/* phone number */
X#define	FLD_EXPECT	  5	/* first login "expect" field */
X#define FLD_SEND	  6	/* first login "send" field */
X
+ END-OF-FILE uucp.h
chmod 'u=rw,g=r,o=r' 'uucp.h'
set `wc -c 'uucp.h'`
count=$1
case $count in
1882)	:;;
*)	echo 'Bad character count in ''uucp.h' >&2
		echo 'Count should be 1882' >&2
esac
exit 0