home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / Mail / collect.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  12KB  |  704 lines

  1. /* Copyright (c) 1979 Regents of the University of California */
  2. #
  3.  
  4. /*
  5.  * Mail -- a mail program
  6.  *
  7.  * Collect input from standard input, handling
  8.  * ~ escapes.
  9.  */
  10.  
  11. #include "rcv.h"
  12. #include <sys/stat.h>
  13.  
  14. /*
  15.  * Read a message from standard output and return a read file to it
  16.  * or NULL on error.
  17.  */
  18.  
  19.  
  20. /*
  21.  * The following hokiness with global variables is so that on
  22.  * receipt of an interrupt signal, the partial message can be salted
  23.  * away on dead.letter.  The output file must be available to flush,
  24.  * and the input to read.  Several open files could be saved all through
  25.  * Mail if stdio allowed simultaneous read/write access.
  26.  */
  27.  
  28. static    int    (*savesig)();        /* Previous SIGINT value */
  29. static    FILE    *newi;            /* File for saving away */
  30. static    FILE    *newo;            /* Output side of same */
  31. static    int    hf;            /* Ignore interrups */
  32.  
  33. FILE *
  34. collect(hp)
  35.     struct header *hp;
  36. {
  37.     FILE *ibuf, *fbuf, *obuf;
  38.     int lc, cc, escape, collrub(), intack();
  39.     register int c, t;
  40.     char linebuf[LINESIZE], *cp;
  41.     extern char tempMail[];
  42.  
  43.     if (value("ignore") != NOSTR)
  44.         hf = 1;
  45.     else
  46.         hf = 0;
  47.     if ((savesig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
  48.         signal(SIGINT, hf ? intack : collrub);
  49.     newi = NULL;
  50.     newo = NULL;
  51.     if ((obuf = fopen(tempMail, "w")) == NULL) {
  52.         perror(tempMail);
  53.         goto err;
  54.     }
  55.     newo = obuf;
  56.     if ((ibuf = fopen(tempMail, "r")) == NULL) {
  57.         perror(tempMail);
  58.         newo = NULL;
  59.         fclose(obuf);
  60.         goto err;
  61.     }
  62.     newi = ibuf;
  63.     unlink(tempMail);
  64.     if (hp->h_seq != 0) {
  65.         puthead(hp, stdout);
  66.         fflush(stdout);
  67.     }
  68.     if (intty && hp->h_subj == NOSTR && value("ask"))
  69.         grabh(hp, GSUBJ);
  70.     escape = ESCAPE;
  71.     if ((cp = value("escape")) != NOSTR)
  72.         escape = *cp;
  73.     while (readline(stdin, linebuf) > 0) {
  74.         if (linebuf[0] != escape) {
  75.             if ((t = putline(obuf, linebuf)) < 0)
  76.                 goto err;
  77.             continue;
  78.         }
  79.         c = linebuf[1];
  80.         switch (c) {
  81.         default:
  82.             /*
  83.              * On double escape, just send the single one.
  84.              * Otherwise, it's an error.
  85.              */
  86.  
  87.             if (c == escape) {
  88.                 if (putline(obuf, &linebuf[1]) < 0)
  89.                     goto err;
  90.                 else
  91.                     break;
  92.             }
  93.             printf("Unknown tilde escape.\n");
  94.             break;
  95.  
  96.         case 'C':
  97.             /*
  98.              * Dump core.
  99.              */
  100.  
  101.             core();
  102.             break;
  103.  
  104.         case '!':
  105.             /*
  106.              * Shell escape, send the balance of the
  107.              * line to sh -c.
  108.              */
  109.  
  110.             shell(&linebuf[2]);
  111.             break;
  112.  
  113.         case '.':
  114.             /*
  115.              * Simulate end of file on input.
  116.              */
  117.             goto eof;
  118.  
  119.         case 'q':
  120.         case 'Q':
  121.             /*
  122.              * Force a quit of sending mail.
  123.              * Act like an interrupt happened.
  124.              */
  125.  
  126.             collrub(SIGINT);
  127.             exit(1);
  128.  
  129.         case 'h':
  130.             /*
  131.              * Grab a bunch of headers.
  132.              */
  133.             if (!intty || !outtty) {
  134.                 printf("~h: no can do!?\n");
  135.                 break;
  136.             }
  137.             grabh(hp, GTO|GSUBJ|GCC);
  138.             printf("(continue)\n");
  139.             break;
  140.  
  141.         case 't':
  142.             /*
  143.              * Add to the To list.
  144.              */
  145.  
  146.             hp->h_to = addto(hp->h_to, &linebuf[2]);
  147.             hp->h_seq++;
  148.             break;
  149.  
  150.         case 's':
  151.             /*
  152.              * Set the Subj list.
  153.              */
  154.  
  155.             cp = &linebuf[2];
  156.             while (any(*cp, " \t"))
  157.                 cp++;
  158.             hp->h_subj = savestr(cp);
  159.             hp->h_seq++;
  160.             break;
  161.  
  162.         case 'c':
  163.             /*
  164.              * Add to the CC list.
  165.              */
  166.  
  167.             hp->h_cc = addto(hp->h_cc, &linebuf[2]);
  168.             hp->h_seq++;
  169.             break;
  170.  
  171.         case 'd':
  172.             copy(deadletter, &linebuf[2]);
  173.             /* fall into . . . */
  174.  
  175.         case 'r':
  176.             /*
  177.              * Invoke a file:
  178.              * Search for the file name,
  179.              * then open it and copy the contents to obuf.
  180.              */
  181.  
  182.             cp = &linebuf[2];
  183.             while (any(*cp, " \t"))
  184.                 cp++;
  185.             if (*cp == '\0') {
  186.                 printf("Interpolate what file?\n");
  187.                 break;
  188.             }
  189.             if (isdir(cp)) {
  190.                 printf("%s: directory\n");
  191.                 break;
  192.             }
  193.             if ((fbuf = fopen(cp, "r")) == NULL) {
  194.                 perror(cp);
  195.                 break;
  196.             }
  197.             printf("\"%s\" ", cp);
  198.             flush();
  199.             lc = 0;
  200.             cc = 0;
  201.             while (readline(fbuf, linebuf) > 0) {
  202.                 lc++;
  203.                 if ((t = putline(obuf, linebuf)) < 0) {
  204.                     fclose(fbuf);
  205.                     goto err;
  206.                 }
  207.                 cc += t;
  208.             }
  209.             fclose(fbuf);
  210.             printf("%d/%d\n", lc, cc);
  211.             break;
  212.  
  213.         case 'w':
  214.             /*
  215.              * Write the message on a file.
  216.              */
  217.  
  218.             cp = &linebuf[2];
  219.             while (any(*cp, " \t"))
  220.                 cp++;
  221.             if (*cp == '\0') {
  222.                 fprintf(stderr, "Write what file!?\n");
  223.                 break;
  224.             }
  225.             fflush(obuf);
  226.             rewind(ibuf);
  227.             exwrite(cp, ibuf, 1);
  228.             break;
  229.  
  230.         case 'm':
  231.             /*
  232.              * Interpolate the named messages, if we
  233.              * are in receiving mail mode.  Does the
  234.              * standard list processing garbage.
  235.              */
  236.  
  237.             if (!rcvmode) {
  238.                 printf("No messages to send from!?!\n");
  239.                 break;
  240.             }
  241.             cp = &linebuf[2];
  242.             while (any(*cp, " \t"))
  243.                 cp++;
  244.             if (forward(cp, obuf) < 0)
  245.                 goto err;
  246.             printf("(continue)\n");
  247.             break;
  248.  
  249.         case '?':
  250.             if ((fbuf = fopen(THELPFILE, "r")) == NULL) {
  251.                 printf("No help just now.\n");
  252.                 break;
  253.             }
  254.             t = getc(fbuf);
  255.             while (t != -1) {
  256.                 putchar(t);
  257.                 t = getc(fbuf);
  258.             }
  259.             fclose(fbuf);
  260.             break;
  261.  
  262.         case 'p':
  263.             /*
  264.              * Print out the current state of the
  265.              * message without altering anything.
  266.              */
  267.  
  268.             fflush(obuf);
  269.             rewind(ibuf);
  270.             printf("-------\nMessage contains:\n");
  271.             puthead(hp, stdout);
  272.             t = getc(ibuf);
  273.             while (t != EOF) {
  274.                 putchar(t);
  275.                 t = getc(ibuf);
  276.             }
  277.             printf("(continue)\n");
  278.             break;
  279.  
  280.         case '^':
  281.         case '|':
  282.             /*
  283.              * Pipe message through command.
  284.              * Collect output as new message.
  285.              */
  286.  
  287.             obuf = mespipe(ibuf, obuf, &linebuf[2]);
  288.             newo = obuf;
  289.             ibuf = newi;
  290.             newi = ibuf;
  291.             printf("(continue)\n");
  292.             break;
  293.  
  294.         case 'v':
  295.         case 'e':
  296.             /*
  297.              * Edit the current message.
  298.              * 'e' means to use EDITOR
  299.              * 'v' means to use VISUAL
  300.              */
  301.  
  302.             if ((obuf = mesedit(ibuf, obuf, c)) == NULL)
  303.                 goto err;
  304.             newo = obuf;
  305.             ibuf = newi;
  306.             printf("(continue)\n");
  307.             break;
  308.             break;
  309.         }
  310.         flush();
  311.     }
  312. eof:
  313.     fclose(obuf);
  314.     rewind(ibuf);
  315.     signal(SIGINT, savesig);
  316.     return(ibuf);
  317.  
  318. err:
  319.     fclose(ibuf);
  320.     fclose(obuf);
  321.     signal(SIGINT, savesig);
  322.     return(NULL);
  323. }
  324.  
  325. /*
  326.  * Write a file, ex-like if f set.
  327.  */
  328.  
  329. exwrite(name, ibuf, f)
  330.     char name[];
  331.     FILE *ibuf;
  332. {
  333.     register FILE *of;
  334.     register int c;
  335.     long cc;
  336.     int lc;
  337.     struct stat junk;
  338.  
  339.     if (stat(name, &junk) >= 0) {
  340.         fprintf(stderr, "%s: File exists\n", name);
  341.         return(-1);
  342.     }
  343.     if ((of = fopen(name, "w")) == NULL) {
  344.         perror(name);
  345.         return(-1);
  346.     }
  347.     lc = 0;
  348.     cc = 0;
  349.     if (f) {
  350.         printf("\"%s\" ", name);
  351.         fflush(stdout);
  352.     }
  353.     while ((c = getc(ibuf)) != EOF) {
  354.         cc++;
  355.         if (c == '\n')
  356.             lc++;
  357.         putc(c, of);
  358.         if (ferror(of)) {
  359.             perror(name);
  360.             fclose(of);
  361.             return(-1);
  362.         }
  363.     }
  364.     fclose(of);
  365.     printf("%d/%ld\n", lc, cc);
  366.     fflush(stdout);
  367.     return(0);
  368. }
  369.  
  370. /*
  371.  * Edit the message being collected on ibuf and obuf.
  372.  * Write the message out onto some poorly-named temp file
  373.  * and point an editor at it.
  374.  *
  375.  * On return, make the edit file the new temp file.
  376.  */
  377.  
  378. FILE *
  379. mesedit(ibuf, obuf, c)
  380.     FILE *ibuf, *obuf;
  381. {
  382.     int pid, s;
  383.     FILE *fbuf;
  384.     register int t;
  385.     int (*sig)();
  386.     struct stat sbuf;
  387.     extern char tempMail[], tempEdit[];
  388.     register char *edit;
  389.  
  390.     sig = signal(SIGINT, SIG_IGN);
  391.     if (stat(tempEdit, &sbuf) >= 0) {
  392.         printf("%s: file exists\n", tempEdit);
  393.         goto out;
  394.     }
  395.     close(creat(tempEdit, 0600));
  396.     if ((fbuf = fopen(tempEdit, "w")) == NULL) {
  397.         perror(tempEdit);
  398.         goto out;
  399.     }
  400.     fflush(obuf);
  401.     rewind(ibuf);
  402.     t = getc(ibuf);
  403.     while (t != EOF) {
  404.         putc(t, fbuf);
  405.         t = getc(ibuf);
  406.     }
  407.     fflush(fbuf);
  408.     if (ferror(fbuf)) {
  409.         perror(tempEdit);
  410.         unlink(tempEdit);
  411.         goto fix;
  412.     }
  413.     fclose(fbuf);
  414.     pid = fork();
  415.     if (pid == 0) {
  416.         if (sig != SIG_IGN)
  417.             signal(SIGINT, SIG_DFL);
  418.         if ((edit = value(c == 'e' ? "EDITOR" : "VISUAL")) == NOSTR)
  419.             edit = c == 'e' ? EDITOR : VISUAL;
  420.         execl(edit, edit, tempEdit, 0);
  421.         perror(edit);
  422.         exit(1);
  423.     }
  424.     if (pid == -1) {
  425.         perror("fork");
  426.         unlink(tempEdit);
  427.         goto out;
  428.     }
  429.     while (wait(&s) != pid)
  430.         ;
  431.     if (s != 0) {
  432.         printf("Fatal error in \"%s\"\n", EDITOR);
  433.         unlink(tempEdit);
  434.         goto out;
  435.     }
  436.  
  437.     /*
  438.      * Now switch to new file.
  439.      */
  440.  
  441.     if ((fbuf = fopen(tempEdit, "a")) == NULL) {
  442.         perror(tempEdit);
  443.         unlink(tempEdit);
  444.         goto out;
  445.     }
  446.     if ((ibuf = fopen(tempEdit, "r")) == NULL) {
  447.         perror(tempEdit);
  448.         fclose(fbuf);
  449.         unlink(tempEdit);
  450.         goto out;
  451.     }
  452.     unlink(tempEdit);
  453.     fclose(obuf);
  454.     fclose(newi);
  455.     obuf = fbuf;
  456.     goto out;
  457. fix:
  458.     perror(tempEdit);
  459. out:
  460.     signal(SIGINT, sig);
  461.     newi = ibuf;
  462.     return(obuf);
  463. }
  464.  
  465. /*
  466.  * Pipe the message through the command.
  467.  * Old message is on stdin of command;
  468.  * New message collected from stdout.
  469.  * Sh -c must return 0 to accept the new message.
  470.  */
  471.  
  472. FILE *
  473. mespipe(ibuf, obuf, cmd)
  474.     FILE *ibuf, *obuf;
  475.     char cmd[];
  476. {
  477.     register FILE *ni, *no;
  478.     int pid, s;
  479.     int (*savesig)();
  480.     char *Shell;
  481.  
  482.     newi = ibuf;
  483.     if ((no = fopen(tempEdit, "w")) == NULL) {
  484.         perror(tempEdit);
  485.         return(obuf);
  486.     }
  487.     if ((ni = fopen(tempEdit, "r")) == NULL) {
  488.         perror(tempEdit);
  489.         fclose(no);
  490.         unlink(tempEdit);
  491.         return(obuf);
  492.     }
  493.     unlink(tempEdit);
  494.     savesig = signal(SIGINT, SIG_IGN);
  495.     fflush(obuf);
  496.     rewind(ibuf);
  497.     if ((Shell = value("SHELL")) == NULL)
  498.         Shell = "/bin/sh";
  499.     if ((pid = fork()) == -1) {
  500.         perror("fork");
  501.         goto err;
  502.     }
  503.     if (pid == 0) {
  504.         /*
  505.          * stdin = current message.
  506.          * stdout = new message.
  507.          */
  508.  
  509.         close(0);
  510.         dup(fileno(ibuf));
  511.         close(1);
  512.         dup(fileno(no));
  513.         for (s = 4; s < 15; s++)
  514.             close(s);
  515.         execl(Shell, Shell, "-c", cmd, 0);
  516.         perror(Shell);
  517.         exit(1);
  518.     }
  519.     while (wait(&s) != pid)
  520.         ;
  521.     if (s != 0) {
  522.         fprintf(stderr, "\"%s\" failed!?\n", cmd);
  523.         goto err;
  524.     }
  525.     if (fsize(ni) == 0) {
  526.         fprintf(stderr, "No bytes from \"%s\" !?\n", cmd);
  527.         goto err;
  528.     }
  529.  
  530.     /*
  531.      * Take new files.
  532.      */
  533.  
  534.     newi = ni;
  535.     fclose(ibuf);
  536.     fclose(obuf);
  537.     signal(SIGINT, savesig);
  538.     return(no);
  539.  
  540. err:
  541.     fclose(no);
  542.     fclose(ni);
  543.     signal(SIGINT, savesig);
  544.     return(obuf);
  545. }
  546.  
  547. /*
  548.  * Interpolate the named messages into the current
  549.  * message, preceding each line with a tab.
  550.  * Return a count of the number of characters now in
  551.  * the message, or -1 if an error is encountered writing
  552.  * the message temporary.
  553.  */
  554.  
  555. forward(ms, obuf)
  556.     char ms[];
  557.     FILE *obuf;
  558. {
  559.     register int *msgvec, *ip;
  560.     extern char tempMail[];
  561.  
  562.     msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec);
  563.     if (msgvec == (int *) NOSTR)
  564.         return(0);
  565.     if (getmsglist(ms, msgvec, 0) < 0)
  566.         return(0);
  567.     if (*msgvec == NULL) {
  568.         *msgvec = first(0, MMNORM);
  569.         if (*msgvec == NULL) {
  570.             printf("No appropriate messages\n");
  571.             return(0);
  572.         }
  573.         msgvec[1] = NULL;
  574.     }
  575.     printf("Interpolating:");
  576.     for (ip = msgvec; *ip != NULL; ip++) {
  577.         touch(*ip);
  578.         printf(" %d", *ip);
  579.         if (transmit(&message[*ip-1], obuf) < 0) {
  580.             perror(tempMail);
  581.             return(-1);
  582.         }
  583.     }
  584.     printf("\n");
  585.     return(0);
  586. }
  587.  
  588. /*
  589.  * Send message described by the passed pointer to the
  590.  * passed output buffer.  Insert a tab in front of each
  591.  * line.  Return a count of the characters sent, or -1
  592.  * on error.
  593.  */
  594.  
  595. transmit(mailp, obuf)
  596.     struct message *mailp;
  597.     FILE *obuf;
  598. {
  599.     register struct message *mp;
  600.     register int c, ch;
  601.     int n, bol;
  602.     FILE *ibuf;
  603.  
  604.     mp = mailp;
  605.     ibuf = setinput(mp);
  606.     c = msize(mp);
  607.     n = c;
  608.     bol = 1;
  609.     while (c-- > 0) {
  610.         if (bol) {
  611.             bol = 0;
  612.             putc('\t', obuf);
  613.             n++;
  614.             if (ferror(obuf)) {
  615.                 perror("/tmp");
  616.                 return(-1);
  617.             }
  618.         }
  619.         ch = getc(ibuf);
  620.         if (ch == '\n')
  621.             bol++;
  622.         putc(ch, obuf);
  623.         if (ferror(obuf)) {
  624.             perror("/tmp");
  625.             return(-1);
  626.         }
  627.     }
  628.     return(n);
  629. }
  630.  
  631. /*
  632.  * On interrupt, go here to save the partial
  633.  * message on #/dead.letter.
  634.  * Then restore signals and execute the normal
  635.  * signal routine.  We only come here if signals
  636.  * were previously set anyway.
  637.  */
  638.  
  639. collrub(s)
  640. {
  641.     register FILE *dbuf;
  642.     register int c;
  643.  
  644.     signal(SIGINT, SIG_IGN);
  645.     fclose(newo);
  646.     rewind(newi);
  647.     if (value("save") == NOSTR)
  648.         goto done;
  649.     if ((dbuf = fopen(deadletter, "w")) == NULL)
  650.         goto done;
  651.     chmod(deadletter, 0600);
  652.     while ((c = getc(newi)) != EOF)
  653.         putc(c, dbuf);
  654.     fclose(dbuf);
  655.  
  656. done:
  657.     fclose(newi);
  658.     signal(SIGINT, savesig);
  659.     if (rcvmode)
  660.         stop();
  661.     else
  662.         exit(1);
  663. }
  664.  
  665. /*
  666.  * Acknowledge an interrupt signal from the tty by typing an @
  667.  */
  668.  
  669. intack(s)
  670. {
  671.     
  672.     signal(SIGINT, SIG_IGN);
  673.     putchar('@');
  674.     fflush(stdout);
  675.     clearerr(stdin);
  676.     signal(SIGINT, intack);
  677. }
  678.  
  679. /*
  680.  * Add a string to the end of a header entry field.
  681.  */
  682.  
  683. char *
  684. addto(hf, news)
  685.     char hf[], news[];
  686. {
  687.     register char *cp, *cp2, *linebuf;
  688.  
  689.     if (hf == NOSTR)
  690.         hf = "";
  691.     linebuf = salloc(strlen(hf) + strlen(news) + 1);
  692.     for (cp = hf; any(*cp, " \t"); cp++)
  693.         ;
  694.     for (cp2 = linebuf; *cp;)
  695.         *cp2++ = *cp++;
  696.     *cp2++ = ' ';
  697.     for (cp = news; any(*cp, " \t"); cp++)
  698.         ;
  699.     while (*cp != '\0')
  700.         *cp2++ = *cp++;
  701.     *cp2 = '\0';
  702.     return(linebuf);
  703. }
  704.