# 2.11BSD#431 - /usr/src/ucb/Mail/collect.c

##### Functions

    collect           X
    collhup           X
    collint           X
    collstop          X
    exwrite           X
    forward           X
    mesedit           X
    mespipe           X
    savedeadletter    X

       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

- in /usr/src/ucb/Mail/def.h line 277
- in /usr/src/ucb/Mail/send.c line 301

collhup defined in line 590; used 2 times

- in line 83, 94

collint defined in line 567; used 3 times

- in line 83, 92, 219

collstop defined in line 546; used 4 times

- in line 83, 95-97(3)

exwrite defined in line 389; used 1 times

- in line 310

forward defined in line 500; used 1 times

- in line 322

mesedit defined in line 436; used 1 times

- in line 361

mespipe defined in line 456; used 1 times

- in line 351

savedeadletter defined in line 602; used 4 times

- in line 585, 594
- in /usr/src/ucb/Mail/send.c line 332, 361

#### Defined variables

collabort defined in line 69; used 2 times

- in line 98, 586

colljmp defined in line 67; used 4 times

- in line 98, 132, 558, 581

colljmp_p defined in line 68; used 4 times

- in line 152-154(2), 555-556(2)

hadintr defined in line 65; used 7 times

- in line 130, 142, 164, 218, 557, 573, 580

sccsid defined in line 35; never used

Last modified: 1993-02-14 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1334 |