home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / msgs / msgs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  16.9 KB  |  861 lines

  1. /*-
  2.  * Copyright (c) 1980 The 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. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1980 The Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)msgs.c    5.8 (Berkeley) 2/4/91";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * msgs - a user bulletin board program
  46.  *
  47.  * usage:
  48.  *    msgs [fhlopq] [[-]number]    to read messages
  49.  *    msgs -s                to place messages
  50.  *    msgs -c [-days]            to clean up the bulletin board
  51.  *
  52.  * prompt commands are:
  53.  *    y    print message
  54.  *    n    flush message, go to next message
  55.  *    q    flush message, quit
  56.  *    p    print message, turn on 'pipe thru more' mode
  57.  *    P    print message, turn off 'pipe thru more' mode
  58.  *    -    reprint last message
  59.  *    s[-][<num>] [<filename>]    save message
  60.  *    m[-][<num>]    mail with message in temp mbox
  61.  *    x    exit without flushing this message
  62.  *    <num>    print message number <num>
  63.  */
  64.  
  65. #define V7        /* will look for TERM in the environment */
  66. #define OBJECT        /* will object to messages without Subjects */
  67. /* #define REJECT    /* will reject messages without Subjects
  68.                (OBJECT must be defined also) */
  69. /* #define UNBUFFERED    /* use unbuffered output */
  70.  
  71. #include <sys/param.h>
  72. #include <sys/dir.h>
  73. #include <sys/stat.h>
  74. #include <ctype.h>
  75. #include <errno.h>
  76. #include <pwd.h>
  77. #include <setjmp.h>
  78. #include <sgtty.h>
  79. #include <signal.h>
  80. #include <stdio.h>
  81. #include <stdlib.h>
  82. #include <string.h>
  83. #include <time.h>
  84. #include "pathnames.h"
  85.  
  86. #define CMODE    0666        /* bounds file creation mode */
  87. #define NO    0
  88. #define YES    1
  89. #define SUPERUSER    0    /* superuser uid */
  90. #define DAEMON        1    /* daemon uid */
  91. #define NLINES    24        /* default number of lines/crt screen */
  92. #define NDAYS    21        /* default keep time for messages */
  93. #define DAYS    *24*60*60    /* seconds/day */
  94. #define MSGSRC    ".msgsrc"    /* user's rc file */
  95. #define BOUNDS    "bounds"    /* message bounds file */
  96. #define NEXT    "Next message? [yq]"
  97. #define MORE    "More? [ynq]"
  98. #define NOMORE    "(No more) [q] ?"
  99.  
  100. typedef    char    bool;
  101.  
  102. FILE    *msgsrc;
  103. FILE    *newmsg;
  104. char    *sep = "-";
  105. char    inbuf[BUFSIZ];
  106. char    fname[128];
  107. char    cmdbuf[128];
  108. char    subj[128];
  109. char    from[128];
  110. char    date[128];
  111. char    *ptr;
  112. char    *in;
  113. bool    local;
  114. bool    ruptible;
  115. bool    totty;
  116. bool    seenfrom;
  117. bool    seensubj;
  118. bool    blankline;
  119. bool    printing = NO;
  120. bool    mailing = NO;
  121. bool    quitit = NO;
  122. bool    sending = NO;
  123. bool    intrpflg = NO;
  124. int    uid;
  125. int    msg;
  126. int    prevmsg;
  127. int    lct;
  128. int    nlines;
  129. int    Lpp = 0;
  130. time_t    t;
  131. time_t    keep;
  132. struct    sgttyb    otty;
  133.  
  134. char    *mktemp();
  135. char    *nxtfld();
  136. void    onintr();
  137. void    onsusp();
  138.  
  139. /* option initialization */
  140. bool    hdrs = NO;
  141. bool    qopt = NO;
  142. bool    hush = NO;
  143. bool    send_msg = NO;
  144. bool    locomode = NO;
  145. bool    use_pager = NO;
  146. bool    clean = NO;
  147. bool    lastcmd = NO;
  148. jmp_buf    tstpbuf;
  149.  
  150. main(argc, argv)
  151. int argc; char *argv[];
  152. {
  153.     bool newrc, already;
  154.     int rcfirst = 0;        /* first message to print (from .rc) */
  155.     int rcback = 0;            /* amount to back off of rcfirst */
  156.     int firstmsg, nextmsg, lastmsg = 0;
  157.     int blast = 0;
  158.     FILE *bounds;
  159.  
  160. #ifdef UNBUFFERED
  161.     setbuf(stdout, NULL);
  162. #endif
  163.  
  164.     gtty(fileno(stdout), &otty);
  165.     time(&t);
  166.     setuid(uid = getuid());
  167.     ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL);
  168.     if (ruptible)
  169.         signal(SIGINT, SIG_DFL);
  170.  
  171.     argc--, argv++;
  172.     while (argc > 0) {
  173.         if (isdigit(argv[0][0])) {    /* starting message # */
  174.             rcfirst = atoi(argv[0]);
  175.         }
  176.         else if (isdigit(argv[0][1])) {    /* backward offset */
  177.             rcback = atoi( &( argv[0][1] ) );
  178.         }
  179.         else {
  180.             ptr = *argv;
  181.             while (*ptr) switch (*ptr++) {
  182.  
  183.             case '-':
  184.                 break;
  185.  
  186.             case 'c':
  187.                 if (uid != SUPERUSER && uid != DAEMON) {
  188.                     fprintf(stderr, "Sorry\n");
  189.                     exit(1);
  190.                 }
  191.                 clean = YES;
  192.                 break;
  193.  
  194.             case 'f':        /* silently */
  195.                 hush = YES;
  196.                 break;
  197.  
  198.             case 'h':        /* headers only */
  199.                 hdrs = YES;
  200.                 break;
  201.  
  202.             case 'l':        /* local msgs only */
  203.                 locomode = YES;
  204.                 break;
  205.  
  206.             case 'o':        /* option to save last message */
  207.                 lastcmd = YES;
  208.                 break;
  209.  
  210.             case 'p':        /* pipe thru 'more' during long msgs */
  211.                 use_pager = YES;
  212.                 break;
  213.  
  214.             case 'q':        /* query only */
  215.                 qopt = YES;
  216.                 break;
  217.  
  218.             case 's':        /* sending TO msgs */
  219.                 send_msg = YES;
  220.                 break;
  221.  
  222.             default:
  223.                 fprintf(stderr,
  224.                     "usage: msgs [fhlopq] [[-]number]\n");
  225.                 exit(1);
  226.             }
  227.         }
  228.         argc--, argv++;
  229.     }
  230.  
  231.     /*
  232.      * determine current message bounds
  233.      */
  234.     sprintf(fname, "%s/%s", _PATH_MSGS, BOUNDS);
  235.     bounds = fopen(fname, "r");
  236.  
  237.     if (bounds != NULL) {
  238.         fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg);
  239.         fclose(bounds);
  240.         blast = lastmsg;    /* save upper bound */
  241.     }
  242.  
  243.     if (clean)
  244.         keep = t - (rcback? rcback : NDAYS) DAYS;
  245.  
  246.     if (clean || bounds == NULL) {    /* relocate message bounds */
  247.         struct direct *dp;
  248.         struct stat stbuf;
  249.         bool seenany = NO;
  250.         DIR    *dirp;
  251.  
  252.         dirp = opendir(_PATH_MSGS);
  253.         if (dirp == NULL) {
  254.             perror(_PATH_MSGS);
  255.             exit(errno);
  256.         }
  257.  
  258.         firstmsg = 32767;
  259.         lastmsg = 0;
  260.  
  261.         for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){
  262.             register char *cp = dp->d_name;
  263.             register int i = 0;
  264.  
  265.             if (dp->d_ino == 0)
  266.                 continue;
  267.             if (dp->d_namlen == 0)
  268.                 continue;
  269.  
  270.             if (clean)
  271.                 sprintf(inbuf, "%s/%s", _PATH_MSGS, cp);
  272.  
  273.             while (isdigit(*cp))
  274.                 i = i * 10 + *cp++ - '0';
  275.             if (*cp)
  276.                 continue;    /* not a message! */
  277.  
  278.             if (clean) {
  279.                 if (stat(inbuf, &stbuf) != 0)
  280.                     continue;
  281.                 if (stbuf.st_mtime < keep
  282.                     && stbuf.st_mode&S_IWRITE) {
  283.                     unlink(inbuf);
  284.                     continue;
  285.                 }
  286.             }
  287.  
  288.             if (i > lastmsg)
  289.                 lastmsg = i;
  290.             if (i < firstmsg)
  291.                 firstmsg = i;
  292.             seenany = YES;
  293.         }
  294.         closedir(dirp);
  295.  
  296.         if (!seenany) {
  297.             if (blast != 0)    /* never lower the upper bound! */
  298.                 lastmsg = blast;
  299.             firstmsg = lastmsg + 1;
  300.         }
  301.         else if (blast > lastmsg)
  302.             lastmsg = blast;
  303.  
  304.         if (!send_msg) {
  305.             bounds = fopen(fname, "w");
  306.             if (bounds == NULL) {
  307.                 perror(fname);
  308.                 exit(errno);
  309.             }
  310.             chmod(fname, CMODE);
  311.             fprintf(bounds, "%d %d\n", firstmsg, lastmsg);
  312.             fclose(bounds);
  313.         }
  314.     }
  315.  
  316.     if (send_msg) {
  317.         /*
  318.          * Send mode - place msgs in _PATH_MSGS
  319.          */
  320.         bounds = fopen(fname, "w");
  321.         if (bounds == NULL) {
  322.             perror(fname);
  323.             exit(errno);
  324.         }
  325.  
  326.         nextmsg = lastmsg + 1;
  327.         sprintf(fname, "%s/%d", _PATH_MSGS, nextmsg);
  328.         newmsg = fopen(fname, "w");
  329.         if (newmsg == NULL) {
  330.             perror(fname);
  331.             exit(errno);
  332.         }
  333.         chmod(fname, 0644);
  334.  
  335.         fprintf(bounds, "%d %d\n", firstmsg, nextmsg);
  336.         fclose(bounds);
  337.  
  338.         sending = YES;
  339.         if (ruptible)
  340.             signal(SIGINT, onintr);
  341.  
  342.         if (isatty(fileno(stdin))) {
  343.             ptr = getpwuid(uid)->pw_name;
  344.             printf("Message %d:\nFrom %s %sSubject: ",
  345.                 nextmsg, ptr, ctime(&t));
  346.             fflush(stdout);
  347.             fgets(inbuf, sizeof inbuf, stdin);
  348.             putchar('\n');
  349.             fflush(stdout);
  350.             fprintf(newmsg, "From %s %sSubject: %s\n",
  351.                 ptr, ctime(&t), inbuf);
  352.             blankline = seensubj = YES;
  353.         }
  354.         else
  355.             blankline = seensubj = NO;
  356.         for (;;) {
  357.             fgets(inbuf, sizeof inbuf, stdin);
  358.             if (feof(stdin) || ferror(stdin))
  359.                 break;
  360.             blankline = (blankline || (inbuf[0] == '\n'));
  361.             seensubj = (seensubj || (!blankline && (strncmp(inbuf, "Subj", 4) == 0)));
  362.             fputs(inbuf, newmsg);
  363.         }
  364. #ifdef OBJECT
  365.         if (!seensubj) {
  366.             printf("NOTICE: Messages should have a Subject field!\n");
  367. #ifdef REJECT
  368.             unlink(fname);
  369. #endif
  370.             exit(1);
  371.         }
  372. #endif
  373.         exit(ferror(stdin));
  374.     }
  375.     if (clean)
  376.         exit(0);
  377.  
  378.     /*
  379.      * prepare to display messages
  380.      */
  381.     totty = (isatty(fileno(stdout)) != 0);
  382.     use_pager = use_pager && totty;
  383.  
  384.     sprintf(fname, "%s/%s", getenv("HOME"), MSGSRC);
  385.     msgsrc = fopen(fname, "r");
  386.     if (msgsrc) {
  387.         newrc = NO;
  388.         fscanf(msgsrc, "%d\n", &nextmsg);
  389.         fclose(msgsrc);
  390.         if (nextmsg > lastmsg+1) {
  391.             printf("Warning: bounds have been reset (%d, %d)\n",
  392.                 firstmsg, lastmsg);
  393.             truncate(fname, (off_t)0);
  394.             newrc = YES;
  395.         }
  396.         else if (!rcfirst)
  397.             rcfirst = nextmsg - rcback;
  398.     }
  399.     else
  400.         newrc = YES;
  401.     msgsrc = fopen(fname, "a");
  402.     if (msgsrc == NULL) {
  403.         perror(fname);
  404.         exit(errno);
  405.     }
  406.     if (rcfirst) {
  407.         if (rcfirst > lastmsg+1) {
  408.             printf("Warning: the last message is number %d.\n",
  409.                 lastmsg);
  410.             rcfirst = nextmsg;
  411.         }
  412.         if (rcfirst > firstmsg)
  413.             firstmsg = rcfirst;    /* don't set below first msg */
  414.     }
  415.     if (newrc) {
  416.         nextmsg = firstmsg;
  417.         fseek(msgsrc, 0L, 0);
  418.         fprintf(msgsrc, "%d\n", nextmsg);
  419.         fflush(msgsrc);
  420.     }
  421.  
  422. #ifdef V7
  423.     if (totty) {
  424.         struct winsize win;
  425.         if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1)
  426.             Lpp = win.ws_row;
  427.         if (Lpp <= 0) {
  428.             if (tgetent(inbuf, getenv("TERM")) <= 0
  429.                 || (Lpp = tgetnum("li")) <= 0) {
  430.                 Lpp = NLINES;
  431.             }
  432.         }
  433.     }
  434. #endif
  435.     Lpp -= 6;    /* for headers, etc. */
  436.  
  437.     already = NO;
  438.     prevmsg = firstmsg;
  439.     printing = YES;
  440.     if (ruptible)
  441.         signal(SIGINT, onintr);
  442.  
  443.     /*
  444.      * Main program loop
  445.      */
  446.     for (msg = firstmsg; msg <= lastmsg; msg++) {
  447.  
  448.         sprintf(fname, "%s/%d", _PATH_MSGS, msg);
  449.         newmsg = fopen(fname, "r");
  450.         if (newmsg == NULL)
  451.             continue;
  452.  
  453.         gfrsub(newmsg);        /* get From and Subject fields */
  454.         if (locomode && !local) {
  455.             fclose(newmsg);
  456.             continue;
  457.         }
  458.  
  459.         if (qopt) {    /* This has to be located here */
  460.             printf("There are new messages.\n");
  461.             exit(0);
  462.         }
  463.  
  464.         if (already && !hdrs)
  465.             putchar('\n');
  466.  
  467.         /*
  468.          * Print header
  469.          */
  470.         if (totty)
  471.             signal(SIGTSTP, onsusp);
  472.         (void) setjmp(tstpbuf);
  473.         already = YES;
  474.         nlines = 2;
  475.         if (seenfrom) {
  476.             printf("Message %d:\nFrom %s %s", msg, from, date);
  477.             nlines++;
  478.         }
  479.         if (seensubj) {
  480.             printf("Subject: %s", subj);
  481.             nlines++;
  482.         }
  483.         else {
  484.             if (seenfrom) {
  485.                 putchar('\n');
  486.                 nlines++;
  487.             }
  488.             while (nlines < 6
  489.                 && fgets(inbuf, sizeof inbuf, newmsg)
  490.                 && inbuf[0] != '\n') {
  491.                 fputs(inbuf, stdout);
  492.                 nlines++;
  493.             }
  494.         }
  495.  
  496.         lct = linecnt(newmsg);
  497.         if (lct)
  498.             printf("(%d%slines) ", lct, seensubj? " " : " more ");
  499.  
  500.         if (hdrs) {
  501.             printf("\n-----\n");
  502.             fclose(newmsg);
  503.             continue;
  504.         }
  505.  
  506.         /*
  507.          * Ask user for command
  508.          */
  509.         if (totty)
  510.             ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT));
  511.         else
  512.             inbuf[0] = 'y';
  513.         if (totty)
  514.             signal(SIGTSTP, SIG_DFL);
  515. cmnd:
  516.         in = inbuf;
  517.         switch (*in) {
  518.             case 'x':
  519.             case 'X':
  520.                 exit(0);
  521.  
  522.             case 'q':
  523.             case 'Q':
  524.                 quitit = YES;
  525.                 printf("--Postponed--\n");
  526.                 exit(0);
  527.                 /* intentional fall-thru */
  528.             case 'n':
  529.             case 'N':
  530.                 if (msg >= nextmsg) sep = "Flushed";
  531.                 prevmsg = msg;
  532.                 break;
  533.  
  534.             case 'p':
  535.             case 'P':
  536.                 use_pager = (*in++ == 'p');
  537.                 /* intentional fallthru */
  538.             case '\n':
  539.             case 'y':
  540.             default:
  541.                 if (*in == '-') {
  542.                     msg = prevmsg-1;
  543.                     sep = "replay";
  544.                     break;
  545.                 }
  546.                 if (isdigit(*in)) {
  547.                     msg = next(in);
  548.                     sep = in;
  549.                     break;
  550.                 }
  551.  
  552.                 prmesg(nlines + lct + (seensubj? 1 : 0));
  553.                 prevmsg = msg;
  554.  
  555.         }
  556.  
  557.         printf("--%s--\n", sep);
  558.         sep = "-";
  559.         if (msg >= nextmsg) {
  560.             nextmsg = msg + 1;
  561.             fseek(msgsrc, 0L, 0);
  562.             fprintf(msgsrc, "%d\n", nextmsg);
  563.             fflush(msgsrc);
  564.         }
  565.         if (newmsg)
  566.             fclose(newmsg);
  567.         if (quitit)
  568.             break;
  569.     }
  570.  
  571.     /*
  572.      * Make sure .rc file gets updated
  573.      */
  574.     if (--msg >= nextmsg) {
  575.         nextmsg = msg + 1;
  576.         fseek(msgsrc, 0L, 0);
  577.         fprintf(msgsrc, "%d\n", nextmsg);
  578.         fflush(msgsrc);
  579.     }
  580.     if (already && !quitit && lastcmd && totty) {
  581.         /*
  582.          * save or reply to last message?
  583.          */
  584.         msg = prevmsg;
  585.         ask(NOMORE);
  586.         if (inbuf[0] == '-' || isdigit(inbuf[0]))
  587.             goto cmnd;
  588.     }
  589.     if (!(already || hush || qopt))
  590.         printf("No new messages.\n");
  591.     exit(0);
  592. }
  593.  
  594. prmesg(length)
  595. int length;
  596. {
  597.     FILE *outf;
  598.  
  599.     if (use_pager && length > Lpp) {
  600.         signal(SIGPIPE, SIG_IGN);
  601.         signal(SIGQUIT, SIG_IGN);
  602.         sprintf(cmdbuf, _PATH_PAGER, Lpp);
  603.         outf = popen(cmdbuf, "w");
  604.         if (!outf)
  605.             outf = stdout;
  606.         else
  607.             setbuf(outf, (char *)NULL);
  608.     }
  609.     else
  610.         outf = stdout;
  611.  
  612.     if (seensubj)
  613.         putc('\n', outf);
  614.  
  615.     while (fgets(inbuf, sizeof inbuf, newmsg)) {
  616.         fputs(inbuf, outf);
  617.         if (ferror(outf)) {
  618.             clearerr(outf);
  619.             break;
  620.         }
  621.     }
  622.  
  623.     if (outf != stdout) {
  624.         pclose(outf);
  625.         signal(SIGPIPE, SIG_DFL);
  626.         signal(SIGQUIT, SIG_DFL);
  627.     }
  628.     else {
  629.         fflush(stdout);
  630.     }
  631.  
  632.     /* trick to force wait on output */
  633.     stty(fileno(stdout), &otty);
  634. }
  635.  
  636. void
  637. onintr()
  638. {
  639.     signal(SIGINT, onintr);
  640.     if (mailing)
  641.         unlink(fname);
  642.     if (sending) {
  643.         unlink(fname);
  644.         puts("--Killed--");
  645.         exit(1);
  646.     }
  647.     if (printing) {
  648.         putchar('\n');
  649.         if (hdrs)
  650.             exit(0);
  651.         sep = "Interrupt";
  652.         if (newmsg)
  653.             fseek(newmsg, 0L, 2);
  654.         intrpflg = YES;
  655.     }
  656. }
  657.  
  658. /*
  659.  * We have just gotten a susp.  Suspend and prepare to resume.
  660.  */
  661. void
  662. onsusp()
  663. {
  664.  
  665.     signal(SIGTSTP, SIG_DFL);
  666.     sigsetmask(0);
  667.     kill(0, SIGTSTP);
  668.     signal(SIGTSTP, onsusp);
  669.     if (!mailing)
  670.         longjmp(tstpbuf, 0);
  671. }
  672.  
  673. linecnt(f)
  674. FILE *f;
  675. {
  676.     off_t oldpos = ftell(f);
  677.     int l = 0;
  678.     char lbuf[BUFSIZ];
  679.  
  680.     while (fgets(lbuf, sizeof lbuf, f))
  681.         l++;
  682.     clearerr(f);
  683.     fseek(f, oldpos, 0);
  684.     return (l);
  685. }
  686.  
  687. next(buf)
  688. char *buf;
  689. {
  690.     int i;
  691.     sscanf(buf, "%d", &i);
  692.     sprintf(buf, "Goto %d", i);
  693.     return(--i);
  694. }
  695.  
  696. ask(prompt)
  697. char *prompt;
  698. {
  699.     char    inch;
  700.     int    n, cmsg;
  701.     off_t    oldpos;
  702.     FILE    *cpfrom, *cpto;
  703.  
  704.     printf("%s ", prompt);
  705.     fflush(stdout);
  706.     intrpflg = NO;
  707.     (void) fgets(inbuf, sizeof inbuf, stdin);
  708.     if ((n = strlen(inbuf)) > 0 && inbuf[n - 1] == '\n')
  709.         inbuf[n - 1] = '\0';
  710.     if (intrpflg)
  711.         inbuf[0] = 'x';
  712.  
  713.     /*
  714.      * Handle 'mail' and 'save' here.
  715.      */
  716.     if ((inch = inbuf[0]) == 's' || inch == 'm') {
  717.         if (inbuf[1] == '-')
  718.             cmsg = prevmsg;
  719.         else if (isdigit(inbuf[1]))
  720.             cmsg = atoi(&inbuf[1]);
  721.         else
  722.             cmsg = msg;
  723.         sprintf(fname, "%s/%d", _PATH_MSGS, cmsg);
  724.  
  725.         oldpos = ftell(newmsg);
  726.  
  727.         cpfrom = fopen(fname, "r");
  728.         if (!cpfrom) {
  729.             printf("Message %d not found\n", cmsg);
  730.             ask (prompt);
  731.             return;
  732.         }
  733.  
  734.         if (inch == 's') {
  735.             in = nxtfld(inbuf);
  736.             if (*in) {
  737.                 for (n=0; in[n] > ' '; n++) { /* sizeof fname? */
  738.                     fname[n] = in[n];
  739.                 }
  740.                 fname[n] = NULL;
  741.             }
  742.             else
  743.                 strcpy(fname, "Messages");
  744.         }
  745.         else {
  746.             strcpy(fname, _PATH_TMP);
  747.             mktemp(fname);
  748.             sprintf(cmdbuf, _PATH_MAIL, fname);
  749.             mailing = YES;
  750.         }
  751.         cpto = fopen(fname, "a");
  752.         if (!cpto) {
  753.             perror(fname);
  754.             mailing = NO;
  755.             fseek(newmsg, oldpos, 0);
  756.             ask(prompt);
  757.             return;
  758.         }
  759.  
  760.         while (n = fread(inbuf, 1, sizeof inbuf, cpfrom))
  761.             fwrite(inbuf, 1, n, cpto);
  762.  
  763.         fclose(cpfrom);
  764.         fclose(cpto);
  765.         fseek(newmsg, oldpos, 0);    /* reposition current message */
  766.         if (inch == 's')
  767.             printf("Message %d saved in \"%s\"\n", cmsg, fname);
  768.         else {
  769.             system(cmdbuf);
  770.             unlink(fname);
  771.             mailing = NO;
  772.         }
  773.         ask(prompt);
  774.     }
  775. }
  776.  
  777. gfrsub(infile)
  778. FILE *infile;
  779. {
  780.     off_t frompos;
  781.  
  782.     seensubj = seenfrom = NO;
  783.     local = YES;
  784.     subj[0] = from[0] = date[0] = NULL;
  785.  
  786.     /*
  787.      * Is this a normal message?
  788.      */
  789.     if (fgets(inbuf, sizeof inbuf, infile)) {
  790.         if (strncmp(inbuf, "From", 4)==0) {
  791.             /*
  792.              * expected form starts with From
  793.              */
  794.             seenfrom = YES;
  795.             frompos = ftell(infile);
  796.             ptr = from;
  797.             in = nxtfld(inbuf);
  798.             if (*in) while (*in && *in > ' ') {
  799.                 if (*in == ':' || *in == '@' || *in == '!')
  800.                     local = NO;
  801.                 *ptr++ = *in++;
  802.                 /* what about sizeof from ? */
  803.             }
  804.             *ptr = NULL;
  805.             if (*(in = nxtfld(in)))
  806.                 strncpy(date, in, sizeof date);
  807.             else {
  808.                 date[0] = '\n';
  809.                 date[1] = NULL;
  810.             }
  811.         }
  812.         else {
  813.             /*
  814.              * not the expected form
  815.              */
  816.             fseek(infile, 0L, 0);
  817.             return;
  818.         }
  819.     }
  820.     else
  821.         /*
  822.          * empty file ?
  823.          */
  824.         return;
  825.  
  826.     /*
  827.      * look for Subject line until EOF or a blank line
  828.      */
  829.     while (fgets(inbuf, sizeof inbuf, infile)
  830.         && !(blankline = (inbuf[0] == '\n'))) {
  831.         /*
  832.          * extract Subject line
  833.          */
  834.         if (!seensubj && strncmp(inbuf, "Subj", 4)==0) {
  835.             seensubj = YES;
  836.             frompos = ftell(infile);
  837.             strncpy(subj, nxtfld(inbuf), sizeof subj);
  838.         }
  839.     }
  840.     if (!blankline)
  841.         /*
  842.          * ran into EOF
  843.          */
  844.         fseek(infile, frompos, 0);
  845.  
  846.     if (!seensubj)
  847.         /*
  848.          * for possible use with Mail
  849.          */
  850.         strncpy(subj, "(No Subject)\n", sizeof subj);
  851. }
  852.  
  853. char *
  854. nxtfld(s)
  855. char *s;
  856. {
  857.     if (*s) while (*s && *s > ' ') s++;    /* skip over this field */
  858.     if (*s) while (*s && *s <= ' ') s++;    /* find start of next field */
  859.     return (s);
  860. }
  861.