home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / elm23-2.zip / filter / parse.c < prev    next >
C/C++ Source or Header  |  1990-04-28  |  11KB  |  352 lines

  1.  
  2. static char rcsid[] ="@(#)$Id: parse.c,v 4.1 90/04/28 22:41:58 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1986, 1987 Dave Taylor
  8.  *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein - elm@DSI.COM
  13.  *            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log:    parse.c,v $
  17.  * Revision 4.1  90/04/28  22:41:58  syd
  18.  * checkin of Elm 2.3 as of Release PL0
  19.  *
  20.  *
  21.  ******************************************************************************/
  22.  
  23.  
  24. /** This is the parser for the filter program.  It accepts a wide variety of
  25.     constructs, building the ruleset table as it goes along.  Check the
  26.     data structure in filter.h for more information on how the rules are
  27.     stored.  The parser is a cunning state-table based program.
  28.  
  29. **/
  30.  
  31. #include <stdio.h>
  32. #include <ctype.h>
  33.  
  34. #include "defs.h"
  35. #include "filter.h"
  36.  
  37. #define NONE            0
  38. #define AND            10
  39.  
  40. #define NEXT_CONDITION        0
  41. #define GETTING_OP        1
  42. #define READING_ARGUMENT    2
  43. #define READING_ACTION        3
  44. #define ACTION_ARGUMENT        4
  45.  
  46. char *strtok(), *whatname(), *actionname();
  47.  
  48. int
  49. get_filter_rules()
  50. {
  51.     /** Given the users home directory, open and parse their rules table,
  52.         building the data structure as we go along.
  53.         returns -1 if we hit an error of any sort...
  54.     **/
  55.  
  56.     FILE *fd;                /* the file descriptor     */
  57.     char  buffer[SLEN],             /* fd reading buffer       */
  58.           *str,                 /* ptr to read string      */
  59.           *word,                /* ptr to 'token'          */
  60.           filename[SLEN],             /* the name of the ruleset */
  61.           action_argument[SLEN],         /* action arg, per rule    */
  62.           cond_argument[SLEN];        /* cond arg, per condition */
  63.     int   not_condition = FALSE,         /* are we in a "not" ??    */
  64.           type=NONE,             /* what TYPE of condition? */
  65.           lasttype,             /* and the previous TYPE?  */
  66.           state = NEXT_CONDITION,        /* the current state       */
  67.           in_single, in_double,         /* for handling spaces.    */
  68.           i,                 /* misc integer for loops  */
  69.           relop = NONE,            /* relational operator     */
  70.           action,                 /* the current action type */
  71.           buflen,                /* the length of buffer    */
  72.           line = 0;                /* line number we're on    */
  73.  
  74.     struct condition_rec    *cond, *newcond;
  75.  
  76.     sprintf(filename,"%s/%s", home, filterfile);
  77.  
  78.     if ((fd = fopen(filename,"r")) == NULL) {
  79.       if (outfd != NULL)
  80.        fprintf(outfd,"filter (%s): Couldn't read user filter rules file!\n",
  81.           username);
  82.       return(-1);
  83.     }
  84.  
  85.     cond_argument[0] = action_argument[0] = '\0';
  86.  
  87.     /* Now, for each line... **/
  88.  
  89.     if ((cond = (struct condition_rec *)
  90.              malloc(sizeof(struct condition_rec))) == NULL) {
  91.       if (outfd != NULL)
  92.         fprintf(outfd,"filter (%s): couldn't malloc first condition rec!\n",
  93.             username);
  94.       return(-1);
  95.     }
  96.  
  97.     rules[total_rules].condition = cond;    /* hooked in! */
  98.  
  99.     while (fgets(buffer, SLEN, fd) != NULL) {
  100.       line++;
  101.  
  102.       if (buffer[0] == '#' || (buflen = strlen(buffer)) < 2)
  103.         continue;        /* nothing to look at! */
  104.  
  105.       in_single = in_double = 0;
  106.  
  107.       for (i=0; i < buflen; i++) {
  108.         if (buffer[i] == '"')
  109.           in_double = ! in_double;
  110.         else if (buffer[i] == '\'')
  111.           in_single = ! in_single;
  112.         if ((in_double || in_single) && buffer[i] == ' ')
  113.           buffer[i] = '_';
  114.       }
  115.  
  116.       lasttype = type;
  117.       type = NONE;
  118.       str = (char *) buffer;
  119.  
  120.       /** Three pieces to this loop - get the `field', the 'relop' (if
  121.           there) then, if needed, get the argument to check against (not
  122.           needed for errors or the AND, of course)
  123.       **/
  124.  
  125.       while ((word = strtok(str, " ()[]:\t\n")) != NULL) {
  126.  
  127.         str = (char *) NULL;        /* we can start stomping! */
  128.  
  129.         lowercase(word);
  130.  
  131.         if (strcmp(word, "if") == 0) {    /* only ONE 'if' allowed */
  132.           if ((word = strtok(str, " ()[]:\t\n")) == NULL)    /* NEXT! */
  133.             continue;
  134.           lowercase(word);
  135.         }
  136.  
  137.         if (state == NEXT_CONDITION) {
  138.           lasttype = type;
  139.           type = NONE;
  140.  
  141.           if (the_same(word, "not") || the_same(word, "!")) {
  142.             not_condition = TRUE;
  143.             if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  144.               continue;
  145.           }
  146.  
  147.                if (the_same(word, "from"))         type = FROM;
  148.           else if (the_same(word, "to"))         type = TO;
  149.           else if (the_same(word, "subject"))   type = SUBJECT;
  150.           else if (the_same(word, "lines"))     type = LINES;
  151.           else if (the_same(word, "contains"))  type = CONTAINS;
  152.           else if (the_same(word, "and") ||
  153.                    the_same(word, "&&"))         type = AND;
  154.  
  155.           else if (the_same(word,"?") || the_same(word, "then") ||
  156.                the_same(word, "always")) {
  157.  
  158.         /** shove THIS puppy into the structure and let's continue! **/
  159.  
  160.             if (lasttype == AND) {
  161.           if (outfd != NULL)
  162.                 fprintf(outfd,
  163.          "filter (%s): Error reading line %d of rules - badly placed \"and\"\n",
  164.             username, line);
  165.           return(-1);
  166.             }
  167.  
  168.             if (the_same(word, "always"))
  169.           cond->matchwhat = ALWAYS;    /* so it's a hack... */
  170.         else
  171.           cond->matchwhat = lasttype;
  172.  
  173.             if (relop == NONE) relop = EQ;    /* otherwise can't do -relop */
  174.             cond->relation  = (not_condition? - (relop) : relop);
  175.  
  176.         for (i=strlen(cond_argument); --i >= 0;)
  177.               if (cond_argument[i] == '_') cond_argument[i] = ' ';
  178.  
  179.         strcpy(cond->argument1, cond_argument);
  180.             if ((newcond = (struct condition_rec *)
  181.              malloc(sizeof(struct condition_rec))) == NULL) {
  182.           if (outfd != NULL)
  183.                 fprintf(outfd,
  184.                      "filter (%s): Couldn't malloc new cond rec!!\n",
  185.                     username);
  186.           return(-1);
  187.             }
  188.             cond->next = NULL;
  189.  
  190.             relop = EQ;    /* default relational condition */
  191.  
  192.             state = READING_ACTION;
  193.             if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  194.               continue;
  195.             goto get_outta_loop;
  196.           }
  197.  
  198.           if (type == NONE) {
  199.         if (outfd != NULL)
  200.               fprintf(outfd,
  201.       "filter (%s): Error reading line %d of rules - field \"%s\" unknown!\n",
  202.              username, line, word);
  203.         return(-1);
  204.           }
  205.  
  206.           if (type == AND) {
  207.  
  208.         /** shove THIS puppy into the structure and let's continue! **/
  209.  
  210.         cond->matchwhat = lasttype;
  211.             cond->relation  = (not_condition? - (relop) : relop);
  212.         strcpy(cond->argument1, cond_argument);
  213.             if ((newcond = (struct condition_rec *)
  214.                  malloc(sizeof(struct condition_rec))) == NULL) {
  215.           if (outfd != NULL)
  216.                 fprintf(outfd,
  217.             "filter (%s): Couldn't malloc new cond rec!!\n",
  218.             username);
  219.           return(-1);
  220.             }
  221.             cond->next = newcond;
  222.         cond = newcond;
  223.         cond->next = NULL;
  224.  
  225.             not_condition = FALSE;
  226.             state = NEXT_CONDITION;
  227.           }
  228.           else {
  229.             state = GETTING_OP;
  230.           }
  231.         }
  232.  
  233. get_outta_loop:     /* jump out when we change state, if needed */
  234.  
  235.         if (state == GETTING_OP) {
  236.  
  237.            if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  238.              continue;
  239.  
  240.            lowercase(word);
  241.  
  242.            relop = NONE;
  243.  
  244.            if (the_same(word, "=") || the_same(word, "in") ||
  245.                    the_same(word, "contains")) {
  246.                  state = READING_ARGUMENT;
  247.              relop = EQ;
  248.            }
  249.            else {
  250.              if (the_same(word, "<="))     relop = LE;
  251.              else if (the_same(word, ">="))    relop = GE;
  252.              else if (the_same(word, ">"))    relop = GT;
  253.              else if (the_same(word, "<>")||
  254.                   the_same(word, "!="))    relop = NE;
  255.              else if (the_same(word, "<"))    relop = LT;
  256.  
  257.          /* maybe there isn't a relop at all!! */
  258.  
  259.          state=READING_ARGUMENT;
  260.  
  261.            }
  262.         }
  263.  
  264.         if (state == READING_ARGUMENT) {
  265.           if (relop != NONE) {
  266.             if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  267.               continue;
  268.           }
  269.           for (i=strlen(word); --i>=0;)
  270.             if (word[i] == '_') word[i] = ' ';
  271.  
  272.           strcpy(cond_argument, word);
  273.           state = NEXT_CONDITION;
  274.         }
  275.  
  276.         if (state == READING_ACTION) {
  277.           action = NONE;
  278.  
  279.           not_condition = FALSE;
  280.  
  281.           if (the_same(word, "delete"))       action = DELETE_MSG;
  282.           else if (the_same(word, "savec"))   action = SAVECC;
  283.           else if (the_same(word, "save"))    action = SAVE;
  284.           else if (the_same(word, "forward")) action = FORWARD;
  285.           else if (the_same(word, "exec"))    action = EXEC;
  286.           else if (the_same(word, "leave"))   action = LEAVE;
  287.           else {
  288.         if (outfd != NULL)
  289.               fprintf(outfd,
  290.     "filter (%s): Error on line %d of rules - action \"%s\" unknown\n",
  291.             username, line, word);
  292.           }
  293.  
  294.           if (action == DELETE_MSG || action == LEAVE) {
  295.             /** add this to the rules section and alloc next... **/
  296.  
  297.             rules[total_rules].action = action;
  298.         rules[total_rules].argument2[0] = '\0';    /* nothing! */
  299.             total_rules++;
  300.  
  301.             if ((cond = (struct condition_rec *)
  302.              malloc(sizeof(struct condition_rec))) == NULL) {
  303.           if (outfd != NULL)
  304.                 fprintf(outfd,
  305.             "filter (%s): couldn't malloc first condition rec!\n",
  306.             username);
  307.               return(-1);
  308.             }
  309.  
  310.             rules[total_rules].condition = cond;    /* hooked in! */
  311.             state = NEXT_CONDITION;
  312.           }
  313.           else {
  314.             state = ACTION_ARGUMENT;
  315.           }
  316.  
  317.           if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  318.             continue;
  319.  
  320.         }
  321.  
  322.         if (state == ACTION_ARGUMENT) {
  323.           strcpy(action_argument, word);
  324.  
  325.           /** add this to the rules section and alloc next... **/
  326.  
  327.           rules[total_rules].action = action;
  328.           expand_macros(action_argument, rules[total_rules].argument2,line,
  329.                 printing_rules);
  330.           total_rules++;
  331.  
  332.           if ((cond = (struct condition_rec *)
  333.              malloc(sizeof(struct condition_rec))) == NULL) {
  334.         if (outfd != NULL)
  335.               fprintf(outfd,
  336.               "filter (%s): couldn't malloc first condition rec!\n",
  337.               username);
  338.             return(-1);
  339.           }
  340.  
  341.           rules[total_rules].condition = cond;    /* hooked in! */
  342.  
  343.           state = NEXT_CONDITION;
  344.           if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  345.             continue;
  346.         }
  347.       }
  348.     }
  349.  
  350.     return(0);
  351. }
  352.