home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / UUCPbb_2_1_src.lzh / UUCPBB21 / recvmail.c < prev    next >
Text File  |  1994-09-25  |  38KB  |  1,272 lines

  1. /*  recvmail.c   This routine allows a user to read his/her mail.
  2.     Copyright (C) 1990, 1993  Rick Adams and Bob Billson
  3.  
  4.     This file is part of the OS-9 UUCP package, UUCPbb.
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     The author of UUCPbb, Bob Billson, can be contacted at:
  21.     bob@kc2wz.bubble.org  or  uunet!kc2wz!bob  or  by snail mail:
  22.     21 Bates Way, Westfield, NJ 07090
  23. */
  24.  
  25. /* Rewritten to support new spooled mail format.  Mail is kept as separate
  26.    files in the directory pointed to by the parameter 'maildir' in the
  27.    /DD/SYS/UUCP/Parameters file.  Each file is named 'mYYMMDDHHMMSS', where
  28.    'YYMMDDHHMMSS' is the date/time RMAIL processed the message  --REB */
  29.  
  30. #include "uucp.h"
  31. #include "mail.h"
  32. #include <ctype.h>
  33. #include <modes.h>
  34. #include <direct.h>                              /* Added - BAS */
  35. #include <sgstat.h>
  36. #ifndef _OSK
  37. #include <os9.h>
  38. #include "dir_6809.h"
  39. #else
  40. #include <dir.h>
  41. #endif
  42.  
  43. #define WORDSIZE   40
  44.  
  45.  
  46. char dspmail(), getresponse();
  47. void givehelp();
  48.  
  49.  
  50. int recvmail (fifo)
  51. flag fifo;
  52. {
  53.      flag dothis, direction;
  54.      int numltrs, ltrsleft;
  55.      register MAILPTR envelop;
  56.      MAILPTR firstenvelop = NULL;
  57.      struct mailbag *whatnow(), *reverselist(), *gathermail();
  58.  
  59.      /* Check waiting for mail.  Exit if there is none.  When we return our
  60.         current data directory will be our mailbox directory. */
  61.  
  62.      if ((numltrs = ltrsleft = checkmail (FALSE, user)) == 0)
  63.           exit (0);
  64.  
  65.      firstenvelop = gathermail (numltrs);
  66.  
  67.      if (!fifo)
  68.           firstenvelop = reverselist (firstenvelop);
  69.  
  70.      /* Open each letter and read it.  Then decide if we want to: save,
  71.         delete, undelete, redisplay, move to the next or previous letter. */
  72.  
  73.      envelop = firstenvelop;
  74.      direction = FORWARD;
  75.      do
  76.           switch (dothis = openenvelop (envelop))
  77.             {
  78.                case ALLREAD:
  79.                     markallmail (firstenvelop, TRUE);
  80.                     break;
  81.  
  82.                case KILLMAIL:
  83.                     markallmail (firstenvelop, FALSE);
  84.                     ltrsleft = 0;
  85.  
  86.                case QUIT:
  87.                     envelop = ENDMAIL;
  88.                     break;
  89.  
  90.                case UNDELETE:
  91.                     undeletemail (firstenvelop, <rsleft);
  92.                     break;
  93.  
  94.                case DELETE:
  95.                     --ltrsleft;
  96.  
  97.                default:
  98.                     envelop = whatnow (dothis, envelop, &direction);
  99.                     break;
  100.             }
  101.      while (envelop != ENDMAIL);
  102.  
  103.      if (!fifo)
  104.           firstenvelop = reverselist (firstenvelop);
  105.  
  106.      if (ltrsleft < numltrs)
  107.           fputs ("\b \bremoving deleted mail...", stdout);
  108.  
  109.      fflush (stdout);
  110. #ifndef _OSK
  111.      loadpager (FALSE);
  112. #endif
  113.  
  114.      if (rmailin)
  115.           munload (rmail, 0);
  116.  
  117.      updatemail_list (firstenvelop, ltrsleft);
  118.      free (firstenvelop);
  119. }
  120.  
  121.  
  122.  
  123. /* Create a double-linked list of all the mail.  Return a pointer to the start
  124.    of the list.   */
  125.  
  126. struct mailbag *gathermail (numltrs)
  127. int numltrs;
  128. {
  129.      char mailine[MLINE];
  130.      register MAILPTR ep;
  131.      FILE *mlptr;
  132.      char *p, *p1;
  133.      MAILPTR elast, envelops;
  134.      int newmail, unreadmail;
  135.  
  136.      if ((mlptr = fopen (mail_list, "r")) == NULL)
  137.           fatal ("gathermail: can't open user's mail..list");
  138.  
  139.      /* create a double-linked list of pointers to each line in mail..list */
  140.      envelops = (MAILPTR) malloc (numltrs * sizeof (MAILBAG));
  141.      
  142.      if (envelops == NULL)
  143.           fatal ("gathermail: can't malloc envelops array");
  144.  
  145.      /* make forward and backward links */
  146.      ep = envelops;
  147.      elast = envelops + numltrs;
  148.      do
  149.        {
  150.           if (ep < elast - 1)
  151.                ep->next = ep + 1;                    /* next envelop or... */
  152.           else
  153.                ep->next = ENDMAIL;                   /* ...end of list */
  154.  
  155.           if (ep != envelops)
  156.                ep->prev = ep - 1;                    /* everything else... */
  157.           else
  158.                ep->prev = ENDMAIL;                   /* ...or first envelop */
  159.        }
  160.      while (++ep < elast);
  161.  
  162.      newmail = unreadmail = 0;
  163.      ep = envelops;
  164.      while (mfgets (mailine, MLINE, mlptr) != NULL)
  165.        {
  166.           /* save the individual mail..list line and point to the fields */
  167.           ep->mline = p1 = strdup (mailine);
  168.  
  169.           if (ep->mline == NULL)
  170.                fatal ("recvmail: can't malloc mail..list line");
  171.  
  172.           /* status */
  173.           ep->status = *p1++;
  174.  
  175.           if (ep->status == 'N')
  176.                ++newmail;
  177.           else if (ep->status == 'U')
  178.                ++unreadmail;
  179.  
  180.           /* file name */
  181.           p = strchr (p1, '|');
  182.           *p = '\0';
  183.           ep->letter = p1;
  184.           ++ep;
  185.        }
  186.      fclose (mlptr);
  187.  
  188.      if (newmail || unreadmail)
  189.        {
  190.           printf ("\nOS-9 Mailx v%s    %d message%s",
  191.                      version, numltrs, numltrs > 0 ? "s" : "");
  192.  
  193.           if (newmail)
  194.                printf ("    %d new", newmail);
  195.  
  196.           if (unreadmail)
  197.                printf ("    %d unread", unreadmail + newmail);
  198.  
  199.           fputs ("\n\nhit <ENTER> to continue...", stdout);
  200.           fflush (stdout);
  201.           getresponse();
  202.           cls();
  203.        }
  204.      return (envelops);
  205. }
  206.  
  207.  
  208.  
  209. /* reverse the order of a double-linked list --REB */
  210.  
  211. struct mailbag *reverselist (list)
  212. MAILPTR list;
  213. {
  214.      register MAILPTR p1;
  215.      MAILPTR p2;
  216.  
  217.      p2 = ENDMAIL;
  218.      while (list)
  219.        {
  220.           p1 = list;
  221.           list = p1->next;
  222.           p1->prev = p1->next;
  223.           p1->next = p2;
  224.           p2 = p1;
  225.        }
  226.      return (p2);
  227. }
  228.  
  229.  
  230.  
  231. struct mailbag *whatnow (whichway, envelop, direction)
  232. flag whichway, *direction;
  233. register MAILPTR envelop;
  234. {
  235.      MAILPTR tmpmail;
  236.  
  237.      tmpmail = envelop;
  238.      switch (whichway)
  239.        {
  240.           case DELETE:                 /* toss letter/envelop, update links */
  241.                envelop->status = 'D';
  242.                whichway = *direction == FORWARD ? NEXT : PREVIOUS;
  243.  
  244.           case NEXT:                               /* move to next message */
  245.                do
  246.                     if ((envelop = envelop->next) == ENDMAIL)
  247.                       {
  248.                          if ( !quitmail() )
  249.                               envelop = tmpmail;
  250.                          break;
  251.                       }
  252.                while (envelop->status == 'D'  ||  envelop->status == 'B');
  253.  
  254.                *direction = FORWARD;
  255.                break;
  256.  
  257.           case PREVIOUS:                              /* show last message */
  258.                do
  259.                     if ((envelop = envelop->prev) == ENDMAIL)
  260.                       {
  261.                          envelop = tmpmail;
  262.                          break;
  263.                       }
  264.                while (envelop->status == 'D' ||  envelop->status == 'B');
  265.  
  266.                *direction = REVERSE;
  267.                break;
  268.  
  269.           case BADLETTER:             /* damaged letter or header, skip it */
  270.                envelop->status = 'B';
  271.                envelop = *direction == FORWARD ? envelop->next != ENDMAIL
  272.                                                     ? envelop->next : envelop
  273.                                                : envelop->next != ENDMAIL
  274.                                                     ? envelop->prev : envelop;
  275.                break;
  276.  
  277.           case AGAIN:                        /* show current message again */
  278.           default:
  279.                break;
  280.        }
  281.      return (envelop);
  282. }
  283.  
  284.  
  285.  
  286. /* mark all mail as either all read or all deleted.  If KILLMAIL is TRUE, all
  287.    mail will be deleted and mail will exit immediately.  Therefore, killed
  288.    mail cannot be restored with the 'x' or 'u' commands. --REB */
  289.  
  290. int markallmail (firstenvelop, nokilli)
  291. MAILPTR firstenvelop;
  292. flag nokilli;
  293. {
  294.      register MAILPTR envelop;
  295.  
  296.      for (envelop = firstenvelop;  envelop;  envelop = envelop->next)
  297.           envelop->status = nokilli ? 'P' : 'D';
  298. }
  299.  
  300.  
  301.  
  302. /* make mail we deleted in this session readable again */
  303.  
  304. int undeletemail (firstenvelop, ltrsleft)
  305. MAILPTR firstenvelop;
  306. int *ltrsleft;
  307. {
  308.      char line[256];
  309.      MAILPTR envelop;
  310.      register char *p;
  311.      char c;
  312.      FILE *fp;
  313.      int i;
  314.  
  315.      p = line;
  316.      envelop = firstenvelop;
  317.      do
  318.           if (envelop->status == 'D')
  319.                if ((fp = fopen (envelop->letter, "r")) != NULL)
  320.                  {
  321.                     /* print header... */
  322.                     cls();
  323.  
  324.                     while (mfgets (p, sizeof (line), fp) != NULL)
  325.                       {
  326.                          if (!*p)
  327.                               break;
  328.  
  329.                          puts (p);
  330.                       }
  331.  
  332.                     /* ...and first four lines of message */
  333.                     putchar ('\n');
  334.  
  335.                     for (i = 0; i < 4; ++i)
  336.                          if (mfgets (p, sizeof (line), fp) == NULL)
  337.                               break;
  338.                          else
  339.                               puts (p);
  340.  
  341.                     fclose (fp);
  342.                     fputs ("\n\nUndelete this or resume reading?   Y/n/r...",
  343.                             stdout);
  344.  
  345.                     fflush (stdout);
  346.                     c = tolower ( getresponse() );
  347.                     switch (c)
  348.                       {
  349.                          case 'r':
  350.                               return (0);
  351.  
  352.                          case 'n':
  353.                               break;
  354.  
  355.                          case 'y':
  356.                          default:
  357.                               envelop->status = 'P';
  358.                               ++(*ltrsleft);
  359.                               break;
  360.                       }
  361.                }
  362.      while ((envelop = envelop->next) != ENDMAIL);
  363.  
  364.      fputs ("\n\nHit ENTER to read mail...", stdout);
  365.      fflush (stdout);
  366.      getresponse();
  367.      return (0);
  368. }
  369.  
  370.  
  371.  
  372. /* returns TRUE if user wants to exit after reading last message --REB */
  373.  
  374. int quitmail()
  375. {
  376.      register char c;
  377.      char answer;
  378.  
  379.      putchar ('\n');
  380.      ReVOn();
  381.      fputs (" Last message...quit?  y/N ", stdout);
  382.      ReVOff();
  383.      c = tolower ( getresponse() );
  384.      CurUp();
  385.      putchar ('\n');
  386.      ErEOLine();
  387.      CurUp();
  388.      putchar ('\n');
  389.  
  390.      if (c == 'y')
  391.        {
  392.           putchar (' ');
  393.           fflush (stdout);
  394.        }
  395.      return (c == 'y' ? TRUE : FALSE);
  396. }
  397.  
  398.  
  399.  
  400. int openenvelop (envelop)
  401. MAILPTR envelop;
  402. {
  403.      FILE *infile;
  404.      flag whichway;
  405.      register char c;
  406.  
  407.      if ((infile = fopen (envelop->letter, "r")) == NULL)
  408.        {
  409.           printf ("\n%s: glue too strong...can't open '%s'\n",
  410.                   pname, envelop->letter);
  411.  
  412.           /* give 'em a chance to read */
  413.           sleep (2);
  414.  
  415.           /* letter disappear on us?  remove it from mail..list */
  416.           return (errno == 216 ? DELETE : BADLETTER);
  417.        }
  418.  
  419.      /* display incoming mail */
  420.      if (getmsg (infile))
  421.        {
  422.           if (usepager)
  423.             {
  424.                sprintf (temp, "%s %s", pager, envelop->letter);
  425.                docmd_na (temp);
  426.                whichway = mailcmd (envelop->letter);
  427.             }
  428.           else
  429.             {  
  430.                c = dspmail (infile, envelop->status);
  431.                switch (tolower (c))
  432.                  {
  433.                     /* want to see letter again */
  434.                     case 'a':
  435.                          whichway = AGAIN;
  436.                          break;
  437.  
  438.                     /* want to see previous letter */
  439.                     case 'p':
  440.                     case '-':
  441.                          whichway = PREVIOUS;
  442.                          break;
  443.  
  444.                     /* go on to next letter */
  445.                     case 'n':
  446.                          whichway = NEXT;
  447.                          break;
  448.  
  449.                     /* exit immediately, leaving mail unchanged */
  450.                     case 'x':
  451.                          exit (0);
  452.  
  453.                     /* we need help */
  454.                     case 'h':
  455.                     case '?':
  456.                          givehelp();
  457.                          /* fall through */
  458.  
  459.                     /* continue with the current letter */
  460.                     default:
  461.                          whichway = mailcmd (envelop->letter);
  462.                          break;
  463.                  }
  464.             }
  465.           if (envelop->status != 'D'  &&  envelop->status != 'B')
  466.                envelop->status = 'P';
  467.        }
  468.      else
  469.        {
  470.           whichway = BADLETTER;
  471.           printf ("\n%s: letter %s's header has illegible handwriting\n",
  472.                   pname, envelop->letter);
  473.           sleep (2);                          /* short pause */
  474.        }
  475.  
  476.      /* close the letter file */
  477.      fclose (infile);
  478.      return (whichway);
  479. }
  480.  
  481.  
  482.  
  483. /* getmsg  --get message
  484.  
  485.    Get header info from next mail message in the spooled mail directory.
  486. */
  487.  
  488. int getmsg (file)
  489. FILE *file;
  490. {
  491.      char replyto[100], replynam[100], resentrply[100], resentfrm[100];
  492.      char resentnam[100], resentdate[40], resentid[100];
  493.      register char *lp;
  494.      char *p;
  495.      flag header;
  496.  
  497.      *subject = *fromdate = *frommsgid = *fromname = '\0';
  498.      *sender = *replynam = *resentrply = *resentfrm = '\0';
  499.      *resentdate = *resentid = '\0';
  500.      header = TRUE;
  501.      lp = line;
  502.  
  503.      /* be sure this are all cleared out -- REB */
  504.      memset (address, '\0', sizeof (address));
  505.      memset (replyto, '\0', sizeof (replyto));
  506.  
  507.      /* Are we still in the header?  If so, look at line */
  508.      while (header)
  509.           if (mfgets (lp, sizeof (line), file) != NULL)
  510.             {
  511.                if (*lp == '\0')
  512.                  {
  513.                     header = FALSE;
  514.                     continue;
  515.                  }
  516.  
  517.                /* Be paranoid and extract From return path this will be
  518.                   overwritten by From: or Reply-to:, if found. */
  519.  
  520.                if (*lp == '>'  &&  strncmp (lp, ">From ", 6) == 0)
  521.                  {
  522.                     strcpy (temp, skipspace (lp+5));
  523.                     for (p = temp; !isspace (*p) && *p != '\0'; p++)
  524.                          ;
  525.  
  526.                     *p = '\0';
  527.                     strcpy (address, temp);
  528.                  }
  529.  
  530.                /* extract From: return path + fromname */
  531.                if (*lp == 'F'  &&  strnucmp (lp, Hfrom, 6) == 0)
  532.                  {
  533.                     strcpy (address, getval (lp));
  534.                     strcpy (fromname, getrealname (lp));
  535.                  }
  536.  
  537.                /* extract Sender: return path */
  538.                if (*lp == 'S'  &&  strnucmp (lp, Hsender, 8) == 0)
  539.                     strcpy (sender, getval (lp));
  540.  
  541.                /* Reply-To, Resent-Reply-To, Resent-From: fields */
  542.                if (*lp == 'R')
  543.                  {
  544.                     /* extract Reply-To: return path */
  545.                     if (strnucmp (lp, Hreplyto, 10) == 0)
  546.                       {
  547.                          strcpy (replyto, getval (lp));
  548.                          strcpy (replynam, getrealname (lp));
  549.                       }
  550.  
  551.                     /* extract Resent-From: path */
  552.                     else if (strnucmp (lp, "Resent-From: ", 13) == 0)
  553.                       {
  554.                          strcpy (resentfrm, getval (lp));
  555.                          strcpy (resentnam, getrealname (lp));
  556.                       }
  557.  
  558.                     /* extract Resent-Reply-To: path */
  559.                     else if (strnucmp (lp, "Resent-Reply-To: ", 17) == 0)
  560.                       {
  561.                          strcpy (resentrply, getval (lp));
  562.                          strcpy (resentnam, getrealname (lp));
  563.                       }  
  564.  
  565.                     /* extract Resent-Date */
  566.                     else if (strnucmp (lp, "Resent-Date: ", 13) == 0)
  567.                          strcpy (resentdate, getstring (lp));
  568.  
  569.                     /* extract Resent-Message-Id */
  570.                     else if (strnucmp (lp, "Resent-Message-Id: ", 19) == 0)
  571.                          strcpy (resentid, getval (lp));
  572.                  }
  573.  
  574.                /* extract message ID */
  575.                if (*lp == 'M'  &&  *resentid == '\0'
  576.                     &&  strnucmp (lp, "Message-Id: ", 12) == 0)
  577.                  {
  578.                     strcpy (frommsgid, getval (lp));
  579.                  }
  580.  
  581.                /* extract message time */
  582.                if (*lp == 'D'  &&  *resentdate == '\0'
  583.                     &&  strnucmp (lp, Hdate, 6) == 0)
  584.                  {
  585.                     strncpy (fromdate, getstring (lp), sizeof (fromdate));
  586.                  }
  587.  
  588.                /* extract subject */
  589.                if (*lp == 'S'  &&  strnucmp (lp, Hsubject, 9) == 0 || 
  590.                                    strnucmp (lp, Hsubj, 6) == 0)
  591.                  {
  592.                     if (*subject == '\0')
  593.                       {
  594.                          strcpy (temp, getstring (lp));
  595.  
  596.                          if (strnucmp (temp, "Re:", 3) != 0)
  597.                               strcpy (subject, "Re: ");
  598.  
  599.                          strcat (subject, temp);
  600.                       }
  601.                  }
  602.             }
  603.           else
  604.                /* header ended prematurely */
  605.                return (FALSE);
  606.  
  607.      /* Resent-Date overrides Date: --REB */
  608.      if (*resentdate != '\0')
  609.           strncpy (fromdate, resentdate, sizeof (fromdate));
  610.  
  611.      /* be sure fromdate is properly terminated */
  612.      fromdate[sizeof (fromdate) - 1] = '\0';
  613.  
  614.      /* Resent-Message-Id: overrides Message-Id: --REB */
  615.      if (*resentid != '\0')
  616.        {
  617.           strncpy (frommsgid, resentid, sizeof (fromdate));
  618.           frommsgid[sizeof (frommsgid) - 1] = '\0';
  619.        }
  620.  
  621.      /*      Resent-Reply-To: supercedes From: in determining return path
  622.         -or- Resent-From:     supercedes From: in determining return path
  623.         -or- Reply-To:        supercedes From: in determining return path  */
  624.  
  625.      if (*resentrply != '\0')
  626.        {
  627.           strcpy (address, resentrply);
  628.           strcpy (fromname, resentnam);
  629.        }
  630.      else if (*resentfrm != '\0')
  631.        {
  632.           strcpy (address, resentfrm);
  633.           strcpy (fromname, resentnam);
  634.        }
  635.      else if (*replyto != '\0')
  636.        {
  637.           strcpy (address, replyto);
  638.           strcpy (fromname, replynam);
  639.        }
  640.  
  641.      if (*fromname == '\0')
  642.           strcpy (fromname, address);
  643.  
  644.      rewind (file);
  645.      return (TRUE);
  646. }
  647.  
  648.  
  649.  
  650. /* dspmail  --display mail message */
  651.  
  652. char dspmail (file, status)
  653. register FILE *file;
  654. char status;
  655. {
  656.      static char *returnon = "ahnp-qx?";
  657.      static int columns = 79, rows;
  658.      static flag firstletter = TRUE;
  659.      register char *p;
  660.      flag header = TRUE;
  661.      int i;
  662.      char c, t;
  663.  
  664.      /* Get number of rows from path descriptor.  We assume at least an
  665.         80 column display is used.  */
  666.  
  667.      if (firstletter)                              /* Changed -- REB */
  668.        {
  669.           struct sgbuf pd;
  670.  
  671.           rows = (_gs_opt (STDOUT, &pd) != ERROR) ? (int) pd.sg_page : 24;
  672.           --rows;
  673.           firstletter = FALSE;
  674.        }
  675.  
  676.      cls();
  677.      i = 0;
  678.      c = '\0';
  679.      p = line;
  680.      while (mfgets (p, sizeof (line), file) != NULL)
  681.        {
  682.           if (header  &&  *p == '\0')
  683.             {
  684.                fputs ("Status: ", stdout);
  685.                switch (status)
  686.                  {
  687.                     case 'N':
  688.                          puts ("NEW");
  689.                          break;
  690.  
  691.                     case 'U':
  692.                          puts ("UNREAD");
  693.                          break;
  694.  
  695.                     default:
  696.                          puts ("READ");
  697.                          break;
  698.                  }
  699.                header = FALSE;
  700.                ++i;
  701.             }
  702.  
  703.           if (i >= rows  ||  *p == '\f')
  704.             {
  705.                ReVOn();
  706.                fputs (" --MORE--", stdout);
  707.                ReVOff ();
  708.                c = tolower ( getresponse() );
  709.                CurUp();
  710.                putchar('\n');
  711.                DelLine();
  712.                CurUp();
  713.                putchar ('\n');
  714.                i = 0;
  715.  
  716.                /* Go to 'mailx>' prompt on <A>gain, <->/<P>revious, <N>ext,
  717.                   <Q>uit, or e<X>it.  Changed --REB  */
  718.  
  719.                if (strchr (returnon, c) != NULL)
  720.                     break;
  721.             }
  722.           fixline (p);
  723.  
  724.           if (header)
  725.                if (!fullheader)
  726.                     if (strnucmp (p, ">From ", 6) == 0)
  727.                          goto showit;
  728.                     else if (strnucmp (p, Hfrom, 6) == 0)
  729.                          goto showit;
  730.                     else if (strnucmp (p, "To: ", 4) == 0)
  731.                          goto showit;
  732.                     else if (strnucmp (p, Hdate, 6) == 0)
  733.                          goto showit;
  734.                     else if (strnucmp (p, Hreplyto, 10) == 0)
  735.                          goto showit;
  736.                     else if (strnucmp (p, Hsubject, 9) == 0
  737.                              ||  strnucmp (p, Hsubj, 6) == 0)
  738.                          goto showit;
  739.                     else if (strnucmp (p, Hcc, 4) == 0)
  740.                          goto showit;
  741.                     else if (strnucmp (p, Hsender, 8) == 0)
  742.                          goto showit;
  743.                     else if (strnucmp (p, Hx, 2) == 0)
  744.                          goto showit;
  745.                     else
  746.                          continue;
  747. showit:   puts (p);
  748.           i += (strlen (p) / columns) + 1;
  749.        }
  750.      fclose (file);
  751.  
  752.      if (c == 'n')                             /* flush keyboard input */
  753.           if ((i = _gs_rdy (0)) > 0)
  754.                read (0, temp, i);
  755.      return (c);
  756. }
  757.  
  758.  
  759.  
  760. /* Returns PREVIOUS if we want to redisplay the previous message.  AGAIN if we
  761.    want to redisplay the current message.  NEXT if we want to move on to the
  762.    next message.  DELETE if we deleted the current message. */
  763.  
  764. int mailcmd (letter)
  765. char *letter;
  766. {
  767.      char path[128]; 
  768.      struct fildes fdes;
  769.      flag noerror, orig_usesig, orig_cc_prompt, cflag;
  770.      int n, f;
  771.      register char c;
  772.      char *p, *words[WORDSIZE], *tmpAdrs, *tmpSubj;
  773.  
  774.      /* make a copy of the filename in case we reply -- REB */
  775.      strcpy (message, letter);
  776.  
  777.      /* run mailx commands for this message */
  778.      for (;;)
  779.        {
  780.           fputs ("\nmailx> ", stdout);
  781.           fflush (stdout);
  782.           c = tolower ( getresponse() );
  783.           switch (c)
  784.             {
  785.                /* Next message */
  786.                case ' ':
  787.                case 'n':
  788.                case '\n':
  789.                     return (NEXT);
  790.  
  791.                /* toggle displaying entire or abbreviated header */
  792.                case 'z':
  793.                     fullheader = !fullheader;
  794.                     backspace (1);
  795.                     printf ("full header display %s...",
  796.                             fullheader ? "on" : "off");
  797.  
  798.                     fflush (stdout);
  799. #ifndef _OSK
  800.                     tsleep (60);                       /* brief pause so    */
  801. #else                                                  /* everyone can read */
  802.                     sleep (1);                         /* the message       */
  803. #endif
  804.                     /* fall through */
  805.  
  806.                /* redisplay the current message */
  807.                case 'a':
  808.                     return (AGAIN);
  809.  
  810.                /* reply command */
  811.                case 'r':
  812.                     /* save current From: */
  813.                     if ((tmpAdrs = strdup (address)) != NULL)
  814.                       {
  815.                          reply = TRUE;
  816.                          putchar ('\n');
  817.                          sendmail();
  818.                          strcpy (address, tmpAdrs);
  819.                          free (tmpAdrs);
  820.                          reply = FALSE;
  821.                       }
  822.                     else
  823.                       {
  824.                          fputs ("mailcmd: can't make copy of From:", stdout);
  825.                          fflush (stdout);
  826.                          continue;
  827.                       }
  828.                     break;
  829.  
  830.                /* save command -- strip or keep header --REB */
  831.                case 's':
  832.                case 'w':
  833.                     /* Set up a flag to tell us later whether or not we need
  834.                        to reset the uid of the file.  We don't want to do this
  835.                        simple hack for just any file as it would allow anyone
  836.                        to put a file anywhere in the file system.  --BAS 2  */
  837.  
  838.                     cflag = FALSE;
  839.                     p = getinput (path, sizeof (path));
  840.  
  841.                     if (*p == '\0')
  842.                       {
  843.                          sprintf (fname, "%s/mbox", homedir);
  844.                          cflag = TRUE;
  845.                          asetuid (0);
  846.                       }
  847.                     else if (*p == '/')
  848.                          strcpy (fname, p);
  849.                     else
  850.                       {
  851.                          sprintf (fname, "%s/%s", homedir, p);
  852.                          cflag = TRUE;
  853.                          asetuid(0);
  854.                       }
  855.                     printf ("\nSaving message to %s\n", fname);
  856.  
  857.                     /* If you don't check the ownership of the file, then it
  858.                        is possible to overwrite any file on the same disk as
  859.                        filename given, if you allow users to make links.
  860.                          --BAS 2 */
  861.  
  862.                     if ((f = open (fname, 1)) > 0)
  863.                       {
  864.                          _gs_gfd (f, &fdes, sizeof (fdes));
  865.                          close (f);
  866.  
  867.                          if (myuid != (unsigned)fdes.fd_own)
  868.                            {
  869.                               printf ("%s: %s exists and it is not yours\n",
  870.                                       pname, fname);
  871.  
  872.                               if (cflag)
  873.                                    asetuid (myuid);
  874.                               continue;
  875.                            }
  876.                       }
  877.  
  878.                     /* save message with header */
  879.                     if (c == 's')
  880.                          noerror = fileapnd (letter, fname, TRUE);
  881.                     else
  882.                          /* save message without header */
  883.                          noerror = fileapskp (letter, fname, TRUE);
  884.  
  885.                     if (noerror == FALSE)
  886.                       {
  887.                          printf ("%s: can't save letter to %s...error %d\n",
  888.                                  pname, fname, errno);
  889.  
  890.                          asetuid (myuid);
  891.                          continue;
  892.                       }
  893.  
  894.                     /* If we need to, reset the ownership of the file-BAS 2 */
  895.                     if (cflag)
  896.                       {
  897.                          chown (fname, myuid);
  898.                          asetuid (myuid);
  899.                       }
  900.  
  901.                /* delete current message -- REB */
  902.                case 'd':
  903.                     CurUp();
  904.                     fputs ("\nDelete? y/N ", stdout);
  905.                     fflush (stdout);
  906.                     c = tolower ( getresponse() );
  907.  
  908.                     if (c == 'y')
  909.                          return (DELETE);
  910.                     else
  911.                       {
  912.                          CurUp();
  913.                          putchar ('\n');
  914.                          ErEOLine();
  915.                          CurUp();
  916.                          fflush (stdout);
  917.                       }
  918.                     break;
  919.  
  920.                /* redisplay previous message */
  921.                case 'p':
  922.                case '-':
  923.                     return (PREVIOUS);
  924.  
  925.                /* forward copy of message to user(s) */
  926.                case 'f':
  927.                     fputs ("orward to: ", stdout);
  928.                     p = getinput (path, sizeof (path));
  929.  
  930.                     if (!*p)
  931.                          continue;
  932.  
  933.                     /* save the current To: */
  934.                     if ((tmpAdrs = strdup (address)) != NULL)
  935.                       {
  936.                          /* clear the old To: */
  937.                          memset (address, '\0', sizeof (address));
  938.                          usesig = NOSIG;
  939.                          forward = TRUE;
  940.                          n = getargs (words, p, WORDSIZE);           /* REB */
  941.  
  942.                          if (parse_addr (n, words) != ABORT)
  943.                               sendmail();
  944.  
  945.                          /* restore previous To: */
  946.                          strcpy (address, tmpAdrs);
  947.                          free (tmpAdrs);
  948.                          usesig = USESIG;
  949.                          forward = FALSE;
  950.                       }
  951.                     else
  952.                       {
  953.                          fputs ("mailcmd: can't make copy of To:", stdout);
  954.                          fflush (stdout);
  955.                          continue;
  956.                       }
  957.                     break;
  958.  
  959.                /* mail command...can include command line options d,p and s */
  960.                case 'm':
  961.                     p = getinput (path, sizeof (path));
  962.  
  963.                     if (*p == '\0')
  964.                          continue;
  965.  
  966.                     /* save original To: and Subject: */
  967.                     if ((tmpAdrs = strdup (address)) == NULL)
  968.                       {
  969.                          fputs ("mailcmd: cannot save original To:",
  970.                                 stdout);
  971.                          fflush (stdout);
  972.                          continue;
  973.                       }
  974.  
  975.                     if ((tmpSubj = strdup (subject)) == NULL)
  976.                       {
  977.                          fputs ("mailcmd: cannot save original Subject:",
  978.                                 stdout);
  979.                          fflush (stdout);
  980.                          continue;
  981.                       }
  982.                          
  983.                     /* clear the address and subject --REB */
  984.                     memset (address, '\0', sizeof (address));
  985.                     memset (subject, '\0', sizeof (subject));
  986.  
  987.                     /* save original cc_prompt and usesig */
  988.                     orig_usesig = usesig;
  989.                     orig_cc_prompt = cc_prompt;
  990.                     n = getargs (words, p, WORDSIZE);
  991.  
  992.                     if (parse_addr (n, words) != ABORT)
  993.                          sendmail();
  994.  
  995.                     /* put back original cc_prompt and usesig */
  996.                     usesig = orig_usesig;
  997.                     cc_prompt = orig_cc_prompt;
  998.                     strcpy (address, tmpAdrs);
  999.                     free (tmpAdrs);
  1000.                     strcpy (subject, tmpSubj);
  1001.                     free (tmpSubj);
  1002.                     break;
  1003.  
  1004.                /* exit mail after killing deleted mail */
  1005.                case 'q':
  1006.                     return (QUIT);
  1007.  
  1008.                /* exit without touch any mail */
  1009.                case 'x':
  1010.                     interrupt (0);
  1011.  
  1012.                /* make ALL deleted mail readable again */
  1013.                case 'u':
  1014.                     return (UNDELETE);
  1015.  
  1016.                /* fork a shell for the user */
  1017.                case '!':
  1018.                     forkshell();
  1019.                     fputs ("\b  ", stdout);
  1020.                     CurUp();
  1021.                     break;
  1022.  
  1023.                /* help command */
  1024.                case 'h':
  1025.                case '?':
  1026.                     givehelp();
  1027.                     break;
  1028.  
  1029.                /* mark all mail read --REB */
  1030.                case 'c':
  1031.                     backspace (1);
  1032.                     fputs ("marking all mail as read...", stdout);
  1033.                     fflush (stdout);
  1034.                     return (ALLREAD);
  1035.  
  1036.                /* delete ALL mail then exit */
  1037.                case 'k':
  1038.                     backspace (1);
  1039.                     fputs ("delete ALL mail?  y/N ", stdout);
  1040.                     fflush (stdout);
  1041.                     c = tolower ( getresponse() );
  1042.                     backspace (23);
  1043.  
  1044.                     if (c == 'y')
  1045.                       {
  1046.                          fputs ("are you sure?  y/N ", stdout);
  1047.                          fflush (stdout);
  1048.                          c = tolower ( getresponse() );
  1049.                          backspace (20);
  1050.  
  1051.                          if (c == 'y')
  1052.                            {
  1053.                               fputs ("killing all mail...", stdout);
  1054.                               fflush (stdout);
  1055.                               return (KILLMAIL);
  1056.                            }
  1057.                       }
  1058.                     CurUp();
  1059.                     fflush (stdout);
  1060.                     break;
  1061.  
  1062.                /* toggle file viewer on or off --REB */
  1063.                case 'v':
  1064.                     fputs ("iewer ", stdout);
  1065.  
  1066.                     if (*pager != '\0')
  1067.                       {
  1068.                          usepager = !usepager;
  1069.                          printf ("now %s...", usepager ? "on" : "off");
  1070.                          fflush (stdout);
  1071. #ifndef _OSK
  1072.                          loadpager (usepager ? TRUE: FALSE);
  1073. #endif
  1074.                        }
  1075.                     else
  1076.                       {
  1077.                          fputs ("is not defined...", stdout);
  1078.                          fflush (stdout);
  1079.                       }
  1080.                     break;
  1081.  
  1082. #ifdef FIXME
  1083.                /* current message is piped to standard input of a program */
  1084.                case '|':
  1085.                     p = getinput (path, sizeof (path));
  1086.  
  1087.                     if (*p == NULL)
  1088.                          continue;
  1089.  
  1090.                     dopipe (letter, p);
  1091.                     break;
  1092. #endif
  1093.                default:
  1094.                     printf ("\nUnknown command: %c\n", c);
  1095.                     break;
  1096.             }
  1097.        }
  1098. }
  1099.  
  1100.  
  1101.  
  1102. /* get a single character response from the user */
  1103.  
  1104. char getresponse()
  1105. {
  1106.      char c;
  1107.  
  1108.      /* wait for valid input */
  1109.      echo (OFF);
  1110.      do
  1111.        {
  1112.           while (_gs_rdy (0) <= 0)
  1113.                tsleep (4);
  1114.  
  1115.           read (0, &c, 1);
  1116.        }
  1117.      while (c < '\x20'  &&  c > '\x7f');
  1118.  
  1119.      echo (ON);
  1120.      if (c != '\n'  &&  c != ' ')
  1121.        {
  1122.           putchar (c);
  1123.           fflush (stdout);
  1124.        }
  1125.      return (c);
  1126. }
  1127.  
  1128.  
  1129.  
  1130. /* Open double overlay windows for keyboard user--white on red over black on
  1131.    black.  Should only be called by CoCo when TERMCAP is not defined. */
  1132.  
  1133. #ifndef TERMCAP
  1134. int popdoublewindow (x, y, width, height)
  1135. int x, y, width, height;
  1136. {
  1137.      char outstr[18];
  1138.  
  1139.      /* turn off the cursor */
  1140.      write (1, "\x05\x20", 2);
  1141.  
  1142.      *(outstr + 0) = *(outstr + 9)  = 0x1b;
  1143.      *(outstr + 1) = *(outstr + 10) = 0x22;
  1144.      *(outstr + 2) = *(outstr + 11) = 1;
  1145.      *(outstr + 5) = *(outstr + 14) = width;
  1146.      *(outstr + 6) = *(outstr + 15) = height;
  1147.  
  1148.      /* bottom window */
  1149.      *(outstr + 3) = x + 1;                    /* offset bottom window */
  1150.      *(outstr + 4) = y + 1;
  1151.      *(outstr + 7) = 2;                        /* black on black */
  1152.      *(outstr + 8) = 2;
  1153.  
  1154.      /* top window */
  1155.      *(outstr + 12) = x;
  1156.      *(outstr + 13) = y;
  1157.      *(outstr + 16) = 0;                        /* white on red */
  1158.      *(outstr + 17) = 4;
  1159.  
  1160.      write (1, outstr, sizeof (outstr));
  1161.      winopen = TRUE;
  1162. }
  1163.  
  1164.  
  1165.  
  1166. /* Close double overlay window */
  1167.  
  1168. int closedoublewindow()
  1169. {
  1170.      write (1, "\x1b\x23\x1b\x23\x08  \n\x09\x05\x21", 11);
  1171.      winopen = FALSE;
  1172. }
  1173. #endif
  1174.  
  1175.  
  1176. /* backspace-space-backspace to delete part of a line */
  1177.  
  1178. int backspace (howmany)
  1179. int howmany;
  1180. {
  1181.      register int i;
  1182.  
  1183.      for (i = 0; i < howmany; ++i)
  1184.           fputs ("\b \b", stdout);
  1185.  
  1186.      fflush (stdout);
  1187. }
  1188.  
  1189.  
  1190.  
  1191. int putdashes (howmany)
  1192. int howmany;
  1193. {
  1194.      register int i;
  1195.  
  1196.      putchar (' ');
  1197.  
  1198.      for (i = 0; i < howmany; ++i)
  1199.           putchar ('=');
  1200.  
  1201.      fflush (stdout);
  1202. }
  1203.  
  1204.  
  1205.  
  1206. void givehelp()
  1207. {
  1208.      register char **hlp;
  1209.      static char *helptxt[] = {
  1210.                             "a\t\t redisplay current message",
  1211.                             "c\t\t mark all mail as read",
  1212.                             "d\t\t delete current message",
  1213.                             "f\t\t forward current message",
  1214.                             "h, ?\t     this message",
  1215.                             "k\t\t delete ALL mail",
  1216.                             "m <address>     send mail to <address>",
  1217.                             "n/ENTER/SPACE   go to next message",
  1218.                             "p, -\t     show previous message",
  1219.                             "q\t\t update and exit",
  1220.                             "r\t\t reply to this message",
  1221.                             "s [filename]    save message to 'filename'",
  1222.                             "\t\t   default is 'mbox'",
  1223.                             "u\t\t undelete mail",
  1224.                             "v\t\t toggle using file viewer",
  1225.                             "w [filename]    save message without header to",
  1226.                             "\t\t   'filename', default is 'mbox'",
  1227.                             "x\t\t exit with no updating",
  1228.                             "z\t\t toggle message header display",
  1229.                             "!\t\t fork a shell",
  1230. #ifdef FIXME
  1231.                             "|cmd\t   run 'cmd' with current message",
  1232.                             "\t\t   as input",
  1233. #endif
  1234.                             NULL
  1235.                          };
  1236.  
  1237. #ifndef TERMCAP
  1238.      if (t2flag)
  1239.           puts ("\n");
  1240.      else
  1241.        {
  1242.           popdoublewindow (31, 0, 48, 22);
  1243.           putdashes (17);
  1244.           printf (" Mailx v%s", version);
  1245.           putdashes (17);
  1246.           putchar (' ');
  1247.        }
  1248. #else
  1249.      putchar ('\n');
  1250.      putdashes (17);
  1251.      printf ("Mailx v%s", version);
  1252.      putdashes (17);
  1253.      putchar ('\n');
  1254. #endif
  1255.      for (hlp = helptxt; *hlp; ++hlp)
  1256.           printf (" %s\n", strdetab (strcpy (temp, *hlp), 7));
  1257.  
  1258. #ifndef TERMCAP
  1259.      if (t2flag)
  1260.           putchar ('\n');
  1261.      else
  1262.        {
  1263.           putdashes (46);
  1264.           getresponse();
  1265.           closedoublewindow();
  1266.        }
  1267. #else
  1268.      putdashes (46);
  1269.      putchar ('\n');
  1270. #endif
  1271. }
  1272.