# include # include # include "dlvrmail.h" static char SccsId[] = "@(#)savemail.c 2.2 1/10/81"; /* ** SAVEMAIL -- Save mail on error ** ** If the MailBack flag is set, mail it back to the originator ** together with an error message; otherwise, just put it in ** dead.letter in the user's home directory (if he exists on ** this machine). ** ** Parameters: ** none ** ** Returns: ** none ** ** Side Effects: ** Saves the letter, by writing or mailing it back to the ** sender, or by putting it in dead.letter in her home ** directory. ** ** WARNING: the user id is reset to the original user. */ savemail() { register struct passwd *pw; register FILE *xfile; char buf[MAXLINE+1]; extern errhdr(); auto addrq to_addr; extern struct passwd *getpwnam(); register char *p; register int i; auto long tim; extern int errno; extern char *ttypath(); extern char *ctime(); extern addrq *parse(); static int exclusive; extern char *DaemonName; if (exclusive++) return; /* ** In the unhappy event we don't know who to return the mail ** to, make someone up. */ if (From.q_paddr == NULL) { if (parse("root", &From, 0) == NULL) { syserr("Cannot parse root!"); ExitStat = EX_SOFTWARE; finis(); } } /* ** If called from Eric Schmidt's network, do special mailback. ** Fundamentally, this is the mailback case except that ** it returns an OK exit status (assuming the return ** worked). */ if (BerkNet) { ExitStat = EX_OK; MailBack++; } /* ** If writing back, do it. ** If the user is still logged in on the same terminal, ** then write the error messages back to hir (sic). ** If not, set the MailBack flag so that it will get ** mailed back instead. */ if (WriteBack) { p = ttypath(); if (p == NULL || freopen(p, "w", stdout) == NULL) { MailBack++; errno = 0; } else { xfile = fopen(Transcript, "r"); if (xfile == NULL) syserr("Cannot open %s", Transcript); printf("\r\nMessage from %s\r\n", DaemonName); printf("Errors occurred while sending mail, transcript follows:\r\n"); while (fgets(buf, sizeof buf, xfile) && !ferror(stdout)) fputs(buf, stdout); if (ferror(stdout)) syserr("savemail: stdout: write err"); fclose(xfile); } } /* ** If mailing back, do it. ** Throw away all further output. Don't do aliases, since ** this could cause loops, e.g., if joe mails to x:joe, ** and for some reason the network for x: is down, then ** the response gets sent to x:joe, which gives a ** response, etc. Also force the mail to be delivered ** even if a version of it has already been sent to the ** sender. */ if (MailBack || From.q_mailer != &Mailer[0]) { freopen("/dev/null", "w", stdout); NoAlias++; ForceMail++; /* fake up an address header for the from person */ bmove((char *) &From, (char *) &to_addr, sizeof to_addr); if (parse(DaemonName, &From, -1) == NULL) { syserr("Can't parse myself!"); ExitStat = EX_SOFTWARE; finis(); } i = deliver(&to_addr, errhdr); bmove((char *) &to_addr, (char *) &From, sizeof From); if (i != 0) syserr("Can't return mail to %s", p); else return; } /* ** Save the message in dead.letter. ** If we weren't mailing back, and the user is local, we ** should save the message in dead.letter so that the ** poor person doesn't have to type it over again -- ** and we all know what poor typists programmers are. */ setuid(getuid()); setgid(getgid()); setpwent(); if (From.q_mailer == &Mailer[0] && (pw = getpwnam(From.q_user)) != NULL) { /* user has a home directory */ p = pw->pw_dir; } else { syserr("Can't return mail to %s (pw=%u)", From.q_paddr, pw); # ifdef DEBUG p = "/usr/tmp"; # else p = NULL; # endif } if (p != NULL) { /* we have a home directory; open dead.letter */ strcpy(buf, p); strcat(buf, "/dead.letter"); xfile = fopen(buf, "a"); if (xfile == NULL) printf("Cannot save mail, sorry\n"); else { rewind(stdin); errno = 0; time(&tim); fprintf(xfile, "----- Mail saved at %s", ctime(&tim)); while (fgets(buf, sizeof buf, stdin) && !ferror(xfile)) fputs(buf, xfile); fputs("\n", xfile); if (ferror(xfile)) syserr("savemail: dead.letter: write err"); fclose(xfile); printf("Letter saved in dead.letter\n"); } } else /* add terminator to writeback message */ if (WriteBack) printf("-----\r\n"); } /* ** ERRHDR -- Output the header for error mail. ** ** This is the edit filter to error mailbacks. ** ** Algorithm: ** Output fixed header. ** Output the transcript part. ** Output the original message. ** ** Parameters: ** xfile -- the transcript file. ** fp -- the output file. ** ** Returns: ** none ** ** Side Effects: ** input from xfile ** output to fp ** ** Called By: ** deliver */ errhdr(fp) register FILE *fp; { char copybuf[512]; register int i; register int xfile; extern int errno; if ((xfile = open(Transcript, 0)) < 0) syserr("Cannot open %s", Transcript); fflush(stdout); errno = 0; fprintf(fp, "To: %s\n", To); fprintf(fp, "Subject: Unable to deliver mail\n"); fprintf(fp, "\n ----- Transcript of session follows -----\n"); fflush(fp); while ((i = read(xfile, copybuf, sizeof copybuf)) > 0) write(fileno(fp), copybuf, i); fprintf(fp, "\n ----- Unsent message follows -----\n"); fflush(fp); rewind(stdin); while ((i = read(fileno(stdin), copybuf, sizeof copybuf)) > 0) write(fileno(fp), copybuf, i); close(xfile); if (errno != 0) syserr("errhdr: I/O error"); }