1 # 2 3 #include "rcv.h" 4 #ifdef VMUNIX 5 #include <wait.h> 6 #endif 7 #include <ctype.h> 8 9 /* 10 * Mail -- a mail program 11 * 12 * Mail to others. 13 */ 14 15 static char *SccsId = "@(#)send.c 1.5 04/01/81"; 16 17 /* 18 * Send message described by the passed pointer to the 19 * passed output buffer. Return -1 on error, but normally 20 * the number of lines written. Adjust the status: field 21 * if need be. 22 */ 23 24 send(mailp, obuf) 25 struct message *mailp; 26 FILE *obuf; 27 { 28 register struct message *mp; 29 register int t; 30 unsigned int c; 31 FILE *ibuf; 32 char line[LINESIZE]; 33 int lc, ishead, infld, fline; 34 35 mp = mailp; 36 ibuf = setinput(mp); 37 c = msize(mp); 38 ishead = (mailp->m_flag & MSTATUS) != 0; 39 infld = 0; 40 fline = 1; 41 lc = 0; 42 while (c > 0) { 43 fgets(line, LINESIZE, ibuf); 44 c -= strlen(line); 45 lc++; 46 if (ishead) { 47 if (fline) { 48 fline = 0; 49 goto writeit; 50 } 51 if (line[0] == '\n') { 52 statusput(mailp, obuf); 53 ishead = 0; 54 goto writeit; 55 } 56 if (isspace(line[0]) && infld) 57 goto writeit; 58 infld = 0; 59 if (!headerp(line)) { 60 statusput(mailp, obuf); 61 putc('\n', obuf); 62 ishead = 0; 63 goto writeit; 64 } 65 infld++; 66 if (icisname(line, "status", 6)) { 67 statusput(mailp, obuf); 68 ishead = 0; 69 continue; 70 } 71 } 72 writeit: 73 fputs(line, obuf); 74 if (ferror(obuf)) 75 return(-1); 76 } 77 if (ferror(obuf)) 78 return(-1); 79 if (ishead && (mailp->m_flag & MSTATUS)) 80 printf("failed to fix up status field\n"); 81 return(lc); 82 } 83 84 /* 85 * Test if the passed line is a header line, RFC 733 style. 86 */ 87 headerp(line) 88 register char *line; 89 { 90 register char *cp = line; 91 92 while (*cp && !isspace(*cp) && *cp != ':') 93 cp++; 94 while (*cp && isspace(*cp)) 95 cp++; 96 return(*cp == ':'); 97 } 98 99 /* 100 * Output a reasonable looking status field. 101 */ 102 103 statusput(mp, obuf) 104 register struct message *mp; 105 register FILE *obuf; 106 { 107 char statout[3]; 108 109 if ((mp->m_flag & (MNEW|MREAD)) == MNEW) 110 return; 111 if (mp->m_flag & MREAD) 112 strcpy(statout, "R"); 113 else 114 strcpy(statout, ""); 115 if ((mp->m_flag & MNEW) == 0) 116 strcat(statout, "O"); 117 fprintf(obuf, "Status: %s\n", statout); 118 } 119 120 121 /* 122 * Interface between the argument list and the mail1 routine 123 * which does all the dirty work. 124 */ 125 126 mail(people) 127 char **people; 128 { 129 register char *cp2; 130 register int s; 131 char *buf, **ap; 132 struct header head; 133 134 for (s = 0, ap = people; *ap != (char *) -1; ap++) 135 s += strlen(*ap) + 1; 136 buf = salloc(s+1); 137 cp2 = buf; 138 for (ap = people; *ap != (char *) -1; ap++) { 139 cp2 = copy(*ap, cp2); 140 *cp2++ = ' '; 141 } 142 if (cp2 != buf) 143 cp2--; 144 *cp2 = '\0'; 145 head.h_to = buf; 146 head.h_subject = NOSTR; 147 head.h_cc = NOSTR; 148 head.h_bcc = NOSTR; 149 head.h_seq = 0; 150 mail1(&head); 151 return(0); 152 } 153 154 155 /* 156 * Send mail to a bunch of user names. The interface is through 157 * the mail routine below. 158 */ 159 160 sendmail(str) 161 char *str; 162 { 163 register char **ap; 164 char *bufp; 165 register int t; 166 struct header head; 167 168 if (blankline(str)) 169 head.h_to = NOSTR; 170 else 171 head.h_to = str; 172 head.h_subject = NOSTR; 173 head.h_cc = NOSTR; 174 head.h_bcc = NOSTR; 175 head.h_seq = 0; 176 mail1(&head); 177 return(0); 178 } 179 180 /* 181 * Mail a message on standard input to the people indicated 182 * in the passed header. (Internal interface). 183 */ 184 185 mail1(hp) 186 struct header *hp; 187 { 188 register char *cp; 189 int pid, i, s, p, gotcha; 190 char **namelist; 191 struct name *to, *np; 192 FILE *mtf, *postage; 193 int remote = rflag != NOSTR || rmail; 194 char **t; 195 196 /* 197 * Collect user's mail from standard input. 198 * Get the result as mtf. 199 */ 200 201 pid = -1; 202 if ((mtf = collect(hp)) == NULL) 203 return(-1); 204 hp->h_seq = 1; 205 if (hp->h_subject == NOSTR) 206 hp->h_subject = sflag; 207 if (fsize(mtf) == 0 && hp->h_subject == NOSTR) { 208 printf("No message !?!\n"); 209 goto out; 210 } 211 if (intty && value("askcc") != NOSTR) 212 grabh(hp, GCC); 213 else if (intty) { 214 printf("EOT\n"); 215 flush(); 216 } 217 218 /* 219 * Now, take the user names from the combined 220 * to and cc lists and do all the alias 221 * processing. 222 */ 223 224 senderr = 0; 225 to = usermap(cat(extract(hp->h_bcc, GBCC), 226 cat(extract(hp->h_to, GTO), extract(hp->h_cc, GCC)))); 227 if (to == NIL) { 228 printf("No recipients specified\n"); 229 goto topdog; 230 } 231 232 /* 233 * Look through the recipient list for names with /'s 234 * in them which we write to as files directly. 235 */ 236 237 to = outof(to, mtf, hp); 238 rewind(mtf); 239 to = verify(to); 240 if (senderr && !remote) { 241 topdog: 242 243 if (fsize(mtf) != 0) { 244 remove(deadletter); 245 exwrite(deadletter, mtf, 1); 246 rewind(mtf); 247 } 248 } 249 for (gotcha = 0, np = to; np != NIL; np = np->n_flink) 250 if ((np->n_type & GDEL) == 0) { 251 gotcha++; 252 break; 253 } 254 if (!gotcha) 255 goto out; 256 to = elide(to); 257 mechk(to); 258 if (count(to) > 1) 259 hp->h_seq++; 260 if (hp->h_seq > 0 && !remote) { 261 fixhead(hp, to); 262 if (fsize(mtf) == 0) 263 printf("Null message body; hope that's ok\n"); 264 if ((mtf = infix(hp, mtf)) == NULL) { 265 fprintf(stderr, ". . . message lost, sorry.\n"); 266 return(-1); 267 } 268 } 269 namelist = unpack(to); 270 if (debug) { 271 printf("Recipients of message:\n"); 272 for (t = namelist; *t != NOSTR; t++) 273 printf(" \"%s\"", *t); 274 printf("\n"); 275 fflush(stdout); 276 return; 277 } 278 if ((cp = value("record")) != NOSTR) 279 savemail(expand(cp), hp, mtf); 280 281 /* 282 * Wait, to absorb a potential zombie, then 283 * fork, set up the temporary mail file as standard 284 * input for "mail" and exec with the user list we generated 285 * far above. Return the process id to caller in case he 286 * wants to await the completion of mail. 287 */ 288 289 #ifdef VMUNIX 290 while (wait3(&s, WNOHANG, 0) > 0) 291 ; 292 #else 293 wait(&s); 294 #endif 295 rewind(mtf); 296 pid = fork(); 297 if (pid == -1) { 298 perror("fork"); 299 remove(deadletter); 300 exwrite(deadletter, mtf, 1); 301 goto out; 302 } 303 if (pid == 0) { 304 #ifdef SIGTSTP 305 if (remote == 0) { 306 sigset(SIGTSTP, SIG_IGN); 307 sigset(SIGTTIN, SIG_IGN); 308 sigset(SIGTTOU, SIG_IGN); 309 } 310 #endif 311 for (i = SIGHUP; i <= SIGQUIT; i++) 312 sigset(i, SIG_IGN); 313 if ((postage = fopen("/crp/kurt/postage", "a")) != NULL) { 314 fprintf(postage, "%s %d %d\n", myname, 315 count(to), fsize(mtf)); 316 fclose(postage); 317 } 318 s = fileno(mtf); 319 for (i = 3; i < 15; i++) 320 if (i != s) 321 close(i); 322 close(0); 323 dup(s); 324 close(s); 325 #ifdef CC 326 submit(getpid()); 327 #endif CC 328 #ifdef DELIVERMAIL 329 execv(DELIVERMAIL, namelist); 330 #endif DELIVERMAIL 331 execv(MAIL, namelist); 332 perror(MAIL); 333 exit(1); 334 } 335 336 out: 337 if (remote) { 338 while ((p = wait(&s)) != pid && p != -1) 339 ; 340 if (s != 0) 341 senderr++; 342 pid = 0; 343 } 344 fclose(mtf); 345 return(pid); 346 } 347 348 /* 349 * Fix the header by glopping all of the expanded names from 350 * the distribution list into the appropriate fields. 351 * If there are any ARPA net recipients in the message, 352 * we must insert commas, alas. 353 */ 354 355 fixhead(hp, tolist) 356 struct header *hp; 357 struct name *tolist; 358 { 359 register struct name *nlist; 360 register int f; 361 register struct name *np; 362 363 for (f = 0, np = tolist; np != NIL; np = np->n_flink) 364 if (any('@', np->n_name)) { 365 f |= GCOMMA; 366 break; 367 } 368 369 if (debug && f & GCOMMA) 370 fprintf(stderr, "Should be inserting commas in recip lists\n"); 371 hp->h_to = detract(tolist, GTO|f); 372 hp->h_cc = detract(tolist, GCC|f); 373 } 374 375 /* 376 * Prepend a header in front of the collected stuff 377 * and return the new file. 378 */ 379 380 FILE * 381 infix(hp, fi) 382 struct header *hp; 383 FILE *fi; 384 { 385 extern char tempMail[]; 386 register FILE *nfo, *nfi; 387 register int c; 388 389 rewind(fi); 390 if ((nfo = fopen(tempMail, "w")) == NULL) { 391 perror(tempMail); 392 return(fi); 393 } 394 if ((nfi = fopen(tempMail, "r")) == NULL) { 395 perror(tempMail); 396 fclose(nfo); 397 return(fi); 398 } 399 remove(tempMail); 400 puthead(hp, nfo, GTO|GSUBJECT|GCC|GNL); 401 c = getc(fi); 402 while (c != EOF) { 403 putc(c, nfo); 404 c = getc(fi); 405 } 406 if (ferror(fi)) { 407 perror("read"); 408 return(fi); 409 } 410 fflush(nfo); 411 if (ferror(nfo)) { 412 perror(tempMail); 413 fclose(nfo); 414 fclose(nfi); 415 return(fi); 416 } 417 fclose(nfo); 418 fclose(fi); 419 rewind(nfi); 420 return(nfi); 421 } 422 423 /* 424 * Dump the to, subject, cc header on the 425 * passed file buffer. 426 */ 427 428 puthead(hp, fo, w) 429 struct header *hp; 430 FILE *fo; 431 { 432 register int gotcha; 433 434 gotcha = 0; 435 if (hp->h_to != NOSTR && w & GTO) 436 fprintf(fo, "To: "), fmt(hp->h_to, fo), gotcha++; 437 if (hp->h_subject != NOSTR && w & GSUBJECT) 438 fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; 439 if (hp->h_cc != NOSTR && w & GCC) 440 fprintf(fo, "Cc: "), fmt(hp->h_cc, fo), gotcha++; 441 if (hp->h_bcc != NOSTR && w & GBCC) 442 fprintf(fo, "Bcc: "), fmt(hp->h_bcc, fo), gotcha++; 443 if (gotcha && w & GNL) 444 putc('\n', fo); 445 return(0); 446 } 447 448 /* 449 * Format the given text to not exceed 72 characters. 450 */ 451 452 fmt(str, fo) 453 register char *str; 454 register FILE *fo; 455 { 456 register int col; 457 register char *cp; 458 459 cp = str; 460 col = 0; 461 while (*cp) { 462 if (*cp == ' ' && col > 65) { 463 fprintf(fo, "\n "); 464 col = 4; 465 cp++; 466 continue; 467 } 468 putc(*cp++, fo); 469 col++; 470 } 471 putc('\n', fo); 472 } 473 474 /* 475 * Save the outgoing mail on the passed file. 476 */ 477 478 savemail(name, hp, fi) 479 char name[]; 480 struct header *hp; 481 FILE *fi; 482 { 483 register FILE *fo; 484 register int c; 485 long now; 486 char *n; 487 488 if ((fo = fopen(name, "a")) == NULL) { 489 perror(name); 490 return(-1); 491 } 492 time(&now); 493 n = rflag; 494 if (n == NOSTR) 495 n = myname; 496 fprintf(fo, "From %s %s", n, ctime(&now)); 497 rewind(fi); 498 for (c = getc(fi); c != EOF; c = getc(fi)) 499 putc(c, fo); 500 fprintf(fo, "\n"); 501 fflush(fo); 502 if (ferror(fo)) 503 perror(name); 504 fclose(fo); 505 return(0); 506 } 507