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

  1. /*--------------------------------------------------------------------*/
  2. /*       m a i l b l i b . c                                          */
  3. /*                                                                    */
  4. /*       Support routines for UUPC/extended mail user agent           */
  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: mailblib.c 1.9 1993/11/13 17:43:26 ahd Exp $
  21.  *
  22.  *    Revision history:
  23.  *    $Log: mailblib.c $
  24.  * Revision 1.9  1993/11/13  17:43:26  ahd
  25.  * Noramalize external command processing
  26.  *
  27.  * Revision 1.8  1993/10/31  21:32:55  ahd
  28.  * Treat .. as parent directory (actually, DON'T treat it as item number).
  29.  *
  30.  * Revision 1.7  1993/10/12  01:32:08  ahd
  31.  * Normalize comments to PL/I style
  32.  *
  33.  * Revision 1.5  1993/10/09  20:16:12  rhg
  34.  * ANSIy the source
  35.  *
  36.  * Revision 1.4  1993/09/20  04:41:54  ahd
  37.  * OS/2 2.x support
  38.  *
  39.  * Revision 1.3  1993/07/31  16:26:01  ahd
  40.  * Changes in support of Robert Denny's Windows support
  41.  *
  42.  */
  43.  
  44. /*--------------------------------------------------------------------*/
  45. /*                        System include files                        */
  46. /*--------------------------------------------------------------------*/
  47.  
  48. #include <stdio.h>
  49. #include <string.h>
  50. #include <stdlib.h>
  51. #include <ctype.h>
  52.  
  53. /*--------------------------------------------------------------------*/
  54. /*                    UUPC/extended include files                     */
  55. /*--------------------------------------------------------------------*/
  56.  
  57. #include "lib.h"
  58. #include "address.h"
  59. #include "mail.h"
  60. #include "maillib.h"
  61. #include "mailblib.h"
  62. #include "mailsend.h"
  63. #include "hlib.h"
  64. #include "alias.h"
  65. #include "expath.h"
  66. #include "execute.h"
  67.  
  68. /*--------------------------------------------------------------------*/
  69. /*                      Variables global to file                      */
  70. /*--------------------------------------------------------------------*/
  71.  
  72. static int *item_list = NULL;
  73. static size_t next_item;
  74.  
  75. currentfile();
  76.  
  77. /*--------------------------------------------------------------------*/
  78. /*                    Internal function prototypes                    */
  79. /*--------------------------------------------------------------------*/
  80.  
  81. static boolean SearchUser( char *token , char **input, const int bits);
  82.  
  83. static boolean SearchSubject( char *token,
  84.                               char **input,
  85.                               char *trailing,
  86.                               const int bits);
  87.  
  88. /*--------------------------------------------------------------------*/
  89. /*                     Externally known functions                     */
  90. /*--------------------------------------------------------------------*/
  91.  
  92. /*--------------------------------------------------------------------*/
  93. /*    S h o w A l i a s                                               */
  94. /*                                                                    */
  95. /*    Print the expansion of an alias                                 */
  96. /*--------------------------------------------------------------------*/
  97.  
  98. void ShowAlias( const char *alias)
  99. {
  100.    char *fullname = AliasByNick( alias );
  101.    static int level = 0;
  102.    int column = level * 2;
  103.  
  104.    if ( alias == NULL )
  105.    {
  106.       printf("Missing operand\n");
  107.       return;
  108.    }
  109.  
  110. /*--------------------------------------------------------------------*/
  111. /*                        Indent nested calls                         */
  112. /*--------------------------------------------------------------------*/
  113.  
  114.    while(column-- > 0 )
  115.       putchar(' ');
  116.  
  117. /*--------------------------------------------------------------------*/
  118. /*       Show the alias, breaking it down recursively if need be      */
  119. /*--------------------------------------------------------------------*/
  120.  
  121.    if (fullname == NULL)
  122.    {
  123.       char user[MAXADDR];
  124.       char path[MAXADDR];
  125.       char node[MAXADDR];
  126.  
  127.       printf("No alias defined for \"%s\"\n",alias);
  128.  
  129.       column = level * 2 + 2;
  130.       while(column-- > 0 )
  131.          putchar(' ');
  132.  
  133.       user_at_node(alias, path, node, user);
  134.                               /* Reduce address to basics */
  135.       printf("(%s@%s via %s)\n", user, node, path);
  136.    }
  137.    else {
  138.  
  139.       printf("%s is aliased to %s\n", alias, fullname);
  140.  
  141.       if (*fullname == '"')
  142.       {
  143.  
  144.          if ( debuglevel > 1)
  145.          {
  146.             char user[MAXADDR];
  147.             char path[MAXADDR];
  148.             char node[MAXADDR];
  149.  
  150.             ExtractAddress(user,fullname, FALSE);
  151.             user_at_node(user,path,node,user);
  152.                                     /* Reduce address to basics */
  153.             column = level * 2 + 2;
  154.             while(column-- > 0 )
  155.                putchar(' ');
  156.  
  157.             printf("(%s@%s via %s)\n", user, node, path);
  158.          }
  159.       }
  160.       else {
  161.          char buf[LSIZE];
  162.  
  163.          strcpy( buf, fullname );
  164.          fullname = strtok( buf , WHITESPACE "," );
  165.  
  166.          while (fullname != NULL )
  167.          {
  168.             char *save = strtok( NULL , "");
  169.             level++;             /* Bump up a level for recursive calls */
  170.             ShowAlias(fullname);
  171.             level--;             /* Restore indent level               */
  172.             fullname = strtok( save , " ," );
  173.          } /* while */
  174.       } /* else */
  175.    } /* else */
  176.  
  177. } /* ShowAlias */
  178.  
  179. /*--------------------------------------------------------------------*/
  180. /*    S a v e I t e m                                                 */
  181. /*                                                                    */
  182. /*    Save an item in another mailbox                                 */
  183. /*--------------------------------------------------------------------*/
  184.  
  185. boolean SaveItem( const int item,
  186.                const boolean delete,
  187.                const copyopt headers,
  188.                char *fname,
  189.                const ACTION verb)
  190. {
  191.    char filename[FILENAME_MAX];
  192.    char *s = "?";
  193.    FILE *stream;
  194.  
  195.    if (fname == NULL)
  196.       fname = "~/mbox";
  197.  
  198. /*--------------------------------------------------------------------*/
  199. /*                        Build the file name                         */
  200. /*--------------------------------------------------------------------*/
  201.  
  202.    switch (*fname)
  203.    {
  204.       case '=':         /* relative to home directory? */
  205.             printf("Syntax is obsolete ... use \"~/%s\"", fname + 1 );
  206.             mkfilename(filename, E_homedir, ++fname);
  207.             break;
  208.  
  209.       case '+':         /* Relative to mail directory?   */
  210.             mkmailbox(filename, ++fname);
  211.             break;
  212.  
  213.       default:
  214.       case '~':         /* Relative to home directory?            */
  215.             strcpy( filename , fname );
  216.             if (expand_path( filename , NULL, E_homedir, E_mailext ) == NULL)
  217.                return FALSE;
  218.             break;
  219.    }  /* end switch */
  220.  
  221. /*--------------------------------------------------------------------*/
  222. /*               Announce our action based on the verb                */
  223. /*--------------------------------------------------------------------*/
  224.  
  225.    switch( verb )
  226.    {
  227.       case M_COPY:
  228.          s = "Copying";
  229.          break;
  230.  
  231.       case M_SAVE:
  232.          s = "Saving";
  233.          break;
  234.  
  235.       case M_WRITE:
  236.          s = "Writing";
  237.          break;
  238.    } /* switch */
  239.  
  240.    printf("%s item %d to %s\n", s , item + 1, filename );
  241.  
  242. /*--------------------------------------------------------------------*/
  243. /*                     Open the mailox to save to                     */
  244. /*--------------------------------------------------------------------*/
  245.  
  246.    if ((stream = FOPEN(filename, "a",TEXT_MODE)) == nil(FILE))
  247.    {
  248.       printf("Cannot append to %s\n", filename);
  249.       return FALSE;
  250.    } /* if */
  251.  
  252.    CopyMsg(item, stream, headers, FALSE);
  253.    fclose(stream);
  254.  
  255. /*--------------------------------------------------------------------*/
  256. /*                   Delete the message if required                   */
  257. /*--------------------------------------------------------------------*/
  258.  
  259.    if (letters[item].status < M_DELETED)
  260.       letters[item].status = delete ? M_DELETED : M_SAVED;
  261.  
  262.    return TRUE;
  263. } /* SaveItem */
  264.  
  265.  
  266. /*--------------------------------------------------------------------*/
  267. /*    P o s i t i o n                                                 */
  268. /*                                                                    */
  269. /*    Makes reasonable choice of next letter to examine               */
  270. /*--------------------------------------------------------------------*/
  271.  
  272. int Position(int absolute, int relative, int start)
  273. {
  274.    int current = start;
  275.  
  276. /*--------------------------------------------------------------------*/
  277. /*                   Explicitly position the letter                   */
  278. /*--------------------------------------------------------------------*/
  279.  
  280.    if ( absolute )
  281.    {
  282.       current = absolute ;
  283.       if (( current <= letternum ) && (current > 0))
  284.          return current - 1;
  285.       else if ( current >= letternum )
  286.          printf("Item %d does not exist, last item in mailbox is %d\n",
  287.                current , letternum);
  288.       else
  289.          printf("Cannot backup beyond top of mailbox\n");
  290.  
  291.       return start;
  292.    } /* if */
  293.  
  294. /*--------------------------------------------------------------------*/
  295. /*           Position the pionter relative to current item            */
  296. /*--------------------------------------------------------------------*/
  297.  
  298.    if ( relative )
  299.    {
  300.       int move ;
  301.       move = (relative > 0) ? 1 : -1;
  302.       if ( (current + move) == letternum )
  303.       {
  304.          printf("At end of mailbox\n");
  305.          return current;
  306.       }
  307.  
  308.       while ( relative )
  309.       {
  310.          current += move;
  311.          if ( current >= letternum )
  312.          {
  313.             printf("Item %d does not exist, last item in mailbox is %d\n",
  314.                   current+relative, letternum);
  315.             return start;
  316.          }
  317.          else if ( current < 0 )
  318.          {
  319.             printf("Cannot backup beyond top of mailbox\n");
  320.             return start;
  321.          }
  322.          else if (letters[current].status != M_DELETED)
  323.             relative -= move;
  324.       } /* while */
  325.  
  326.       return current;
  327.    } /* if */
  328.  
  329. /*--------------------------------------------------------------------*/
  330. /*                   Implicitly position the letter                   */
  331. /*--------------------------------------------------------------------*/
  332.  
  333.    while (current < letternum)
  334.    {
  335.       if (letters[current].status != M_DELETED)
  336.          return current;
  337.       else
  338.          ++current;
  339.    } /* while */
  340.  
  341.    current = start;
  342.  
  343.    while (current-- > 0)
  344.       if (letters[current].status != M_DELETED)
  345.          return current;
  346.  
  347.    printf("At end of mailbox\n");
  348.    return start;
  349. } /* Position */
  350.  
  351. /*--------------------------------------------------------------------*/
  352. /*    D e l i v e r M a i l                                           */
  353. /*                                                                    */
  354. /*    Compose interactive outgoing mail                               */
  355. /*--------------------------------------------------------------------*/
  356.  
  357. boolean DeliverMail( char *addresses , int item)
  358. {
  359.    char *Largv[MAXADDRS];
  360.    int   Largc;
  361.  
  362.    Largc = getargs(addresses , Largv );
  363.    return Collect_Mail(stdin, Largc , Largv, item , FALSE);
  364. } /* DeliverMail */
  365.  
  366. /*--------------------------------------------------------------------*/
  367. /*    R e p l y                                                       */
  368. /*                                                                    */
  369. /*    Reply to incoming mail                                          */
  370. /*--------------------------------------------------------------------*/
  371.  
  372. boolean Reply( const int current )
  373. {
  374.    char *Largv[MAXADDRS];
  375.    char subject[LSIZE];
  376.    char addr[LSIZE];
  377.    char line[LSIZE];
  378.    char *column;
  379.    int   Largc = 0;
  380.  
  381.    subject[0] = '\0';
  382.  
  383. /*--------------------------------------------------------------------*/
  384. /*               Determine if we can reply to the mail                */
  385. /*--------------------------------------------------------------------*/
  386.  
  387.    if (!RetrieveLine(letters[current].replyto, addr, LSIZE))
  388.    {
  389.       printf("Cannot determine return address\n");
  390.       return FALSE;
  391.    }
  392.  
  393. /*--------------------------------------------------------------------*/
  394. /*                  Get the incoming subject, if any                  */
  395. /*--------------------------------------------------------------------*/
  396.  
  397.    if (RetrieveLine(letters[current].subject, line, LSIZE))
  398.    {
  399.       register char  *sp = line;
  400.  
  401.       while (!isspace(*sp))     /* Skip "Subject:"      */
  402.          sp++;
  403.       while (isspace(*sp))      /* Skip leading whitespace */
  404.          sp++;
  405.       Largv[Largc++] = "-s";
  406.  
  407.       if (!equalni(sp,"Re:",3))
  408.          strcat(subject,"Re: ");
  409.       strcat(subject,sp);
  410.       Largv[Largc++] = subject;
  411.    }
  412.  
  413. /*--------------------------------------------------------------------*/
  414. /*                   Get the extract return address                   */
  415. /*--------------------------------------------------------------------*/
  416.  
  417.    column = addr;
  418.    while (!isspace(*column) && strlen(column))
  419.       column++;
  420.  
  421.    BuildAddress(line,column);      /* Build standard "To:" addr  */
  422.    printf("Replying to %s\n", line);
  423.  
  424. /*--------------------------------------------------------------------*/
  425. /*                    Format the outgoing address                     */
  426. /*--------------------------------------------------------------------*/
  427.  
  428.    Largv[Largc++] = line;
  429.  
  430.    if (letters[current].status < M_ANSWERED)
  431.       letters[current].status = M_ANSWERED;
  432.  
  433.    return Collect_Mail(stdin, Largc, Largv, current, TRUE);
  434.  
  435. } /* Reply */
  436.  
  437.  
  438. /*--------------------------------------------------------------------*/
  439. /*    F o r w a r d I t e m                                           */
  440. /*                                                                    */
  441. /*    Forward (resend) mail to another address                        */
  442. /*--------------------------------------------------------------------*/
  443.  
  444. boolean ForwardItem( const int item , const char *string )
  445. {
  446.    FILE *stream;
  447.    char  *Largv[MAXADDRS];
  448.    char buf[LSIZE];
  449.    char tmailbag[FILENAME_MAX];
  450.    int   Largc;
  451.    boolean success;
  452.  
  453. /*--------------------------------------------------------------------*/
  454. /*              copy current message to a temporary file              */
  455. /*--------------------------------------------------------------------*/
  456.  
  457.    mktempname(tmailbag, "TMP");
  458.    stream = FOPEN(tmailbag, "w",TEXT_MODE);
  459.    if (stream == NULL )
  460.    {
  461.       printerr(tmailbag);
  462.       return FALSE;
  463.    } /* if */
  464.  
  465.    CopyMsg(item, stream, noreceived,FALSE);
  466.  
  467.    fclose(stream);
  468.  
  469. /*--------------------------------------------------------------------*/
  470. /*               mail the content of the temporary file               */
  471. /*--------------------------------------------------------------------*/
  472.  
  473.    stream = FOPEN(tmailbag, "r",TEXT_MODE);
  474.    if (stream == NULL )
  475.    {
  476.       printerr(tmailbag);
  477.       panic();
  478.    }
  479.  
  480.    strcpy( buf , string );
  481.    Largc = getargs( buf , Largv );
  482.    success = Send_Mail(stream, Largc , Largv, NULL, TRUE);
  483.  
  484. /*--------------------------------------------------------------------*/
  485. /*                   Clean up and return to caller                    */
  486. /*--------------------------------------------------------------------*/
  487.  
  488.    if (letters[item].status < (int) M_FORWARDED)
  489.       letters[item].status = (int) M_FORWARDED;
  490.    remove(tmailbag);
  491.  
  492.    return success;
  493. } /* ForwardItem */
  494.  
  495.  
  496. /*--------------------------------------------------------------------*/
  497. /*    s u b s h e l l                                                 */
  498. /*                                                                    */
  499. /*    Invoke inferior command processor                               */
  500. /*--------------------------------------------------------------------*/
  501.  
  502. void subshell( char *command )
  503. {
  504.    if ( command == NULL )
  505.    {
  506.       static char *new_prompt = NULL;
  507.  
  508.       char *exit_prompt =  "PROMPT=Enter EXIT to return to MAIL$_";
  509.       char *old_prompt;
  510.  
  511.       if ( new_prompt == NULL )
  512.       {
  513.          old_prompt = getenv( "PROMPT" );
  514.          if ( old_prompt == NULL )
  515.             old_prompt = "$p$g";
  516.  
  517.          new_prompt = malloc( strlen( old_prompt ) + strlen( exit_prompt ) + 1);
  518.          checkref( new_prompt );
  519.  
  520.          strcpy( new_prompt , exit_prompt );
  521.          strcat( new_prompt, old_prompt );
  522.  
  523.          if (putenv( new_prompt ) )
  524.          {
  525.             printmsg(0,"Prompt update failed ...");
  526.             printerr("putenv");
  527.          } /* if (putenv( new_prompt ) ) */
  528.  
  529.       } /* if ( new_prompt == NULL ) */
  530.  
  531.       executeCommand( getenv( "COMSPEC" ),
  532.                       NULL,
  533.                       NULL,
  534.                       TRUE,
  535.                       FALSE);
  536.    } /* if */
  537.    else
  538.       executeCommand( command,
  539.                       NULL,
  540.                       NULL,
  541.                       TRUE,
  542.                       TRUE );
  543.  
  544. } /* subshell */
  545.  
  546. /*--------------------------------------------------------------------*/
  547. /*    S e l e c t I t e m s                                           */
  548. /*                                                                    */
  549. /*    Select mail items to be processed by the current command        */
  550. /*--------------------------------------------------------------------*/
  551.  
  552. boolean SelectItems( char **input, int current , int bits)
  553. {
  554.    char *next_token = *input;
  555.    char *token = NULL;
  556.    char trailing[LSIZE];      /* for saving trailing part of line    */
  557.    int item;
  558.    boolean hit = FALSE;
  559.  
  560. /*--------------------------------------------------------------------*/
  561. /*                 Reset all mail items to unselected                 */
  562. /*--------------------------------------------------------------------*/
  563.  
  564.    next_item = 0;
  565.  
  566. /*--------------------------------------------------------------------*/
  567. /*            If no operands, return the current mail item            */
  568. /*--------------------------------------------------------------------*/
  569.  
  570.    if ( *input == NULL )
  571.    {
  572.       SetItem( current+1 );
  573.       return SetTrailing( input , bits );
  574.    }
  575.  
  576. /*--------------------------------------------------------------------*/
  577. /*             Select all items if the user requested so              */
  578. /*--------------------------------------------------------------------*/
  579.  
  580.    strcpy( trailing , next_token );
  581.    token = strtok( next_token , WHITESPACE );
  582.    if (equal(token,"*"))      /* Select all items?                   */
  583.    {
  584.       *input = strtok( NULL , "" );
  585.  
  586.       for ( item = 1; item <= letternum; item++)
  587.          SetItem( item );
  588.  
  589.       return SetTrailing( input , bits );
  590.    } /* if */
  591.  
  592. /*--------------------------------------------------------------------*/
  593. /*   If the first token begins with a slash (/), scan for items       */
  594. /*   with the subject.                                                */
  595. /*--------------------------------------------------------------------*/
  596.  
  597.    if ( *token == '/' )
  598.       return SearchSubject( token, input, trailing, bits);
  599.  
  600. /*--------------------------------------------------------------------*/
  601. /*          Scan the line until we hit a non-numeric operand          */
  602. /*--------------------------------------------------------------------*/
  603.  
  604.    while ( token != NULL)
  605.    {
  606.       boolean success = TRUE;
  607.       next_token = strtok( NULL , "");
  608.                               /* Remember next of line for next pass */
  609.  
  610.       if (Numeric( token ))
  611.          hit = success = SetItem( atoi(token) );
  612.       else if (equal( token, "$"))
  613.          hit = success = SetItem( letternum );
  614.       else if (equal( token, "."))
  615.          hit = success = SetItem( current + 1 );
  616.       else if (equaln( token, "..", 2))   /* Parent directory?       */
  617.          break;                        /* Yes --> quit loop          */
  618.       else if (strpbrk(token,"@!") != NULL ) /* User id?             */
  619.          break;                  /* Yes --> Exit loop gracefully     */
  620.       else if (isdigit(*token) || (*token == '$') || (*token == '.'))
  621.                                  /* Is it start-end combination?     */
  622.       {                          /* Yes --> Handle it                */
  623.          char *start, *end ;
  624.          int  istart, iend;
  625.          start = strtok( token , "-");
  626.          end   = strtok( NULL , "");
  627.  
  628.          if (equal(start,"$"))
  629.             istart = letternum;
  630.          else if (equal(start,"."))
  631.             istart = current + 1 ;
  632.          else if (!Numeric( start ))
  633.          {
  634.             printf("%s: Operand is not numeric\n", start );
  635.             return FALSE;
  636.          } /* if */
  637.          else
  638.             istart = atoi( start );
  639.  
  640.          if ( (end == NULL) )
  641.          {
  642.             printf("Missing end of item range\n" );
  643.             return FALSE;
  644.          } /* if */
  645.  
  646.          if (equal(end,"$"))
  647.             iend = letternum;
  648.          else if (equal(end,"."))
  649.             iend = current + 1 ;
  650.          else if (!Numeric( end ))
  651.          {
  652.             printf("%s: Operand is not numeric\n", end );
  653.             return FALSE;
  654.          } /* if */
  655.          else
  656.             iend = atoi( end );
  657.  
  658.          if ( iend < istart)
  659.          {
  660.             printf("Ending item (%d) is less than starting item (%d)\n",
  661.                    iend , istart );
  662.             return FALSE;
  663.          } /* if */
  664.  
  665.          for ( item = istart; (item <= iend) && success; item++ )
  666.             hit = success = SetItem ( item );
  667.  
  668.       } /* else */
  669.       else
  670.          break ;
  671.  
  672.       if ( !success )
  673.          return FALSE;
  674.  
  675.       if ( next_token != NULL )
  676.       {
  677.          strcpy( trailing , next_token );
  678.                               /* Save current line so we can back up */
  679.          token = strtok( next_token, WHITESPACE );
  680.       }
  681.       else
  682.          token = NULL;
  683.    } /* while */
  684.  
  685. /*--------------------------------------------------------------------*/
  686. /*   Determine if we have a user id to search for.  This is harder    */
  687. /*   than the above search for subject lines, because the user id     */
  688. /*   doesn't have to have a special delimiter; thus, we do our        */
  689. /*   best to discard other types of items and assume a user id        */
  690. /*   only if we don't know what it is.                                */
  691. /*--------------------------------------------------------------------*/
  692.  
  693.    if ( ! hit )
  694.    {
  695.       if ( (bits & (FILE_OP | USER_OP)) == 0x0000)
  696.       {
  697.          *input = next_token;
  698.          return SearchUser( token, input, bits);
  699.       }
  700.       else if ((bits & USER_OP) == 0x0000)
  701.       {
  702.          if ((strpbrk(token,"@%!") != NULL) || (next_token != NULL))
  703.          {
  704.             *input = next_token;
  705.             return SearchUser( token, input, bits);
  706.          }
  707.       }
  708.    } /* if (! hit) */
  709.  
  710. /*--------------------------------------------------------------------*/
  711. /*      Handle trailing operands when user selected items by number   */
  712. /*--------------------------------------------------------------------*/
  713.  
  714.    if ( token != NULL )
  715.    {
  716.       if (!hit)               /* Any numeric operands?               */
  717.          SetItem( current+1 );   /* No --> Set current as default    */
  718.       strcpy( *input, trailing );
  719.    }
  720.    else
  721.       *input = NULL ;
  722.  
  723.    return SetTrailing( input , bits );
  724.  
  725. } /* SelectItems */
  726.  
  727.  
  728. /*--------------------------------------------------------------------*/
  729. /*    S e a r c h S u j e c t                                         */
  730. /*                                                                    */
  731. /*    Search for mail items to select by the subject                  */
  732. /*--------------------------------------------------------------------*/
  733.  
  734. static boolean SearchSubject( char *token,
  735.                               char **input,
  736.                               char *trailing,
  737.                               const int bits)
  738. {
  739.    char line[LSIZE];
  740.    int item;
  741.    char *next_token;
  742.    boolean hit = FALSE;
  743.  
  744.    token = strtok(trailing,"/");    /* Get subject to search      */
  745.    if ( token == NULL )
  746.    {
  747.       printf("Missing subject to search for\n");
  748.       return FALSE;
  749.    }
  750.    token = strlwr(token);  /* Case insensitive search             */
  751.    next_token = strtok(NULL,"");
  752.                            /* Get rest of line                    */
  753.    for ( item = 1; item <= letternum; item++)
  754.    {
  755.       if (letters[item-1].status == M_DELETED)
  756.          continue;
  757.       if (
  758.            RetrieveLine(letters[item-1].subject, line, LSIZE ) &&
  759.           strstr( strlwr(line), token ))
  760.                            /* This item have subject?             */
  761.       {
  762.          SetItem( item );
  763.          hit = TRUE;
  764.       } /* if */
  765.    } /* for */
  766.  
  767.    if (hit)                /* Did we find the string for user?    */
  768.    {
  769.       if ( next_token == NULL )
  770.          *input = NULL;
  771.       else
  772.          strcpy( *input, next_token );
  773.       return SetTrailing( input , bits ); /* Yes --> Success      */
  774.    } /* if (hit) */
  775.    else {
  776.       printf("No mail items found with subject \"%s\"\n",token);
  777.       return FALSE;
  778.    }  /* else */
  779. } /* SearchSubject */
  780.  
  781.  
  782. /*--------------------------------------------------------------------*/
  783. /*    S e a r c h U s e r                                             */
  784. /*                                                                    */
  785. /*    Search for a user id on mail items                              */
  786. /*--------------------------------------------------------------------*/
  787.  
  788. static boolean SearchUser( char *token , char **input, const int bits)
  789. {
  790.    char line[LSIZE];
  791.    int item;
  792.    boolean hit = FALSE;
  793.  
  794.    token = strlwr(token);  /* Case insensitive search          */
  795.  
  796. /*--------------------------------------------------------------------*/
  797. /*    Our loop is as follows for each item in the mailbox:            */
  798. /*                                                                    */
  799. /*       If the letter is deleted, ignore it                          */
  800. /*       If the From line can be retrieved from the item:             */
  801. /*                                                                    */
  802. /*          1) Read the line                                          */
  803. /*          2) Scan up to the first whitespace                        */
  804. /*             2a) If there is no whitespace, use entire line         */
  805. /*             2b) If there is whitespace, step past it to next       */
  806. /*                 non-whitespace character                           */
  807. /*          3) Lowercase the line                                     */
  808. /*          4) Scan for the the target address in the line:           */
  809. /*             4a) If found select the item for processing            */
  810. /*             4b) If not found, build a standard outgoing address    */
  811. /*                 and search again.  If found, select the item       */
  812. /*                                                                    */
  813. /*       If the From line cannot be retrieved:                        */
  814. /*          1) call ReturnAddress to format the return address        */
  815. /*             (Because the line cannot be retrieved, it will         */
  816. /*              "-- unknown --", the same string displayed by         */
  817. /*              Headers.                                              */
  818. /*          2) Scan for the the target address in the returned        */
  819. /*             address                                                */
  820. /*          3) If found, select the item for processing               */
  821. /*--------------------------------------------------------------------*/
  822.  
  823.    for ( item = 1; item <= letternum; item++)
  824.    {
  825.       printmsg(2,"Examining item %d", item);
  826.       if (letters[item-1].status == M_DELETED)
  827.          continue;
  828.       if (RetrieveLine(letters[item - 1].from, line, LSIZE))
  829.       {
  830.          char *addr  = strpbrk(line,WHITESPACE);
  831.          if (addr == NULL)    /* Whitespace in input line?        */
  832.             addr = line;      /* No --> Use entire line           */
  833.          else
  834.             while(isspace(*addr))   /* Yes --> Skip past first WS */
  835.                addr++;
  836.          printmsg(2,"SearchUser: Address %d is: %s",item-1,addr);
  837.          if ( strstr( strlwr(addr), token ))    /* Find address?  */
  838.             hit = SetItem( item );  /* Yes--> Select item for use */
  839.          else {                     /* No--> Expand & search again*/
  840.             char result[MAXADDR];
  841.             BuildAddress( result, addr);
  842.                            /* Get expanded address for user       */
  843.             printmsg(2,"SearchUser: Formatted address %d is: %s",
  844.                   item-1,result);
  845.             if ( strstr( strlwr(result), token ))
  846.                            /* This item have correct sender?      */
  847.                hit = SetItem( item );  /* Yes --> Set it          */
  848.             else
  849.                printmsg(2,"SearchUser: Item %d not selected.",
  850.                      item-1);
  851.          } /* else */
  852.       } /* if */
  853.       else {
  854.          ReturnAddress(line,&letters[item - 1]);
  855.                            /* Get standard error text for letter  */
  856.          printmsg(2,"SearchUser: Default address %d is: %s",
  857.                   item-1,line);
  858.          if ( strstr( strlwr(line), token ))
  859.                            /* This item have correct sender?      */
  860.             hit = SetItem( item );  /* Yes --> Set it             */
  861.       } /* else */
  862.    } /* for */
  863.  
  864. /*--------------------------------------------------------------------*/
  865. /*        End of loop; determined success and return to caller        */
  866. /*--------------------------------------------------------------------*/
  867.  
  868.    if (hit)             /* Did we find the string for user?    */
  869.       return SetTrailing( input , bits ); /* Yes --> Success   */
  870.    else {
  871.       printf("No mail items found from \"%s\"\n",token);
  872.       return FALSE;
  873.    }  /* else */
  874.  
  875. }  /* SearchUser */
  876.  
  877.  
  878. /*--------------------------------------------------------------------*/
  879. /*    S e t T r a i l i n g                                           */
  880. /*                                                                    */
  881. /*    Determine success of command parse based on trailing operands   */
  882. /*--------------------------------------------------------------------*/
  883.  
  884. boolean SetTrailing( char **input, int bits )
  885. {
  886.  
  887. /*--------------------------------------------------------------------*/
  888. /*                        Trim trailing spaces                        */
  889. /*--------------------------------------------------------------------*/
  890.  
  891.    if (*input != NULL)
  892.    {
  893.       char *s = *input;
  894.       while( isspace(*s))
  895.          s++;
  896.       if ( *s == '\0' )       /* Anything left in string?            */
  897.          *input = NULL;       /* No --> Flag input as NULL           */
  898.       else
  899.          *input = s;          /* Yes --> Point input to next operand */
  900.    }
  901.  
  902. /*--------------------------------------------------------------------*/
  903. /*                     Trailing address operands?                     */
  904. /*--------------------------------------------------------------------*/
  905.  
  906.    if (( bits & USER_OP ) || ( *input == NULL ))
  907.       return TRUE;            /* Let Get_Operand check operands      */
  908.  
  909. /*--------------------------------------------------------------------*/
  910. /*                        Trailing file name?                         */
  911. /*--------------------------------------------------------------------*/
  912.  
  913.    if ( bits & FILE_OP )
  914.    {
  915.       char *token = strtok( *input , WHITESPACE );
  916.       token = strtok( NULL , "" );
  917.  
  918.       if ( token == NULL )
  919.          return TRUE;
  920.       else {
  921.          printf("%s: Only one file operand allowed on command\n",
  922.             token);
  923.          return FALSE;
  924.       } /* else */
  925.    } /* if */
  926.  
  927. /*--------------------------------------------------------------------*/
  928. /*                   No operand allowed; reject it                    */
  929. /*--------------------------------------------------------------------*/
  930.  
  931.    printf("%s: Unknown operand on command\n", *input);
  932.    return FALSE;
  933.  
  934. } /* SetTrailing */
  935.  
  936. /*--------------------------------------------------------------------*/
  937. /*    S e t I t e m                                                   */
  938. /*                                                                    */
  939. /*    Validate and select a single item                               */
  940. /*--------------------------------------------------------------------*/
  941.  
  942. boolean SetItem( int item )
  943. {
  944.    if ( item_list == NULL )
  945.    {
  946.       item_list = calloc( letternum, sizeof *item_list);
  947.       checkref( item_list );
  948.    }
  949.  
  950.    if ((item > 0) && ( item <= letternum ))
  951.    {
  952.       item_list[ next_item++ ] = item - 1;
  953.       return TRUE;
  954.    }
  955.    else {
  956.       printf("Invalid item (%d) selected for processing\n",item);
  957.       return FALSE;
  958.    } /* else */
  959. } /* SetItem */
  960.  
  961. /*--------------------------------------------------------------------*/
  962. /*    G e t _ O p e r a n d                                           */
  963. /*                                                                    */
  964. /*    Get next operand to process                                     */
  965. /*--------------------------------------------------------------------*/
  966.  
  967. boolean Get_Operand( int *item,
  968.                      char **token,
  969.                      int bits,
  970.                      boolean first_pass )
  971. {
  972.  
  973. /*--------------------------------------------------------------------*/
  974. /*                         Handle no operand                          */
  975. /*--------------------------------------------------------------------*/
  976.  
  977.    if (bits & NO_OPERANDS)
  978.    {
  979.       if ( *token == NULL )
  980.          return first_pass;
  981.       else {
  982.          printf("Operands not allowed on this command!\n");
  983.          return FALSE;
  984.       } /* else */
  985.    }
  986.  
  987. /*--------------------------------------------------------------------*/
  988. /*        User operands are like string operands, but required        */
  989. /*--------------------------------------------------------------------*/
  990.  
  991.    if ( (bits & USER_OP) && (*token == NULL))
  992.    {
  993.       printf("Missing addressees for command\n");
  994.       return FALSE;
  995.    }
  996. /*--------------------------------------------------------------------*/
  997. /*                       Handle letter operand                        */
  998. /*--------------------------------------------------------------------*/
  999.  
  1000.    if ( bits & LETTER_OP )
  1001.    {
  1002.       static size_t subscript;
  1003.       subscript = first_pass ? 0 : subscript + 1;
  1004.  
  1005.       if (subscript < next_item)
  1006.       {
  1007.          *item = item_list[subscript];
  1008.          return TRUE;
  1009.       } /* else */
  1010.       else {
  1011.          free( item_list );
  1012.          item_list = NULL;
  1013.          return FALSE;
  1014.       } /* else */
  1015.    } /* if*/
  1016.  
  1017. /*--------------------------------------------------------------------*/
  1018. /*                   Handle string operands                           */
  1019. /*--------------------------------------------------------------------*/
  1020.  
  1021.    if ( bits & (STRING_OP | USER_OP))
  1022.    {
  1023.       char *buf = *token;
  1024.       if (first_pass &&
  1025.           (buf != NULL) &&
  1026.           ( buf[ strlen(buf) - 1 ] == '\n'))
  1027.          buf[ strlen(buf) - 1 ] = '\0';
  1028.       return first_pass;
  1029.    }
  1030.  
  1031. /*--------------------------------------------------------------------*/
  1032. /*                     Handle tokenized operands                      */
  1033. /*--------------------------------------------------------------------*/
  1034.  
  1035.    if ( bits & TOKEN_OP )
  1036.    {
  1037.       static char *rest = NULL ;
  1038.       if (first_pass)
  1039.          rest = *token;
  1040.  
  1041.       if ((rest == NULL) || (*rest == '\0'))
  1042.       {
  1043.          *token = NULL;
  1044.          return first_pass;
  1045.       } /* if */
  1046.  
  1047.       *token = strtok( rest , WHITESPACE );
  1048.       if ( token == NULL )
  1049.       {
  1050.          rest = NULL;
  1051.          return first_pass;
  1052.       }
  1053.       else {
  1054.          rest = strtok( NULL , "" );
  1055.          return TRUE;
  1056.       } /* else */
  1057.    } /* if */
  1058.  
  1059. /*--------------------------------------------------------------------*/
  1060. /*                      Handle integer operands                       */
  1061. /*--------------------------------------------------------------------*/
  1062.  
  1063.    if ( bits & KEWSHORT_OP)
  1064.    {
  1065.       char *p;
  1066.       if ( (*token == NULL) || ! first_pass )
  1067.       {
  1068.          *item = 1;
  1069.          return first_pass;
  1070.       }
  1071.       p = strtok( *token, WHITESPACE );
  1072.  
  1073.       if (!Numeric( p ))
  1074.       {
  1075.          printf("%s: Operand is not numeric\n", p );
  1076.          return FALSE;
  1077.       } /* if */
  1078.  
  1079.       *item = atoi( p );
  1080.       p = strtok( NULL, WHITESPACE );
  1081.       if (p != NULL )
  1082.       {
  1083.          printf("%s: extra operand not allowed on command\n", p);
  1084.          return FALSE;
  1085.       }
  1086.       return TRUE;
  1087.    } /* if */
  1088.  
  1089. /*--------------------------------------------------------------------*/
  1090. /*                   We cannot handle this command                    */
  1091. /*--------------------------------------------------------------------*/
  1092.  
  1093.    printf("Unknown processing option = %x, cannot process command\n",
  1094.          bits);
  1095.    return FALSE;
  1096.  
  1097. } /* Get_Operand */
  1098.  
  1099. /*--------------------------------------------------------------------*/
  1100. /*    P u s h I t e m L i s t                                         */
  1101. /*                                                                    */
  1102. /*    Save item parsing list                                          */
  1103. /*--------------------------------------------------------------------*/
  1104.  
  1105. int PushItemList( int **save_list )
  1106. {
  1107.    *save_list = item_list;
  1108.    item_list = NULL;
  1109.    return next_item;
  1110. } /* PushItemList */
  1111.  
  1112. /*--------------------------------------------------------------------*/
  1113. /*    P o p I t e m L i s t                                           */
  1114. /*                                                                    */
  1115. /*    Restore parsing information saved by PushItemList               */
  1116. /*--------------------------------------------------------------------*/
  1117.  
  1118. void PopItemList( int *save_list, int save_item )
  1119. {
  1120.    item_list = save_list;
  1121.    next_item = save_item;
  1122. } /* PopItemList */
  1123.