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