|
|
1.1 ! root 1: #ident "@(#)send.c 1.6 'attmail mail(1) command'" ! 2: #ident "@(#)mailx:send.c 1.11.1.2" ! 3: /* Copyright (c) 1984 AT&T */ ! 4: /* All Rights Reserved */ ! 5: ! 6: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ ! 7: /* The copyright notice above does not evidence any */ ! 8: /* actual or intended publication of such source code. */ ! 9: ! 10: #ident "@(#)mailx:send.c 1.11.1.1" ! 11: ! 12: #include "rcv.h" ! 13: ! 14: /* ! 15: * mailx -- a modified version of a University of California at Berkeley ! 16: * mail program ! 17: * ! 18: * Mail to others. ! 19: */ ! 20: ! 21: static void fmt(); ! 22: static FILE *infix(); ! 23: static void statusput(); ! 24: static int savemail(); ! 25: static int sendmail(); ! 26: static int Sendmail(); ! 27: ! 28: static off_t textpos; ! 29: ! 30: /* ! 31: * Send message described by the passed pointer to the ! 32: * passed output buffer. Return -1 on error, but normally ! 33: * the number of lines written. Adjust the status: field ! 34: * if need be. If doign is set, suppress ignored header fields. ! 35: */ ! 36: long ! 37: send(mailp, obuf, doign) ! 38: struct message *mailp; ! 39: FILE *obuf; ! 40: { ! 41: register struct message *mp; ! 42: long clen, n, c; ! 43: FILE *ibuf; ! 44: char line[LINESIZE+1], field[BUFSIZ]; ! 45: int ishead, infld, fline, dostat, nread, unused; ! 46: char *cp, *cp2; ! 47: int oldign = 0; /* previous line was ignored */ ! 48: long lc; ! 49: ! 50: mp = mailp; ! 51: ibuf = setinput(mp); ! 52: c = mp->m_size; ! 53: ishead = 1; ! 54: dostat = 1; ! 55: infld = 0; ! 56: fline = 1; ! 57: lc = 0; ! 58: clearerr(obuf); ! 59: while (c > 0L) { ! 60: nread = getline(line, LINESIZE, ibuf, &unused); ! 61: c -= nread; ! 62: lc++; ! 63: if (ishead) { ! 64: /* ! 65: * First line is the From line, so no headers ! 66: * there to worry about ! 67: */ ! 68: if (fline) { ! 69: fline = 0; ! 70: goto writeit; ! 71: } ! 72: /* ! 73: * If line is blank, we've reached end of ! 74: * headers, so force out status: field ! 75: * and note that we are no longer in header ! 76: * fields ! 77: */ ! 78: if (line[0] == '\n') { ! 79: if (dostat) { ! 80: statusput(mailp, obuf, doign); ! 81: dostat = 0; ! 82: } ! 83: ishead = 0; ! 84: putc('\n', obuf); ! 85: continue; ! 86: } ! 87: /* ! 88: * If this line is a continuation ! 89: * of a previous header field, just echo it. ! 90: */ ! 91: if (isspace(line[0]) && infld) ! 92: if (oldign) ! 93: continue; ! 94: else ! 95: goto writeit; ! 96: infld = 0; ! 97: /* ! 98: * If we are no longer looking at real ! 99: * header lines, force out status: ! 100: * This happens in uucp style mail where ! 101: * there are no headers at all. ! 102: */ ! 103: if (!headerp(line)) { ! 104: if (dostat) { ! 105: statusput(mailp, obuf, doign); ! 106: dostat = 0; ! 107: } ! 108: putc('\n', obuf); ! 109: ishead = 0; ! 110: goto writeit; ! 111: } ! 112: infld++; ! 113: /* ! 114: * Pick up the header field. ! 115: * If it is an ignored field and ! 116: * we care about such things, skip it. ! 117: */ ! 118: cp = line; ! 119: cp2 = field; ! 120: while (*cp && *cp != ':' && !isspace(*cp)) ! 121: *cp2++ = *cp++; ! 122: *cp2 = 0; ! 123: oldign = doign && isign(field); ! 124: if (oldign) ! 125: continue; ! 126: /* ! 127: * If the field is "status," go compute and print the ! 128: * real Status: field ! 129: */ ! 130: if (icequal(field, "status")) { ! 131: if (dostat) { ! 132: statusput(mailp, obuf, doign); ! 133: dostat = 0; ! 134: } ! 135: continue; ! 136: } ! 137: } ! 138: writeit: ! 139: if ((!ishead) && (!(mp->m_text))) { ! 140: fwrite(line, 1, nread, obuf); /* output first non-hdr */ ! 141: if (ferror(obuf)) ! 142: return(-1); ! 143: clen = mp->m_clen - nread; ! 144: n = clen < sizeof line ? clen : sizeof line; ! 145: for (;n > 0;) { ! 146: if ((n = fread(line, 1, n, ibuf)) <= 0) { ! 147: fprintf(stderr, "\t(Unexpected end-of-file).\n"); ! 148: clen = 0; ! 149: } else { ! 150: if (fwrite(line, 1, n, obuf) != n) { ! 151: fprintf(stderr, "\t Error writing to the new file.\n"); ! 152: fflush(obuf); ! 153: if (ferror(obuf)) ! 154: return (-1); ! 155: } ! 156: } ! 157: clen -= n; ! 158: if (clen <= 0) { ! 159: break; ! 160: } ! 161: } ! 162: c = 0L; ! 163: } else { ! 164: fwrite(line, 1, nread, obuf); ! 165: if (ferror(obuf)) ! 166: return(-1); ! 167: } ! 168: } ! 169: fflush(obuf); ! 170: if (ferror(obuf)) ! 171: return(-1); ! 172: if (ishead && (mailp->m_flag & MSTATUS)) ! 173: printf("failed to fix up status field\n"); ! 174: return(lc); ! 175: } ! 176: ! 177: /* ! 178: * Test if the passed line is a header line, RFC 733 style. ! 179: */ ! 180: headerp(line) ! 181: register char *line; ! 182: { ! 183: register char *cp = line; ! 184: ! 185: if (*cp=='>' && strncmp(cp+1, "From", 4)==0) ! 186: return(1); ! 187: while (*cp && !isspace(*cp) && *cp != ':') ! 188: cp++; ! 189: while (*cp && isspace(*cp)) ! 190: cp++; ! 191: return(*cp == ':'); ! 192: } ! 193: ! 194: /* ! 195: * Output a reasonable looking status field. ! 196: * But if "status" is ignored and doign, forget it. ! 197: */ ! 198: static void ! 199: statusput(mp, obuf, doign) ! 200: register struct message *mp; ! 201: register FILE *obuf; ! 202: { ! 203: char statout[3]; ! 204: ! 205: if (doign && isign("status")) ! 206: return; ! 207: if ((mp->m_flag & (MNEW|MREAD)) == MNEW) ! 208: return; ! 209: if (mp->m_flag & MREAD) ! 210: strcpy(statout, "R"); ! 211: else ! 212: strcpy(statout, ""); ! 213: if ((mp->m_flag & MNEW) == 0) ! 214: strcat(statout, "O"); ! 215: fprintf(obuf, "Status: %s\n", statout); ! 216: } ! 217: ! 218: /* ! 219: * Interface between the argument list and the mail1 routine ! 220: * which does all the dirty work. ! 221: */ ! 222: ! 223: mail(people) ! 224: char **people; ! 225: { ! 226: register char *cp2; ! 227: register int s; ! 228: char *buf, **ap; ! 229: struct header head; ! 230: char recfile[128]; ! 231: ! 232: for (s = 0, ap = people; *ap; ap++) ! 233: s += strlen(*ap) + 2; ! 234: buf = salloc((unsigned)(s+1)); ! 235: cp2 = buf; ! 236: for (ap = people; *ap; ap++) { ! 237: cp2 = copy(*ap, cp2); ! 238: /* *cp2++ = ','; adb: not in our mail */ ! 239: *cp2++ = ' '; ! 240: } ! 241: *cp2 = '\0'; ! 242: head.h_to = buf; ! 243: strncpy(recfile, buf, sizeof recfile); ! 244: head.h_subject = head.h_cc = head.h_bcc = head.h_defopt = NOSTR; ! 245: head.h_others = NOSTRPTR; ! 246: head.h_seq = 0; ! 247: mail1(&head, Fflag ? recfile : 0); ! 248: return(0); ! 249: } ! 250: ! 251: sendm(str) ! 252: char *str; ! 253: { ! 254: if (value("flipm") != NOSTR) ! 255: return(Sendmail(str)); ! 256: else return(sendmail(str)); ! 257: } ! 258: ! 259: Sendm(str) ! 260: char *str; ! 261: { ! 262: if (value("flipm") != NOSTR) ! 263: return(sendmail(str)); ! 264: else return(Sendmail(str)); ! 265: } ! 266: ! 267: /* ! 268: * Send mail to a bunch of user names. The interface is through ! 269: * the mail routine below. ! 270: */ ! 271: static int ! 272: sendmail(str) ! 273: char *str; ! 274: { ! 275: struct header head; ! 276: ! 277: if (blankline(str)) ! 278: head.h_to = NOSTR; ! 279: else ! 280: head.h_to = addto(NOSTR, str); ! 281: head.h_subject = head.h_cc = head.h_bcc = head.h_defopt = NOSTR; ! 282: head.h_others = NOSTRPTR; ! 283: head.h_seq = 0; ! 284: mail1(&head, (char *) 0); ! 285: return(0); ! 286: } ! 287: ! 288: /* ! 289: * Send mail to a bunch of user names. The interface is through ! 290: * the mail routine below. ! 291: * save a copy of the letter ! 292: */ ! 293: static int ! 294: Sendmail(str) ! 295: char *str; ! 296: { ! 297: char recfile[128]; ! 298: struct header head; ! 299: ! 300: if (blankline(str)) ! 301: head.h_to = NOSTR; ! 302: else ! 303: head.h_to = addto(NOSTR, str); ! 304: strncpy(recfile, head.h_to, sizeof recfile); ! 305: head.h_subject = head.h_cc = head.h_bcc = head.h_defopt = NOSTR; ! 306: head.h_others = NOSTRPTR; ! 307: head.h_seq = 0; ! 308: mail1(&head, recfile); ! 309: return(0); ! 310: } ! 311: ! 312: /* ! 313: * Mail a message on standard input to the people indicated ! 314: * in the passed header. (Internal interface). ! 315: */ ! 316: void ! 317: mail1(hp, rec) ! 318: struct header *hp; ! 319: char *rec; ! 320: { ! 321: pid_t p, pid; ! 322: int i, s, gotcha; ! 323: char **namelist, *deliver; ! 324: struct name *to, *np; ! 325: FILE *mtf, *fp; ! 326: int remote = rflag != NOSTR || rmail; ! 327: char **t; ! 328: char *deadletter; ! 329: char recfile[128]; ! 330: ! 331: /* ! 332: * Collect user's mail from standard input. ! 333: * Get the result as mtf. ! 334: */ ! 335: ! 336: pid = (pid_t)-1; ! 337: if ((mtf = collect(hp)) == NULL) ! 338: return; ! 339: hp->h_seq = 1; ! 340: if (hp->h_subject == NOSTR) ! 341: hp->h_subject = sflag; ! 342: if (fsize(mtf) == 0 && hp->h_subject == NOSTR) { ! 343: printf("No message !?!\n"); ! 344: goto out; ! 345: } ! 346: if (intty) { ! 347: printf("EOT\n"); ! 348: flush(); ! 349: } ! 350: ! 351: /* ! 352: * Now, take the user names from the combined ! 353: * to and cc lists and do all the alias ! 354: * processing. ! 355: */ ! 356: ! 357: senderr = 0; ! 358: to = cat(extract(hp->h_bcc, GBCC), ! 359: cat(extract(hp->h_to, GTO), ! 360: extract(hp->h_cc, GCC))); ! 361: /* to = translate(outpre(elide(usermap(to)))); I can't imagine why outpre is used--adb */ ! 362: to = translate(elide(usermap(to))); ! 363: if (!senderr) ! 364: mapf(to, myname); ! 365: mechk(to); ! 366: for (gotcha = 0, np = to; np != NIL; np = np->n_flink) ! 367: if ((np->n_type & GDEL) == 0) ! 368: gotcha++; ! 369: hp->h_to = detract(to, GTO); ! 370: hp->h_cc = detract(to, GCC); ! 371: hp->h_bcc = detract(to, GBCC); ! 372: if ((mtf = infix(hp, mtf)) == NULL) { ! 373: fprintf(stderr, ". . . message lost, sorry.\n"); ! 374: return; ! 375: } ! 376: rewind(mtf); ! 377: if (askme && isatty(0)) { ! 378: char ans[64]; ! 379: puthead(hp, stdout, GTO|GCC|GBCC); ! 380: printf("Send? [yes] "); ! 381: if (fgets(ans, sizeof(ans), stdin) && ans[0] && tolower(ans[0]) != 'y') ! 382: goto dead; ! 383: } ! 384: if (senderr) ! 385: goto dead; ! 386: /* ! 387: * Look through the recipient list for names with /'s ! 388: * in them which we write to as files directly. ! 389: */ ! 390: i = outof(to, mtf); ! 391: rewind(mtf); ! 392: if (!gotcha && !i) { ! 393: printf("No recipients specified\n"); ! 394: goto dead; ! 395: } ! 396: if (senderr) ! 397: goto dead; ! 398: if ((gotcha - i) == 0) ! 399: return; ! 400: ! 401: getrecf(rec, recfile, !!rec); ! 402: if (recfile != NOSTR && *recfile) ! 403: savemail(expand(recfile), hp, mtf); ! 404: if (!gotcha) ! 405: goto out; ! 406: namelist = unpack(to); ! 407: if (debug) { ! 408: fprintf(stderr, "Recipients of message:\n"); ! 409: for (t = namelist; *t != NOSTR; t++) ! 410: fprintf(stderr, " \"%s\"", *t); ! 411: fprintf(stderr, "\n"); ! 412: return; ! 413: } ! 414: ! 415: /* ! 416: * Wait, to absorb a potential zombie, then ! 417: * fork, set up the temporary mail file as standard ! 418: * input for "mail" and exec with the user list we generated ! 419: * far above. Return the process id to caller in case he ! 420: * wants to await the completion of mail. ! 421: */ ! 422: ! 423: wait(&s); ! 424: rewind(mtf); ! 425: pid = fork(); ! 426: if (pid == (pid_t)-1) { ! 427: perror("fork"); ! 428: dead: ! 429: deadletter = Getf("DEAD"); ! 430: removefile(deadletter); /* adb -- old style */ ! 431: if (fp = fopen(deadletter, "w")) { /* adb */ ! 432: puthead(hp, fp, GMASK); ! 433: fseek(mtf, textpos, 0); ! 434: lcwrite(deadletter, mtf, fp); ! 435: fclose(fp); ! 436: chmod(deadletter, DEADPERM); ! 437: } else ! 438: perror(deadletter); ! 439: goto out; ! 440: } ! 441: if (pid == 0) { ! 442: sigchild(); ! 443: #ifdef SIGTSTP ! 444: if (remote == 0) { ! 445: sigset(SIGTSTP, SIG_IGN); ! 446: sigset(SIGTTIN, SIG_IGN); ! 447: sigset(SIGTTOU, SIG_IGN); ! 448: } ! 449: #endif ! 450: sigignore(SIGHUP); ! 451: sigignore(SIGINT); ! 452: sigignore(SIGQUIT); ! 453: s = fileno(mtf); ! 454: for (i = 3; i < 32; i++) ! 455: if (i != s) ! 456: close(i); ! 457: close(0); ! 458: dup(s); ! 459: close(s); ! 460: #ifdef CC ! 461: submit(getpid()); ! 462: #endif /* CC */ ! 463: if ((deliver = value("sendmail")) == NOSTR) ! 464: deliver = MAIL; ! 465: execvp(expand(deliver), namelist); ! 466: perror(deliver); ! 467: exit(1); ! 468: } ! 469: ! 470: if (value("sendwait")!=NOSTR) ! 471: remote++; ! 472: out: ! 473: if (remote) { ! 474: while ((p = wait(&s)) != pid && p != (pid_t)-1) ! 475: ; ! 476: if (s != 0) ! 477: senderr++; ! 478: pid = 0; ! 479: } ! 480: fclose(mtf); ! 481: return; ! 482: } ! 483: ! 484: /* ! 485: * Prepend a header in front of the collected stuff ! 486: * and return the new file. ! 487: */ ! 488: ! 489: static FILE * ! 490: infix(hp, fi) ! 491: struct header *hp; ! 492: FILE *fi; ! 493: { ! 494: register FILE *nfo, *nfi; ! 495: register int c; ! 496: char *from, *postmark; ! 497: ! 498: rewind(fi); ! 499: if ((nfo = fopen(tempMail, "w")) == NULL) { ! 500: perror(tempMail); ! 501: return(fi); ! 502: } ! 503: if ((nfi = fopen(tempMail, "r")) == NULL) { ! 504: perror(tempMail); ! 505: fclose(nfo); ! 506: return(fi); ! 507: } ! 508: removefile(tempMail); ! 509: postmark = value("postmark"); ! 510: from = value("from"); ! 511: if ((from != 0) || (postmark != 0)) { ! 512: fprintf(nfo, "From: "); ! 513: if (from) ! 514: fprintf(nfo, "%s@%s%s", myname, host, maildomain()); ! 515: else ! 516: fprintf(nfo, "%s!%s", host, myname); ! 517: if (postmark && *postmark) ! 518: fprintf(nfo, " (%s)", postmark); ! 519: putc('\n', nfo); ! 520: } ! 521: puthead(hp, nfo, GMASK & ~GBCC); ! 522: textpos = ftell(nfo); ! 523: while ((c = getc(fi)) != EOF) ! 524: putc(c, nfo); ! 525: if (ferror(fi)) { ! 526: perror("read"); ! 527: return(fi); ! 528: } ! 529: fflush(nfo); ! 530: if (ferror(nfo)) { ! 531: perror(tempMail); ! 532: fclose(nfo); ! 533: fclose(nfi); ! 534: return(fi); ! 535: } ! 536: fclose(nfo); ! 537: fclose(fi); ! 538: rewind(nfi); ! 539: return(nfi); ! 540: } ! 541: ! 542: /* ! 543: * Dump the message header on the ! 544: * passed file buffer. ! 545: */ ! 546: ! 547: puthead(hp, fo, w) ! 548: struct header *hp; ! 549: FILE *fo; ! 550: { ! 551: register int gotcha; ! 552: ! 553: gotcha = 0; ! 554: if (hp->h_to != NOSTR && (w & GTO)) ! 555: fprintf(fo, "To: "), fmt(hp->h_to, fo), gotcha++; ! 556: if (hp->h_cc != NOSTR && (w & GCC)) ! 557: fprintf(fo, "Cc: "), fmt(hp->h_cc, fo), gotcha++; ! 558: if (hp->h_bcc != NOSTR && (w & GBCC)) ! 559: fprintf(fo, "Bcc: "), fmt(hp->h_bcc, fo), gotcha++; ! 560: if (hp->h_defopt != NOSTR && (w & GDEFOPT)) ! 561: fprintf(fo, "Default-Options: %s\n", hp->h_defopt), gotcha++; ! 562: if (w & GSUBJECT) ! 563: if (hp->h_subject != NOSTR && *hp->h_subject) ! 564: fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; ! 565: else ! 566: if (sflag && *sflag) ! 567: fprintf(fo, "Subject: %s\n", sflag), gotcha++; ! 568: if (hp->h_others != NOSTRPTR && (w & GOTHER)) { ! 569: char **p; ! 570: for (p = hp->h_others; *p; p++) ! 571: fprintf(fo, "%s\n", *p); ! 572: gotcha++; ! 573: } ! 574: if (gotcha && (w & GNL)) ! 575: putc('\n', fo); ! 576: return(0); ! 577: } ! 578: ! 579: /* ! 580: * Format the given text to not exceed 78 characters. ! 581: */ ! 582: static void ! 583: fmt(str, fo) ! 584: register char *str; ! 585: register FILE *fo; ! 586: { ! 587: register int col = 4; ! 588: char name[256]; ! 589: int len; ! 590: ! 591: str = strcpy(salloc(strlen(str)+1), str); ! 592: while (str = yankword(str, name, 1)) { ! 593: len = strlen(name); ! 594: if (col > 4) { ! 595: if (col + len > 76) { ! 596: fputs(",\n ", fo); ! 597: col = 4; ! 598: } else { ! 599: fputs(", ", fo); ! 600: col += 2; ! 601: } ! 602: } ! 603: fputs(name, fo); ! 604: col += len; ! 605: } ! 606: putc('\n', fo); ! 607: } ! 608: ! 609: /* ! 610: * Save the outgoing mail on the passed file. ! 611: */ ! 612: static int ! 613: savemail(name, hp, fi) ! 614: char name[]; ! 615: struct header *hp; ! 616: FILE *fi; ! 617: { ! 618: register FILE *fo; ! 619: char line[BUFSIZ]; ! 620: long now; ! 621: char *n; ! 622: ! 623: if (debug) ! 624: fprintf(stderr, "save in '%s'\n", name); ! 625: if ((fo = fopen(name, "a")) == NULL) { ! 626: perror(name); ! 627: return(-1); ! 628: } ! 629: time(&now); ! 630: n = rflag; ! 631: if (n == NOSTR) ! 632: n = myname; ! 633: fprintf(fo, "From %s %s", n, ctime(&now)); ! 634: puthead(hp, fo, GMASK); ! 635: fseek(fi, textpos, 0); ! 636: while (fgets(line, sizeof line, fi)) { ! 637: if (!strncmp(line, "From ", 5)) ! 638: putc('>', fo); ! 639: fputs(line, fo); ! 640: } ! 641: putc('\n', fo); ! 642: fflush(fo); ! 643: if (ferror(fo)) ! 644: perror(name); ! 645: fclose(fo); ! 646: return(0); ! 647: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.