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