[comp.os.minix] umail part 1 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 'umheader.c'
sed 's/^X//' > 'umheader.c' << '+ END-OF-FILE ''umheader.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   H E A D E R   C O N V E R S I O N   M O D U L E
X *
X * Headers:	This module reads the header part of a message into
X *		memory, and then rearranges it into RFC-822 order.
X *		The preferred order of fields is:
X *
X *		1.  From (old-style V6/V7)
X *		2.  From:
X *		3.  Received:	(top to bottom)
X *		4.  Sender:
X *
X *		5.  Unknown fields (user-defined)
X *
X *		6.  To:
X *		7.  Cc:
X *		8.  Bcc:
X *		9.  Subject:
X *		10. Message-ID:
X *		11. Date:
X *
X *		This order may be changed and/or expanded in the future,
X *		especially the "Resent-" fields should be added.
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 <time.h>
X#include "umail.h"
X
X
Xtypedef struct __hdr {
X	struct __hdr *next;
X	int done;		/* 1==READ, 0==UNREAD */
X	int count;		/* 1==FIRST, 2.. == NEXT PART */
X	int std;		/* 1==RFC, 0==USER_DEFINED */
X	char *name;		/* field name */
X	char *value;		/* field value */
X} HEADER;
X#define NILHEAD ((HEADER *)NULL)
X
X
Xstatic HEADER *hlist = NILHEAD;		/* old message header */
Xstatic char *rfcfields[] = {		/* list of RFC-822 fields */
X	"FROM ",	"FROM",		"RECEIVED",	"SENDER",
X	"TO",		"CC",		"BCC",		"SUBJECT",
X	"MESSAGE-ID",	"DATE",		NULL
X};
Xstatic char olduser[1024];		/* old user */
Xstatic char olddate[48];		/* old date */
Xstatic char oldhost[48];		/* old host machine */
X
X
X/*
X * Look for a field in the header table in memory.
X * If found, return its value, otherwise return NULL.
X */
Xstatic char *hfind(name)
Xchar *name;
X{
X  register HEADER *hp;
X  char tmp[48];
X
X  hp = hlist;
X  while (hp != NILHEAD) {
X	strcpy(tmp, hp->name);
X	strupr(tmp);
X	if (!strcmp(tmp, name)) return(hp->value);
X	hp = hp->next;
X  }
X  return(NULL);
X}
X
X
X/*
X * Look for a field in the header table in memory.
X * If found, mark the field as READ, and return its adress.
X * Otherwise, return NILHEAD.
X */
Xstatic HEADER *hsearch(name)
Xchar *name;
X{
X  register HEADER *hp;
X  char tmp[48];
X
X  hp = hlist;
X  while (hp != NILHEAD) {
X	strcpy(tmp, hp->name);
X	strupr(tmp);
X	if (!strcmp(tmp, name)) {
X		if (hp->done == 0) {
X			hp->done = 1;
X			return(hp);
X		}
X	}
X	hp = hp->next;
X  }
X  return(NILHEAD);
X}
X
X
X/*
X * Decode an old-style (V6/V7) mail header.
X * This has a syntax like:
X *
X *	From <user> <date> [remote from <host>]
X *	To: <user>
X *	Subject: <text>
X *
X * We want to find out the <user>, <date> and possible <date> fields.
X * Return TRUE for OK, or FALSE if error.
X */
Xstatic int get_oldhdr(rmt)
Xint *rmt;		/* REMOTE or LOCAL mail? */
X{
X  register char *bp, *sp, *cp;
X
X  sp = hfind("FROM ");
X  if (sp == NULL) {	/* No From-line??? */
X	sprintf(errmsg, "%s: no From line", dfile);
X       	return(FALSE);
X  }
X  
X  strcpy(olduser, sp);		/* stuff field into 'user' */
X  sp = olduser;			/* skip until <date> field */
X  while (*sp && *sp!=' ' && *sp!='\t') sp++;
X  *sp++ = '\0';			/* mark 'end-of-user' */
X
X  /*
X   * SP now contains <date> and (possible) <remote> fields.
X   * Parse line to seek out "remote from".
X   */
X  cp = sp;		/* save the Date-pointer */
X  while (TRUE) {
X	bp = strchr(sp++, 'r');
X	if (bp != NULL) {	 /* we found an 'r' */
X		if (!strncmp(bp, "remote from ", 12)) break;
X        } else break;
X  }
X
X  if (bp != NULL) {		/* remote host found --> remote mail */
X	sp = strrchr(bp, ' ');	/* seek to start of "remote from" text */
X	*(bp - 1) = '\0';	/* mark end-of-date */
X       	strcpy(olddate, cp);	/* set old date */
X	strcpy(oldhost, ++sp);	/* set host name */
X	sprintf(mailsender, "%s!%s", oldhost, olduser);
X	*rmt = TRUE;
X  } else {
X	  strcpy(olddate, cp);	/* set old date */
X	  strcpy(oldhost, "");	/* no remote host */
X	  strcpy(mailsender, olduser);
X	  *rmt = FALSE;	
X    }
X  return(TRUE);
X}
X
X
X/*
X * Analyze the current header.
X *
X * See if this mail was generated locally or came from somewhere else.
X * Note, that old-style mailers use "postmarks" (i.e. header lines
X * looking like "From <user> <date>" with a possible suffix of
X * "remote from <host>". New-style mailers (should) only use the
X * "From: <path>" and "Date: <date>" lines in their headers.
X * UMAIL knows both types. By default it uses new-style headers,
X * but it can use (and generate) old headers by defining OLDMAILER.
X *
X * Return TRUE if we think this mail has been generated remotely,
X * or FALSE if this message was generated by local mail.
X */
Xstatic int chk_hdr(void)
X{
X  int remmail;				/* remote mail? */
X  long now;
X  register char *sp, *bp;		/* fast scanning pointers */
X
X  bp = hfind("FROM");			/* get RFC-From: field */
X  sp = hfind("DATE");			/* get RFC-Date: field */
X
X  if (sp==NULL || bp==NULL) {		/* should have both or none! */
X	if (oldmailer == TRUE) {	/* try old-style header */
X		if (get_oldhdr(&remmail) == FALSE) {
X			strcat(errmsg, "\n\nBad adress or header!\n");
X			return(FALSE);
X		}
X	}
X  } else {	/* only use new-style From:=lines */
X	  strcpy(olddate, sp);	/* Save the DATE field */
X	  strcpy(oldhost, bp);
X	  sp = oldhost;		/* skip comments */
X	  while (*sp && *sp!=' ' && *sp!='\t') sp++;
X	  *sp = '\0';
X	  strcpy(mailsender, oldhost);
X
X	  sp = strchr(oldhost, '!');	/* check for pathname! */
X	  if (sp != NULL) {	/* found one; this was remote! */
X		remmail = TRUE;
X		*sp++ = '\0';
X		strcpy(olduser, sp);
X	  } else {
X		  remmail = FALSE;
X		  strcpy(olduser, bp);
X		  strcpy(oldhost, "");
X	    }
X    }
X  return(remmail);
X}
X
X
X/*
X * Create a new RFC-822 message header.
X * This is necessary because we are processing
X * a locally-generated message.
X * The header should become:
X *
X *      From <host!user> <date> remote from <here>
X *      From: <host>!<user>
X *	Received: by <here> with <proto>;
X *                <receive-date>
X *	Sender: <user>@<host>.<domain> (Real Name)
X *	To: <user>
X *	Subject: <text>
X */
Xstatic void new_hdr(outfp)
XFILE *outfp;
X{
X  long rcvtm;				/* current time */
X  char *date;				/* current date in MET */
X  char *fmt1 = "%s:%s\n";
X  char *fmt2 = "%s\n";
X  register char *sp;
X
X  /* get the current date and time */
X  time(&rcvtm); date = maketime(&rcvtm);
X
X  if (oldmailer == TRUE) {
X	fprintf(outfp, "From %s %s remote from %s\n",
X				olduser, xtime(&rcvtm), myname);
X  }
X  fprintf(outfp, "From: %s!%s (%s)\n", myname, olduser, realname(olduser));
X  fprintf(outfp, "Received: by %s.%s (UMAIL %s) with UUCP;\n          %s\n",
X				myname, mydomain, Version, date);
X  fprintf(outfp, "Sender: %s (%s)\n", full_id(olduser), realname(olduser));
X  if (myorg != NULL) fprintf(outfp, "Organization: %s\n", myorg);
X  if ((sp = hfind("TO")) != NULL) fprintf(outfp, "To: %s\n", sp);
X  if ((sp = hfind("SUBJECT")) != NULL) fprintf(outfp, "Subject: %s\n", sp);
X  fprintf(outfp, "Date: %s\n", olddate);
X  fprintf(outfp, "\n");
X}
X
X
X/*
X * Update the current header.
X * This is necessary because the message comes from
X * a remote system without RFC-conforming mailer...
X * We should include ALL RFC-822 fields in this routine!
X */
Xstatic void upd_hdr(outfp)
XFILE *outfp;
X{
X  long rcvtm;				/* current time */
X  char *date;				/* current date in MET */
X  char *fmt1 = "%s: %s\n";
X  char *fmt2 = "%s\n";
X  register char *sp;
X  register HEADER *hp;
X
X  /* get the current date and time */
X  time(&rcvtm); date = maketime(&rcvtm);
X
X  /* First of all, get the Old V6/V7 From-line */
X  if (oldmailer == TRUE) {
X	hp = hsearch("FROM ");		/* to make it DONE */
X	if (oldhost[0] == '\0')
X		fprintf(outfp, "From %s %s remote from %s\n",
X					olduser, xtime(&rcvtm), myname);
X    	  else fprintf(outfp, "From %s!%s %s remote from %s\n",
X				oldhost, olduser, xtime(&rcvtm), myname);
X  }
X
X  /*
X   * Write the modified From:-line
X   * Note, that we must only add our name if the mail is to be forwarded
X   * to another system. If it will be delivered locally, leave it.
X   */
X  hp = hsearch("FROM");
X  if (hp != NILHEAD) {
X	if (aremote == TRUE) {	/* adressee is REMOTE. add our name! */
X		fprintf(outfp, "%s: %s!%s\n", hp->name, myname, hp->value);
X	} else {		/* adressee is LOCAL */	
X		fprintf(outfp, "%s: %s\n", hp->name, hp->value);
X	  }
X  }
X
X  /* Our own Receive:-line */
X  fprintf(outfp, "Received: by %s.%s (UMAIL %s) with UUCP;\n          %s\n",
X				myname, mydomain, Version, date);
X
X  /* Next, all other Received:-lines */
X  while ((hp = hsearch("RECEIVED")) != NILHEAD) {
X	if (hp->count > 1) fprintf(outfp, fmt2, hp->value);
X	  else fprintf(outfp, fmt1, hp->name, hp->value);
X  }
X
X  /* The old Sender:-line */
X  hp = hsearch("SENDER");
X  if (hp != NILHEAD) {
X	if (hp->count > 1) fprintf(outfp, fmt2, hp->value);
X	  else fprintf(outfp, fmt1, hp->name, hp->value);
X  }
X
X  /* insert all unknown fields here */
X  hp = hlist;
X  while (hp != NILHEAD) {
X	if (hp->std == 0) {
X		hp->done = 1;
X		fprintf(outfp, fmt1, hp->name, hp->value);
X	}
X	hp = hp->next;
X  }
X
X  /* Write the To:-line too */
X  hp = hsearch("TO");
X  if (hp != NILHEAD) {
X	if (hp->count > 1) fprintf(outfp, fmt2, hp->value);
X	  else fprintf(outfp, fmt1, hp->name, hp->value);
X  }
X
X  /* The CarbonCopy Cc:-line */
X  hp = hsearch("CC");
X  if (hp != NILHEAD) {
X	if (hp->count > 1) fprintf(outfp, fmt2, hp->value);
X	  else fprintf(outfp, fmt1, hp->name, hp->value);
X  }
X
X  /* And the BlindCarbonCopy as well */
X  hp = hsearch("BCC");
X  if (hp != NILHEAD) {
X	if (hp->count > 1) fprintf(outfp, fmt2, hp->value);
X	  else fprintf(outfp, fmt1, hp->name, hp->value);
X  }
X
X  /* Finally, the old Subject:-line */
X  hp = hsearch("SUBJECT");
X  if (hp != NILHEAD) {
X	if (hp->count > 1) fprintf(outfp, fmt2, hp->value);
X	  else fprintf(outfp, fmt1, hp->name, hp->value);
X  }
X
X  /* A message ID */
X  hp = hsearch("MESSAGE-ID");
X  if (hp != NILHEAD) {
X	if (hp->count > 1) fprintf(outfp, fmt2, hp->value);
X	  else fprintf(outfp, fmt1, hp->name, hp->value);
X  }
X
X  /* And the old date of sending */
X  hp = hsearch("DATE");
X  if (hp != NILHEAD) {
X	if (hp->count > 1) fprintf(outfp, fmt2, hp->value);
X	  else fprintf(outfp, fmt1, hp->name, hp->value);
X  } else fprintf(outfp, fmt1, "Date: ", date);
X
X  /* an empty line marks the end of the header! */
X  fprintf(outfp, "\n");
X}
X
X
X/*
X * Read the message-header into memory.
X */
Xstatic int read_hdr(infp)
Xregister FILE *infp;
X{
X  char hdrbuf[1024];
X  char lastf[128];
X  int i, numfields = 0;
X  int lastc = 1;
X  register HEADER *hp, *xp;
X  register char *bp, *sp;
X
X  while (TRUE) {
X	if (mfgets(hdrbuf, 1024, infp) == NULL) break;	/* end of file */
X	if (hdrbuf[0] == '\0') break;	/* end of header */
X
X	numfields++;
X	bp = hdrbuf;
X
X	/* first check if this is the V6/V7 From-line */
X	if (strncmp(hdrbuf, "From ", 5)) {
X		/* No From-line. */
X		if (*bp==' ' || *bp=='\t') {
X			lastc++;	/* next part of previous field */	
X			bp = lastf;	/* previous field */
X			sp = hdrbuf;	/* value */
X		} else {
X			sp = strchr(bp, ':');	/* plain field, get sepa */
X			if (sp != NULL) {	/* do we have one? */
X				*sp++ = '\0';		/* end it */
X				while (*sp && (*sp==' ' || *sp=='\t')) sp++;
X				strcpy(lastf, bp);    /* set as prev field */
X				lastc = 1;	
X			} else sp = bp;	      /* no sepa, use entire field */
X	  	  }
X	} else {
X		bp = "From ";
X		sp = &hdrbuf[5];
X	  }
X
X	/* Add a new header field to the message header in memory */
X	hp = (HEADER *) malloc(sizeof(HEADER)); 	/* allocate new variable */
X	if (hlist == NILHEAD) {			/* first variable */
X    		hlist = hp;
X  	} else {
X          	xp = hlist;
X          	while (xp->next != NILHEAD) xp = xp->next;
X          	xp->next = hp;
X    	  }
X
X  	hp->next = NILHEAD;
X  	hp->name = (char *) malloc(strlen(bp) + 2);
X  	hp->value = (char *) malloc(strlen(sp) + 2);
X
X  	strcpy(hp->name, bp);
X  	strcpy(hp->value, sp);
X  	hp->done = 0;		/* not yet read */
X  	hp->count = lastc;	/* folding level */
X  	hp->std = 0;		/* standard field? */
X
X	/* now see if this field is an RFC-822 field */
X	i = 0;
X  	sp = rfcfields[i];
X	strcpy(hdrbuf, hp->name);	/* convert field name to uppercase */
X	strupr(hdrbuf);
X  	while (sp != NULL) {
X		if (!strcmp(sp, hdrbuf)) break;
X 		sp = rfcfields[++i];
X  	}
X  	if (sp != NULL) hp->std = 1;
X  }
X}
X
X
X/*
X * Read the header from the input file 'infd', and adapt some
X * fields to the new values.
X * Then, sort the entries and generate a new header.
X * Put that new header into file 'outfp'.
X * Return TRUE if REMOTE, FALSE if LOCAL mail.
X */
Xint header(infp, outfp)
Xregister FILE *infp;
Xregister FILE *outfp;
X{
X  int remote;
X  char *sp;
X
X  (void) read_hdr(infp);		/* read in the current header */
X	
X  remote = chk_hdr(outfp);		/* analyze old header */
X
X  if (remote == FALSE) new_hdr(outfp);	/* locally-generated mail */
X    else upd_hdr(outfp);
X
X  return(remote);
X}
+ END-OF-FILE umheader.c
chmod 'u=rw,g=r,o=r' 'umheader.c'
set `wc -c 'umheader.c'`
count=$1
case $count in
12680)	:;;
*)	echo 'Bad character count in ''umheader.c' >&2
		echo 'Count should be 12680' >&2
esac
echo Extracting 'ummain.c'
sed 's/^X//' > 'ummain.c' << '+ END-OF-FILE ''ummain.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 * Usage:	umail [-c <config>] [-d] [-i <infile>] [-n] <user> ...
X *
X * Author:	F. van Kempen, Jul-Oct '89 (waltje@minixug.nluug.nl)
X */
X#include <stdio.h>
X#include <string.h>
X#include <alloc.h>
X#include <ctype.h>
X#include <time.h>
X#include <pwd.h>
X#include "umail.h"
X
X
Xchar *Version = VERSION;	/* UMAIL version ID */
Xint immediate, debug = FALSE;	/* commandline option flags */
Xint restrict = FALSE;		/* restricted (UUCP) use only */
Xint aremote;			/* is the adressee REMOTE or LOCAL ? */
Xchar dfile[128], infile[128];	/* names of message temp-files */
Xchar errmsg[512];		/* global error message */
Xchar mailsender[1024];		/* who sent the message? */
Xchar mailaddr[1024];		/* final routed adress to use. */
Xchar mailhost[64];		/* which host to send to */
Xchar mailcmd[512];		/* command to use to send the mail */
Xchar mailopts[64];		/* which options the mailer uses */
XNAME *namelist = NILNAME;	/* list of my network names */
XVAR *varlist = NILVAR;		/* list of configuration variables */
XHOST *hostlist = NILHOST;	/* list of reacheable host names */
XROUTE *routemap = NILROUTE;	/* list of domain routes */
X
X/* configuration settings */
Xchar *myname = NULL;		/* my UUCP site name */
Xchar *mydomain = NULL;		/* my UUCP domain name */
Xchar *myorg = NULL;		/* Name of my organization */
Xint oldmailer = FALSE;		/* does our mailer use old From-lines? */
Xint escape = FALSE;		/* can we offer a routing-escape? */
X
X
Xextern int getopt(), optind;	/* from standard library */
Xextern char *optarg, *fgets();
Xextern long ftell();
X
X
X/* 
X * Convert strings S to upper case. 
X */
Xchar *strupr(s)
Xchar *s;
X{
X  register char *sp;
X
X  sp = s;
X  while (*sp) {
X	if (*sp>='a' && *sp<='z') *sp = _toupper(*sp);
X  	sp++;
X  }
X  return(s);
X}
X
X
X/* 
X * Convert strings S to lower case. 
X */
Xchar *strlwr(s)
Xchar *s;
X{
X  register char *sp;
X
X  sp = s;
X  while (*sp) {
X	if (*sp>='A' && *sp<='Z') *sp = _tolower(*sp);
X  	sp++;
X  }
X  return(s);
X}
X
X
X/*
X * Add 'NAME' to the list of our names.
X */
Xvoid add_name(name)
Xchar *name;
X{
X  register NAME *np, *xp;
X
X  np = (NAME *) malloc(sizeof(NAME));       /* allocate new variable */
X  if (namelist == NILNAME) {                /* first variable */
X    	namelist = np;
X  } else {
X          xp = namelist;
X          while (xp->next != NILNAME) xp = xp->next;
X          xp->next = np;
X    }
X
X  np->next = NILNAME;
X  np->name = (char *) malloc(strlen(name) + 2);
X
X  strcpy(np->name, name);
X}
X
X
X/*
X * Add host 'NAME' to the list of hosts.
X */
Xvoid add_host(name, smart, cmd, opts)
Xchar *name;
Xint smart;
Xchar *cmd;
Xchar *opts;
X{
X  register HOST *hp, *xp;
X
X  hp = (HOST *) malloc(sizeof(HOST));       /* allocate new variable */
X  if (hostlist == NILHOST) {                /* first variable */
X    	hostlist = hp;
X  } else {
X          xp = hostlist;
X          while (xp->next != NILHOST) xp = xp->next;
X          xp->next = hp;
X    }
X
X  hp->next = NILHOST;
X  hp->name = (char *) malloc(strlen(name) + 2);
X  hp->command = (char *) malloc(strlen(cmd) + 2);
X  hp->opts = (char *) malloc(strlen(opts) + 2);
X
X  strcpy(hp->name, name);
X  strcpy(hp->command, cmd);
X  strcpy(hp->opts, opts);
X  hp->smart = smart;
X}
X
X
X/*
X * Add route 'DOMAIN' to the routing table.
X */
Xvoid add_route(domain, host, route)
Xchar *domain;
Xchar *host;
Xchar *route;
X{
X  register ROUTE *rp, *xp;
X
X  rp = (ROUTE *) malloc(sizeof(ROUTE));     /* allocate new route */
X  if (routemap == NILROUTE) {               /* first route */
X	routemap = rp;
X  } else {
X          xp = routemap;
X          while (xp->next != NILROUTE) xp = xp->next;
X          xp->next = rp;
X    }
X
X  rp->next = NILROUTE;
X  rp->domain = (char *) malloc(strlen(domain) + 2);
X  rp->host = (char *) malloc(strlen(host) + 2);
X  rp->route = (char *) malloc(strlen(route) + 2);
X
X  strcpy(rp->domain, domain);
X  strcpy(rp->host, host);
X  strcpy(rp->route, route);
X}
X
X
X/*
X * Add variable 'NAME' to the variable list.
X */
Xvoid add_var(name, val)
Xchar *name;
Xchar *val;
X{
X  register VAR *vp, *xp;
X
X  strupr(name);
X
X  vp = (VAR *) malloc(sizeof(VAR));         /* allocate new variable */
X  if (varlist == NILVAR) {                  /* first variable */
X    	varlist = vp;
X  } else {
X          xp = varlist;
X          while (xp->next != NILVAR) xp = xp->next;
X          xp->next = vp;
X    }
X
X  vp->next = NILVAR;
X  vp->name = (char *) malloc(strlen(name) + 2);
X  vp->value = (char *) malloc(strlen(val) + 2);
X
X  strcpy(vp->name, name);
X  strcpy(vp->value, val);
X}
X
X
X/*
X * Get a variable from the variable list.
X * Return NULL if not defined.
X */
Xchar *lookup(what)
Xchar *what;
X{
X  register VAR *vp;
X
X  vp = varlist;
X  while (vp != NILVAR) {
X    	if (!strcmp(vp->name, what)) return(vp->value);
X    	vp = vp->next;
X  }
X  return(NULL);
X}
X
X
X/*
X * Return TRUE or FALSE value, depending on
X * the value of the given variable.
X */
Xint boolean(ascii)
Xchar *ascii;
X{
X  strupr(ascii);
X  if (ascii==NULL || !strcmp(ascii, "FALSE")) return(FALSE);
X    else if (!strcmp(ascii, "TRUE")) return(TRUE);
X           else fprintf(stderr, "Bad value of boolean: \"%s\"\n", ascii);
X  return(FALSE);
X}
X
X
X/*
X * Lookup a host in our hosts-table.
X */
XHOST *gethost(host)
Xchar *host;
X{
X  register HOST *hp;
X
X  hp = hostlist;
X  while (hp != NILHOST) {
X	if (!strcmp(hp->name, host)) return(hp);
X	hp = hp->next;
X  }
X  return(NILHOST);
X}
X
X
X/*
X * Lookup a domain in our domain-table.
X */
XROUTE *getdomain(domain)
Xchar *domain;
X{
X  register ROUTE *rp;
X
X  rp = routemap;
X  while (rp != NILROUTE) {
X	if (!strcmp(rp->domain, domain)) return(rp);
X	rp = rp->next;
X  }
X  return(NILROUTE);
X}
X
X
X/*
X * mfgets (modified fgets)
X * Same as fgets() only this version deletes '\n'
X */
Xchar *mfgets(s, n, iop)
Xchar *s;
Xregister int n;
Xregister FILE *iop;
X{
X  register int c;
X  register char *cs;
X
X  cs = s;
X  while (--n > 0 && (c = getc(iop)) != EOF) {
X	if (c == '\n') {
X		*cs = '\0';
X		break;
X        } else *cs++ = c;
X  }
X  return((c == EOF && cs == s) ? (char *)NULL : s);
X}
X
X
X/*
X * Return the full UUCP ID of the calling user
X */
Xchar *full_id(user)
Xchar *user;
X{
X  static char fullbuf[48];
X
X  sprintf(fullbuf, "%s@%s.%s", user, myname, mydomain);
X  return(fullbuf);
X}
X
X
X/*
X * Return the Real Name of the calling user
X */
Xchar *realname(who)
Xchar *who;
X{
X  struct passwd *pw;
X
X  if ((pw = getpwnam(who)) != NULL) return(pw->pw_gecos);
X    else return("unknown flag");
X}
X
X
X/*
X * Make a decent DATE/TIME string.
X * Note, that there are TWO possible date formats:
X *
X *	Sat, 12 Oct 89 20:29:00\0
X * and
X *	Sat 12 Oct 20:29:00 1989\0
X *
X * Most Internet mailers use this first form, so we try
X * to this also. We use the function xtime() for the work...
X */
Xchar *maketime(salt)
Xlong *salt;
X{
X  static char datetime[48];		/* date and time in MET format */
X  char *sp;
X
X  sp = lookup("TIMEZONE");		/* get Time Zone from config file */
X  if (sp == NULL) sp = "";		/* must have SOME pointer! */
X
X  sprintf(datetime, "%s %s", xtime(salt), sp);
X
X  return(datetime);
X}
X
X
X/*
X * Copy a file from 'inf' to 'outf'.
X */
Xvoid fcopy(inf, outf)
Xregister FILE *inf, *outf;
X{
X  char cpbuff[1024];
X
X  while (TRUE) {
X	if (fgets(cpbuff, sizeof(cpbuff), inf) == (char *)NULL) break;
X	fwrite(cpbuff, sizeof(char), strlen(cpbuff), outf);
X  }
X}
X
X
X/*
X * Load the configuration parameters into their variables.
X */
Xstatic void setup(cfg)
Xchar *cfg;
X{
X  if (scanner(cfg) != 0) {		/* read the configuration file */
X          perror(cfg);
X          exit(1);
X  }
X
X  myname = lookup("SYSTEM");
X  if (myname == NULL) {
X	fprintf(stderr, "Missing SYSTEM definition\n");
X	exit(-1);
X  }
X  mydomain = lookup("DOMAIN");
X  if (mydomain == NULL) {
X	fprintf(stderr, "Missing DOMAIN definition\n");
X	exit(-1);
X  }
X  myorg = lookup("ORGANIZATION");
X  oldmailer = boolean(lookup("OLDMAILER"));
X  escape = boolean(lookup("ESCAPE"));
X}
X
X
X/*
X * Something went wrong.
X * Tell the caller how we should be called!
X */
Xstatic void usage()
X{
X  fprintf(stderr,
X	"Usage: umail [-c <config>] [-d] [-i <infile>] [-n] <users>\n");
X}
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  FILE *fdfile, *infp;			/* message file pointers */
X  BOX *box;				/* conversion/routing adresses */
X  char *cfgfile = CONFIG;		/* config file; to save space */
X  register int st;			/* error status, to exit() */
X  
X  if (argv[0][0] == 'r') {		/* 'rmail' link? */
X 	restrict = TRUE;		/* yes, restrict usage */
X  }
X
X  while ((st = getopt(argc, argv, "c:di:n")) != EOF) switch(st) {
X	case 'c':			/* use non-standard CONFIGH file */
X		cfgfile = optarg;
X		break;
X
X	case 'd':			/* turn on DEBUG mode */
X		debug = TRUE;
X		break;
X	case 'i':			/* use non-stdin input file */
X		strncpy(infile, optarg, 128 - 1);
X		break;
X	case 'n':			/* call UUCICO after processing */
X		immediate = TRUE;
X		break;
X	default:
X		usage();
X		exit(1);
X  }
X
X  if (optind >= argc) {			/* we need another parameter! */
X    	usage();			/* (the adressee ) */
X	exit(-1);
X  }
X
X  umask(0117);				/* change umask to -rw-rw---- */
X
X  setup(cfgfile);			/* read CONFIG and setup */
X
X  strcpy(dfile, "/tmp/umXXXXXX");	/* create temp. message file */
X  mktemp(dfile);
X  if ((fdfile = fopen(dfile, "w")) == (FILE *)NULL) {
X	perror("rmail 1");
X	exit(1);
X  }
X
X  box = convert(argv[optind]);		/* convert Internet adress to UUCP */
X  if (box == NILBOX) st = FALSE;
X    else st = route(box);		/* run it through routing tables */
X
X  if (infile[0] != '\0') {		/* open input file if -i option */
X	infp = fopen(infile, "r");
X	if (infp == (FILE *)NULL) {
X		perror(infile);
X		exit(1);
X	}
X  } else infp = stdin;			/* otherwise use stdin! */
X
X  header(infp, fdfile);			/* analyze message header */
X
X  fcopy(infp, fdfile);			/* copy message to the temp. file */
X
X  fclose(fdfile);
X  if (infp != stdin) fclose(infp);
X
X  if (st == FALSE) {			/* conversion/routing went wrong? */ 
X	errmail(errmsg, FALSE);		/* yes; return the message! */
X	st = -1;
X  } else st = sendit(mailaddr, mailhost, mailcmd, mailopts, dfile);
X
X  unlink(dfile);			/* remote data file */
X  exit(st);				/* and exit! */
X}
+ END-OF-FILE ummain.c
chmod 'u=rw,g=r,o=r' 'ummain.c'
set `wc -c 'ummain.c'`
count=$1
case $count in
10125)	:;;
*)	echo 'Bad character count in ''ummain.c' >&2
		echo 'Count should be 10125' >&2
esac
exit 0