v08i070: Smail release 2.3, Part04/05
sources-request at mirror.UUCP
sources-request at mirror.UUCP
Wed Feb 18 11:32:45 AEST 1987
Submitted by: Larry Auton <lda at clyde.att.com>
Mod.sources: Volume 8, Issue 70
Archive-name: smail2/Part04
[ OOPS! Please excuse the "Part03/03" header on the last part. --r$ ]
#! /bin/sh
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If all goes well, you will see the message "End of shell archive."
# Contents: src/deliver.c src/headers.c src/main.c src/make.cf.sh
# src/map.c src/misc.c src/resolve.c src/smail.prompt
# src/svbinmail.c src/sysexits.h
# Wrapped by rs at mirror on Mon Feb 9 17:10:08 1987
PATH=/bin:/usr/bin:/usr/ucb; export PATH
echo shar: extracting "'src/deliver.c'" '(11313 characters)'
if test -f 'src/deliver.c' ; then
echo shar: will not over-write existing file "'src/deliver.c'"
else
sed 's/^X//' >src/deliver.c <<'@//E*O*F src/deliver.c//'
X/*
X** Deliver.c
X**
X** Routines to effect delivery of mail for rmail/smail.
X**
X*/
X
X#ifndef lint
Xstatic char *sccsid="@(#)deliver.c 2.3 (smail) 1/26/87";
X#endif
X
X# include <stdio.h>
X# include <sys/types.h>
X# include <ctype.h>
X# include "defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
Xextern int exitstat; /* set if a forked mailer fails */
Xextern enum edebug debug; /* how verbose we are */
Xextern char hostname[]; /* our uucp hostname */
Xextern char hostdomain[]; /* our host's domain */
Xextern enum ehandle handle; /* what we handle */
Xextern enum erouting routing; /* how we're routing addresses */
Xextern char *uuxargs; /* arguments given to uux */
Xextern int queuecost; /* threshold for queueing mail */
Xextern int maxnoqueue; /* max number of uucico's */
Xextern char *spoolfile; /* file name of spooled message */
Xextern FILE *spoolfp; /* file ptr to spooled message */
Xextern int spoolmaster; /* set if creator of spoolfile */
Xextern char nows[]; /* local time in ctime(3) format*/
Xextern char arpanows[]; /* local time in arpadate format*/
Xchar stderrfile[20]; /* error file for stderr traping*/
X
X/*
X**
X** deliver(): hand the letter to the proper mail programs.
X**
X** Issues one command for each different host of <hostv>,
X** constructing the proper command for LOCAL or UUCP mail.
X** Note that LOCAL mail has blank host names.
X**
X** The <userv> names for each host are arguments to the command.
X**
X** Prepends a "From" line to the letter just before going
X** out, with a "remote from <hostname>" if it is a UUCP letter.
X**
X*/
X
Xdeliver(argc, hostv, userv, formv, costv)
Xint argc; /* number of addresses */
Xchar *hostv[]; /* host names */
Xchar *userv[]; /* user names */
Xenum eform formv[]; /* form for each address */
Xint costv[]; /* cost vector */
X{
X FILE *out; /* pipe to mailer */
X FILE *popen(); /* to fork a mailer */
X#ifdef RECORD
X void record(); /* record all transactions */
X#endif
X#ifdef LOG
X void log();
X#endif
X char *mktemp();
X char from[SMLBUF]; /* accumulated from argument */
X char lcommand[SMLBUF]; /* local command issued */
X char rcommand[SMLBUF]; /* remote command issued */
X char scommand[SMLBUF]; /* retry command issued */
X char *command; /* actual command */
X char buf[SMLBUF]; /* copying rest of the letter */
X enum eform form; /* holds form[i] for speed */
X long size; /* number of bytes of message */
X char *flags; /* flags for uux */
X char *sflag; /* flag for smail */
X int i, j, stat, retrying;
X char *c, *postmaster();
X int failcount = 0;
X int noqcnt = 0; /* number of uucico's started */
X char *uux_noqueue = UUX_NOQUEUE;/* uucico starts immediately */
X char *uux_queue = UUX_QUEUE; /* uucico job gets queued */
X off_t message;
X
X/*
X** rewind the spool file and read the collapsed From_ line
X*/
X (void) fseek(spoolfp, 0L, 0);
X (void) fgets(from, sizeof(from), spoolfp);
X if((c = index(from, '\n')) != 0) *c = '\0';
X message = ftell(spoolfp);
X
X/*
X** We pass through the list of addresses.
X*/
X stderrfile[0] = '\0';
X for(i = 0; i < argc; i++) {
X char *lend = lcommand;
X char *rend = rcommand;
X char *send = scommand;
X
X/*
X** If we don't have sendmail, arrange to trap standard error
X** for inclusion in the message that is returned with failed mail.
X*/
X (void) unlink(stderrfile);
X (void) strcpy(stderrfile, "/tmp/stderrXXXXXX");
X (void) mktemp(stderrfile);
X (void) freopen(stderrfile, "w", stderr);
X
X *lend = *rend = *send = '\0';
X
X/*
X** If form == ERROR, the address was bad
X** If form == SENT, it has been sent on a previous pass.
X*/
X form = formv[i];
X if (form == SENT) {
X continue;
X }
X/*
X** Build the command based on whether this is local mail or uucp mail.
X** By default, don't allow more than 'maxnoqueue' uucico commands to
X** be started by a single invocation of 'smail'.
X*/
X if(uuxargs == NULL) { /* flags not set on command line */
X if(noqcnt < maxnoqueue && costv[i] <= queuecost) {
X flags = uux_noqueue;
X } else {
X flags = uux_queue;
X }
X } else {
X flags = uuxargs;
X }
X
X retrying = 0;
X if(routing == JUSTDOMAIN) {
X sflag = "-r";
X } else if(routing == ALWAYS) {
X sflag = "-R";
X } else {
X sflag = "";
X }
X
X (void) sprintf(lcommand, LMAIL(from, hostv[i]));
X (void) sprintf(rcommand, RMAIL(flags, from, hostv[i]));
X
X/*
X** For each address with the same host name and form, append the user
X** name to the command line, and set form = ERROR so we skip this address
X** on later passes.
X*/
X /* we initialized lend (rend) to point at the
X * beginning of its buffer, so that at
X * least one address will be used regardless
X * of the length of lcommand (rcommand).
X */
X for (j = i; j < argc; j++) {
X if ((formv[j] != form)
X || (strcmpic(hostv[i], hostv[j]) != 0)
X || ((lend - lcommand) > MAXCLEN)
X || ((rend - rcommand) > MAXCLEN)) {
X continue;
X }
X
X /*
X ** seek to the end of scommand
X ** and add on a 'smail' command
X ** multiple commands are separated by ';'
X */
X
X send += strlen(send);
X if(send != scommand) {
X *send++ = ';' ;
X }
X
X (void) sprintf(send, RETRY(sflag));
X send += strlen(send);
X
X lend += strlen(lend);
X rend += strlen(rend);
X
X if (form == LOCAL) {
X (void) sprintf(lend, LARG(userv[j]));
X (void) sprintf(send, LARG(userv[j]));
X } else {
X (void) sprintf(lend, RLARG(hostv[i], userv[j]));
X (void) sprintf(send, RLARG(hostv[i], userv[j]));
X }
X
X (void) sprintf(rend, RARG(userv[j]));
X formv[j] = SENT;
X }
Xretry:
X/*
X** rewind the spool file and read the collapsed From_ line
X*/
X (void) fseek(spoolfp, message, 0);
X
X /* if the address was in a bogus form (usually DOMAIN),
X ** then don't bother trying the uux.
X **
X ** Rather, go straight to the next smail routing level.
X */
X if(form == ERROR) {
X static char errbuf[SMLBUF];
X (void) sprintf(errbuf,
X "address resolution ('%s' @ '%s') failed",
X userv[i], hostv[i]);
X command = errbuf;
X size = 0;
X goto form_error;
X }
X
X if (retrying) {
X command = scommand;
X } else if (form == LOCAL) {
X command = lcommand;
X } else {
X command = rcommand;
X if(flags == uux_noqueue) {
X noqcnt++;
X }
X }
X ADVISE("COMMAND: %s\n", command);
X
X/*
X** Fork the mailer and set it up for writing so we can send the mail to it,
X** or for debugging divert the output to stdout.
X*/
X if (debug == YES) {
X out = stdout;
X } else {
X failcount = 0;
X do {
X out = popen(command, "w");
X if (out) break;
X /*
X * Fork failed. System probably overloaded.
X * Wait awhile and try again 10 times.
X * If it keeps failing, probably some
X * other problem, like no uux or smail.
X */
X (void) sleep(60);
X } while (++failcount < 10);
X }
X if(out == NULL) {
X exitstat = EX_UNAVAILABLE;
X (void) printf("couldn't execute %s.\n", command);
X continue;
X }
X
X size = 0;
X/*
X** Output our From_ line.
X*/
X if (form == LOCAL) {
X#ifdef SENDMAIL
X size += fprintf(out, LFROM(from, nows, hostname));
X#else
X char *p;
X if((p=index(from, '!')) == NULL) {
X size += fprintf(out,
X LFROM(from, nows, hostname));
X } else {
X *p = NULL;
X size += fprintf(out, RFROM(p+1, nows, from));
X *p = '!';
X }
X#endif
X } else {
X size += fprintf(out, RFROM(from, nows, hostname));
X }
X
X#ifdef SENDMAIL
X/*
X** If using sendmail, insert a Received: line only for mail
X** that is being passed to uux. If not using sendmail, always
X** insert the received line, since sendmail isn't there to do it.
X*/
X if(command == rcommand && handle != ALL)
X#endif
X {
X size += fprintf(out,
X "Received: by %s (%s)\n\tid AA%05d; %s\n",
X hostdomain, VERSION,
X getpid(), arpanows);
X }
X
X/*
X** Copy input.
X*/
X while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
X size += fputs(buf, out);
X }
X/*
X** Get exit status and if non-zero, set global exitstat so when we exit
X** we can indicate an error.
X*/
Xform_error:
X if (debug != YES) {
X if(form == ERROR) {
X exitstat = EX_NOHOST;
X } else if (stat = pclose(out)) {
X exitstat = stat >> 8;
X }
X /*
X * The 'retrying' check prevents a smail loop.
X */
X if(exitstat != 0) {
X /*
X ** the mail failed, probably because the host
X ** being uux'ed isn't in L.sys or local user
X ** is unknown.
X */
X
X if((retrying == 0) /* first pass */
X && (routing != REROUTE) /* have higher level */
X && (form != LOCAL)) { /* can't route local */
X /*
X ** Try again using a higher
X ** level of routing.
X */
X ADVISE("%s failed (%d)\ntrying %s\n",
X command, exitstat, scommand);
X exitstat = 0;
X retrying = 1;
X form = SENT;
X goto retry;
X }
X
X /*
X ** if we have no other routing possibilities
X ** see that the mail is returned to sender.
X */
X
X if((routing == REROUTE)
X || (form == LOCAL)) {
X
X /*
X ** if this was our last chance,
X ** return the mail to the sender.
X */
X
X ADVISE("%s failed (%d)\n",
X command, exitstat);
X
X (void) fseek(spoolfp, message, 0);
X#ifdef SENDMAIL
X /* if we have sendmail, then it
X ** was handed the mail, which failed.
X ** sendmail returns the failed mail
X ** for us, so we need not do it again.
X */
X if(form != LOCAL)
X#endif
X {
X return_mail(from, command);
X }
X exitstat = 0;
X }
X }
X# ifdef LOG
X else {
X if(retrying == 0) log(command, from, size); /* */
X }
X# endif
X }
X }
X/*
X** Update logs and records.
X*/
X# ifdef RECORD
X (void) fseek(spoolfp, message, 0);
X record(command, from, size);
X# endif
X
X/*
X** close spool file pointer.
X** if we created it, then unlink file.
X*/
X (void) fclose(spoolfp);
X if(spoolmaster) {
X (void) unlink(spoolfile);
X }
X (void) unlink(stderrfile);
X}
X
X/*
X** return mail to sender, as determined by From_ line.
X*/
Xreturn_mail(from, fcommand)
Xchar *from, *fcommand;
X{
X char buf[SMLBUF];
X char domain[SMLBUF], user[SMLBUF];
X char *r;
X FILE *fp, *out, *popen();
X int i = 0;
X
X r = buf;
X
X (void) sprintf(r, "%s %s", SMAIL, VFLAG);
X r += strlen(r);
X
X if(islocal(from, domain, user)) {
X (void) sprintf(r, LARG(user));
X } else {
X (void) sprintf(r, RLARG(domain, user));
X }
X
X i = 0;
X do {
X out = popen(buf, "w");
X if (out) break;
X /*
X * Fork failed. System probably overloaded.
X * Wait awhile and try again 10 times.
X * If it keeps failing, probably some
X * other problem, like no uux or smail.
X */
X (void) sleep(60);
X } while (++i < 10);
X
X if(out == NULL) {
X (void) printf("couldn't execute %s.\n", buf);
X return;
X }
X
X (void) fprintf(out, "Date: %s\n", arpanows);
X (void) fprintf(out, "From: MAILER-DAEMON@%s\n", hostdomain);
X (void) fprintf(out, "Subject: failed mail\n");
X (void) fprintf(out, "To: %s\n", from);
X (void) fprintf(out, "\n");
X (void) fprintf(out, "======= command failed =======\n\n");
X (void) fprintf(out, " COMMAND: %s\n\n", fcommand);
X
X (void) fprintf(out, "======= standard error follows =======\n");
X (void) fflush(stderr);
X if((fp = fopen(stderrfile, "r")) != NULL) {
X while(fgets(buf, sizeof(buf), fp) != NULL) {
X (void) fputs(buf, out);
X }
X }
X (void) fclose(fp);
X (void) fprintf(out, "======= text of message follows =======\n");
X/*
X** Copy input.
X*/
X (void) fprintf(out, "From %s\n", from);
X while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
X (void) fputs(buf, out);
X }
X (void) pclose(out);
X}
@//E*O*F src/deliver.c//
if test 11313 -ne "`wc -c <'src/deliver.c'`"; then
echo shar: error transmitting "'src/deliver.c'" '(should have been 11313 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/headers.c'" '(13909 characters)'
if test -f 'src/headers.c' ; then
echo shar: will not over-write existing file "'src/headers.c'"
else
sed 's/^X//' >src/headers.c <<'@//E*O*F src/headers.c//'
X/*
X** message spooing, header and address parsing and completion
X** functions for smail/rmail
X*/
X
X#ifndef lint
Xstatic char *sccsid="@(#)headers.c 2.3 (smail) 1/26/87";
X#endif
X
X# include <stdio.h>
X# include <sys/types.h>
X# include <time.h>
X# include <ctype.h>
X# include <pwd.h>
X# include "defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
Xextern enum edebug debug; /* how verbose we are */
Xextern char hostname[]; /* */
Xextern char hostdomain[]; /* */
Xextern char *spoolfile; /* file name of spooled message */
Xextern FILE *spoolfp; /* file ptr to spooled message */
Xextern int spoolmaster; /* set if creator of spoolfile */
Xextern time_t now; /* time */
Xextern char nows[], arpanows[]; /* time strings */
Xextern struct tm *gmt, *loc; /* time structs */
X
Xstatic char toline[SMLBUF];
Xstatic char fromline[SMLBUF];
Xstatic char dateline[SMLBUF];
Xstatic char midline[SMLBUF];
Xstatic char *ieof = "NOTNULL";
X
Xstruct reqheaders {
X char *name;
X char *field;
X char have;
X};
X
Xstatic struct reqheaders reqtab[] = {
X "Date:" , dateline , 'N' ,
X "From:" , fromline , 'N' ,
X "Message-Id:" , midline , 'N' ,
X "To:" , toline , 'N' ,
X NULL , NULL , 'N'
X};
X
X
X/*
X**
X** parse(): parse <address> into <domain, user, form>.
X**
X** input form
X** ----- ----
X** user LOCAL
X** domain!user DOMAIN
X** user at domain DOMAIN
X** @domain,address LOCAL (just for sendmail)
X** host!address UUCP
X**
X*/
X
Xenum eform
Xparse(address, domain, user)
Xchar *address; /* input address */
Xchar *domain; /* output domain */
Xchar *user; /* output user */
X{
X int parts;
X char *partv[MAXPATH]; /* to crack address */
X
X/*
X** If this is route address form @hosta, at hostb:user at hostd, break for
X** LOCAL since only sendmail would want to eat it.
X*/
X if (*address == '@')
X goto local;
X/*
X** Try splitting at @. If it work, this is user at domain, form DOMAIN.
X** Prefer the righthand @ in a at b@c.
X*/
X if ((parts = ssplit(address, '@', partv)) >= 2) {
X (void) strcpy(domain, partv[parts-1]);
X (void) strncpy(user, partv[0], partv[parts-1]-partv[0]-1);
X user[partv[parts-1]-partv[0]-1] = '\0';
X return (DOMAIN);
X }
X/*
X** Try splitting at !. If it works, see if the piece before the ! has
X** a . in it (domain!user, form DOMAIN) or not (host!user, form UUCP).
X*/
X if (ssplit(address, '!', partv) > 1) {
X (void) strcpy(user, partv[1]);
X (void) strncpy(domain, partv[0], partv[1]-partv[0]-1);
X domain[partv[1]-partv[0]-1] = '\0';
X
X if((parts = ssplit(domain, '.', partv)) < 2) {
X return(UUCP);
X }
X
X if(partv[parts-1][0] == '\0') {
X partv[parts-1][-1] = '\0'; /* strip trailing . */
X }
X return (DOMAIN);
X }
X/*
X** Done trying. This must be just a user name, form LOCAL.
X*/
Xlocal:
X (void) strcpy(user, address);
X (void) strcpy(domain, "");
X return(LOCAL); /* user */
X}
X
Xbuild(domain, user, form, result)
Xchar *domain;
Xchar *user;
Xenum eform form;
Xchar *result;
X{
X switch((int) form) {
X case LOCAL:
X (void) sprintf(result, "%s", user);
X break;
X case UUCP:
X (void) sprintf(result, "%s!%s", domain, user);
X break;
X case DOMAIN:
X (void) sprintf(result, "%s@%s", user, domain);
X break;
X }
X}
X
X/*
X** ssplit(): split a line into array pointers.
X**
X** Each pointer wordv[i] points to the first character after the i'th
X** occurence of c in buf. Note that each wordv[i] includes wordv[i+1].
X**
X*/
X
Xssplit(buf, c, ptr)
Xregister char *buf; /* line to split up */
Xchar c; /* character to split on */
Xchar **ptr; /* the resultant vector */
X{
X int count = 0;
X int wasword = 0;
X
X for(; *buf; buf++) {
X if (!wasword) {
X count++;
X *ptr++ = buf;
X }
X wasword = (c != *buf);
X }
X if (!wasword) {
X count++;
X *ptr++ = buf;
X }
X *ptr = NULL;
X return(count);
X}
X
X/*
X** Determine whether an address is a local address
X*/
X
Xislocal(addr, domain, user)
Xchar *addr, *domain, *user;
X{
X enum eform form, parse();
X
X /*
X ** parse the address
X */
X
X form = parse(addr, domain, user);
X
X if((form == LOCAL) /* user */
X ||(strcmpic(domain, hostdomain) == 0) /* user at hostdomain */
X ||(strcmpic(domain, hostname) == 0)) {/* user at hostname */
X return(1);
X }
X return(0);
X}
X
X/*
X** spool - message spooling module
X**
X** (1) get dates for headers, etc.
X** (2) if the message is on the standard input (no '-f')
X** (a) create a temp file for spooling the message.
X** (b) collapse the From_ headers into a path.
X** (c) if the mail originated locally, then
X** (i) establish default headers
X** (ii) scan the message headers for required header fields
X** (iii) add any required message headers that are absent
X** (d) copy rest of the message to the spool file
X** (e) close the spool file
X** (3) open the spool file for reading
X*/
X
Xvoid
Xspool(argc, argv)
Xint argc;
Xchar **argv;
X{
X static char *tmpf = "/tmp/rmXXXXXX"; /* temp file name */
X char *mktemp();
X char buf[SMLBUF];
X static char splbuf[SMLBUF];
X char from[SMLBUF], domain[SMLBUF], user[SMLBUF];
X void rline(), scanheaders(), compheaders();
X
X /*
X ** if the mail has already been spooled by
X ** a previous invocation of smail don't respool.
X ** check the file name to prevent things like
X ** rmail -f /etc/passwd badguy at dreadfuldomain
X */
X
X if((spoolfile != NULL)
X && (strncmp(spoolfile, tmpf, strlen(tmpf) - 6) != 0)) {
X error(EX_TEMPFAIL, "spool: bad file name '%s'\n", spoolfile);
X }
X
X /*
X ** set dates in local, arpa, and gmt forms
X */
X setdates();
X
X /*
X ** If necessary, copy stdin to a temp file.
X */
X
X if(spoolfile == NULL) {
X spoolfile = strcpy(splbuf, tmpf);
X (void) mktemp(spoolfile);
X
X if((spoolfp = fopen(spoolfile, "w")) == NULL) {
X error(EX_CANTCREAT, "can't create %s.\n", spoolfile);
X }
X
X spoolmaster = 1;
X
X /*
X ** rline reads the standard input,
X ** collapsing the From_ and >From_
X ** lines into a single uucp path.
X ** first non-from_ line is in buf[];
X */
X
X rline(from, buf);
X
X /*
X ** if the mail originated here, we parse the header
X ** and add any required headers that are missing.
X */
X
X if(islocal(from, domain, user)) {
X /*
X ** initialize default headers
X */
X def_headers(argc, argv, from);
X
X /*
X ** buf has first, non-from_ line
X */
X scanheaders(buf);
X /*
X ** buf has first, non-header line,
X */
X
X compheaders();
X
X if(buf[0] != '\n') {
X (void) fputs("\n", spoolfp);
X }
X }
X
X /*
X ** now, copy the rest of the letter into the spool file
X ** terminate on either EOF or '^.$'
X */
X
X while(ieof != NULL) {
X (void) fputs(buf, spoolfp);
X if((fgets(buf, SMLBUF, stdin) == NULL)
X || (buf[0] == '.' && buf[1] == '\n')) {
X ieof = NULL;
X }
X }
X
X /*
X ** close the spool file, and the standard input.
X */
X
X (void) fclose(spoolfp);
X (void) fclose(stdin); /* you don't see this too often! */
X }
X
X if((spoolfp = fopen(spoolfile, "r")) == NULL) {
X error(EX_TEMPFAIL, "can't open %s.\n", spoolfile);
X }
X}
X
X/*
X**
X** rline(): collapse From_ and >From_ lines.
X**
X** Same idea as the old rmail, but also turns user at domain to domain!user.
X**
X*/
X
Xvoid
Xrline(from, retbuf)
Xchar *from;
Xchar *retbuf;
X{
X int parts; /* for cracking From_ lines ... */
X char *partv[16]; /* ... apart using ssplit() */
X char user[SMLBUF]; /* for rewriting user at host */
X char domain[SMLBUF]; /* " " " */
X char addr[SMLBUF]; /* " " " */
X enum eform form, parse(); /* " " " */
X extern build(); /* " " " */
X struct passwd *pwent, *getpwuid();/* to get default user */
X char *c;
X int nhops, i;
X char buf[SMLBUF], tmp[SMLBUF], *hop[128], *e, *b, *p;
X
X if(spoolmaster == 0) return;
X
X buf[0] = from[0] = addr[0] = '\0';
X/*
X** Read each line until we hit EOF or a line not beginning with "From "
X** or ">From " (called From_ lines), accumulating the new path in from
X** and stuffing the actual sending user (the user name on the last From_
X** line) in addr.
X*/
X for(;;) {
X (void) strcpy(retbuf, buf);
X if(ieof == NULL) {
X break;
X }
X if((fgets(buf, sizeof(buf), stdin) == NULL)
X || (buf[0] == '.' && buf[1] == '\n')) {
X ieof = NULL;
X break;
X }
X if (strncmp("From ", buf, 5)
X && strncmp(">From ", buf, 6)) {
X break;
X }
X/*
X** Crack the line apart using ssplit.
X*/
X if(c = index(buf, '\n')) {
X *c = '\0';
X }
X parts = ssplit(buf, ' ', partv);
X/*
X** Tack host! onto the from argument if "remote from host" is present.
X*/
X
X if (parts > 3
X && !strncmp("remote from ", partv[parts-3], 12))
X {
X (void) strcat(from, partv[parts-1]);
X (void) strcat(from, "!");
X }
X/*
X** Stuff user name into addr, overwriting the user name from previous
X** From_ lines, since only the last one counts. Then rewrite user at host
X** into host!user, since @'s don't belong in the From_ argument.
X*/
X (void) strncpy(addr, partv[1], partv[2]-partv[1]-1);
X addr[partv[2]-partv[1]-1] = '\0'; /* ugh */
X
X (void) parse(addr, domain, user);
X if(*domain == '\0') {
X form = LOCAL;
X } else {
X form = UUCP;
X }
X
X build(domain, user, form, addr);
X }
X/*
X** Now tack the user name onto the from argument.
X*/
X (void) strcat(from, addr);
X/*
X** If we still have no from argument, we have junk headers, but we try
X** to get the user's name using /etc/passwd.
X*/
X if (from[0] == '\0') {
X if ((pwent = getpwuid(getuid())) == NULL) {
X (void) strcpy(from, "nowhere"); /* bad news */
X } else {
X (void) strcpy(from, pwent->pw_name);
X }
X }
X
X /* split the from line on '!'s */
X nhops = ssplit(from, '!', hop);
X
X for(i = 0; i < (nhops - 1); i++) {
X b = hop[i];
X if(*b == '\0') {
X continue;
X }
X e = hop[i+1];
X e-- ;
X *e = '\0'; /* null terminate each path segment */
X e++;
X
X#ifdef HIDDENHOSTS
X/*
X** Strip hidden hosts: anything.hostname.MYDOM -> hostname.MYDOM
X*/
X for(p = b;(p = index(p, '.')) != NULL; p++) {
X if(strcmpic(hostdomain, p+1) == 0) {
X (void) strcpy(b, hostdomain);
X break;
X }
X }
X#endif
X
X/*
X** Strip useless MYDOM: hostname.MYDOM -> hostname
X*/
X if(strcmpic(hop[i], hostdomain) == 0) {
X (void) strcpy(hop[i], hostname);
X }
X }
X
X/*
X** Now strip out any redundant information in the From_ line
X** a!b!c!c!d => a!b!c!d
X*/
X
X for(i = 0; i < (nhops - 2); i++) {
X b = hop[i];
X e = hop[i+1];
X if(strcmpic(b, e) == 0) {
X *b = '\0';
X }
X }
X/*
X** Reconstruct the From_ line
X*/
X tmp[0] = '\0'; /* empty the tmp buffer */
X
X for(i = 0; i < (nhops - 1); i++) {
X if((hop[i][0] == '\0') /* deleted this hop */
X ||((tmp[0] == '\0') /* first hop == hostname */
X &&(strcmpic(hop[i], hostname) == 0))) {
X continue;
X }
X (void) strcat(tmp, hop[i]);
X (void) strcat(tmp, "!");
X }
X (void) strcat(tmp, hop[i]);
X (void) strcpy(from, tmp);
X (void) strcpy(retbuf, buf);
X (void) fprintf(spoolfp, "%s\n", from);
X}
X
Xvoid
Xscanheaders(buf)
Xchar *buf;
X{
X int inheader = 0;
X
X while(ieof != NULL) {
X if(buf[0] == '\n') {
X break; /* end of headers */
X }
X
X /*
X ** header lines which begin with whitespace
X ** are continuation lines
X */
X if((inheader == 0)
X || ((buf[0] != ' ' && buf[0] != '\t'))) {
X /* not a continuation line
X ** check for header
X */
X if(isheader(buf) == 0) {
X /*
X ** not a header
X */
X break;
X }
X inheader = 1;
X haveheaders(buf);
X }
X (void) fputs(buf, spoolfp);
X if((fgets(buf, SMLBUF, stdin) == NULL)
X || (buf[0] == '.' && buf[1] == '\n')) {
X ieof = NULL;
X }
X }
X
X if(isheader(buf)) {
X buf[0] = '\0';
X }
X}
X
X/*
X** complete headers - add any required headers that are not in the message
X*/
Xvoid
Xcompheaders()
X{
X struct reqheaders *i;
X
X /*
X ** look at the table of required headers and
X ** add those that are missing to the spooled message.
X */
X for(i = reqtab; i->name != NULL; i++) {
X if(i->have != 'Y') {
X (void) fprintf(spoolfp, "%s\n", i->field);
X }
X }
X}
X
X/*
X** look at a string and determine
X** whether or not it is a valid header.
X*/
Xisheader(s)
Xchar *s;
X{
X char *p;
X
X /*
X ** header field names must terminate with a colon
X ** and may not be null.
X */
X if(((p = index(s, ':')) == NULL) || (s == p)) {
X return(0);
X
X }
X /*
X ** header field names must consist entirely of
X ** printable ascii characters.
X */
X while(s != p) {
X if((*s < '!') || (*s > '~')) {
X return(0);
X }
X s++;
X }
X /*
X ** we hit the ':', so the field may be a header
X */
X return(1);
X}
X
X/*
X** compare the header field to those in the required header table.
X** if it matches, then mark the required header as being present
X** in the message.
X*/
Xhaveheaders(s)
Xchar *s;
X{
X struct reqheaders *i;
X
X for(i = reqtab; i->name != NULL; i++) {
X if(strncmpic(i->name, s, strlen(i->name)) == 0) {
X i->have = 'Y';
X break;
X }
X }
X}
X
X/*
X** create default headers for the message.
X*/
Xdef_headers(argc, argv, from)
Xint argc;
Xchar **argv;
Xchar *from;
X{
X def_to(argc, argv); /* default To: */
X def_date(); /* default Date: */
X def_from(from); /* default From: */
X def_mid(); /* default Message-Id: */
X}
X
X/*
X** default Date: in arpa format
X*/
Xdef_date()
X{
X (void) strcpy(dateline, "Date: ");
X (void) strcat(dateline, arpanows);
X}
X
X/*
X** default Message-Id
X** Message-Id: <yymmddhhmm.AAppppp at hostdomain>
X**
X** yy year
X** mm month
X** dd day
X** hh hour
X** mm minute
X** ppppp process-id
X**
X** date and time are set by GMT
X*/
Xdef_mid()
X{
X (void) sprintf(midline, "Message-Id: <%02d%02d%02d%02d%02d.AA%05d@%s>",
X gmt->tm_year,
X gmt->tm_mon+1,
X gmt->tm_mday,
X gmt->tm_hour,
X gmt->tm_min,
X getpid(),
X hostdomain);
X}
X
X/*
X** default From:
X** From: user at hostdomain
X*/
Xdef_from(from)
Xchar *from;
X{
X (void) sprintf(fromline, "From: %s@%s", from, hostdomain);
X}
X
X/*
X** default To:
X** To: recip1, recip2, ...
X**
X** lines longer than 50 chars are continued on another line.
X*/
Xdef_to(argc, argv)
Xint argc;
Xchar **argv;
X{
X int i, n;
X char *bol;
X
X bol = toline;
X (void) strcpy(bol, "To:");
X for(n = i = 0; i < argc; i++) {
X n = strlen(bol);
X if(n > 50) {
X (void) strcat(bol, "\n\t");
X bol = bol + strlen(bol);
X *bol = '\0';
X n = 8;
X }
X if(i == 0) {
X (void) strcat(bol, " ");
X } else {
X (void) strcat(bol, ", ");
X }
X (void) strcat(bol, argv[i]);
X }
X}
@//E*O*F src/headers.c//
if test 13909 -ne "`wc -c <'src/headers.c'`"; then
echo shar: error transmitting "'src/headers.c'" '(should have been 13909 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/main.c'" '(4213 characters)'
if test -f 'src/main.c' ; then
echo shar: will not over-write existing file "'src/main.c'"
else
sed 's/^X//' >src/main.c <<'@//E*O*F src/main.c//'
X/*
X**
X** rmail/smail - UUCP mailer with automatic routing.
X**
X** Christopher Seiwald /+\
X** chris at cbosgd.att.com +\
X** January, 1985 \+/
X**
X*/
X
X#ifndef lint
Xstatic char *sccsid="@(#)main.c 2.2 (smail) 1/26/87";
X#endif
X
X/*
X**
X** usage: rmail [options] address...
X** smail [options] address...
X** options:
X** -d debug - verbose and don't invoke mailers.
X** -v verbose - just verbose.
X** -h hostname set hostname
X** -H hostdomain set hostdomain (default hostname.MYDOM)
X** -p pathfile path database filename
X** -r force routing of host!address
X** -R reroute even explicit path!user
X** -l user at domain goes to local mailer
X** -L all mail goes local
X** -q number mail queueing cost threshold
X** -m number limit on number of uux_noqueue jobs
X** -u string string of flags for uux
X** -a aliasfile aliases filename (not used with SENDMAIL)
X*/
X
X#include <stdio.h>
X#include <ctype.h>
X#include "defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
Xint exitstat = 0; /* exit status, set by resolve, deliver */
X
Xenum edebug debug = NO; /* set by -d or -v option */
Xenum ehandle handle = HANDLE; /* which mail we can handle, see defs.h */
Xenum erouting routing = ROUTING;/* to route or not to route, see defs.h */
X
Xchar hostname[SMLBUF] = ""; /* set by -h, defaults in defs.h */
Xchar hostdomain[SMLBUF] = ""; /* set by -H, defaults in defs.h */
X
Xchar *pathfile = PATHS; /* or set by -p */
Xchar *uuxargs = NULL; /* or set by -u */
Xchar *aliasfile = ALIAS; /* or set by -a */
Xint queuecost = QUEUECOST; /* or set by -q */
Xint maxnoqueue = MAXNOQUEUE; /* or set by -m */
X
Xchar *spoolfile = NULL; /* name of the file containing letter */
XFILE *spoolfp; /* file pointer to spoolfile */
Xint spoolmaster = 0; /* indicates 'control' of spoolfile */
Xvoid spool();
X
X
X/*
X**
X** rmail/smail: mail stdin letter to argv addresses.
X**
X** After processing command line options and finding our host and domain
X** names, we map addresses into <host,user,form,cost> sets. Then we deliver.
X**
X*/
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X{
X char *hostv[MAXARGS]; /* UUCP neighbor */
X char *userv[MAXARGS]; /* address given to host */
X int costv[MAXARGS]; /* cost of resolved route */
X enum eform formv[MAXARGS]; /* invalid, local, or uucp */
X char *p;
X int c;
X int nargc;
X char **nargv, **alias();
X
X char *optstr = "dvrRlLH:h:p:u:q:a:m:f:";
X extern char *optarg;
X extern int optind;
X
X/*
X** see if we aren't invoked as rmail
X*/
X if((p = rindex(argv[0], '/')) == NULL) {
X p = argv[0];
X } else {
X p++;
X }
X
X if(*p != 'r' ) {
X handle = ALL;
X }
X
X/*
X** Process command line arguments
X*/
X while ((c = getopt(argc, argv, optstr)) != EOF) {
X switch ( c ) {
X case 'd': debug = YES; break;
X case 'v': debug = VERBOSE; break;
X case 'r': routing = ALWAYS; break;
X case 'R': routing = REROUTE; break;
X case 'l': handle = JUSTUUCP; break;
X case 'L': handle = NONE; break;
X case 'f': spoolfile = optarg; break;
X case 'p': pathfile = optarg; break;
X case 'u': uuxargs = optarg; break;
X case 'a': aliasfile = optarg; break;
X case 'H': (void) strcpy(hostdomain, optarg); break;
X case 'h': (void) strcpy(hostname, optarg); break;
X case 'm': if(isdigit(*optarg)) {
X maxnoqueue = atoi(optarg);
X }
X break;
X case 'q': if(isdigit(*optarg)) {
X queuecost = atoi(optarg);
X }
X break;
X default:
X error( EX_USAGE, "valid flags are %s\n", optstr);
X }
X }
X if ( argc <= optind ) {
X error( EX_USAGE, "usage: %s [flags] address...\n", argv[0] );
X }
X
X/*
X** Get our default hostname and hostdomain.
X*/
X getmynames();
X
X/*
X** Spool the letter in a temporary file.
X*/
X nargc = argc - optind;
X spool(nargc, &argv[optind]);
X
X/*
X** If we have sendmail, aliasing was done there, so alias() is a NOP.
X** If we don't have sendmail, do our own aliasing.
X*/
X nargv = alias(&nargc, &argv[optind]);
X
X/*
X** Map argv addresses to <host, user, form, cost>.
X*/
X map(nargc, nargv, hostv, userv, formv, costv);
X/*
X** Deliver.
X*/
X deliver(nargc, hostv, userv, formv, costv);
X/*
X** Exitstat was set if any resolve or deliver failed, otherwise 0.
X*/
X return( exitstat );
X}
@//E*O*F src/main.c//
if test 4213 -ne "`wc -c <'src/main.c'`"; then
echo shar: error transmitting "'src/main.c'" '(should have been 4213 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/make.cf.sh'" '(3038 characters)'
if test -f 'src/make.cf.sh' ; then
echo shar: will not over-write existing file "'src/make.cf.sh'"
else
sed 's/^X//' >src/make.cf.sh <<'@//E*O*F src/make.cf.sh//'
X#! /bin/sh
X#
X# @(#)make.cf.sh 2.1 (smail) 12/14/86
X#
Xcat <<!EOM!
XThis script will prompt you for the automatically configurable parameters
Xin the stock version of the sendmail configuration file. Naturally, any
Xlocal extensions will have to be added manually.
X
XClyde is a VAX running AT&T System V Release 2.0, with a port of sendmail.
XClyde is a gateway for the domain .att.com.
X
XBelow is a trace of the session that
Xconfigured the sendmail.cf on clyde.ATT.COM:
X===
X
X!EOM!
X
Xecho "press return to continue"; read foo
X
Xcat <<!EOM!
XEnter Date (MM-DD-YY):
X06-24-86
XEnter This Host's Name:
Xclyde
XEnter This Host's Official Domain:
XATT.COM
XEnter Any Equivalent Domain Classes:
XATT
XEnter Any Domains For Which This Host Is An Authority:
XATT.UUCP
XDoes This Host Have SMTP Connections (y/n)?
Xno
XEnter Full Path to Executable That Will Provide Local Mail Delivery:
X/bin/lmail
XIs /bin/lmail A Berkeley Mailer [i.e., use -r to specify sender] (y/n)?
Xno
XWill This Host Act As A Gateway Between Domains (y/n)?
Xyes
XAre subdomains beneath this hosts' domain to be hidden (y/n)?
Xyes
X===
X!EOM!
X# get date of configuration
XCF_DATE=`/bin/sh ./smail.prompt string "Enter Date (MM-DD-YY):"`
X
X# get host name
XCF_HOST=`/bin/sh ./smail.prompt string "Enter This Host's Name:"`
X
X# get host domain
XCF_DOMAIN=`/bin/sh ./smail.prompt string "Enter This Host's Official Domain:"`
X
X# get domain classes
XCF_DCLASS=`/bin/sh ./smail.prompt string "Enter Any Equivalent Domain Classes:"`
X
X# get domain authority
XCF_AUTHORITY=`/bin/sh ./smail.prompt string "Enter Any Domains For Which This Host Is An Authority:"`
X
XCF_SMTP=`/bin/sh ./smail.prompt yesno "Does This Host Have SMTP Connections (y/n)?"`
Xif test "$CF_SMTP" = "yes"
Xthen
X
X#get list of local SMTP connections
X CF_SMTP=`/bin/sh ./smail.prompt file "Enter Full Path to File that Contains List of SMTP Connections:"`
X
X CF_SMTP="FE$CF_SMTP %s"
Xelse
X CF_SMTP=""
Xfi
X
X# get path to local delivery agent
XCF_LOCALMAIL=`/bin/sh ./smail.prompt file "Enter Full Path to Executable That Will Provide Local Mail Delivery:"`
X
XCF_SYSTEM=`/bin/sh ./smail.prompt yesno "Is $CF_LOCALMAIL A Berkeley Mailer [i.e., use -r to specify sender] (y/n)?"`
Xif test "$CF_SYSTEM" = "yes"
Xthen
X CF_SVMAIL="#"
X CF_BSMAIL=""
Xelse
X CF_SVMAIL=""
X CF_BSMAIL="#"
Xfi
X
XCF_GATEWAY=`/bin/sh ./smail.prompt yesno "Will This Host Act As A Gateway Between Domains(y/n)?"`
Xif test "$CF_GATEWAY" = "yes"
Xthen
X CF_GATEWAY=""
Xelse
X CF_GATEWAY="#"
Xfi
X
XCF_HIDDENHOSTS=`/bin/sh ./smail.prompt yesno "Are subdomains beneath this hosts' domain to be hidden (y/n)?"`
Xif test "$CF_HIDDENHOSTS" = "yes"
Xthen
X CF_HIDDENHOSTS=""
Xelse
X CF_HIDDENHOSTS="#"
Xfi
X
Xsed \
X -e "s/CF_HOST/Dw$CF_HOST/" \
X -e "s/CF_DOMAIN/DD$CF_DOMAIN/" \
X -e "s/CF_AUTHORITY/DA$CF_AUTHORITY/" \
X -e "s/CF_DCLASS/CDUUCP $CF_DCLASS/" \
X -e "s;CF_SMTP;$CF_SMTP;" \
X -e "s;CF_DATE;$CF_DATE;" \
X -e "s;CF_LOCALMAIL;$CF_LOCALMAIL;" \
X -e "s;CF_BSMAIL;$CF_BSMAIL;" \
X -e "s;CF_SVMAIL;$CF_SVMAIL;" \
X -e "s;CF_GATEWAY;$CF_GATEWAY;" \
X -e "s;CF_HIDDENHOSTS;$CF_HIDDENHOSTS;" \
X template.cf > sendmail.cf
@//E*O*F src/make.cf.sh//
if test 3038 -ne "`wc -c <'src/make.cf.sh'`"; then
echo shar: error transmitting "'src/make.cf.sh'" '(should have been 3038 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/map.c'" '(1425 characters)'
if test -f 'src/map.c' ; then
echo shar: will not over-write existing file "'src/map.c'"
else
sed 's/^X//' >src/map.c <<'@//E*O*F src/map.c//'
X#ifndef lint
Xstatic char *sccsid="@(#)map.c 2.2 (smail) 1/26/87";
X#endif
X
X# include <stdio.h>
X# include <sys/types.h>
X# include "defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
Xextern int queuecost;
X
X/*
X**
X** map(): map addresses into <host, user, form, cost> sets.
X**
X** Calls resolve() for each address of argv. The result is hostv and
X** userv arrays (pointing into buffers userz and hostz), and formv array.
X**
X*/
X
Xmap(argc, argv, hostv, userv, formv, costv)
Xint argc; /* address count */
Xchar **argv; /* address vector */
Xchar *hostv[]; /* remote host vector */
Xchar *userv[]; /* user name vector */
Xenum eform formv[]; /* address format vector */
Xint costv[]; /* cost vector */
X{
X int i, cost;
X enum eform resolve();
X char *c;
X static char userbuf[BIGBUF], *userz;
X static char hostbuf[BIGBUF], *hostz;
X
X userz = userbuf;
X hostz = hostbuf;
X
X for( i=0; i<argc; i++ ) {
X#ifdef DEFQUEUE
X cost = queuecost+1; /* default is queueing */
X#else
X cost = queuecost-1; /* default is no queueing */
X#endif
X userv[i] = userz; /* put results here */
X hostv[i] = hostz;
X if ( **argv == '(' ) { /* strip () */
X ++*argv;
X c = index( *argv, ')' );
X if (c)
X *c = '\0';
X }
X /* here it comes! */
X formv[i] = resolve(*argv++, hostz, userz, &cost);
X costv[i] = cost;
X userz += strlen( userz ) + 1; /* skip past \0 */
X hostz += strlen( hostz ) + 1;
X }
X}
@//E*O*F src/map.c//
if test 1425 -ne "`wc -c <'src/map.c'`"; then
echo shar: error transmitting "'src/map.c'" '(should have been 1425 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/misc.c'" '(7381 characters)'
if test -f 'src/misc.c' ; then
echo shar: will not over-write existing file "'src/misc.c'"
else
sed 's/^X//' >src/misc.c <<'@//E*O*F src/misc.c//'
X
X/*
X** Miscellaneous support functions for smail/rmail
X*/
X
X#ifndef lint
Xstatic char *sccsid="@(#)misc.c 2.3 (smail) 1/26/87";
X#endif
X
X# include <stdio.h>
X# include <sys/types.h>
X# include <ctype.h>
X# include "defs.h"
X#ifdef BSD
X# include <sys/time.h>
X# include <sys/timeb.h>
X# include <strings.h>
X#else
X# include <time.h>
X# include <sys/utsname.h>
X# include <string.h>
X#endif
X
Xextern int exitstat; /* set if a forked mailer fails */
Xextern enum edebug debug; /* how verbose we are */
Xextern enum ehandle handle; /* what we handle */
Xextern char *uuxargs; /* arguments given to uux */
Xextern int queuecost; /* threshold for queueing mail */
Xextern int maxnoqueue; /* max number of uucico's */
Xextern enum erouting routing; /* when to route addresses */
Xextern char hostdomain[]; /* */
Xextern char hostname[]; /* */
Xextern char *pathfile; /* location of path database */
Xextern char *spoolfile; /* file name of spooled message */
Xextern FILE *spoolfp; /* file ptr to spooled message */
Xextern int spoolmaster; /* set if creator of spoolfile */
X
Xstruct tm *gmt, *loc; /* GMT and local time structure */
Xtime_t now; /* current system time */
Xchar nows[50]; /* time in ctime format */
Xchar arpanows[50]; /* time in arpa format */
X
X# ifdef LOG
Xvoid
Xlog(command, from, size)
Xchar *command, *from;
Xlong size;
X{
X FILE *fd;
X char *logtime, tbuf[50];
X int cmask;
X
X logtime = strcpy(tbuf, nows);
X logtime[16] = '\0';
X logtime += 4;
X
X cmask = umask(0);
X fd = fopen(LOG, "a");
X (void) umask(cmask);
X
X if (fd != NULL) {
X (void) fprintf(fd, "%s\t%ld\t%s\t%s\n",
X logtime, size, from, command);
X (void) fclose(fd);
X }
X}
X# endif
X
X# ifdef RECORD
XFILE *
Xrecord(command, from, size)
Xchar *command, *from;
Xlong size;
X{
X FILE *fd;
X char *logtime, buf[SMLBUF];
X int cmask;
X
X logtime = strcpy(buf, nows);
X logtime[16] = 0;
X logtime += 4;
X
X cmask = umask(0);
X fd = fopen(RECORD, "a");
X (void) umask(cmask);
X
X if (fd != NULL) {
X (void) fprintf(fd, "%s: %s, from %s, %ld bytes\n",
X logtime, command, from, size);
X }
X while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
X (void) fputs(buf, fd);
X }
X (void) fclose(fd);
X}
X# endif
X
X
Xsetdates()
X{
X time_t time();
X struct tm *gmtime();
X char *ctime(), *arpadate();
X
X (void) time(&now);
X (void) strcpy(nows, ctime(&now));
X gmt = gmtime(&now);
X loc = localtime(&now);
X (void) strcpy(arpanows, arpadate(nows));
X}
X
X/*
X** Note: This routine was taken from sendmail
X**
X** ARPADATE -- Create date in ARPANET format
X**
X** Parameters:
X** ud -- unix style date string. if NULL, one is created.
X**
X** Returns:
X** pointer to an ARPANET date field
X**
X** Side Effects:
X** none
X**
X** WARNING:
X** date is stored in a local buffer -- subsequent
X** calls will overwrite.
X**
X** Bugs:
X** Timezone is computed from local time, rather than
X** from whereever (and whenever) the message was sent.
X** To do better is very hard.
X**
X** Some sites are now inserting the timezone into the
X** local date. This routine should figure out what
X** the format is and work appropriately.
X*/
X
Xchar *
Xarpadate(ud)
X register char *ud;
X{
X register char *p;
X register char *q;
X static char b[40];
X extern char *ctime();
X register int i;
X extern struct tm *localtime();
X#ifndef BSD
X extern char *tzname[];
X time_t t, time();
X#else
X /* V7 and 4BSD */
X struct timeb t;
X extern struct timeb *ftime();
X extern char *timezone();
X#endif
X
X /*
X ** Get current time.
X ** This will be used if a null argument is passed and
X ** to resolve the timezone.
X */
X
X#ifndef BSD
X (void) time(&t);
X if (ud == NULL)
X ud = ctime(&t);
X#else
X /* V7 or 4BSD */
X ftime(&t);
X if (ud == NULL)
X ud = ctime(&t.time);
X#endif
X
X /*
X ** Crack the UNIX date line in a singularly unoriginal way.
X */
X
X q = b;
X
X p = &ud[8]; /* 16 */
X if (*p == ' ')
X p++;
X else
X *q++ = *p++;
X *q++ = *p++;
X *q++ = ' ';
X
X p = &ud[4]; /* Sep */
X *q++ = *p++;
X *q++ = *p++;
X *q++ = *p++;
X *q++ = ' ';
X
X p = &ud[22]; /* 1979 */
X *q++ = *p++;
X *q++ = *p++;
X *q++ = ' ';
X
X p = &ud[11]; /* 01:03:52 */
X for (i = 8; i > 0; i--)
X *q++ = *p++;
X
X /* -PST or -PDT */
X#ifndef BSD
X p = tzname[localtime(&t)->tm_isdst];
X#else
X p = timezone(t.timezone, localtime(&t.time)->tm_isdst);
X#endif
X if (p[3] != '\0')
X {
X /* hours from GMT */
X p += 3;
X *q++ = *p++;
X if (p[1] == ':')
X *q++ = '0';
X else
X *q++ = *p++;
X *q++ = *p++;
X p++; /* skip ``:'' */
X *q++ = *p++;
X *q++ = *p++;
X }
X else
X {
X *q++ = ' ';
X *q++ = *p++;
X *q++ = *p++;
X *q++ = *p++;
X }
X
X p = &ud[0]; /* Mon */
X *q++ = ' ';
X *q++ = '(';
X *q++ = *p++;
X *q++ = *p++;
X *q++ = *p++;
X *q++ = ')';
X
X *q = '\0';
X return (b);
X}
X
X/*
X * The user name "postmaster" must be accepted regardless of what
X * combination of upper and lower case is used. This function is
X * used to convert all case variants of "postmaster" to all lower
X * case. If the user name passed in is not "postmaster", it is
X * returned unchanged.
X */
Xchar *
Xpostmaster(user)
Xchar *user;
X{
X static char *pm = "postmaster";
X
X if(strcmpic(user, pm) == 0) {
X return(pm);
X } else {
X return(user);
X }
X}
X
X/*
X** strncmpic: string compare, ignore case, stop after 'n' chars
X*/
X
Xstrncmpic(s1, s2, n)
Xchar *s1, *s2;
Xint n;
X{
X register char *u = s1;
X register char *p = s2;
X
X while((n > 0) && (*p != '\0')) {
X /* chars match or only case different */
X if(lower(*u) == lower(*p)) {
X p++; /* examine next char */
X u++;
X } else {
X break; /* no match - stop comparison */
X }
X n--;
X }
X if(n > 0) {
X return(lower(*u) - lower(*p)); /* return "difference" */
X } else {
X return(0);
X }
X}
X
X/*
X** strcmpic: string compare, ignore case
X*/
X
Xstrcmpic(s1, s2)
Xchar *s1, *s2;
X{
X register char *u = s1;
X register char *p = s2;
X
X while(*p != '\0') {
X /* chars match or only case different */
X if(lower(*u) == lower(*p)) {
X p++; /* examine next char */
X u++;
X } else {
X break; /* no match - stop comparison */
X }
X }
X
X return(lower(*u) - lower(*p)); /* return "difference" */
X}
X
X/*
X * Return 1 iff the string is "UUCP" (ignore case).
X */
Xisuucp(str)
Xchar *str;
X{
X if(strcmpic(str, "UUCP") == 0) {
X return(1);
X } else {
X return(0);
X }
X}
X
X/*
X** sform(form) returns a pointer to a string that tells what 'form' means
X*/
X
Xchar *
Xsform(form)
Xenum eform form;
X{
X if(form == ERROR) return("ERROR");
X if(form == LOCAL) return("LOCAL");
X if(form == DOMAIN) return("DOMAIN");
X if(form == UUCP) return("UUCP");
X if(form == ROUTE) return("ROUTE");
X return("UNKNOWN");
X}
X
X/*
X**
X** getmynames(): what is my host name and host domain?
X**
X** Hostname set by -h, failing that by #define HOSTNAME, failing
X** that by gethostname() or uname().
X**
X** Hostdomain set by -h, failing that by #define HOSTDOMAIN,
X** failing that as hostname.MYDOM, or as just hostname.
X**
X** See defs.h for the inside story.
X**
X*/
X
Xgetmynames()
X{
X#ifdef HOSTNAME
X if (!*hostname)
X (void) strcpy(hostname, HOSTNAME);
X#endif
X#ifdef GETHOSTNAME
X if (!*hostname)
X gethostname(hostname, SMLBUF - 1);
X#endif
X#ifdef UNAME
X if (!*hostname) {
X struct utsname site;
X
X if (uname(&site) < 0)
X error(EX_SOFTWARE, "uname() call failed", 0);
X (void) strcpy(hostname, site.nodename);
X }
X#endif
X if (!*hostname)
X error(EX_SOFTWARE, "can't determine hostname.\n", 0);
X#ifdef HOSTDOMAIN
X if (!*hostdomain)
X (void) strcpy(hostdomain, HOSTDOMAIN);
X#endif
X#ifdef MYDOM
X if (!*hostdomain)
X (void) strcat(strcpy(hostdomain, hostname), MYDOM);
X#endif
X if (!*hostdomain)
X (void) strcpy(hostdomain, hostname);
X
X}
@//E*O*F src/misc.c//
if test 7381 -ne "`wc -c <'src/misc.c'`"; then
echo shar: error transmitting "'src/misc.c'" '(should have been 7381 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/resolve.c'" '(7236 characters)'
if test -f 'src/resolve.c' ; then
echo shar: will not over-write existing file "'src/resolve.c'"
else
sed 's/^X//' >src/resolve.c <<'@//E*O*F src/resolve.c//'
X/*
X**
X** Resolve.c
X**
X** Routes then resolves addresses into UUCP or LOCAL.
X**
X*/
X#ifndef lint
Xstatic char *sccsid="@(#)resolve.c 2.2 (smail) 1/26/87";
X#endif
X
X#include <ctype.h>
X#include <stdio.h>
X#include "defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
Xextern int exitstat; /* set if address doesn't resolve */
Xextern enum ehandle handle; /* what mail we can handle */
Xextern enum edebug debug; /* verbose and debug modes */
Xextern enum erouting routing; /* when to route addresses */
Xextern char hostdomain[]; /* */
Xextern char hostname[]; /* */
Xextern char *pathfile; /* location of path database */
X
Xchar *sform();
X
X/*
X**
X** rsvp(): how to resolve addresses.
X**
X** After parsing an address into <form>, the resolved form will be
X** rsvp( form ). If == ROUTE, we route the parsed address and parse again.
X**
X*/
X
X# define rsvp(a) table[(int)a][(int)handle]
X
Xenum eform table[5][3] = {
X/* all justuucp none */
X{ ERROR, ERROR, ERROR }, /* error */
X{ LOCAL, LOCAL, LOCAL }, /* local */
X{ ROUTE, LOCAL, LOCAL }, /* domain */
X{ UUCP, UUCP, LOCAL }, /* uucp */
X{ ERROR, ERROR, ERROR }}; /* route */
X
X/*
X**
X** resolve(): resolve addresses to <host, user, form>.
X**
X** This is a gnarly piece of code, but it does it all. Each section
X** is documented.
X**
X*/
X
Xenum eform
Xresolve( address, domain, user , cost)
Xchar *address; /* the input address */
Xchar *domain; /* the returned domain */
Xchar *user; /* the returned user */
Xint *cost; /* the returned cost */
X{
X enum eform form; /* the returned form */
X enum eform parse(); /* to crack addresses */
X int parts; /* to ssplit addresses */
X char *partv[MAXPATH]; /* " " " */
X char temp[SMLBUF]; /* " " " */
X int i;
X
X
X/*
X** If we set REROUTE and are prepared to deliver UUCP mail, we split the
X** address apart at !'s and try to resolve successively larger righthand
X** substrings until we succeed. Otherwise, we just resolve the whole thing
X** once.
X*/
X if ((routing == REROUTE) && (rsvp( UUCP ) == UUCP)) {
X parts = ssplit( address, '!', partv );
X } else {
X parts = 1;
X partv[0] = address;
X }
X/*
X** This for(i) loop selects successively larger
X** righthand substrings of the address.
X*/
X for( i = parts - 1; i >= 0; i-- ) {
X/*
X** Parse the address.
X*/
X (void) strcpy( temp, partv[i] );
X form = parse( temp, domain, user );
X
XDEBUG("resolve: parse address '%s' = '%s' @ '%s' (%s)\n",
X temp,user,domain,sform(form));
X
X/*
X** If we are looking at a substring (that's not the entire string)
X** which parses to a LOCAL address, we skip to the next larger substring.
X*/
X if((i != 0) && (form == LOCAL))
X continue;
X/*
X** Routing, when required, is the next step.
X** We route the address if we have a ROUTE form
X** or if we have a UUCP form and we are told to
X** route ALWAYS or REROUTE (i.e., routing != JUSTDOMAIN)
X*/
X if((rsvp( form ) == ROUTE)
X ||((rsvp( form ) == UUCP) && (routing != JUSTDOMAIN ))) {
X
X int look_smart = 0;
X
X if((routing == REROUTE) && (i == 0)) {
X look_smart = 1; /* last chance */
X }
X
X /* route() puts the new route in 'temp' */
X if(route(domain,user,look_smart,temp,cost) != EX_OK) {
X continue; /* If routing fails, try
X /* next larger substring.
X /* */
X }
X/*
X** After routing, reparse the new route into domain and user.
X*/
X form = parse( temp, domain, user );
X
XDEBUG("resolve: parse route '%s' = '%s' @ '%s' (%s)\n",
X temp,user,domain,sform(form));
X
X }
X break; /* route is resolved */
X }
X/*
X** For LOCAL mail in non-local format, we rewrite the full address into
X** <user> and leave <domain> blank.
X*/
X if ((rsvp( form ) == LOCAL) && (form != LOCAL )) {
X build( domain, user, form, temp );
X (void) strcpy( user, temp );
X (void) strcpy( domain, "" );
X form = LOCAL;
X }
X/*
X** If we were supposed to route an address but failed (form == ERROR),
X** or after routing we are left with an address that still needs to
X** be routed (rsvp( form ) == ROUTE), complain.
X*/
X if ((form == ERROR) || (rsvp( form ) == ROUTE )) {
X exitstat = EX_NOHOST;
X ADVISE("resolve failed '%s' = '%s' @ '%s' (%s)\n",
X address, user, domain, sform(form));
X form = ERROR;
X } else {
X ADVISE("resolve '%s' = '%s' @ '%s' (%s)\n",
X address, user, domain, sform(form));
X }
X return ( form );
X}
X
X/*
X**
X** route(): route domain, plug in user.
X**
X** Less complicated than it looks. Each section is documented.
X**
X*/
X
Xroute(domain, user, look_smart, result, cost)
Xchar *domain; /* domain or host name */
Xchar *user; /* user name */
Xint look_smart; /* do we try to route through a smarter host? */
Xchar *result; /* output route */
Xint *cost; /* cost of output route */
X{
X int uucpdom = 0;
X int domains, step; /* to split domain */
X char *domainv[MAXDOMS]; /* " " " */
X char temp[SMLBUF], path[SMLBUF];
X
X/*
X** Fully qualify the domain, and then strip the last (top level domain)
X** component off, so that we look it up separately.
X*/
X temp[0] = '.';
X (void) strcpy(temp+1, domain );
X
X domains = ssplit( temp+1, '.', domainv );
X
X/*
X** check target domain for the local host name and host domain.
X** if it matches, then the path skip the lookup in the database.
X** this prevents mail loops for cases where SMARTHOST is defined
X** in the routing table, but the local host is not. It also is
X** a little faster when the local host is the target domain.
X*/
X if((strcmpic(domain, hostname) == 0)
X || (strcmpic(domain, hostdomain) == 0)) {
X step = 0;
X *cost = 0;
X (void) strcpy(path, "%s");
XDEBUG("route: '%s' is local\n", domain);
X goto route_complete;
X }
X
X /* If the domain ends in .UUCP, trim that off. */
X if((domains > 0) && isuucp(domainv[domains-1])) {
X domains--;
X domainv[domains][-1] = '\0';
X uucpdom = 1;
X }
X/*
X** Try to get the path for successive components of the domain.
X** Example for osgd.cb.att.uucp:
X** osgd.cb.att
X** cb.att
X** att
X** uucp ( remember stripping top level? )
X** SMARTHOST
X** Returns with error if we find no path.
X*/
X for(step = 0; (step < domains); step++) {
X if((getpath(domainv[step]-1, path, cost) == EX_OK) /* w/ dot */
X || (getpath(domainv[step] , path, cost) == EX_OK))/* no dot */
X break;
X }
X
X if(step == domains) {
X /*
X ** we've looked at each component of the domain without success
X */
X /*
X ** If domain is a UUCP address, look for a UUCP gateway.
X */
X if((uucpdom == 0) || (getpath(".UUCP", path, cost) != EX_OK)) {
X /*
X ** The domain not is a UUCP address, or we can't
X ** find a UUCP gateway. If this is our last chance,
X ** look for a smarter host to deliver the mail.
X */
X if((look_smart == 0)
X || (getpath(SMARTHOST, path, cost) != EX_OK)) {
X /*
X ** All our efforts have been in vain.
X ** Tell them the bad news.
X */
X DEBUG("route '%s' failed\n", domain);
X return( EX_NOHOST );
X }
X }
X }
X
Xroute_complete:
X
XDEBUG("route: '%s' (%s) = '%s' (%d)\n", domain, domainv[step], path, *cost);
X
X/*
X** If we matched on the entire domain name, this address is fully resolved,
X** and we plug <user> into it. If we matched on only part of the domain
X** name, we plug <domain>!<user> in.
X*/
X build(domain, user, (step == 0) ? LOCAL : UUCP, temp);
X (void) sprintf(result, path, temp);
X return( EX_OK );
X}
@//E*O*F src/resolve.c//
if test 7236 -ne "`wc -c <'src/resolve.c'`"; then
echo shar: error transmitting "'src/resolve.c'" '(should have been 7236 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/smail.prompt'" '(762 characters)'
if test -f 'src/smail.prompt' ; then
echo shar: will not over-write existing file "'src/smail.prompt'"
else
sed 's/^X//' >src/smail.prompt <<'@//E*O*F src/smail.prompt//'
X#
X# @(#)smail.prompt 2.1 (smail) 12/14/86
X#
X
Xloop=true
Xwhile test $loop = true
Xdo
X case "$1" in
X string)
X echo "$2" 1>&2
X read ans
X if test ! -z "$ans"
X then
X echo $ans
X loop=false;
X fi
X ;;
X file)
X echo "$2" 1>&2
X read ans
X case "$ans" in
X /*)
X if test -f "$ans"
X then
X echo $ans
X loop=false;
X else
X echo "file '$ans' not found" 1>&2
X fi
X ;;
X *)
X echo "must give FULL PATH to file" 1>&2
X ;;
X esac
X ;;
X yesno)
X echo "$2" 1>&2
X read ans
X case "$ans" in
X y|Y|yes|Yes|YES)
X echo "yes"
X loop=false
X ;;
X n|N|no|No|NO)
X echo "no"
X loop=false
X ;;
X *)
X echo "Please enter yes or no" 1>&2
X ;;
X esac
X ;;
X *)
X
X echo "usage: $0 string|yesno prompt_message" 1>&2
X echo BOGUS_PROMPT_STRING
X loop=false
X ;;
X esac
Xdone
@//E*O*F src/smail.prompt//
if test 762 -ne "`wc -c <'src/smail.prompt'`"; then
echo shar: error transmitting "'src/smail.prompt'" '(should have been 762 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/svbinmail.c'" '(1749 characters)'
if test -f 'src/svbinmail.c' ; then
echo shar: will not over-write existing file "'src/svbinmail.c'"
else
sed 's/^X//' >src/svbinmail.c <<'@//E*O*F src/svbinmail.c//'
X#ifndef lint
Xstatic char *sccsid = "@(#)svbinmail.c 2.2 (smail) 1/26/87";
X#endif
X/* */
X/* This program will be used in place of /bin/mail on SVR2 sites.
X/* It looks at the arguments and decides whether to call
X/* SENDER for sending mail, or READER for reading mail.
X/*
X/* before installing as /bin/mail, move the stock /bin/mail to /bin/lmail
X/*
X/* */
X
X#include <stdio.h>
X#include "defs.h"
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
X#ifdef SENDMAIL
X#define SENDER SENDMAIL
X#else
X#define SENDER "/bin/rmail"
X#endif
X
X#define READER "/bin/lmail"
X
X#define TRUE 1
X#define FALSE 0
X
Xchar prog[128];
X
Xvoid perror(), exit(), usage();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X extern int optind;
X extern char *optarg;
X
X int i, j, c;
X int reading, sending;
X
X reading = sending = FALSE;
X
X (void) strcpy(prog, argv[0]);
X
X if(argc == 1) {
X reading = TRUE;
X } else {
X while((c = getopt(argc, argv, "epqrtf:")) != EOF) {
X switch(c) {
X case 'e':
X case 'p':
X case 'q':
X case 'r':
X case 'f':
X reading = TRUE;
X break;
X case 't':
X sending = TRUE;
X break;
X default:
X usage();
X return(1);
X }
X }
X }
X
X /* any arguments left over -> sending */
X if(argc > optind) {
X sending = TRUE;
X }
X
X if((reading == TRUE) && (sending == TRUE)) {
X usage();
X return(1);
X }
X
X if(sending == TRUE) {
X argv[0] = SENDER;
X for(i = 1, j = optind; j < argc; i++, j++) {
X argv[i] = argv[j];
X }
X argv[i] = NULL;
X } else {
X argv[0] = READER;
X }
X
X (void) execvp(argv[0], argv);
X (void) fprintf(stderr, "%s: execvp(\"%s\", argv) failed: ",
X prog, argv[0]);
X perror("");
X return(1);
X}
X
Xvoid
Xusage()
X{
X (void) fprintf(stderr, "usage:\t%s [ -epqr ] [ -f file ]\n", prog);
X (void) fprintf(stderr, "\t%s [ -t ] persons\n", prog);
X}
@//E*O*F src/svbinmail.c//
if test 1749 -ne "`wc -c <'src/svbinmail.c'`"; then
echo shar: error transmitting "'src/svbinmail.c'" '(should have been 1749 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/sysexits.h'" '(483 characters)'
if test -f 'src/sysexits.h' ; then
echo shar: will not over-write existing file "'src/sysexits.h'"
else
sed 's/^X//' >src/sysexits.h <<'@//E*O*F src/sysexits.h//'
X/*
X** @(#)sysexits.h 2.1 (smail) 12/14/86
X*/
X
X# define EX_OK 0 /* successful termination */
X# define EX_USAGE 64 /* command line usage error */
X# define EX_NOHOST 68 /* host name unknown */
X# define EX_UNAVAILABLE 69 /* service unavailable */
X# define EX_SOFTWARE 70 /* internal software error */
X# define EX_OSFILE 72 /* critical OS file missing */
X# define EX_CANTCREAT 73 /* can't create (user) output file */
X# define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
@//E*O*F src/sysexits.h//
if test 483 -ne "`wc -c <'src/sysexits.h'`"; then
echo shar: error transmitting "'src/sysexits.h'" '(should have been 483 characters)'
fi
fi # end of overwriting check
echo shar: "End of shell archive."
exit 0
More information about the Mod.sources
mailing list