|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - downloadIndex: ┃ T d ┃
Length: 11313 (0x2c31) Types: TextFile Names: »deliver.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─ ⟦this⟧ »EUUGD11/euug-87hel/sec8/smail/src/deliver.c«
/* ** Deliver.c ** ** Routines to effect delivery of mail for rmail/smail. ** */ #ifndef lint static char *sccsid="@(#)deliver.c 2.3 (smail) 1/26/87"; #endif # include <stdio.h> # include <sys/types.h> # include <ctype.h> # include "defs.h" #ifdef BSD #include <strings.h> #else #include <string.h> #endif extern int exitstat; /* set if a forked mailer fails */ extern enum edebug debug; /* how verbose we are */ extern char hostname[]; /* our uucp hostname */ extern char hostdomain[]; /* our host's domain */ extern enum ehandle handle; /* what we handle */ extern enum erouting routing; /* how we're routing addresses */ extern char *uuxargs; /* arguments given to uux */ extern int queuecost; /* threshold for queueing mail */ extern int maxnoqueue; /* max number of uucico's */ extern char *spoolfile; /* file name of spooled message */ extern FILE *spoolfp; /* file ptr to spooled message */ extern int spoolmaster; /* set if creator of spoolfile */ extern char nows[]; /* local time in ctime(3) format*/ extern char arpanows[]; /* local time in arpadate format*/ char stderrfile[20]; /* error file for stderr traping*/ /* ** ** deliver(): hand the letter to the proper mail programs. ** ** Issues one command for each different host of <hostv>, ** constructing the proper command for LOCAL or UUCP mail. ** Note that LOCAL mail has blank host names. ** ** The <userv> names for each host are arguments to the command. ** ** Prepends a "From" line to the letter just before going ** out, with a "remote from <hostname>" if it is a UUCP letter. ** */ deliver(argc, hostv, userv, formv, costv) int argc; /* number of addresses */ char *hostv[]; /* host names */ char *userv[]; /* user names */ enum eform formv[]; /* form for each address */ int costv[]; /* cost vector */ { FILE *out; /* pipe to mailer */ FILE *popen(); /* to fork a mailer */ #ifdef RECORD void record(); /* record all transactions */ #endif #ifdef LOG void log(); #endif char *mktemp(); char from[SMLBUF]; /* accumulated from argument */ char lcommand[SMLBUF]; /* local command issued */ char rcommand[SMLBUF]; /* remote command issued */ char scommand[SMLBUF]; /* retry command issued */ char *command; /* actual command */ char buf[SMLBUF]; /* copying rest of the letter */ enum eform form; /* holds form[i] for speed */ long size; /* number of bytes of message */ char *flags; /* flags for uux */ char *sflag; /* flag for smail */ int i, j, stat, retrying; char *c, *postmaster(); int failcount = 0; int noqcnt = 0; /* number of uucico's started */ char *uux_noqueue = UUX_NOQUEUE;/* uucico starts immediately */ char *uux_queue = UUX_QUEUE; /* uucico job gets queued */ off_t message; /* ** rewind the spool file and read the collapsed From_ line */ (void) fseek(spoolfp, 0L, 0); (void) fgets(from, sizeof(from), spoolfp); if((c = index(from, '\n')) != 0) *c = '\0'; message = ftell(spoolfp); /* ** We pass through the list of addresses. */ stderrfile[0] = '\0'; for(i = 0; i < argc; i++) { char *lend = lcommand; char *rend = rcommand; char *send = scommand; /* ** If we don't have sendmail, arrange to trap standard error ** for inclusion in the message that is returned with failed mail. */ (void) unlink(stderrfile); (void) strcpy(stderrfile, "/tmp/stderrXXXXXX"); (void) mktemp(stderrfile); (void) freopen(stderrfile, "w", stderr); *lend = *rend = *send = '\0'; /* ** If form == ERROR, the address was bad ** If form == SENT, it has been sent on a previous pass. */ form = formv[i]; if (form == SENT) { continue; } /* ** Build the command based on whether this is local mail or uucp mail. ** By default, don't allow more than 'maxnoqueue' uucico commands to ** be started by a single invocation of 'smail'. */ if(uuxargs == NULL) { /* flags not set on command line */ if(noqcnt < maxnoqueue && costv[i] <= queuecost) { flags = uux_noqueue; } else { flags = uux_queue; } } else { flags = uuxargs; } retrying = 0; if(routing == JUSTDOMAIN) { sflag = "-r"; } else if(routing == ALWAYS) { sflag = "-R"; } else { sflag = ""; } (void) sprintf(lcommand, LMAIL(from, hostv[i])); (void) sprintf(rcommand, RMAIL(flags, from, hostv[i])); /* ** For each address with the same host name and form, append the user ** name to the command line, and set form = ERROR so we skip this address ** on later passes. */ /* we initialized lend (rend) to point at the * beginning of its buffer, so that at * least one address will be used regardless * of the length of lcommand (rcommand). */ for (j = i; j < argc; j++) { if ((formv[j] != form) || (strcmpic(hostv[i], hostv[j]) != 0) || ((lend - lcommand) > MAXCLEN) || ((rend - rcommand) > MAXCLEN)) { continue; } /* ** seek to the end of scommand ** and add on a 'smail' command ** multiple commands are separated by ';' */ send += strlen(send); if(send != scommand) { *send++ = ';' ; } (void) sprintf(send, RETRY(sflag)); send += strlen(send); lend += strlen(lend); rend += strlen(rend); if (form == LOCAL) { (void) sprintf(lend, LARG(userv[j])); (void) sprintf(send, LARG(userv[j])); } else { (void) sprintf(lend, RLARG(hostv[i], userv[j])); (void) sprintf(send, RLARG(hostv[i], userv[j])); } (void) sprintf(rend, RARG(userv[j])); formv[j] = SENT; } retry: /* ** rewind the spool file and read the collapsed From_ line */ (void) fseek(spoolfp, message, 0); /* if the address was in a bogus form (usually DOMAIN), ** then don't bother trying the uux. ** ** Rather, go straight to the next smail routing level. */ if(form == ERROR) { static char errbuf[SMLBUF]; (void) sprintf(errbuf, "address resolution ('%s' @ '%s') failed", userv[i], hostv[i]); command = errbuf; size = 0; goto form_error; } if (retrying) { command = scommand; } else if (form == LOCAL) { command = lcommand; } else { command = rcommand; if(flags == uux_noqueue) { noqcnt++; } } ADVISE("COMMAND: %s\n", command); /* ** Fork the mailer and set it up for writing so we can send the mail to it, ** or for debugging divert the output to stdout. */ if (debug == YES) { out = stdout; } else { failcount = 0; do { out = popen(command, "w"); if (out) break; /* * Fork failed. System probably overloaded. * Wait awhile and try again 10 times. * If it keeps failing, probably some * other problem, like no uux or smail. */ (void) sleep(60); } while (++failcount < 10); } if(out == NULL) { exitstat = EX_UNAVAILABLE; (void) printf("couldn't execute %s.\n", command); continue; } size = 0; /* ** Output our From_ line. */ if (form == LOCAL) { #ifdef SENDMAIL size += fprintf(out, LFROM(from, nows, hostname)); #else char *p; if((p=index(from, '!')) == NULL) { size += fprintf(out, LFROM(from, nows, hostname)); } else { *p = NULL; size += fprintf(out, RFROM(p+1, nows, from)); *p = '!'; } #endif } else { size += fprintf(out, RFROM(from, nows, hostname)); } #ifdef SENDMAIL /* ** If using sendmail, insert a Received: line only for mail ** that is being passed to uux. If not using sendmail, always ** insert the received line, since sendmail isn't there to do it. */ if(command == rcommand && handle != ALL) #endif { size += fprintf(out, "Received: by %s (%s)\n\tid AA%05d; %s\n", hostdomain, VERSION, getpid(), arpanows); } /* ** Copy input. */ while(fgets(buf, sizeof(buf), spoolfp) != NULL) { size += fputs(buf, out); } /* ** Get exit status and if non-zero, set global exitstat so when we exit ** we can indicate an error. */ form_error: if (debug != YES) { if(form == ERROR) { exitstat = EX_NOHOST; } else if (stat = pclose(out)) { exitstat = stat >> 8; } /* * The 'retrying' check prevents a smail loop. */ if(exitstat != 0) { /* ** the mail failed, probably because the host ** being uux'ed isn't in L.sys or local user ** is unknown. */ if((retrying == 0) /* first pass */ && (routing != REROUTE) /* have higher level */ && (form != LOCAL)) { /* can't route local */ /* ** Try again using a higher ** level of routing. */ ADVISE("%s failed (%d)\ntrying %s\n", command, exitstat, scommand); exitstat = 0; retrying = 1; form = SENT; goto retry; } /* ** if we have no other routing possibilities ** see that the mail is returned to sender. */ if((routing == REROUTE) || (form == LOCAL)) { /* ** if this was our last chance, ** return the mail to the sender. */ ADVISE("%s failed (%d)\n", command, exitstat); (void) fseek(spoolfp, message, 0); #ifdef SENDMAIL /* if we have sendmail, then it ** was handed the mail, which failed. ** sendmail returns the failed mail ** for us, so we need not do it again. */ if(form != LOCAL) #endif { return_mail(from, command); } exitstat = 0; } } # ifdef LOG else { if(retrying == 0) log(command, from, size); /* */ } # endif } } /* ** Update logs and records. */ # ifdef RECORD (void) fseek(spoolfp, message, 0); record(command, from, size); # endif /* ** close spool file pointer. ** if we created it, then unlink file. */ (void) fclose(spoolfp); if(spoolmaster) { (void) unlink(spoolfile); } (void) unlink(stderrfile); } /* ** return mail to sender, as determined by From_ line. */ return_mail(from, fcommand) char *from, *fcommand; { char buf[SMLBUF]; char domain[SMLBUF], user[SMLBUF]; char *r; FILE *fp, *out, *popen(); int i = 0; r = buf; (void) sprintf(r, "%s %s", SMAIL, VFLAG); r += strlen(r); if(islocal(from, domain, user)) { (void) sprintf(r, LARG(user)); } else { (void) sprintf(r, RLARG(domain, user)); } i = 0; do { out = popen(buf, "w"); if (out) break; /* * Fork failed. System probably overloaded. * Wait awhile and try again 10 times. * If it keeps failing, probably some * other problem, like no uux or smail. */ (void) sleep(60); } while (++i < 10); if(out == NULL) { (void) printf("couldn't execute %s.\n", buf); return; } (void) fprintf(out, "Date: %s\n", arpanows); (void) fprintf(out, "From: MAILER-DAEMON@%s\n", hostdomain); (void) fprintf(out, "Subject: failed mail\n"); (void) fprintf(out, "To: %s\n", from); (void) fprintf(out, "\n"); (void) fprintf(out, "======= command failed =======\n\n"); (void) fprintf(out, " COMMAND: %s\n\n", fcommand); (void) fprintf(out, "======= standard error follows =======\n"); (void) fflush(stderr); if((fp = fopen(stderrfile, "r")) != NULL) { while(fgets(buf, sizeof(buf), fp) != NULL) { (void) fputs(buf, out); } } (void) fclose(fp); (void) fprintf(out, "======= text of message follows =======\n"); /* ** Copy input. */ (void) fprintf(out, "From %s\n", from); while(fgets(buf, sizeof(buf), spoolfp) != NULL) { (void) fputs(buf, out); } (void) pclose(out); }