home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / EXTRAS / UUCODE / UUPC / TEST / UPC12ES3.ZIP / MAIL / mail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-31  |  49.7 KB  |  1,485 lines

  1. /*--------------------------------------------------------------------*/
  2. /*       m a i l . c                                                  */
  3. /*                                                                    */
  4. /*       Mailer User-Agent (UA)                                       */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*       Changes Copyright (c) 1989-1993 by Kendra Electronic         */
  9. /*       Wonderworks.                                                 */
  10. /*                                                                    */
  11. /*       All rights reserved except those explicitly granted by       */
  12. /*       the UUPC/extended license agreement.                         */
  13. /*--------------------------------------------------------------------*/
  14.  
  15. /*--------------------------------------------------------------------*/
  16. /*                          RCS Information                           */
  17. /*--------------------------------------------------------------------*/
  18.  
  19. /*
  20.  *    $Id: mail.c 1.14 1993/10/31 21:32:55 ahd Exp $
  21.  *
  22.  *    Revision history:
  23.  *    $Log: mail.c $
  24.  * Revision 1.14  1993/10/31  21:32:55  ahd
  25.  * Don't print current header after headers command
  26.  *
  27.  * Revision 1.13  1993/10/31  19:04:03  ahd
  28.  * Change "DOS" to "system" in short command help text
  29.  *
  30.  * Revision 1.12  1993/10/28  12:19:01  ahd
  31.  * Cosmetic time formatting twiddles and clean ups
  32.  *
  33.  * Revision 1.11  1993/10/12  01:32:08  ahd
  34.  * Normalize comments to PL/I style
  35.  *
  36.  * Revision 1.9  1993/10/09  20:16:12  rhg
  37.  * ANSIfy the source
  38.  *
  39.  * Revision 1.8  1993/09/23  03:26:51  ahd
  40.  * Use current version variables for Visual C++ under Windows NT
  41.  *
  42.  * Revision 1.7  1993/09/20  04:39:51  ahd
  43.  * OS/2 2.x support
  44.  *
  45.  * Revision 1.6  1993/07/31  16:26:01  ahd
  46.  * Changes in support of Robert Denny's Windows support
  47.  *
  48.  * Revision 1.5  1993/07/24  03:40:55  ahd
  49.  * Change description of "-" command, previous command.
  50.  *
  51.  * version  1.0   Stuart Lynne
  52.  * version 1.5 Samuel Lam <skl@van-bc.UUCP>  August/87
  53.  *
  54.  * version 1.6 Drew Derbyshire   May/89
  55.  *             Support for single user aliases, -u option for reading
  56.  *             alternate mailboxes, parsing addresses via external routine,
  57.  *             parsing Resent- fields, suppressing Received: fields,
  58.  *             automatic positioning to next message.                   ahd
  59.  * 23 Sep 89   Version 1.07a
  60.  *             Support lists in aliases                                 ahd
  61.  *
  62.  * 29 Sep 89   Version 1.07b
  63.  *             Add prompting for subject in outgoing mail.              ahd
  64.  * 01 Oct 89   Add additional function prototypes to catch bad calls    ahd
  65.  * 02 Oct 89   Alter large strings/structures to use malloc()/free()    ahd
  66.  * 12 Oct 89   Version 1.07d
  67.  *             Correct free() of line in Send_Mail
  68.  * 12 Dec 89   Version 1.07g
  69.  *             Various spelling corrections
  70.  * 18 Mar 90   Version 1.07i
  71.  *             Add ~user support for save/write command
  72.  *             Add ignore list for user
  73.  *             Shorten lines printed by aborting from a print command   ahd
  74.  * 30 Apr  90  Add autoedit support for sending mail                    ahd
  75.  *  2 May  90  Add support for options= flags                           ahd
  76.  *  3 May  90  Split selected subroutines into maillib.c                ahd
  77.  *  4 May  90  Add 'save' option.                                       ahd
  78.  *  8 May  90  Add 'pager' option                                       ahd
  79.  * 10 May  90  Add 'purge' option                                       ahd
  80.  * 13 May  90  Alter logging so that no numbers are printed on console  ahd
  81.  * Additions for unofficial version 1.07k, Philip David Meese June 1990
  82.  * 16 June 90
  83.  *            -added mail command: Copy current (without delete)        pdm
  84.  *            -altered calls to Collect_Mail to support mail subcmds    pdm
  85.  *            -added handling of '+' to indicate "relative to home
  86.  *                directory" for BSD like mail users.                   pdm
  87.  * 12 Feb 91 rewrite parser a for more BSD like syntax
  88. */
  89.  
  90.  static const char rcsid[] =
  91.       "$Id: mail.c 1.14 1993/10/31 21:32:55 ahd Exp $";
  92.  
  93. /*--------------------------------------------------------------------*/
  94. /*                        System include files                        */
  95. /*--------------------------------------------------------------------*/
  96.  
  97. #include <ctype.h>
  98. #include <stdio.h>
  99. #include <io.h>
  100. #include <stdlib.h>
  101. #include <string.h>
  102. #include <limits.h>
  103. #include <time.h>
  104. #include <dos.h>
  105. #include <direct.h>
  106.  
  107. #ifdef _Windows
  108. #include <windows.h>
  109. #include <alloc.h>
  110. #endif
  111.  
  112. /*--------------------------------------------------------------------*/
  113. /*                    UUPC/extended include files                     */
  114. /*--------------------------------------------------------------------*/
  115.  
  116. #include "lib.h"
  117. #include "address.h"
  118. #include "alias.h"                                            /* ahd */
  119. #include "dater.h"
  120. #include "expath.h"
  121. #include "getopt.h"
  122. #include "hlib.h"
  123. #include "mail.h"
  124. #include "mailblib.h"
  125. #include "maillib.h"                                           /* ahd */
  126. #include "mailsend.h"
  127. #include "mlib.h"
  128. #include "pushpop.h"
  129. #include "stater.h"
  130. #include "timestmp.h"
  131.  
  132. #if defined(_Windows)
  133. #include "winutil.h"
  134. #endif
  135.  
  136. /*--------------------------------------------------------------------*/
  137. /*                          Global variables                          */
  138. /*--------------------------------------------------------------------*/
  139.  
  140. #ifdef _Windows
  141. unsigned _stklen = 10 * 1024;
  142. unsigned _heaplen = 30 * 1024;
  143. #endif
  144.  
  145. currentfile();
  146.  
  147. static char *tmailbox;
  148. static char mfilename[FILENAME_MAX];
  149. int letternum = 0;
  150.  
  151. static boolean useto = FALSE;
  152.  
  153. FILE *fmailbox;
  154.  
  155. #define MAXLETTERS   100
  156.  
  157. static int maxletters = MAXLETTERS;
  158.  
  159. struct  ldesc *letters;
  160.  
  161. /*--------------------------------------------------------------------*/
  162. /*                       Local procedure names                        */
  163. /*--------------------------------------------------------------------*/
  164.  
  165. static void    Cleanup(void);
  166.  
  167. static void Interactive_Mail( const boolean PrintOnly,
  168.                               const boolean postoffice );
  169.  
  170. static void    IncludeNew( const char *target, const char *user);
  171.  
  172. static void    PrintSubject(int msgnum, int letternum);
  173.  
  174. static void    UpdateMailbox(int letternum, boolean postoffice);
  175.  
  176. static int     CreateBox(FILE *rmailbox,
  177.                          FILE *fmailbox,
  178.                          const char *tmailbox);
  179.  
  180. static void usage( void );
  181.  
  182. /*--------------------------------------------------------------------*/
  183. /*                          Global variables                          */
  184. /*--------------------------------------------------------------------*/
  185.  
  186. static char *replytolist[] = { "Resent-Reply-To:",
  187.                         "Resent-From:",
  188.                         "Reply-To:",
  189.                         "From:",
  190.                          NULL };
  191.  
  192. static char *fromlist[] =    { "Resent-From:",
  193.                                "From:",
  194.                                NULL};
  195.  
  196. static char *tolist[] =    {   "Resent-To:",
  197.                                "To:",
  198.                                NULL};
  199.  
  200. static char *subjectlist[] = { "Resent-Subject:",
  201.                                "Subject:",
  202.                                 NULL };
  203.  
  204. static char *datelist[]  =   { "Resent-Date:",
  205.                                "Date:" ,
  206.                                NULL} ;
  207.  
  208.  
  209. /*--------------------------------------------------------------------*/
  210. /*                  Information on existing mailbox                   */
  211. /*--------------------------------------------------------------------*/
  212.  
  213. static long    mboxsize = 0;
  214. static time_t  mboxage  = 0;
  215.  
  216. /*--------------------------------------------------------------------*/
  217. /*                       Command parsing table                        */
  218. /*--------------------------------------------------------------------*/
  219.  
  220. #define NUMERIC_CMD "9999"
  221. #define EMPTY_CMD   ""
  222.  
  223. static struct CommandTable {
  224.    char *sym;
  225.    ACTION verb;
  226.    unsigned int bits;
  227.    char *help;
  228. } table[] = {
  229.  { EMPTY_CMD,     M_EMPTY,    NODISPLAY | NO_OPERANDS | AUTOPRINT ,
  230.          NULL},
  231.  { "!",           M_SYSTEM,   STRING_OP,
  232.          "Execute system command"},
  233.  { "+",           M_DOWN,     KEWSHORT_OP | AUTOPRINT,
  234.          "Alias for next"},
  235.  { "-",           M_UP,       KEWSHORT_OP | AUTOPRINT,
  236.          "Alias for previous"},
  237.  { "?",           M_FASTHELP, NO_OPERANDS,
  238.          "Print this help"},
  239.  { "alias",       M_ALIAS,    TOKEN_OP,
  240.          "Print user alias"},
  241.  { "copy",        M_COPY,     LETTER_OP | FILE_OP ,
  242.          "Copy item to file"},
  243.  { "delete",      M_DELETE,   LETTER_OP | POSITION | AUTOPRINT ,
  244.          "Delete mail item"},
  245.  { "debug",       M_DEBUG,    KEWSHORT_OP,
  246.          "Enable debug output"},
  247.  { "dquit",       M_DELETEQ,  LETTER_OP ,
  248.          "Delete then quit"},
  249.  { "exit",        M_EXIT,     NO_OPERANDS,
  250.          "Exit without updating mailbox"},
  251.  { "forward",     M_FORWARD,  LETTER_OP | USER_OP,
  252.          "Resend item to others"},
  253.  { "go",          M_GOTO,     LETTER_OP | AUTOPRINT ,
  254.          "Go to item"},
  255.  { "Headers",     M_HEADERS,  LETTER_OP | POSITION | NOAUTOHEADER,
  256.          "Print specified item summary"},
  257.  { "headers",     M_HEADERS,  NO_OPERANDS | NOAUTOHEADER,
  258.          "Print all item summaries"},
  259.  { "help",        M_HELP,     NO_OPERANDS,
  260.          "Print long help text"},
  261.  { "mail",        M_MAIL,     USER_OP,
  262.          "Compose and send mail"},
  263.  { "next",        M_DOWN,     KEWSHORT_OP | AUTOPRINT ,
  264.          "Move to next item"},
  265.   {"print",       M_EXTPRINT, LETTER_OP | POSITION ,
  266.          "Print item (condensed)"},
  267.   {"Print",       M_INTPRINT, LETTER_OP | POSITION ,
  268.          "Print item (condensed)"},
  269.   {"previous",    M_UP,       KEWSHORT_OP | AUTOPRINT ,
  270.          "Move to previous item"},
  271.   {"quit",        M_QUIT,     NO_OPERANDS,
  272.          "Update mailbox, exit"},
  273.   {"reply",       M_REPLY,    LETTER_OP | POSITION ,
  274.          "Reply to sender of item"},
  275.   {"save",        M_SAVE,     LETTER_OP | FILE_OP | POSITION | AUTOPRINT ,
  276.          "Copy item, delete"},
  277.   {"set",         M_SET,      STRING_OP,
  278.          "Print/set boolean options"},
  279.   {"status",     M_STATUS,  NO_OPERANDS,
  280.          "Report version/status info"},
  281.   {"type",        M_EXTTYPE,  LETTER_OP | POSITION,
  282.          "Print item with all headers"},
  283.   {"Type",        M_INTTYPE,  LETTER_OP | POSITION,
  284.          "Print item with all headers"},
  285.   {"undelete",    M_UNDELETE, LETTER_OP | POSITION | AUTOPRINT ,
  286.          "Rescue item after save/delete"},
  287.   {"write",       M_WRITE,    LETTER_OP | FILE_OP | POSITION | AUTOPRINT ,
  288.          "Copy item w/o header, delete"},
  289.   {"xit",         M_EXIT,     NO_OPERANDS,
  290.          "alias for exit"},
  291.   { NUMERIC_CMD,   M_GOTO,     NODISPLAY | KEWSHORT_OP | AUTOPRINT ,
  292.          NULL} ,
  293.   { NULL,          M_INVALID,  NODISPLAY | STRING_OP,
  294.          NULL }
  295.          } ;
  296.  
  297. /*--------------------------------------------------------------------*/
  298. /*    m a i n                                                         */
  299. /*                                                                    */
  300. /*    Main program                                                    */
  301. /*--------------------------------------------------------------------*/
  302.  
  303. void main(int argc, char **argv)
  304. {
  305.  
  306.    boolean PrintOnly = FALSE;
  307.    boolean postoffice = TRUE;
  308.    boolean readmail   = FALSE;
  309.    boolean sendmail   = FALSE;
  310.    int option;
  311.    char    *subject = NULL;
  312.  
  313. #if defined(__CORE__)
  314.    copywrong = strdup(copyright);
  315.    checkref(copywrong);
  316. #endif
  317.  
  318.    banner( argv );
  319.  
  320.    if (!configure( B_MUA ))
  321.       exit(1);    /* system configuration failed */
  322.  
  323.    if (!InitRouter())
  324.       exit(1);    /* system configuration failed */
  325.  
  326.    tmailbox = mktempname(NULL, "TMP");
  327.    PushDir(".");
  328.  
  329. /*--------------------------------------------------------------------*/
  330. /*                       get mailbox file name                        */
  331. /*--------------------------------------------------------------------*/
  332.  
  333.    strcpy( mfilename, E_mailbox );
  334.    if ( strchr( mfilename ,'.' ) == NULL )
  335.       mfilename[8] = '\0';       /* Prevent OS/2 filename length
  336.                                     overrun                          */
  337.  
  338.    if ( bflag[ F_MULTITASK ] )
  339.    {
  340.       if (expand_path( mfilename, E_homedir, E_homedir, E_mailext ) == NULL )
  341.          panic();
  342.    }
  343.    else
  344.       mkmailbox(mfilename, E_mailbox );
  345.  
  346. /*--------------------------------------------------------------------*/
  347. /*                          parse arguments                           */
  348. /*--------------------------------------------------------------------*/
  349.  
  350.    while ((option = getopt(argc, argv, "f:ps:tu:x:")) != EOF)
  351.    {
  352.       char oname[FILENAME_MAX];
  353.  
  354.       switch (option)
  355.       {
  356.       case 'f':
  357.          readmail = TRUE;
  358.          strcpy( mfilename, optarg );
  359.          if (expand_path( mfilename, NULL, E_homedir, E_mailext ) == NULL )
  360.             usage();
  361.  
  362. /*--------------------------------------------------------------------*/
  363. /*    This next one is a little tricky ...  If we log outgoing        */
  364. /*    mail, we copy the name of the outgoing mail file into a         */
  365. /*    temporary buffer, and expand the name of the file to include    */
  366. /*    the path name.  If this name is the same as the current         */
  367. /*    file, flip-flip the useto flag which says use the To:           */
  368. /*    related fields when scanning headers, not the From:  related    */
  369. /*    fields.                                                         */
  370. /*--------------------------------------------------------------------*/
  371.  
  372.          if (( E_filesent != NULL ) &&
  373.              (expand_path( strcpy( oname, E_filesent) ,
  374.                           E_homedir, E_homedir , E_mailext ) != NULL ) &&
  375.              equali( oname , mfilename ))
  376.                            /* Our outgoing filename?              */
  377.             useto = ! useto;  /* Yes --> Automatically switch     */
  378.          postoffice = FALSE;
  379.          break;
  380.  
  381.       case 'p':
  382.          readmail = TRUE;
  383.          PrintOnly = TRUE;
  384.          break;
  385.  
  386.       case 'u':                  /* Read alternate mailbox?       */
  387.          readmail = TRUE;
  388.          mkmailbox(mfilename, optarg);
  389.          postoffice = FALSE;
  390.          break;
  391.  
  392.       case 'x':
  393.          debuglevel = atoi(optarg);
  394.          break;
  395.  
  396.       case 's':
  397.          sendmail = TRUE;
  398.          subject = optarg;
  399.          break;
  400.  
  401.       case 't':
  402.          readmail = TRUE;
  403.          useto = ! useto;
  404.          break;
  405.  
  406.       case '?':
  407.          usage();
  408.  
  409.       } /* switch */
  410.  
  411.    } /* while */
  412.  
  413. /*--------------------------------------------------------------------*/
  414. /*                        Check for conflicts                         */
  415. /*--------------------------------------------------------------------*/
  416.  
  417.    sendmail |= (optind != argc);
  418.  
  419.    if ( sendmail && readmail )
  420.    {
  421.       puts("Conflicting options specified");
  422.       usage();
  423.    }
  424.  
  425.    if ((optind == argc) && sendmail)
  426.    {
  427.       puts("Missing addresses for sending mail");
  428.       usage();
  429.    }
  430.  
  431. /*--------------------------------------------------------------------*/
  432. /*        We have the options, now decide how to process them         */
  433. /*--------------------------------------------------------------------*/
  434.  
  435.    if (sendmail)
  436.    {
  437.       argc -= optind;
  438.  
  439.       if ( subject != NULL )
  440.       {
  441.  
  442.          argv    = &argv[optind-2];
  443.          argv[0] = "-s";
  444.          argv[1] = subject;
  445.  
  446.          Collect_Mail(stdin, argc+2 , argv , -1, FALSE);
  447.       } /* if ( subject != NULL ) */
  448.       else {
  449.          Collect_Mail(stdin, argc, &argv[optind], -1, FALSE);
  450.  
  451. #ifdef _Windows
  452.          atexit ( CloseEasyWin );
  453. #endif
  454.       }
  455.  
  456.    } /* if (sendmail) */
  457.    else  {
  458.       if ( postoffice && bflag[ F_MULTITASK ] )
  459.          IncludeNew( mfilename, E_mailbox);
  460.       Interactive_Mail( PrintOnly , postoffice );
  461.    }
  462.  
  463.    Cleanup();
  464.    PopDir();
  465.    exit(0);
  466.  
  467. } /*main*/
  468.  
  469. /*--------------------------------------------------------------------*/
  470. /*    C l e a n u p                                                   */
  471. /*                                                                    */
  472. /*    Remove temporary files when exiting                             */
  473. /*--------------------------------------------------------------------*/
  474.  
  475. void Cleanup()
  476. {
  477.  
  478.    printmsg(2,"Deleting temporary mailbox %s", tmailbox);
  479.  
  480.    if ( fmailbox != NULL )
  481.    {
  482.       fclose(fmailbox);
  483.       fmailbox = NULL;
  484.    }
  485.  
  486.    unlink(tmailbox);
  487.  
  488. } /*Cleanup*/
  489.  
  490.  
  491. /*--------------------------------------------------------------------*/
  492. /*    I n t e r a c t i v e _ M a i l                                 */
  493. /*                                                                    */
  494. /*    main procedure for reading mail                                 */
  495. /*--------------------------------------------------------------------*/
  496.  
  497. static void Interactive_Mail( const boolean PrintOnly,
  498.                               const boolean postoffice )
  499. {
  500.    char resp[LSIZE];
  501.    int current = 0;                                               /* ahd  */
  502.    boolean done      = FALSE;                                     /* ahd  */
  503.    boolean modified;
  504.    FILE *rmailbox;
  505.  
  506. /*--------------------------------------------------------------------*/
  507. /*               Open real and temporary mailbox files                */
  508. /*--------------------------------------------------------------------*/
  509.  
  510.    if ((rmailbox = FOPEN(mfilename, "r",TEXT_MODE)) == nil(FILE)) {
  511.       printf("No mail in %s\n", mfilename);
  512.       return;
  513.    }
  514.  
  515.    mboxage = stater( mfilename, &mboxsize );
  516.                               /* Remember mailbox information        */
  517.  
  518.    if ((fmailbox = FOPEN(tmailbox, "w", BINARY_MODE)) == nil(FILE)) {
  519.       printerr(tmailbox);
  520.       return;
  521.    }
  522.  
  523.    letters = calloc(maxletters,sizeof(letters[0]));
  524.    checkref(letters);
  525.  
  526. /*--------------------------------------------------------------------*/
  527. /*                 Copy real mailbox to temporary one                 */
  528. /*--------------------------------------------------------------------*/
  529.  
  530.    setvbuf(rmailbox, NULL, _IOFBF, 8192);
  531.    setvbuf(fmailbox, NULL, _IOFBF, 8192);
  532.  
  533.    letternum = CreateBox(rmailbox, fmailbox, tmailbox);
  534.  
  535.    fclose(rmailbox);
  536.    fclose(fmailbox);
  537.  
  538.    rmailbox = fmailbox = NULL;
  539.  
  540.    if (letternum < 1)            /* Did we find any mail in the box? */
  541.    {                             /* No --> Return to caller          */
  542.       if (letternum == 0)
  543.          printf("No mail in %s\n", mfilename);
  544.       return;
  545.    }
  546.  
  547. /*--------------------------------------------------------------------*/
  548. /*        Shrink mailbox status array to what we actually need        */
  549. /*--------------------------------------------------------------------*/
  550.  
  551.    letters = realloc( letters, (letternum + 1) *  sizeof(letters[0]));
  552.    checkref(letters);
  553.  
  554.    fmailbox = FOPEN(tmailbox, "r", BINARY_MODE);
  555.  
  556.    if (fmailbox == NULL)
  557.    {
  558.       printerr(tmailbox);
  559.       panic();
  560.    } /* if */
  561.    setvbuf(fmailbox, NULL, _IOFBF, 8192);
  562.  
  563.    modified = postoffice && (!PrintOnly);
  564.  
  565.    if (PrintOnly) {
  566.       int j = 0;
  567.       while (j < letternum)
  568.       {
  569.          Pager(j, TRUE, noreceived, !j );
  570.          j++ ;
  571.       }
  572.       return;
  573.    }
  574.  
  575.    PrintSubject(-1,letternum); /* print all subjects */
  576.  
  577. /*--------------------------------------------------------------------*/
  578. /*               Determine first letter in to prompt at               */
  579. /*--------------------------------------------------------------------*/
  580.  
  581.       if (letternum == 0)
  582.          current = -1;
  583.       else
  584.          current = 0;
  585.  
  586. /*--------------------------------------------------------------------*/
  587. /*            Begin main command loop for reading the mail            */
  588. /*--------------------------------------------------------------------*/
  589.  
  590.    if (!bflag[F_EXPERT])
  591.       printf("Enter \"?\" for short help or \"help\" for long help.\n");
  592.  
  593. #ifdef _Windows
  594.    atexit ( CloseEasyWin );
  595. #endif
  596.  
  597.    while( ! done )
  598.    {
  599.       char *command, *operand;
  600.       int integer;
  601.       boolean first_pass = TRUE;
  602.       int previous = current;
  603.       struct CommandTable *cmd_ptr = table;
  604.       boolean success = TRUE;
  605.       boolean crlf    = FALSE;      /* crlf after delete command?    */
  606.  
  607.       printf("%d%s",current + 1,
  608.                (letters[current].status == M_DELETED) ? "*" : " ");
  609.       if (!Console_fgets(resp, LSIZE, "? ")) /* End of file?         */
  610.       {
  611.          done = TRUE;
  612.          continue;            /* Yes --> Exit loop                   */
  613.       }
  614.       PageReset();
  615.  
  616. /*--------------------------------------------------------------------*/
  617. /*                     Locate command to execute                      */
  618. /*--------------------------------------------------------------------*/
  619.  
  620.       integer = strlen( resp );
  621.       if (integer && ( resp[ integer - 1 ] == '\n'))
  622.          resp[ integer - 1 ] = '\0';   /* Trim newline, if any       */
  623.  
  624.       operand = command = strtok( resp, WHITESPACE );
  625.       if ( command == NULL )
  626.          command = EMPTY_CMD;
  627.       else if (Numeric(command))
  628.          command = NUMERIC_CMD;
  629.  
  630.       while( cmd_ptr->sym != NULL)
  631.       {
  632.          if (equaln(command, cmd_ptr->sym, strlen(command)))
  633.             break;            /* Exit if we have a hit               */
  634.          cmd_ptr++;           /* Examine next command                */
  635.       } /* while */
  636.  
  637. /*--------------------------------------------------------------------*/
  638. /*     Get rest of command line, and trim leading spaces from it      */
  639. /*--------------------------------------------------------------------*/
  640.  
  641.       if (!equal(command, NUMERIC_CMD) && (operand != NULL))
  642.       {
  643.          operand = strtok( NULL , "");
  644.                               /* Save rest of string for later       */
  645.          if ( operand != NULL )
  646.          {
  647.             while( isspace( *operand ))
  648.                operand++ ;
  649.  
  650.             if (*operand == '\0')
  651.                operand = NULL ;
  652.          } /* if */
  653.       }
  654.  
  655. /*--------------------------------------------------------------------*/
  656. /*        Parse items to be selected from mailbox for command         */
  657. /*--------------------------------------------------------------------*/
  658.  
  659.       if (cmd_ptr->bits & (LETTER_OP) )
  660.          success = SelectItems( &operand, current, cmd_ptr->bits);
  661.  
  662. /*--------------------------------------------------------------------*/
  663. /*                  Process the operands in the list                  */
  664. /*--------------------------------------------------------------------*/
  665.  
  666.       while( success &&
  667.              Get_Operand( &integer, &operand, cmd_ptr->bits, first_pass) )
  668.       {
  669.          switch( cmd_ptr->verb )
  670.          {
  671.             case M_ALIAS:
  672.                ShowAlias( operand );
  673.                break;
  674.  
  675.             case M_COPY:
  676.                success = SaveItem( integer,
  677.                          FALSE,        /* Do not delete */
  678.                          seperators,   /* Do save headers */
  679.                          (operand == NULL) ? "PRN" : operand ,
  680.                          cmd_ptr->verb );
  681.                break;
  682.  
  683.             case M_DEBUG:
  684.                debuglevel = integer;
  685.                printmsg(0,"Debug set to %d",debuglevel);
  686.                break;
  687.  
  688.             case M_DELETEQ:
  689.                done = TRUE;
  690.             case M_DELETE:
  691.                if (letters[integer].status < M_DELETED)
  692.                {
  693.                   letters[integer].status = M_DELETED;
  694.                   if ( ! crlf )
  695.                      printf("Deleting item(s) %d",integer + 1 );
  696.                   else
  697.                      printf(" %d",integer + 1 );
  698.                   crlf  = modified = TRUE;
  699.                }
  700.                break;
  701.  
  702.             case M_DOWN:
  703.                current = Position( 0 , integer , current );
  704.                break;
  705.  
  706.             case M_EMPTY:
  707.                if ( bflag[F_DOSKEY] && !bflag[F_EXPERT] )
  708.                {
  709.                   printf("DOSKEY active, empty line ignored\n");
  710.                   PrintSubject( current , letternum );
  711.                   success = FALSE;
  712.                }
  713.                else if (letters[current].status == M_UNREAD)
  714.                   success = Pager( current , TRUE, noreceived, first_pass);
  715.                else
  716.                   current = Position( 0 , 1 , current );
  717.                break;
  718.  
  719.             case M_EXIT:
  720.                modified = FALSE;
  721.                done     = TRUE;
  722.                break;
  723.  
  724.             case M_EXTPRINT:
  725.                success = Pager( integer , TRUE, noreceived, first_pass);
  726.                break;
  727.  
  728.             case M_EXTTYPE:
  729.                success = Pager( integer , TRUE, noseperator, first_pass);
  730.                break;
  731.  
  732.             case M_FASTHELP:
  733.             {
  734.                size_t subscript = 0;
  735. #ifndef _Windows
  736.                size_t column    = 0;
  737. #endif
  738.                fputs("Valid commands are:\n",stdout);
  739.                while( table[subscript].sym != NULL)
  740.                {
  741.                   if ( !(table[subscript].bits & NODISPLAY ))
  742.                   {
  743. #ifdef _Windows
  744.                      fputc( '\n' , stdout );
  745. #else
  746.                      fputc( ( column++ % 2 ) ? ' ' : '\n' , stdout );
  747. #endif
  748.                      printf("%-9s%-30s",table[subscript].sym,
  749.                                        table[subscript].help );
  750.                   } /* if */
  751.                   subscript ++;
  752.                } /* while */
  753.                fputs("\n\nEnter \"help\" for additional information.\n",
  754.                         stdout);
  755.                break;
  756.             } /* case */
  757.  
  758.             case M_FORWARD:
  759.                success = ForwardItem( integer, operand);
  760.                break;
  761.  
  762.             case M_GOTO:
  763.                current = Position( integer, 0, current );
  764.                break;
  765.  
  766.             case M_HEADERS:
  767.                PrintSubject( (cmd_ptr->bits & NO_OPERANDS) ?
  768.                                  -1 : integer, letternum );
  769.                break;
  770.  
  771.             case M_HELP:
  772.             {
  773.                char filename[FILENAME_MAX];
  774.                mkfilename(filename, E_confdir, "mail.hlp");
  775.                Sub_Pager(filename, TRUE );
  776.                break;
  777.             }
  778.  
  779.             case M_INTPRINT:
  780.                success = Pager( integer , FALSE, noreceived, first_pass);
  781.                break;
  782.  
  783.             case M_INTTYPE:
  784.                success = Pager( integer , FALSE, noseperator, first_pass);
  785.                break;
  786.  
  787.             case M_INVALID:
  788.                printf("Invalid command \"%s\".  Enter \"?\" for help.\n",
  789.                         command);
  790.                break;
  791.  
  792.             case M_MAIL:
  793.                success = DeliverMail( operand , current);
  794.                break;
  795.  
  796.             case M_NOOP:
  797.                break;
  798.  
  799.             case M_REPLY:
  800.                success = Reply( integer );
  801.                break;
  802.  
  803.             case M_QUIT:
  804.                done = TRUE;
  805.                break;
  806.  
  807.             case M_SAVE:
  808.                success = SaveItem( integer,
  809.                          TRUE,         /* Do delete */
  810.                          seperators,   /* Do save headers */
  811.                          operand ,
  812.                          cmd_ptr->verb );
  813.                modified = TRUE;
  814.                break;
  815.  
  816.             case M_SET:
  817.                if (operand == NULL)
  818.                   sayoptions( configFlags);
  819.                else
  820.                   options(operand, USER_CONFIG, configFlags, bflag);
  821.                break;
  822.  
  823.             case M_SYSTEM:
  824.                subshell( operand );
  825.                break;
  826.  
  827.             case M_UNDELETE:
  828.                letters[integer].status = M_UNREAD;
  829.                break;
  830.  
  831.             case M_UP:
  832.                current = Position( 0 , - integer , current );
  833.                break;
  834.  
  835.             case M_STATUS:
  836.                printf("%s:\t%s created %s %s running under %s %d.%02d\n",
  837.                        compilep, compilev, compiled, compilet,
  838.  
  839. #ifdef WIN32
  840.                      "Windows NT",
  841.                      _winmajor,
  842.                      _winminor);
  843. #elif defined(__OS2__)
  844.                     "OS/2(R)" ,
  845.                     (int) _osmajor / 10,
  846.                       _osminor);
  847. #elif defined(__TURBOC__)
  848.                     "DOS",
  849.                     _osmajor,
  850.                     _osminor);
  851. #else
  852.                     (_osmode == DOS_MODE) ? "DOS" : "OS/2(R)" ,
  853.                     (_osmode == DOS_MODE) ? _osmajor : ((int) _osmajor / 10 ),
  854.                      _osminor);
  855. #endif
  856. #ifdef _Windows
  857.                printf("Windows version: %s\t", compilew );
  858. #endif
  859.                printf("Magic Word:\t%s\n","flarp");
  860.                printf("Return address:\t\"%s\" <%s@%s>\n"
  861.                       "Domain name:\t%s\tNodename:\t%s\n",
  862.                         E_name, E_mailbox, E_fdomain, E_domain, E_nodename );
  863.                printf("Current File:\t%s\tNumber of items: %d\n"
  864.                       "File size:\t%ld bytes\tLast updated:\t%s",
  865.                         mfilename, letternum + 1 , mboxsize ,
  866.                         ctime( & mboxage ) );
  867.                break;
  868.  
  869.             case M_WRITE:
  870.                success = SaveItem( integer,
  871.                          TRUE,      /* Do delete */
  872.                          noheader,  /* Do not save headers */
  873.                          operand,
  874.                          cmd_ptr->verb );
  875.                modified = TRUE;
  876.          } /* switch */
  877.          first_pass = FALSE;
  878.       } /* while */
  879.  
  880.       success = ! first_pass; /* If first_pass not run, then
  881.                                  Get_Operand failed                  */
  882.  
  883.       if ( crlf )
  884.          putchar('\n');
  885.  
  886.       if ( success && !done )
  887.       {
  888.          if (cmd_ptr->bits & POSITION)
  889.             current = Position( 0 , 0 , integer );
  890.  
  891.          if ( current != previous )
  892.          {
  893.             if ( (cmd_ptr->bits & AUTOPRINT ) &&
  894.                   bflag[F_AUTOPRINT] &&
  895.                   (letters[current].status != M_DELETED) )
  896.                Pager( current , TRUE, noreceived, TRUE);
  897.             else if ( !(cmd_ptr->bits & NOAUTOHEADER ) )
  898.                PrintSubject( current , letternum );
  899.          } /* if */
  900.       } /* if */
  901.    } /* while */
  902.  
  903. /*--------------------------------------------------------------------*/
  904. /*                       End main command loop                        */
  905. /*--------------------------------------------------------------------*/
  906.  
  907.    if (modified)
  908.       UpdateMailbox(letternum, postoffice);
  909.  
  910.    free(letters);
  911.  
  912. } /*Interactive_Mail*/
  913.  
  914. /*--------------------------------------------------------------------*/
  915. /*    I n c l u d e N e w                                             */
  916. /*                                                                    */
  917. /*    Includes mail from the system box into the user's local         */
  918. /*    mailbox                                                         */
  919. /*--------------------------------------------------------------------*/
  920.  
  921. static void IncludeNew( const char *target, const char *user)
  922. {
  923.    time_t age;
  924.    long size;
  925.    FILE *stream_in;
  926.    FILE *stream_out;
  927.    int  bytes;
  928.  
  929.    char sysbox[FILENAME_MAX];
  930.    char buf[BUFSIZ];
  931.  
  932.    mkmailbox(sysbox, user);
  933.  
  934. /*--------------------------------------------------------------------*/
  935. /*      Return semi-quietly if we can't open the system mailbox       */
  936. /*--------------------------------------------------------------------*/
  937.  
  938.    stream_in   = FOPEN( sysbox, "r", BINARY_MODE);
  939.    if ( stream_in == NULL )
  940.    {
  941.       if ( debuglevel > 1 )
  942.          printerr( sysbox );
  943.       return;
  944.    }
  945.  
  946. /*--------------------------------------------------------------------*/
  947. /*      Determine if we have new mail, returning quietly if not       */
  948. /*--------------------------------------------------------------------*/
  949.  
  950.    age = stater( sysbox , &size );
  951.  
  952.    if ( age == (time_t) -1L)
  953.       panic();
  954.  
  955.    printmsg( 1, "Including mail from %s through %.24s",
  956.             sysbox,
  957.             ctime(&age));
  958.  
  959. /*--------------------------------------------------------------------*/
  960. /*                    Now open up the output file                     */
  961. /*--------------------------------------------------------------------*/
  962.  
  963.    stream_out  = FOPEN( target, "a+", BINARY_MODE);
  964.  
  965.    if ( stream_out == NULL )
  966.    {
  967.       printerr( target );
  968.       panic();
  969.    }
  970.  
  971. /*--------------------------------------------------------------------*/
  972. /*                       Loop to read the data                        */
  973. /*--------------------------------------------------------------------*/
  974.  
  975.    while ((bytes = fread(buf,sizeof(char), sizeof buf, stream_in)) > 0)
  976.    {
  977.       if ((int) fwrite(buf, sizeof(char), bytes, stream_out) != bytes)
  978.       {
  979.          printmsg(0, "Error including new mail into %s", target );
  980.          printerr( target );
  981.          fclose( stream_in );
  982.          fclose( stream_out );
  983.          panic();
  984.       }
  985.    } /* while */
  986.  
  987. /*--------------------------------------------------------------------*/
  988. /*                   Clean up and return to caller                    */
  989. /*--------------------------------------------------------------------*/
  990.  
  991.    if ( ferror( stream_in ))
  992.    {
  993.       printerr( sysbox );
  994.       panic();
  995.    }
  996.  
  997.    fclose( stream_in  );
  998.    fclose( stream_out );
  999.  
  1000.    filebkup( sysbox );
  1001.    unlink(sysbox);
  1002.  
  1003. } /* IncludeNew */
  1004.  
  1005. /*--------------------------------------------------------------------*/
  1006. /*    C r e a t e B o x                                               */
  1007. /*                                                                    */
  1008. /*    Creates the temporary mailbox and related tables                */
  1009. /*--------------------------------------------------------------------*/
  1010.  
  1011. int CreateBox(FILE *rmailbox, FILE *fmailbox , const char *tmailbox)
  1012. {
  1013.  
  1014. /*--------------------------------------------------------------------*/
  1015. /*          Copy real mailbox file to temporary mailbox file          */
  1016. /*--------------------------------------------------------------------*/
  1017.  
  1018.    int letternum = 0;
  1019.    boolean inheader = FALSE;
  1020.    long position;
  1021.    char line[LSIZE];
  1022.    char **list;
  1023.    size_t replyprior = 0;
  1024.    size_t dateprior = 0;
  1025.    size_t subjectprior = 0;
  1026.    size_t fromprior = 0;
  1027.  
  1028.    struct ldesc *letter = NULL;
  1029.  
  1030.    while ((fgets(line, LSIZE, rmailbox) != nil(char)) ){
  1031.  
  1032.       if (inheader)
  1033.       {
  1034.          if (*line == '\n')
  1035.             inheader = FALSE;
  1036.       }  /* inheader */
  1037.       else {               /* Determine if starting new message   */
  1038.          if (equal(line,MESSAGESEP) ||
  1039.             (bflag[F_FROMSEP] && equaln(line, "From ", 5)))
  1040.          {
  1041.              while (equal(line,MESSAGESEP))
  1042.              if (fgets(line, LSIZE, rmailbox) == NULL)
  1043.              {
  1044.                printerr(mfilename);
  1045.                panic();
  1046.              } /* if */
  1047.  
  1048. /*--------------------------------------------------------------------*/
  1049. /*               Make the mailbox bigger if we need to                */
  1050. /*--------------------------------------------------------------------*/
  1051.  
  1052.              position = ftell(fmailbox);
  1053.              if ( (letternum+1) == maxletters )
  1054.              {
  1055.                maxletters = max((int) ((maxletters * mboxsize) / position),
  1056.                                  (letternum * 11) / 10 );
  1057.                printmsg(2,"Reallocating mailbox array from %d to %d entries",
  1058.                      letternum+1, maxletters );
  1059.                letters = realloc( letters, maxletters *  sizeof(letters[0]));
  1060.                checkref( letters );
  1061.              }
  1062.  
  1063. /*--------------------------------------------------------------------*/
  1064. /*             Initialize this entry in th mailbox array              */
  1065. /*--------------------------------------------------------------------*/
  1066.  
  1067.              letter = &letters[letternum++];
  1068.  
  1069.              fromprior = subjectprior = replyprior = dateprior = INT_MAX;
  1070.              letter->from = letter->subject = letter->date =
  1071.                   letter->replyto = MISSING;
  1072.              letter->adr = position;
  1073.              letter->status = M_UNREAD;
  1074.              letter->lines = 0L;
  1075.              inheader = TRUE;
  1076.              printf("Reading message %d (%d%% done)\r",letternum,
  1077.                         (int) (position * 100 / mboxsize));
  1078.          }
  1079.          else
  1080.          {
  1081.             if(letter == NULL)   /* Did we find first letter?     */
  1082.             {                    /* No --> Abort with message     */
  1083.                fprintf(stderr,"%s  %s\n\a",
  1084.                   "This mailbox is not in UUPC/extended format!",
  1085.                   bflag[F_FROMSEP] ?
  1086.                   "Messages must be seperated by From lines!" :
  1087.                   "(Try \"options=fromsep\" in your configuration file)");
  1088.                panic();
  1089.             } /* if */
  1090.  
  1091.             letter->lines++;
  1092.          } /* else */
  1093.       } /* else */
  1094.  
  1095.       if (inheader)
  1096.       {
  1097.          size_t priority = 0;
  1098.  
  1099. /*--------------------------------------------------------------------*/
  1100. /*              Search for the best Date: related field               */
  1101. /*--------------------------------------------------------------------*/
  1102.  
  1103.          while ( (dateprior > priority) && (datelist[priority] != NULL ))
  1104.          {
  1105.             if (equalni(line, datelist[priority],
  1106.                              strlen(datelist[priority]) ) )
  1107.             {
  1108.                letter->date = ftell(fmailbox);
  1109.                dateprior = priority;
  1110.             }
  1111.             priority++;
  1112.          }
  1113.  
  1114. /*--------------------------------------------------------------------*/
  1115. /*             Search for the best Subject: related field             */
  1116. /*--------------------------------------------------------------------*/
  1117.  
  1118.          priority = 0;
  1119.          while ( (subjectprior > priority) &&
  1120.                  (subjectlist[priority] != NULL ))
  1121.          {
  1122.             if (equalni(line, subjectlist[priority],
  1123.                              strlen(subjectlist[priority]) ) )
  1124.             {
  1125.                letter->subject = ftell(fmailbox);
  1126.                subjectprior = priority;
  1127.             }
  1128.             priority++;
  1129.          }
  1130.  
  1131. /*--------------------------------------------------------------------*/
  1132. /*           Search for the best From: header related field           */
  1133. /*--------------------------------------------------------------------*/
  1134.  
  1135.          list = (useto) ? tolist : fromlist;
  1136.          priority = 0;
  1137.          while ( (fromprior > priority) && (list[priority] != NULL ))
  1138.          {
  1139.             if (equalni(line, list[priority],
  1140.                              strlen(list[priority]) ) )
  1141.             {
  1142.                letter->from = ftell(fmailbox);
  1143.                fromprior = priority;
  1144.             }
  1145.             priority++;
  1146.          } /* while */
  1147.  
  1148. /*--------------------------------------------------------------------*/
  1149. /*             Search for the best Reply-To related field             */
  1150. /*--------------------------------------------------------------------*/
  1151.  
  1152.          priority = 0;
  1153.          while ( (replyprior > priority) &&
  1154.                  (replytolist[priority] != NULL ))
  1155.          {
  1156.             if (equalni(line, replytolist[priority],
  1157.                              strlen(replytolist[priority]) ) )
  1158.             {
  1159.                letter->replyto = ftell(fmailbox);
  1160.                replyprior = priority;
  1161.             } /* if */
  1162.             priority++;
  1163.          }  /* while */
  1164.       } /* inheader */
  1165.  
  1166.       if (fputs(line, fmailbox) == EOF )
  1167.       {
  1168.          printerr(tmailbox);
  1169.          panic();
  1170.       } /* if */
  1171.  
  1172.  
  1173.    } /* while */
  1174.  
  1175.    letters[letternum].adr = ftell(fmailbox);
  1176.    letters[letternum].status = M_DELETED;
  1177.  
  1178.  
  1179.    fclose(rmailbox);
  1180.    fclose(fmailbox);
  1181.  
  1182.    return letternum;
  1183.  
  1184. } /* CreateBox */
  1185.  
  1186. /*--------------------------------------------------------------------*/
  1187. /*    P r i n t S u j e c t                                           */
  1188. /*                                                                    */
  1189. /*    Print the subject line of one or all messages in the mailbox    */
  1190. /*--------------------------------------------------------------------*/
  1191.  
  1192. void PrintSubject(int msgnum,int letternum)
  1193. {
  1194.    struct ldesc *ld;
  1195.    char from[LSIZE];
  1196.    char subject[LSIZE];
  1197.    char date[LSIZE];
  1198.    char line[LSIZE];
  1199.  
  1200.    int k, mink, maxk;
  1201.  
  1202.    if (msgnum == -1)
  1203.    {                                         /* print all of them? */
  1204.       sprintf(line," %d messages in file %s.\n",letternum,mfilename);
  1205.       PageLine(line);
  1206.       mink = 0;
  1207.       maxk = letternum - 1;
  1208.    } else
  1209.       mink = maxk = msgnum;
  1210.  
  1211.    for (k = mink ; k <= maxk ; k++) {
  1212.  
  1213.       ld = &letters[k];
  1214.       if ((ld->status == M_DELETED) && (msgnum == -1))
  1215.          continue;
  1216.  
  1217.       ReturnAddress(from,ld);       /* Get return address for letter */
  1218.  
  1219.       /* Date: Wed May 13 23:59:53 1987 */
  1220.       *date = '\0';  /* default date to null */
  1221.       if (RetrieveLine(ld->date, date, LSIZE)) {
  1222.          sscanf(date, "%*s %*s %s %s", line, subject);
  1223.          sprintf(date, "%s %s", line, subject);
  1224.       }
  1225.  
  1226.       strcpy(subject, "--- no subject ---");
  1227.       if (RetrieveLine(ld->subject, line, LSIZE)) {
  1228.          register char  *sp;
  1229.          sp = line;
  1230.          while (!isspace(*sp))
  1231.             sp++;
  1232.          while (isspace(*sp))
  1233.             sp++;
  1234.          strcpy(subject, sp);
  1235.       }
  1236.  
  1237.       /* make sure the fields aren't too long */
  1238.  
  1239.       from[25] = '\0';
  1240.       date[6] = '\0';
  1241.       subject[30] = '\0';
  1242.  
  1243.       sprintf(line, "%3d%c %6s  %-25s  %-30s  (%5ld)\n", k + 1,
  1244.          ((ld->status == M_DELETED) ? '*' : ' '),
  1245.             date, from, subject, ld->lines);
  1246.  
  1247.       if (PageLine(line))
  1248.          break;
  1249.  
  1250.    }
  1251.  
  1252. } /*PrintSubject*/
  1253.  
  1254.  
  1255. /*--------------------------------------------------------------------*/
  1256. /*    U p d a t e  M a i l b o x                                      */
  1257. /*                                                                    */
  1258. /*    Update the permanent mailbox for the user                       */
  1259. /*--------------------------------------------------------------------*/
  1260.  
  1261. void UpdateMailbox(int letternum, boolean postoffice)
  1262. {
  1263.    int current;
  1264.    boolean changed = FALSE;
  1265.    boolean problem = FALSE;
  1266.    FILE *fmailbag;
  1267.    FILE *mbox = NULL;
  1268.    char *mboxname = NULL;
  1269.    long newsize;
  1270.    time_t newage;
  1271.    size_t msave = 0;
  1272.    size_t psave = 0;
  1273.  
  1274. /*--------------------------------------------------------------------*/
  1275. /*    Auto save into user's home directory mailbox if we were         */
  1276. /*    reading the system mailbox and the user specified the           */
  1277. /*    'save' option.                                                  */
  1278. /*--------------------------------------------------------------------*/
  1279.  
  1280.    postoffice = postoffice && bflag[F_SAVE];
  1281.  
  1282. /*--------------------------------------------------------------------*/
  1283. /*     Determine if anything was actually changed in the mailbox      */
  1284. /*--------------------------------------------------------------------*/
  1285.  
  1286.    for (current = 0;
  1287.         (current < letternum) && (! changed);
  1288.         current++)
  1289.    {
  1290.       if (letters[current].status == M_DELETED)
  1291.          changed = TRUE;
  1292.  
  1293.       if (postoffice && (letters[current].status != M_UNREAD))
  1294.          changed = TRUE;
  1295.    }
  1296.  
  1297.    if (!changed)
  1298.       return;
  1299.  
  1300. /*--------------------------------------------------------------------*/
  1301. /*    Determine if the mailbox has changed since we built our         */
  1302. /*    temporary file                                                  */
  1303. /*--------------------------------------------------------------------*/
  1304.  
  1305.    newage = stater( mfilename , &newsize );
  1306.  
  1307.    if ( mboxsize != newsize )
  1308.    {
  1309.       printf("%s size has changed from %ld to %ld bytes\n",
  1310.             mfilename, mboxsize, newsize );
  1311.       problem = TRUE;
  1312.    }
  1313.  
  1314.    if ( mboxage != newage )
  1315.    {
  1316.       char mboxbuf[DATEBUF];
  1317.       char newbuf[DATEBUF];
  1318.       printf("%s date stamp has changed from %s to %s\n",
  1319.             mfilename, dater(mboxage, mboxbuf), dater(newage, newbuf) );
  1320.       problem = TRUE;
  1321.    }
  1322.  
  1323.    while ( problem )
  1324.    {
  1325.       int c;
  1326.  
  1327.       printf("WARNING! File %s has changed, data may be lost if updated!\n",
  1328.             mfilename);
  1329.       fputs("Update anyway? ",stdout);
  1330.  
  1331.       c     = Get_One();
  1332.  
  1333.       switch (tolower( c ))
  1334.       {
  1335.          case 'y':
  1336.             puts("Yes");
  1337.             problem = FALSE;
  1338.             break;
  1339.  
  1340.          case 'n':
  1341.             printf("No\nUpdate aborted, %s left unchanged.\n",
  1342.                      mfilename);
  1343.             return;
  1344.  
  1345.          default:
  1346.             printf("%c - Invalid Response\n",c);
  1347.             break;
  1348.       } /* switch */
  1349.    } /* while ( problem ) */
  1350.  
  1351. /*--------------------------------------------------------------------*/
  1352. /*                Allocate auto save related variables                */
  1353. /*--------------------------------------------------------------------*/
  1354.  
  1355.    if (postoffice)
  1356.    {
  1357.       mboxname = malloc(FILENAME_MAX);
  1358.       checkref(mboxname);
  1359.       strcpy( mboxname, "mbox" );
  1360.       expand_path( mboxname, E_homedir, E_homedir, E_mailext );
  1361.    } /* if (postoffice) */
  1362.  
  1363. /*--------------------------------------------------------------------*/
  1364. /*                   Create a backup file if needed                   */
  1365. /*--------------------------------------------------------------------*/
  1366.  
  1367.    if ( bflag[F_BACKUP] )
  1368.       filebkup( mfilename );
  1369.  
  1370. /*--------------------------------------------------------------------*/
  1371. /*                    Begin re-writing the mailbox                    */
  1372. /*--------------------------------------------------------------------*/
  1373.  
  1374.    if ((fmailbag = FOPEN(mfilename, "w",TEXT_MODE)) == nil(FILE))
  1375.    {
  1376.       printf("UpdateMailbox: can't rewrite %s.\n", mfilename);
  1377.       Cleanup();
  1378.    } /* if */
  1379.  
  1380.    setvbuf(fmailbag, NULL, _IOFBF, 8192);
  1381.  
  1382. /*--------------------------------------------------------------------*/
  1383. /*    We got the files open, now actually loop through copying        */
  1384. /*    data from our temporary mailbox back into the permenent one,    */
  1385. /*    or in the user's mbox if he read the message and the post       */
  1386. /*    office is open.                                                 */
  1387. /*--------------------------------------------------------------------*/
  1388.  
  1389.    printf("Cleaning up ", current+ 1);
  1390.  
  1391.    for (current = 0; current < letternum;  current++)
  1392.    {
  1393.       if (letters[current].status == M_DELETED)
  1394.       {
  1395.          /* No operation */
  1396.          fputc('.', stdout);
  1397.       }
  1398.       else if (postoffice && (letters[current].status != M_UNREAD))
  1399.       {
  1400.  
  1401.          if ( mbox == NULL )  /* Mailbox already open?               */
  1402.          {                    /* No --> Do so now                    */
  1403.             mbox = FOPEN(mboxname, "a",TEXT_MODE);
  1404.             if (mbox == NULL) /* Open fail?                          */
  1405.             {                  /* Yes --> Disable postoffice autosave*/
  1406.                printf("\nUpdateMailbox: can't append to %s.\n", mboxname);
  1407.                postoffice = FALSE;
  1408.                current--;     /* Process this entry again            */
  1409.             } /* if */
  1410.             else
  1411.                setvbuf(mbox, NULL, _IOFBF, 8192);
  1412.          } /* if ( mbox == NULL ) */
  1413.  
  1414.          if ( mbox != NULL )
  1415.          {
  1416.             fputc('+', stdout);
  1417.             CopyMsg(current, mbox, seperators, FALSE);
  1418.             msave++;
  1419.          } /* mbox */
  1420.       }
  1421.       else {
  1422.          fputc('*', stdout);
  1423.          CopyMsg(current, fmailbag, seperators, FALSE);
  1424.          psave ++;
  1425.       } /* else */
  1426.  
  1427.    } /* for */
  1428.    fputs(" done!\n", stdout);
  1429.  
  1430. /*--------------------------------------------------------------------*/
  1431. /*    Close the post office.  We close the 'mbox' in the user's       */
  1432. /*    home directory, report if any data was saved in it, and         */
  1433. /*    then free the storage associated with the postoffice processing.*/
  1434. /*--------------------------------------------------------------------*/
  1435.  
  1436.    if ( postoffice )
  1437.    {
  1438.  
  1439.       if (msave > 0)          /* Did we write data into mailbox?  */
  1440.       {                       /* Yes --> Report it                */
  1441.          fclose(mbox);
  1442.          printf("%d letter%s saved in %s%s",
  1443.                msave,
  1444.                (msave > 1) ? "s" : "" ,
  1445.                mboxname,
  1446.                (psave > 0) ? ", " : ".\n");
  1447.       }
  1448.  
  1449.       free(mboxname);
  1450.    } /* if (postoffice) */
  1451.  
  1452. /*--------------------------------------------------------------------*/
  1453. /*    Now, clean up after the input mailbox.  We close it, and        */
  1454. /*    report when anything was saved into it.  If nothing was         */
  1455. /*    saved, we delete the file if the 'purge' option is active.      */
  1456. /*--------------------------------------------------------------------*/
  1457.  
  1458.    fclose(fmailbag);
  1459.  
  1460.    if (psave > 0)
  1461.       printf("%d letter%s held in %s.\n",
  1462.             psave ,
  1463.             (psave > 1) ? "s" : "" , mfilename);
  1464.    else if (bflag[F_PURGE] )
  1465.    {
  1466.       remove(mfilename);
  1467.       printf("Empty mail box %s has been deleted.\n", mfilename);
  1468.    }
  1469.  
  1470. } /* UpdateMailbox */
  1471.  
  1472. /*--------------------------------------------------------------------*/
  1473. /*    U s a g e                                                       */
  1474. /*                                                                    */
  1475. /*    Report command line syntax                                      */
  1476. /*--------------------------------------------------------------------*/
  1477.  
  1478. static void usage( void )
  1479. {
  1480.    puts("\nUsage:\tmail [-s subject] recipient ... "
  1481.          "[-c recipient ...] [-b receipient ...]\n"
  1482.          "\tmail [-f mailbox] [-u user] [-t] [-p] [-x debug]");
  1483.    exit(1);
  1484. }
  1485.