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: }

Defined functions

fixhead defined in line 421; used 1 times
fmt defined in line 518; used 3 times
headerp defined in line 142; used 1 times
  • in line 93
infix defined in line 446; used 2 times
mail defined in line 183; used 1 times
mail1 defined in line 242; used 4 times
puthead defined in line 494; used 4 times
savemail defined in line 562; used 1 times
sendmail defined in line 217; used 2 times
statusput defined in line 158; used 3 times

Defined variables

sccsid defined in line 8; never used
Last modified: 1985-06-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1810
Valid CSS Valid XHTML 1.0 Strict