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, with or without
   6:  * modification, are permitted provided that the following conditions
   7:  * are met:
   8:  * 1. Redistributions of source code must retain the above copyright
   9:  *    notice, this list of conditions and the following disclaimer.
  10:  * 2. Redistributions in binary form must reproduce the above copyright
  11:  *    notice, this list of conditions and the following disclaimer in the
  12:  *    documentation and/or other materials provided with the distribution.
  13:  * 3. All advertising materials mentioning features or use of this software
  14:  *    must display the following acknowledgement:
  15:  *	This product includes software developed by the University of
  16:  *	California, Berkeley and its contributors.
  17:  * 4. Neither the name of the University nor the names of its contributors
  18:  *    may be used to endorse or promote products derived from this software
  19:  *    without specific prior written permission.
  20:  *
  21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31:  * SUCH DAMAGE.
  32:  */
  33: 
  34: #if !defined(lint) && defined(DOSCCS)
  35: static char sccsid[] = "@(#)collect.c	5.24 (Berkeley) 4/1/91";
  36: #endif
  37: 
  38: /*
  39:  * Mail -- a mail program
  40:  *
  41:  * Collect input from standard input, handling
  42:  * ~ escapes.
  43:  */
  44: 
  45: #include "rcv.h"
  46: #include <sys/stat.h>
  47: 
  48: /*
  49:  * Read a message from standard output and return a read file to it
  50:  * or NULL on error.
  51:  */
  52: 
  53: /*
  54:  * The following hokiness with global variables is so that on
  55:  * receipt of an interrupt signal, the partial message can be salted
  56:  * away on dead.letter.
  57:  */
  58: 
  59: static  sig_t   saveint;        /* Previous SIGINT value */
  60: static  sig_t   savehup;        /* Previous SIGHUP value */
  61: static  sig_t   savetstp;       /* Previous SIGTSTP value */
  62: static  sig_t   savettou;       /* Previous SIGTTOU value */
  63: static  sig_t   savettin;       /* Previous SIGTTIN value */
  64: static  FILE    *collf;         /* File for saving away */
  65: static  int hadintr;        /* Have seen one SIGINT so far */
  66: 
  67: static  jmp_buf colljmp;        /* To get back to work */
  68: static  int colljmp_p;      /* whether to long jump */
  69: static  jmp_buf collabort;      /* To end collection with error */
  70: 
  71: FILE *
  72: collect(hp, printheaders)
  73:     struct header *hp;
  74: {
  75:     FILE *fbuf;
  76:     int lc, escape, eofcount;
  77:     long cc;
  78:     register int c, t;
  79:     char linebuf[LINESIZE], *cp;
  80:     extern char tempMail[];
  81:     char getsub;
  82:     long omask;
  83:     void collint(), collhup(), collstop();
  84: 
  85:     collf = NULL;
  86:     /*
  87: 	 * Start catching signals from here, but we're still die on interrupts
  88: 	 * until we're in the main loop.
  89: 	 */
  90:     omask = sigblock(sigmask(SIGINT) | sigmask(SIGHUP));
  91:     if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
  92:         signal(SIGINT, collint);
  93:     if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
  94:         signal(SIGHUP, collhup);
  95:     savetstp = signal(SIGTSTP, collstop);
  96:     savettou = signal(SIGTTOU, collstop);
  97:     savettin = signal(SIGTTIN, collstop);
  98:     if (setjmp(collabort) || setjmp(colljmp)) {
  99:         rm(tempMail);
 100:         goto err;
 101:     }
 102:     sigsetmask(omask & ~(sigmask(SIGINT) | sigmask(SIGHUP)));
 103: 
 104:     noreset++;
 105:     if ((collf = Fopen(tempMail, "w+")) == NULL) {
 106:         perror(tempMail);
 107:         goto err;
 108:     }
 109:     unlink(tempMail);
 110: 
 111:     /*
 112: 	 * If we are going to prompt for a subject,
 113: 	 * refrain from printing a newline after
 114: 	 * the headers (since some people mind).
 115: 	 */
 116:     t = GTO|GSUBJECT|GCC|GNL;
 117:     getsub = 0;
 118:     if (hp->h_subject == NOSTR && value("interactive") != NOSTR &&
 119:         (value("ask") != NOSTR || value("asksub") != NOSTR))
 120:         t &= ~GNL, getsub++;
 121:     if (printheaders) {
 122:         puthead(hp, stdout, t);
 123:         fflush(stdout);
 124:     }
 125:     if ((cp = value("escape")) != NOSTR)
 126:         escape = *cp;
 127:     else
 128:         escape = ESCAPE;
 129:     eofcount = 0;
 130:     hadintr = 0;
 131: 
 132:     if (!setjmp(colljmp)) {
 133:         if (getsub)
 134:             grabh(hp, GSUBJECT);
 135:     } else {
 136:         /*
 137: 		 * Come here for printing the after-signal message.
 138: 		 * Duplicate messages won't be printed because
 139: 		 * the write is aborted if we get a SIGTTOU.
 140: 		 */
 141: cont:
 142:         if (hadintr) {
 143:             fflush(stdout);
 144:             fprintf(stderr,
 145:             "\n(Interrupt -- one more to kill letter)\n");
 146:         } else {
 147:             printf("(continue)\n");
 148:             fflush(stdout);
 149:         }
 150:     }
 151:     for (;;) {
 152:         colljmp_p = 1;
 153:         c = readline(stdin, linebuf, LINESIZE);
 154:         colljmp_p = 0;
 155:         if (c < 0) {
 156:             if (value("interactive") != NOSTR &&
 157:                 value("ignoreeof") != NOSTR && ++eofcount < 25) {
 158:                 printf("Use \".\" to terminate letter\n");
 159:                 continue;
 160:             }
 161:             break;
 162:         }
 163:         eofcount = 0;
 164:         hadintr = 0;
 165:         if (linebuf[0] == '.' && linebuf[1] == '\0' &&
 166:             value("interactive") != NOSTR &&
 167:             (value("dot") != NOSTR || value("ignoreeof") != NOSTR))
 168:             break;
 169:         if (linebuf[0] != escape || value("interactive") == NOSTR) {
 170:             if (putline(collf, linebuf) < 0)
 171:                 goto err;
 172:             continue;
 173:         }
 174:         c = linebuf[1];
 175:         switch (c) {
 176:         default:
 177:             /*
 178: 			 * On double escape, just send the single one.
 179: 			 * Otherwise, it's an error.
 180: 			 */
 181:             if (c == escape) {
 182:                 if (putline(collf, &linebuf[1]) < 0)
 183:                     goto err;
 184:                 else
 185:                     break;
 186:             }
 187:             printf("Unknown tilde escape.\n");
 188:             break;
 189:         case 'C':
 190:             /*
 191: 			 * Dump core.
 192: 			 */
 193:             core();
 194:             break;
 195:         case '!':
 196:             /*
 197: 			 * Shell escape, send the balance of the
 198: 			 * line to sh -c.
 199: 			 */
 200:             shell(&linebuf[2]);
 201:             break;
 202:         case ':':
 203:             /*
 204: 			 * Escape to command mode, but be nice!
 205: 			 */
 206:             execute(&linebuf[2], 1);
 207:             goto cont;
 208:         case '.':
 209:             /*
 210: 			 * Simulate end of file on input.
 211: 			 */
 212:             goto out;
 213:         case 'q':
 214:             /*
 215: 			 * Force a quit of sending mail.
 216: 			 * Act like an interrupt happened.
 217: 			 */
 218:             hadintr++;
 219:             collint(SIGINT);
 220:             exit(1);
 221:         case 'h':
 222:             /*
 223: 			 * Grab a bunch of headers.
 224: 			 */
 225:             grabh(hp, GTO|GSUBJECT|GCC|GBCC);
 226:             goto cont;
 227:         case 't':
 228:             /*
 229: 			 * Add to the To list.
 230: 			 */
 231:             hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO));
 232:             break;
 233:         case 's':
 234:             /*
 235: 			 * Set the Subject list.
 236: 			 */
 237:             cp = &linebuf[2];
 238:             while (isspace(*cp))
 239:                 cp++;
 240:             hp->h_subject = savestr(cp);
 241:             break;
 242:         case 'c':
 243:             /*
 244: 			 * Add to the CC list.
 245: 			 */
 246:             hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC));
 247:             break;
 248:         case 'b':
 249:             /*
 250: 			 * Add stuff to blind carbon copies list.
 251: 			 */
 252:             hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC));
 253:             break;
 254:         case 'd':
 255:             strcpy(linebuf + 2, getdeadletter());
 256:             /* fall into . . . */
 257:         case 'r':
 258:             /*
 259: 			 * Invoke a file:
 260: 			 * Search for the file name,
 261: 			 * then open it and copy the contents to collf.
 262: 			 */
 263:             cp = &linebuf[2];
 264:             while (isspace(*cp))
 265:                 cp++;
 266:             if (*cp == '\0') {
 267:                 printf("Interpolate what file?\n");
 268:                 break;
 269:             }
 270:             cp = expand(cp);
 271:             if (cp == NOSTR)
 272:                 break;
 273:             if (isdir(cp)) {
 274:                 printf("%s: Directory\n", cp);
 275:                 break;
 276:             }
 277:             if ((fbuf = Fopen(cp, "r")) == NULL) {
 278:                 perror(cp);
 279:                 break;
 280:             }
 281:             printf("\"%s\" ", cp);
 282:             fflush(stdout);
 283:             lc = 0;
 284:             cc = 0;
 285:             while (readline(fbuf, linebuf, LINESIZE) >= 0) {
 286:                 lc++;
 287:                 if ((t = putline(collf, linebuf)) < 0) {
 288:                     Fclose(fbuf);
 289:                     goto err;
 290:                 }
 291:                 cc += t;
 292:             }
 293:             Fclose(fbuf);
 294:             printf("%d/%ld\n", lc, cc);
 295:             break;
 296:         case 'w':
 297:             /*
 298: 			 * Write the message on a file.
 299: 			 */
 300:             cp = &linebuf[2];
 301:             while (*cp == ' ' || *cp == '\t')
 302:                 cp++;
 303:             if (*cp == '\0') {
 304:                 fprintf(stderr, "Write what file!?\n");
 305:                 break;
 306:             }
 307:             if ((cp = expand(cp)) == NOSTR)
 308:                 break;
 309:             rewind(collf);
 310:             exwrite(cp, collf, 1);
 311:             break;
 312:         case 'm':
 313:         case 'M':
 314:         case 'f':
 315:         case 'F':
 316:             /*
 317: 			 * Interpolate the named messages, if we
 318: 			 * are in receiving mail mode.  Does the
 319: 			 * standard list processing garbage.
 320: 			 * If ~f is given, we don't shift over.
 321: 			 */
 322:             if (forward(linebuf + 2, collf, c) < 0)
 323:                 goto err;
 324:             goto cont;
 325:         case '?':
 326:             if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) {
 327:                 perror(_PATH_TILDE);
 328:                 break;
 329:             }
 330:             while ((t = getc(fbuf)) != EOF)
 331:                 (void) putchar(t);
 332:             Fclose(fbuf);
 333:             break;
 334:         case 'p':
 335:             /*
 336: 			 * Print out the current state of the
 337: 			 * message without altering anything.
 338: 			 */
 339:             rewind(collf);
 340:             printf("-------\nMessage contains:\n");
 341:             puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL);
 342:             while ((t = getc(collf)) != EOF)
 343:                 (void) putchar(t);
 344:             goto cont;
 345:         case '|':
 346:             /*
 347: 			 * Pipe message through command.
 348: 			 * Collect output as new message.
 349: 			 */
 350:             rewind(collf);
 351:             mespipe(collf, &linebuf[2]);
 352:             goto cont;
 353:         case 'v':
 354:         case 'e':
 355:             /*
 356: 			 * Edit the current message.
 357: 			 * 'e' means to use EDITOR
 358: 			 * 'v' means to use VISUAL
 359: 			 */
 360:             rewind(collf);
 361:             mesedit(collf, c);
 362:             goto cont;
 363:         }
 364:     }
 365:     goto out;
 366: err:
 367:     if (collf != NULL) {
 368:         Fclose(collf);
 369:         collf = NULL;
 370:     }
 371: out:
 372:     if (collf != NULL)
 373:         rewind(collf);
 374:     noreset--;
 375:     sigblock(sigmask(SIGINT) | sigmask(SIGHUP));
 376:     signal(SIGINT, saveint);
 377:     signal(SIGHUP, savehup);
 378:     signal(SIGTSTP, savetstp);
 379:     signal(SIGTTOU, savettou);
 380:     signal(SIGTTIN, savettin);
 381:     sigsetmask(omask);
 382:     return collf;
 383: }
 384: 
 385: /*
 386:  * Write a file, ex-like if f set.
 387:  */
 388: 
 389: exwrite(name, fp, f)
 390:     char name[];
 391:     FILE *fp;
 392: {
 393:     register FILE *of;
 394:     register int c;
 395:     long cc;
 396:     int lc;
 397:     struct stat junk;
 398: 
 399:     if (f) {
 400:         printf("\"%s\" ", name);
 401:         fflush(stdout);
 402:     }
 403:     if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) {
 404:         if (!f)
 405:             fprintf(stderr, "%s: ", name);
 406:         fprintf(stderr, "File exists\n");
 407:         return(-1);
 408:     }
 409:     if ((of = Fopen(name, "w")) == NULL) {
 410:         perror(NOSTR);
 411:         return(-1);
 412:     }
 413:     lc = 0;
 414:     cc = 0;
 415:     while ((c = getc(fp)) != EOF) {
 416:         cc++;
 417:         if (c == '\n')
 418:             lc++;
 419:         (void) putc(c, of);
 420:         if (ferror(of)) {
 421:             perror(name);
 422:             Fclose(of);
 423:             return(-1);
 424:         }
 425:     }
 426:     Fclose(of);
 427:     printf("%d/%ld\n", lc, cc);
 428:     fflush(stdout);
 429:     return(0);
 430: }
 431: 
 432: /*
 433:  * Edit the message being collected on fp.
 434:  * On return, make the edit file the new temp file.
 435:  */
 436: mesedit(fp, c)
 437:     FILE *fp;
 438: {
 439:     sig_t sigint = signal(SIGINT, SIG_IGN);
 440:     FILE *nf = run_editor(fp, (off_t)-1, c, 0);
 441: 
 442:     if (nf != NULL) {
 443:         fseek(nf, (off_t)0, 2);
 444:         collf = nf;
 445:         Fclose(fp);
 446:     }
 447:     (void) signal(SIGINT, sigint);
 448: }
 449: 
 450: /*
 451:  * Pipe the message through the command.
 452:  * Old message is on stdin of command;
 453:  * New message collected from stdout.
 454:  * Sh -c must return 0 to accept the new message.
 455:  */
 456: mespipe(fp, cmd)
 457:     FILE *fp;
 458:     char cmd[];
 459: {
 460:     FILE *nf;
 461:     sig_t sigint = signal(SIGINT, SIG_IGN);
 462:     extern char tempEdit[];
 463: 
 464:     if ((nf = Fopen(tempEdit, "w+")) == NULL) {
 465:         perror(tempEdit);
 466:         goto out;
 467:     }
 468:     (void) unlink(tempEdit);
 469:     /*
 470: 	 * stdin = current message.
 471: 	 * stdout = new message.
 472: 	 */
 473:     if (run_command(cmd, 0L, fileno(fp), fileno(nf), NOSTR) < 0) {
 474:         (void) Fclose(nf);
 475:         goto out;
 476:     }
 477:     if (fsize(nf) == 0) {
 478:         fprintf(stderr, "No bytes from \"%s\" !?\n", cmd);
 479:         (void) Fclose(nf);
 480:         goto out;
 481:     }
 482:     /*
 483: 	 * Take new files.
 484: 	 */
 485:     (void) fseek(nf, 0L, 2);
 486:     collf = nf;
 487:     (void) Fclose(fp);
 488: out:
 489:     (void) signal(SIGINT, sigint);
 490: }
 491: 
 492: /*
 493:  * Interpolate the named messages into the current
 494:  * message, preceding each line with a tab.
 495:  * Return a count of the number of characters now in
 496:  * the message, or -1 if an error is encountered writing
 497:  * the message temporary.  The flag argument is 'm' if we
 498:  * should shift over and 'f' if not.
 499:  */
 500: forward(ms, fp, f)
 501:     char ms[];
 502:     FILE *fp;
 503: {
 504:     register int *msgvec;
 505:     extern char tempMail[];
 506:     struct ignoretab *ig;
 507:     char *tabst;
 508: 
 509:     msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec);
 510:     if (msgvec == (int *) NOSTR)
 511:         return(0);
 512:     if (getmsglist(ms, msgvec, 0) < 0)
 513:         return(0);
 514:     if (*msgvec == 0) {
 515:         *msgvec = first(0, MMNORM);
 516:         if (*msgvec == NULL) {
 517:             printf("No appropriate messages\n");
 518:             return(0);
 519:         }
 520:         msgvec[1] = NULL;
 521:     }
 522:     if (f == 'f' || f == 'F')
 523:         tabst = NOSTR;
 524:     else if ((tabst = value("indentprefix")) == NOSTR)
 525:         tabst = "\t";
 526:     ig = isupper(f) ? NULL : ignore;
 527:     printf("Interpolating:");
 528:     for (; *msgvec != 0; msgvec++) {
 529:         struct message *mp = message + *msgvec - 1;
 530: 
 531:         touch(mp);
 532:         printf(" %d", *msgvec);
 533:         if (send(mp, fp, ig, tabst) < 0) {
 534:             perror(tempMail);
 535:             return(-1);
 536:         }
 537:     }
 538:     printf("\n");
 539:     return(0);
 540: }
 541: 
 542: /*
 543:  * Print (continue) when continued after ^Z.
 544:  */
 545: /*ARGSUSED*/
 546: void
 547: collstop(s)
 548: {
 549:     sig_t old_action = signal(s, SIG_DFL);
 550: 
 551:     sigsetmask(sigblock(0L) & ~sigmask(s));
 552:     kill(0, s);
 553:     sigblock(sigmask(s));
 554:     signal(s, old_action);
 555:     if (colljmp_p) {
 556:         colljmp_p = 0;
 557:         hadintr = 0;
 558:         longjmp(colljmp, 1);
 559:     }
 560: }
 561: 
 562: /*
 563:  * On interrupt, come here to save the partial message in ~/dead.letter.
 564:  * Then jump out of the collection loop.
 565:  */
 566: /*ARGSUSED*/
 567: void
 568: collint(s)
 569: {
 570:     /*
 571: 	 * the control flow is subtle, because we can be called from ~q.
 572: 	 */
 573:     if (!hadintr) {
 574:         if (value("ignore") != NOSTR) {
 575:             puts("@");
 576:             fflush(stdout);
 577:             clearerr(stdin);
 578:             return;
 579:         }
 580:         hadintr = 1;
 581:         longjmp(colljmp, 1);
 582:     }
 583:     rewind(collf);
 584:     if (value("nosave") == NOSTR)
 585:         savedeadletter(collf);
 586:     longjmp(collabort, 1);
 587: }
 588: 
 589: /*ARGSUSED*/
 590: void
 591: collhup(s)
 592: {
 593:     rewind(collf);
 594:     savedeadletter(collf);
 595:     /*
 596: 	 * Let's pretend nobody else wants to clean up,
 597: 	 * a true statement at this time.
 598: 	 */
 599:     exit(1);
 600: }
 601: 
 602: savedeadletter(fp)
 603:     register FILE *fp;
 604: {
 605:     register FILE *dbuf;
 606:     register int c;
 607:     char *cp;
 608: 
 609:     if (fsize(fp) == 0)
 610:         return;
 611:     cp = getdeadletter();
 612:     c = umask(077);
 613:     dbuf = Fopen(cp, "a");
 614:     (void) umask(c);
 615:     if (dbuf == NULL)
 616:         return;
 617:     while ((c = getc(fp)) != EOF)
 618:         (void) putc(c, dbuf);
 619:     Fclose(dbuf);
 620:     rewind(fp);
 621: }

Defined functions

collect defined in line 71; used 2 times
collhup defined in line 590; used 2 times
collint defined in line 567; used 3 times
collstop defined in line 546; used 4 times
exwrite defined in line 389; used 1 times
forward defined in line 500; used 1 times
mesedit defined in line 436; used 1 times
mespipe defined in line 456; used 1 times
savedeadletter defined in line 602; used 4 times

Defined variables

collabort defined in line 69; used 2 times
colljmp defined in line 67; used 4 times
colljmp_p defined in line 68; used 4 times
hadintr defined in line 65; used 7 times
sccsid defined in line 35; never used
Last modified: 1993-02-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3897
Valid CSS Valid XHTML 1.0 Strict