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