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