|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that this notice is preserved and that due credit is given ! 7: * to the University of California at Berkeley. The name of the University ! 8: * may not be used to endorse or promote products derived from this ! 9: * software without specific prior written permission. This software ! 10: * is provided ``as is'' without express or implied warranty. ! 11: */ ! 12: ! 13: #ifdef notdef ! 14: static char sccsid[] = "@(#)send.c 5.5 (Berkeley) 2/18/88"; ! 15: #endif /* notdef */ ! 16: ! 17: #include "rcv.h" ! 18: #include <sys/wait.h> ! 19: #include <sys/stat.h> ! 20: ! 21: /* ! 22: * Mail -- a mail program ! 23: * ! 24: * Mail to others. ! 25: */ ! 26: ! 27: /* ! 28: * Send message described by the passed pointer to the ! 29: * passed output buffer. Return -1 on error, but normally ! 30: * the number of lines written. Adjust the status: field ! 31: * if need be. If doign is set, suppress ignored header fields. ! 32: */ ! 33: send(mp, obuf, doign) ! 34: register struct message *mp; ! 35: FILE *obuf; ! 36: { ! 37: long count; ! 38: register FILE *ibuf; ! 39: char line[LINESIZE]; ! 40: int lc, ishead, infld, ignoring, dostat; ! 41: register char *cp, *cp2; ! 42: register int c; ! 43: int length; ! 44: ! 45: ibuf = setinput(mp); ! 46: count = mp->m_size; ! 47: ishead = 1; ! 48: dostat = !doign || !isign("status"); ! 49: infld = 0; ! 50: lc = 0; ! 51: /* ! 52: * Process headers first ! 53: */ ! 54: while (count > 0 && ishead) { ! 55: if (fgets(line, LINESIZE, ibuf) == NULL) ! 56: break; ! 57: count -= length = strlen(line); ! 58: if (lc == 0) { ! 59: /* ! 60: * First line is the From line, so no headers ! 61: * there to worry about ! 62: */ ! 63: ignoring = 0; ! 64: } else if (line[0] == '\n') { ! 65: /* ! 66: * If line is blank, we've reached end of ! 67: * headers, so force out status: field ! 68: * and note that we are no longer in header ! 69: * fields ! 70: */ ! 71: if (dostat) { ! 72: statusput(mp, obuf); ! 73: dostat = 0; ! 74: } ! 75: ishead = 0; ! 76: ignoring = 0; ! 77: } else if (infld && (line[0] == ' ' || line[0] == '\t')) { ! 78: /* ! 79: * If this line is a continuation (via space or tab) ! 80: * of a previous header field, just echo it ! 81: * (unless the field should be ignored). ! 82: * In other words, nothing to do. ! 83: */ ! 84: } else { ! 85: /* ! 86: * Pick up the header field if we have one. ! 87: */ ! 88: for (cp = line; (c = *cp++) && c != ':' && !isspace(c);) ! 89: ; ! 90: cp2 = --cp; ! 91: while (isspace(*cp++)) ! 92: ; ! 93: if (cp[-1] != ':') { ! 94: /* ! 95: * Not a header line, force out status: ! 96: * This happens in uucp style mail where ! 97: * there are no headers at all. ! 98: */ ! 99: if (dostat) { ! 100: statusput(mp, obuf); ! 101: dostat = 0; ! 102: } ! 103: (void) putc('\n', obuf); /* add blank line */ ! 104: lc++; ! 105: ishead = 0; ! 106: ignoring = 0; ! 107: } else { ! 108: /* ! 109: * If it is an ignored field and ! 110: * we care about such things, skip it. ! 111: */ ! 112: *cp2 = 0; /* temporarily null terminate */ ! 113: if (doign && isign(line)) ! 114: ignoring = 1; ! 115: else if ((line[0] == 's' || line[0] == 'S') && ! 116: icequal(line, "status")) { ! 117: /* ! 118: * If the field is "status," go compute ! 119: * and print the real Status: field ! 120: */ ! 121: if (dostat) { ! 122: statusput(mp, obuf); ! 123: dostat = 0; ! 124: } ! 125: ignoring = 1; ! 126: } else { ! 127: ignoring = 0; ! 128: *cp2 = c; /* restore */ ! 129: } ! 130: infld = 1; ! 131: } ! 132: } ! 133: if (!ignoring) { ! 134: (void) fwrite(line, sizeof *line, length, obuf); ! 135: if (ferror(obuf)) ! 136: return -1; ! 137: lc++; ! 138: } ! 139: } ! 140: /* ! 141: * Copy out message body ! 142: */ ! 143: while (count > 0) { ! 144: cp = line; ! 145: c = count < LINESIZE ? count : LINESIZE; ! 146: if ((c = fread(cp, sizeof *cp, c, ibuf)) <= 0) ! 147: break; ! 148: if (fwrite(cp, sizeof *cp, c, obuf) != c) ! 149: return -1; ! 150: count -= c; ! 151: while (--c >= 0) ! 152: if (*cp++ == '\n') ! 153: lc++; ! 154: } ! 155: if (ishead && (mp->m_flag & MSTATUS)) ! 156: printf("failed to fix up status field\n"); ! 157: return (lc); ! 158: } ! 159: ! 160: /* ! 161: * Output a reasonable looking status field. ! 162: * But if "status" is ignored and doign, forget it. ! 163: */ ! 164: statusput(mp, obuf) ! 165: register struct message *mp; ! 166: FILE *obuf; ! 167: { ! 168: char statout[3]; ! 169: register char *cp = statout; ! 170: ! 171: if (mp->m_flag & MREAD) ! 172: *cp++ = 'R'; ! 173: if ((mp->m_flag & MNEW) == 0) ! 174: *cp++ = 'O'; ! 175: *cp = 0; ! 176: if (statout[0]) ! 177: fprintf(obuf, "Status: %s\n", statout); ! 178: } ! 179: ! 180: /* ! 181: * Interface between the argument list and the mail1 routine ! 182: * which does all the dirty work. ! 183: */ ! 184: ! 185: mail(people) ! 186: char **people; ! 187: { ! 188: register char *cp2; ! 189: register int s; ! 190: char *buf, **ap; ! 191: struct header head; ! 192: ! 193: for (s = 0, ap = people; *ap != 0; ap++) ! 194: s += strlen(*ap) + 1; ! 195: buf = salloc(s+1); ! 196: cp2 = buf; ! 197: for (ap = people; *ap != 0; ap++) { ! 198: cp2 = copy(*ap, cp2); ! 199: *cp2++ = ' '; ! 200: } ! 201: if (cp2 != buf) ! 202: cp2--; ! 203: *cp2 = '\0'; ! 204: head.h_to = buf; ! 205: head.h_subject = NOSTR; ! 206: head.h_cc = NOSTR; ! 207: head.h_bcc = NOSTR; ! 208: head.h_seq = 0; ! 209: (void) mail1(&head); ! 210: return(0); ! 211: } ! 212: ! 213: ! 214: /* ! 215: * Send mail to a bunch of user names. The interface is through ! 216: * the mail routine below. ! 217: */ ! 218: ! 219: sendmail(str) ! 220: char *str; ! 221: { ! 222: struct header head; ! 223: ! 224: if (blankline(str)) ! 225: head.h_to = NOSTR; ! 226: else ! 227: head.h_to = str; ! 228: head.h_subject = NOSTR; ! 229: head.h_cc = NOSTR; ! 230: head.h_bcc = NOSTR; ! 231: head.h_seq = 0; ! 232: (void) mail1(&head); ! 233: return(0); ! 234: } ! 235: ! 236: /* ! 237: * Mail a message on standard input to the people indicated ! 238: * in the passed header. (Internal interface). ! 239: */ ! 240: ! 241: mail1(hp) ! 242: struct header *hp; ! 243: { ! 244: register char *cp; ! 245: int pid, i, p, gotcha; ! 246: union wait s; ! 247: char **namelist, *deliver; ! 248: struct name *to, *np; ! 249: struct stat sbuf; ! 250: FILE *mtf, *postage; ! 251: int remote = rflag != NOSTR || rmail; ! 252: char **t; ! 253: ! 254: /* ! 255: * Collect user's mail from standard input. ! 256: * Get the result as mtf. ! 257: */ ! 258: ! 259: pid = -1; ! 260: if ((mtf = collect(hp)) == NULL) ! 261: return(-1); ! 262: hp->h_seq = 1; ! 263: if (hp->h_subject == NOSTR) ! 264: hp->h_subject = sflag; ! 265: if (intty && value("askcc") != NOSTR) ! 266: grabh(hp, GCC); ! 267: else if (intty) { ! 268: printf("EOT\n"); ! 269: (void) fflush(stdout); ! 270: } ! 271: ! 272: /* ! 273: * Now, take the user names from the combined ! 274: * to and cc lists and do all the alias ! 275: * processing. ! 276: */ ! 277: ! 278: senderr = 0; ! 279: to = usermap(cat(extract(hp->h_bcc, GBCC), ! 280: cat(extract(hp->h_to, GTO), extract(hp->h_cc, GCC)))); ! 281: if (to == NIL) { ! 282: printf("No recipients specified\n"); ! 283: goto topdog; ! 284: } ! 285: ! 286: /* ! 287: * Look through the recipient list for names with /'s ! 288: * in them which we write to as files directly. ! 289: */ ! 290: ! 291: to = outof(to, mtf, hp); ! 292: rewind(mtf); ! 293: to = verify(to); ! 294: if (senderr && !remote) { ! 295: topdog: ! 296: ! 297: if (fsize(mtf) != 0) { ! 298: (void) remove(deadletter); ! 299: (void) exwrite(deadletter, mtf, 1); ! 300: rewind(mtf); ! 301: } ! 302: } ! 303: for (gotcha = 0, np = to; np != NIL; np = np->n_flink) ! 304: if ((np->n_type & GDEL) == 0) { ! 305: gotcha++; ! 306: break; ! 307: } ! 308: if (!gotcha) ! 309: goto out; ! 310: to = elide(to); ! 311: mechk(to); ! 312: if (count(to) > 1) ! 313: hp->h_seq++; ! 314: if (hp->h_seq > 0 && !remote) { ! 315: fixhead(hp, to); ! 316: if (fsize(mtf) == 0) ! 317: if (hp->h_subject == NOSTR) ! 318: printf("No message, no subject; hope that's ok\n"); ! 319: else ! 320: printf("Null message body; hope that's ok\n"); ! 321: if ((mtf = infix(hp, mtf)) == NULL) { ! 322: fprintf(stderr, ". . . message lost, sorry.\n"); ! 323: return(-1); ! 324: } ! 325: } ! 326: namelist = unpack(to); ! 327: if (debug) { ! 328: printf("Recipients of message:\n"); ! 329: for (t = namelist; *t != NOSTR; t++) ! 330: printf(" \"%s\"", *t); ! 331: printf("\n"); ! 332: (void) fflush(stdout); ! 333: return 0; ! 334: } ! 335: if ((cp = value("record")) != NOSTR) ! 336: (void) savemail(expand(cp), mtf); ! 337: ! 338: /* ! 339: * Wait, to absorb a potential zombie, then ! 340: * fork, set up the temporary mail file as standard ! 341: * input for "mail" and exec with the user list we generated ! 342: * far above. Return the process id to caller in case he ! 343: * wants to await the completion of mail. ! 344: */ ! 345: ! 346: while (wait3(&s, WNOHANG, (struct timeval *) 0) > 0) ! 347: ; ! 348: rewind(mtf); ! 349: pid = fork(); ! 350: if (pid == -1) { ! 351: perror("fork"); ! 352: (void) remove(deadletter); ! 353: (void) exwrite(deadletter, mtf, 1); ! 354: goto out; ! 355: } ! 356: if (pid == 0) { ! 357: #ifdef SIGTSTP ! 358: if (remote == 0) { ! 359: (void) signal(SIGTSTP, SIG_IGN); ! 360: (void) signal(SIGTTIN, SIG_IGN); ! 361: (void) signal(SIGTTOU, SIG_IGN); ! 362: } ! 363: #endif ! 364: (void) signal(SIGHUP, SIG_IGN); ! 365: (void) signal(SIGINT, SIG_IGN); ! 366: (void) signal(SIGQUIT, SIG_IGN); ! 367: if (!stat(POSTAGE, &sbuf)) ! 368: if ((postage = fopen(POSTAGE, "a")) != NULL) { ! 369: fprintf(postage, "%s %d %ld\n", myname, ! 370: count(to), fsize(mtf)); ! 371: (void) fclose(postage); ! 372: } ! 373: (void) close(0); ! 374: (void) dup(fileno(mtf)); ! 375: for (i = getdtablesize(); --i > 2;) ! 376: (void) close(i); ! 377: #ifdef SENDMAIL ! 378: if ((deliver = value("sendmail")) == NOSTR) ! 379: deliver = SENDMAIL; ! 380: execv(deliver, namelist); ! 381: #endif SENDMAIL ! 382: execv(MAIL, namelist); ! 383: perror(MAIL); ! 384: exit(1); ! 385: } ! 386: ! 387: out: ! 388: if (remote || (value("verbose") != NOSTR)) { ! 389: while ((p = wait(&s)) != pid && p != -1) ! 390: ; ! 391: if (s.w_status != 0) ! 392: senderr++; ! 393: pid = 0; ! 394: } ! 395: (void) fclose(mtf); ! 396: return(pid); ! 397: } ! 398: ! 399: /* ! 400: * Fix the header by glopping all of the expanded names from ! 401: * the distribution list into the appropriate fields. ! 402: * If there are any ARPA net recipients in the message, ! 403: * we must insert commas, alas. ! 404: */ ! 405: ! 406: fixhead(hp, tolist) ! 407: struct header *hp; ! 408: struct name *tolist; ! 409: { ! 410: register int f; ! 411: register struct name *np; ! 412: ! 413: for (f = 0, np = tolist; np != NIL; np = np->n_flink) ! 414: if (any('@', np->n_name)) { ! 415: f |= GCOMMA; ! 416: break; ! 417: } ! 418: ! 419: if (debug && f & GCOMMA) ! 420: fprintf(stderr, "Should be inserting commas in recip lists\n"); ! 421: hp->h_to = detract(tolist, GTO|f); ! 422: hp->h_cc = detract(tolist, GCC|f); ! 423: } ! 424: ! 425: /* ! 426: * Prepend a header in front of the collected stuff ! 427: * and return the new file. ! 428: */ ! 429: ! 430: FILE * ! 431: infix(hp, fi) ! 432: struct header *hp; ! 433: FILE *fi; ! 434: { ! 435: extern char tempMail[]; ! 436: register FILE *nfo, *nfi; ! 437: register int c; ! 438: ! 439: rewind(fi); ! 440: if ((nfo = fopen(tempMail, "w")) == NULL) { ! 441: perror(tempMail); ! 442: return(fi); ! 443: } ! 444: if ((nfi = fopen(tempMail, "r")) == NULL) { ! 445: perror(tempMail); ! 446: (void) fclose(nfo); ! 447: return(fi); ! 448: } ! 449: (void) remove(tempMail); ! 450: (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GNL); ! 451: c = getc(fi); ! 452: while (c != EOF) { ! 453: (void) putc(c, nfo); ! 454: c = getc(fi); ! 455: } ! 456: if (ferror(fi)) { ! 457: perror("read"); ! 458: return(fi); ! 459: } ! 460: (void) fflush(nfo); ! 461: if (ferror(nfo)) { ! 462: perror(tempMail); ! 463: (void) fclose(nfo); ! 464: (void) fclose(nfi); ! 465: return(fi); ! 466: } ! 467: (void) fclose(nfo); ! 468: (void) fclose(fi); ! 469: rewind(nfi); ! 470: return(nfi); ! 471: } ! 472: ! 473: /* ! 474: * Dump the to, subject, cc header on the ! 475: * passed file buffer. ! 476: */ ! 477: ! 478: puthead(hp, fo, w) ! 479: struct header *hp; ! 480: FILE *fo; ! 481: { ! 482: register int gotcha; ! 483: ! 484: gotcha = 0; ! 485: if (hp->h_to != NOSTR && w & GTO) ! 486: fmt("To: ", hp->h_to, fo), gotcha++; ! 487: if (hp->h_subject != NOSTR && w & GSUBJECT) ! 488: fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; ! 489: if (hp->h_cc != NOSTR && w & GCC) ! 490: fmt("Cc: ", hp->h_cc, fo), gotcha++; ! 491: if (hp->h_bcc != NOSTR && w & GBCC) ! 492: fmt("Bcc: ", hp->h_bcc, fo), gotcha++; ! 493: if (gotcha && w & GNL) ! 494: (void) putc('\n', fo); ! 495: return(0); ! 496: } ! 497: ! 498: /* ! 499: * Format the given text to not exceed 72 characters. ! 500: */ ! 501: ! 502: fmt(str, txt, fo) ! 503: register char *str, *txt; ! 504: register FILE *fo; ! 505: { ! 506: register int col; ! 507: register char *bg, *bl, *pt, ch; ! 508: ! 509: col = strlen(str); ! 510: if (col) ! 511: fprintf(fo, "%s", str); ! 512: pt = bg = txt; ! 513: bl = 0; ! 514: while (*bg) { ! 515: pt++; ! 516: if (++col > 72) { ! 517: if (!bl) { ! 518: bl = bg; ! 519: while (*bl && !isspace(*bl)) ! 520: bl++; ! 521: } ! 522: if (!*bl) ! 523: goto finish; ! 524: ch = *bl; ! 525: *bl = '\0'; ! 526: fprintf(fo, "%s\n ", bg); ! 527: col = 4; ! 528: *bl = ch; ! 529: pt = bg = ++bl; ! 530: bl = 0; ! 531: } ! 532: if (!*pt) { ! 533: finish: ! 534: fprintf(fo, "%s\n", bg); ! 535: return; ! 536: } ! 537: if (isspace(*pt)) ! 538: bl = pt; ! 539: } ! 540: } ! 541: ! 542: /* ! 543: * Save the outgoing mail on the passed file. ! 544: */ ! 545: ! 546: /*ARGSUSED*/ ! 547: savemail(name, fi) ! 548: char name[]; ! 549: register FILE *fi; ! 550: { ! 551: register FILE *fo; ! 552: char buf[BUFSIZ]; ! 553: register i; ! 554: time_t now, time(); ! 555: char *n; ! 556: char *ctime(); ! 557: ! 558: if ((fo = fopen(name, "a")) == NULL) { ! 559: perror(name); ! 560: return (-1); ! 561: } ! 562: (void) time(&now); ! 563: if ((n = rflag) == NOSTR) ! 564: n = myname; ! 565: fprintf(fo, "From %s %s", n, ctime(&now)); ! 566: rewind(fi); ! 567: while ((i = fread(buf, 1, sizeof buf, fi)) > 0) ! 568: (void) fwrite(buf, 1, i, fo); ! 569: (void) putc('\n', fo); ! 570: (void) fflush(fo); ! 571: if (ferror(fo)) ! 572: perror(name); ! 573: (void) fclose(fo); ! 574: return (0); ! 575: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.