| 1 | # include <stdio.h> |
| 2 | # include <pwd.h> |
| 3 | # include "dlvrmail.h" |
| 4 | |
| 5 | static char SccsId[] = "@(#)savemail.c 2.1 %G%"; |
| 6 | |
| 7 | /* |
| 8 | ** SAVEMAIL -- Save mail on error |
| 9 | ** |
| 10 | ** If the MailBack flag is set, mail it back to the originator |
| 11 | ** together with an error message; otherwise, just put it in |
| 12 | ** dead.letter in the user's home directory (if he exists on |
| 13 | ** this machine). |
| 14 | ** |
| 15 | ** Parameters: |
| 16 | ** none |
| 17 | ** |
| 18 | ** Returns: |
| 19 | ** none |
| 20 | ** |
| 21 | ** Side Effects: |
| 22 | ** Saves the letter, by writing or mailing it back to the |
| 23 | ** sender, or by putting it in dead.letter in her home |
| 24 | ** directory. |
| 25 | ** |
| 26 | ** WARNING: the user id is reset to the original user. |
| 27 | */ |
| 28 | |
| 29 | # define MY_NAME "~MAILER~DAEMON~" |
| 30 | |
| 31 | savemail() |
| 32 | { |
| 33 | register struct passwd *pw; |
| 34 | register FILE *xfile; |
| 35 | char buf[MAXLINE+1]; |
| 36 | extern errhdr(); |
| 37 | auto addrq to_addr; |
| 38 | extern struct passwd *getpwnam(); |
| 39 | register char *p; |
| 40 | register int i; |
| 41 | auto long tim; |
| 42 | extern int errno; |
| 43 | extern char *ttypath(); |
| 44 | extern char *ctime(); |
| 45 | extern addrq *parse(); |
| 46 | static int exclusive; |
| 47 | |
| 48 | if (exclusive++) |
| 49 | return; |
| 50 | |
| 51 | /* |
| 52 | ** In the unhappy event we don't know who to return the mail |
| 53 | ** to, make someone up. |
| 54 | */ |
| 55 | |
| 56 | if (From.q_paddr == NULL) |
| 57 | { |
| 58 | if (parse("root", &From, 0) == NULL) |
| 59 | { |
| 60 | syserr("Cannot parse root!"); |
| 61 | ExitStat = EX_SOFTWARE; |
| 62 | finis(); |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | /* |
| 67 | ** If called from Eric Schmidt's network, do special mailback. |
| 68 | ** Fundamentally, this is the mailback case except that |
| 69 | ** it returns an OK exit status (assuming the return |
| 70 | ** worked). |
| 71 | */ |
| 72 | |
| 73 | if (BerkNet) |
| 74 | { |
| 75 | ExitStat = EX_OK; |
| 76 | MailBack++; |
| 77 | } |
| 78 | |
| 79 | /* |
| 80 | ** If writing back, do it. |
| 81 | ** If the user is still logged in on the same terminal, |
| 82 | ** then write the error messages back to hir (sic). |
| 83 | ** If not, set the MailBack flag so that it will get |
| 84 | ** mailed back instead. |
| 85 | */ |
| 86 | |
| 87 | if (WriteBack) |
| 88 | { |
| 89 | p = ttypath(); |
| 90 | if (p == NULL || freopen(p, "w", stdout) == NULL) |
| 91 | { |
| 92 | MailBack++; |
| 93 | errno = 0; |
| 94 | } |
| 95 | else |
| 96 | { |
| 97 | xfile = fopen(Transcript, "r"); |
| 98 | if (xfile == NULL) |
| 99 | syserr("Cannot open %s", Transcript); |
| 100 | printf("\r\nMessage from %s\r\n", MY_NAME); |
| 101 | printf("Errors occurred while sending mail, transcript follows:\r\n"); |
| 102 | while (fgets(buf, sizeof buf, xfile) && !ferror(stdout)) |
| 103 | fputs(buf, stdout); |
| 104 | if (ferror(stdout)) |
| 105 | syserr("savemail: stdout: write err"); |
| 106 | fclose(xfile); |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | /* |
| 111 | ** If mailing back, do it. |
| 112 | ** Throw away all further output. Don't do aliases, since |
| 113 | ** this could cause loops, e.g., if joe mails to x:joe, |
| 114 | ** and for some reason the network for x: is down, then |
| 115 | ** the response gets sent to x:joe, which gives a |
| 116 | ** response, etc. Also force the mail to be delivered |
| 117 | ** even if a version of it has already been sent to the |
| 118 | ** sender. |
| 119 | */ |
| 120 | |
| 121 | if (MailBack || From.q_mailer != &Mailer[0]) |
| 122 | { |
| 123 | freopen("/dev/null", "w", stdout); |
| 124 | NoAlias++; |
| 125 | ForceMail++; |
| 126 | |
| 127 | /* fake up an address header for the from person */ |
| 128 | bmove((char *) &From, (char *) &to_addr, sizeof to_addr); |
| 129 | if (parse(MY_NAME, &From, -1) == NULL) |
| 130 | { |
| 131 | syserr("Can't parse myself!"); |
| 132 | ExitStat = EX_SOFTWARE; |
| 133 | finis(); |
| 134 | } |
| 135 | i = deliver(&to_addr, errhdr); |
| 136 | bmove((char *) &to_addr, (char *) &From, sizeof From); |
| 137 | if (i != 0) |
| 138 | syserr("Can't return mail to %s", p); |
| 139 | else |
| 140 | return; |
| 141 | } |
| 142 | |
| 143 | /* |
| 144 | ** Save the message in dead.letter. |
| 145 | ** If we weren't mailing back, and the user is local, we |
| 146 | ** should save the message in dead.letter so that the |
| 147 | ** poor person doesn't have to type it over again -- |
| 148 | ** and we all know what poor typists programmers are. |
| 149 | */ |
| 150 | |
| 151 | setuid(getuid()); |
| 152 | setgid(getgid()); |
| 153 | setpwent(); |
| 154 | if (From.q_mailer == &Mailer[0] && (pw = getpwnam(From.q_user)) != NULL) |
| 155 | { |
| 156 | /* user has a home directory */ |
| 157 | p = pw->pw_dir; |
| 158 | } |
| 159 | else |
| 160 | { |
| 161 | syserr("Can't return mail to %s (pw=%u)", From.q_paddr, pw); |
| 162 | # ifdef DEBUG |
| 163 | p = "/usr/tmp"; |
| 164 | # else |
| 165 | p = NULL; |
| 166 | # endif |
| 167 | } |
| 168 | if (p != NULL) |
| 169 | { |
| 170 | /* we have a home directory; open dead.letter */ |
| 171 | strcpy(buf, p); |
| 172 | strcat(buf, "/dead.letter"); |
| 173 | xfile = fopen(buf, "a"); |
| 174 | if (xfile == NULL) |
| 175 | printf("Cannot save mail, sorry\n"); |
| 176 | else |
| 177 | { |
| 178 | rewind(stdin); |
| 179 | errno = 0; |
| 180 | time(&tim); |
| 181 | fprintf(xfile, "----- Mail saved at %s", ctime(&tim)); |
| 182 | while (fgets(buf, sizeof buf, stdin) && !ferror(xfile)) |
| 183 | fputs(buf, xfile); |
| 184 | fputs("\n", xfile); |
| 185 | if (ferror(xfile)) |
| 186 | syserr("savemail: dead.letter: write err"); |
| 187 | fclose(xfile); |
| 188 | printf("Letter saved in dead.letter\n"); |
| 189 | } |
| 190 | } |
| 191 | else |
| 192 | |
| 193 | /* add terminator to writeback message */ |
| 194 | if (WriteBack) |
| 195 | printf("-----\r\n"); |
| 196 | } |
| 197 | \f/* |
| 198 | ** ERRHDR -- Output the header for error mail. |
| 199 | ** |
| 200 | ** This is the edit filter to error mailbacks. |
| 201 | ** |
| 202 | ** Algorithm: |
| 203 | ** Output fixed header. |
| 204 | ** Output the transcript part. |
| 205 | ** Output the original message. |
| 206 | ** |
| 207 | ** Parameters: |
| 208 | ** xfile -- the transcript file. |
| 209 | ** fp -- the output file. |
| 210 | ** |
| 211 | ** Returns: |
| 212 | ** none |
| 213 | ** |
| 214 | ** Side Effects: |
| 215 | ** input from xfile |
| 216 | ** output to fp |
| 217 | ** |
| 218 | ** Called By: |
| 219 | ** deliver |
| 220 | */ |
| 221 | |
| 222 | |
| 223 | errhdr(fp) |
| 224 | register FILE *fp; |
| 225 | { |
| 226 | char copybuf[512]; |
| 227 | register int i; |
| 228 | register int xfile; |
| 229 | extern int errno; |
| 230 | |
| 231 | if ((xfile = open(Transcript, 0)) < 0) |
| 232 | syserr("Cannot open %s", Transcript); |
| 233 | fflush(stdout); |
| 234 | errno = 0; |
| 235 | fprintf(fp, "To: %s\n", To); |
| 236 | fprintf(fp, "Subject: Unable to deliver mail\n"); |
| 237 | fprintf(fp, "\n ----- Transcript of session follows -----\n"); |
| 238 | fflush(fp); |
| 239 | while ((i = read(xfile, copybuf, sizeof copybuf)) > 0) |
| 240 | write(fileno(fp), copybuf, i); |
| 241 | fprintf(fp, "\n ----- Unsent message follows -----\n"); |
| 242 | fflush(fp); |
| 243 | rewind(stdin); |
| 244 | while ((i = read(fileno(stdin), copybuf, sizeof copybuf)) > 0) |
| 245 | write(fileno(fp), copybuf, i); |
| 246 | close(xfile); |
| 247 | if (errno != 0) |
| 248 | syserr("errhdr: I/O error"); |
| 249 | } |