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