home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / elm-2.4-pl20.tar.Z / elm-2.4-pl20.tar / filter / parse.c < prev    next >
C/C++ Source or Header  |  1993-01-12  |  14KB  |  469 lines

  1.  
  2. static char rcsid[] ="@(#)$Id: parse.c,v 5.6 1992/12/11 01:45:04 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.6 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1988-1992 USENET Community Trust
  8.  *             Copyright (c) 1986,1987 Dave Taylor
  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 5.6  1992/12/11  01:45:04  syd
  18.  * remove sys/types.h include, it is now included by defs.h
  19.  * and this routine includes defs.h or indirectly includes defs.h
  20.  * From: Syd
  21.  *
  22.  * Revision 5.5  1992/12/07  05:08:03  syd
  23.  * add sys/types for time_t
  24.  * From: Syd
  25.  *
  26.  * Revision 5.4  1992/11/15  01:40:43  syd
  27.  * Add regexp processing to filter.
  28.  * Add execc operator
  29.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  30.  *
  31.  * Revision 5.3  1992/10/28  14:52:25  syd
  32.  * fix compiler warning
  33.  * From: steve@nshore.org (Stephen J. Walick)
  34.  *
  35.  * Revision 5.2  1992/10/24  14:20:24  syd
  36.  * remove the 25 (MAXRULES) limitation.
  37.  * Basically it mallocs rules in hunks of RULESINC (25) as it goes along.
  38.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  39.  *
  40.  * Revision 5.1  1992/10/03  22:18:09  syd
  41.  * Initial checkin as of 2.4 Release at PL0
  42.  *
  43.  *
  44.  ******************************************************************************/
  45.  
  46.  
  47. /** This is the parser for the filter program.  It accepts a wide variety of
  48.     constructs, building the ruleset table as it goes along.  Check the 
  49.     data structure in filter.h for more information on how the rules are
  50.     stored.  The parser is a cunning state-table based program.
  51.  
  52. **/
  53.  
  54. #include <stdio.h>
  55. #include <ctype.h>
  56.  
  57. #include "defs.h"
  58. #include "filter.h"
  59. #include "s_filter.h"
  60.  
  61. #define NONE            0
  62. #define AND            10
  63.  
  64. #define NEXT_CONDITION        0
  65. #define GETTING_OP        1
  66. #define READING_ARGUMENT    2
  67. #define READING_ACTION        3
  68. #define ACTION_ARGUMENT        4
  69.  
  70. char *strtok(), *whatname(), *actionname();
  71.  
  72. static int
  73. grow(ptr, oldsize, incr)
  74. struct ruleset_record **ptr;
  75. int oldsize, incr;
  76. {
  77.     struct ruleset_record *newptr;
  78.     int newsize;
  79.  
  80.     if (ptr == 0) return 0;
  81.  
  82.     newsize = oldsize + incr;
  83.     if (oldsize == 0)
  84.       newptr = (struct ruleset_record *)
  85.             malloc(sizeof(struct ruleset_record)*newsize);
  86.     else
  87.       newptr = (struct ruleset_record *)
  88.             realloc((char *) *ptr, sizeof(struct ruleset_record)*newsize);
  89.  
  90.     if (newptr == NULL){
  91.       if (outfd != NULL)
  92.         fprintf(outfd,catgets(elm_msg_cat,
  93.                   FilterSet,FilterCantAllocRules,
  94.             "filter (%s): Can't alloc memory for %d rules!\n"),
  95.             username, newsize);
  96.       if (outfd != NULL) fclose(outfd);
  97.       exit(1);
  98.     }
  99.  
  100.     *ptr = newptr;
  101.     return newsize;
  102. }
  103.  
  104. int
  105. get_filter_rules()
  106. {
  107.     /** Given the users home directory, open and parse their rules table,
  108.         building the data structure as we go along.
  109.         returns -1 if we hit an error of any sort...
  110.     **/
  111.  
  112.     FILE
  113.          *fd;                /* the file descriptor     */
  114.     char
  115.          buffer[SLEN],             /* fd reading buffer       */
  116.          *str,                 /* ptr to read string      */
  117.          *word,                /* ptr to 'token'          */
  118.          filename[SLEN],             /* the name of the ruleset */
  119.          action_argument[SLEN],         /* action arg, per rule    */
  120.          cond_argument[SLEN];        /* cond arg, per condition */
  121.     int
  122.          not_condition = FALSE,         /* are we in a "not" ??    */
  123.          type=NONE,             /* what TYPE of condition? */
  124.          lasttype=NONE,             /* and the previous TYPE?  */
  125.          state = NEXT_CONDITION,        /* the current state       */
  126.          in_single, in_double,         /* for handling spaces.    */
  127.          i,                 /* misc integer for loops  */
  128.          relop = NONE,            /* relational operator     */
  129.          action,                 /* the current action type */
  130.          buflen,                /* the length of buffer    */
  131.          line = 0;                /* line number we're on    */
  132.     struct condition_rec
  133.          *cond, *newcond;
  134.  
  135.     strcpy(filename,filterfile);
  136.  
  137.     if ((fd = fopen(filename,"r")) == NULL) {
  138.       if (outfd != NULL)
  139.        fprintf(outfd,catgets(elm_msg_cat,FilterSet,FilterCouldntReadRules,
  140.        "filter (%s): Couldn't read filter rules file \"%s\"!\n"),username,
  141.           filename);
  142.       return(-1);
  143.     }
  144.  
  145.     if (sizeof_rules == 0)
  146.       sizeof_rules = grow(&rules, sizeof_rules, RULESINC);
  147.  
  148.     cond_argument[0] = action_argument[0] = '\0';
  149.  
  150.     /* Now, for each line... **/
  151.  
  152.     if ((cond = (struct condition_rec *) 
  153.              malloc(sizeof(struct condition_rec))) == NULL) {
  154.       if (outfd != NULL)
  155.         fprintf(outfd,catgets(elm_msg_cat,
  156.                   FilterSet,FilterCouldntMallocFirst,
  157.           "filter (%s): couldn't malloc first condition rec!\n"),
  158.             username);
  159.       return(-1);
  160.     }
  161.     
  162.     rules[total_rules].condition = cond;    /* hooked in! */
  163.  
  164.     while (fgets(buffer, SLEN, fd) != NULL) {
  165.       line++;
  166.  
  167.       if (buffer[0] == '#' || (buflen = strlen(buffer)) < 2)
  168.         continue;        /* nothing to look at! */
  169.  
  170.       in_single = in_double = 0;
  171.  
  172.       for (i=0; i < buflen; i++) {
  173.         if (buffer[i] == '"') 
  174.           in_double = ! in_double;
  175.         else if (buffer[i] == '\'')
  176.           in_single = ! in_single;
  177.         if ((in_double || in_single) && buffer[i] == ' ')
  178.           buffer[i] = '_';
  179.       }
  180.  
  181.       if (lasttype != AND && lasttype != NONE) {
  182.         lasttype = type;
  183.         type = NONE;
  184.       }
  185.       str = (char *) buffer;
  186.  
  187.       /** Three pieces to this loop - get the `field', the 'relop' (if
  188.           there) then, if needed, get the argument to check against (not 
  189.           needed for errors or the AND, of course)
  190.       **/
  191.  
  192.       while ((word = strtok(str, " ()[]:\t\n")) != NULL) {
  193.  
  194.         str = (char *) NULL;        /* we can start stomping! */
  195.       
  196.         lowercase(word);
  197.  
  198.         if (strcmp(word, "if") == 0) {    /* only ONE 'if' allowed */
  199.           if ((word = strtok(str, " ()[]:\t\n")) == NULL)    /* NEXT! */
  200.             continue;
  201.           lowercase(word);
  202.         }
  203.     
  204.         if (state == NEXT_CONDITION) {
  205.           lasttype = type;
  206.           type = NONE;
  207.  
  208.           if (the_same(word, "not") || the_same(word, "!")) {
  209.             not_condition = TRUE;
  210.             if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  211.               continue;
  212.           }
  213.  
  214.           if (the_same(word, "from"))
  215.            type = FROM;
  216.           else if (the_same(word, "to"))
  217.            type = TO;
  218.           else if (the_same(word, "subject"))
  219.            type = SUBJECT;
  220.           else if (the_same(word, "sender"))
  221.            type = SENDER;
  222.           else if (the_same(word, "lines"))
  223.            type = LINES;
  224.           else if (the_same(word, "contains"))
  225.            type = CONTAINS;
  226.           else if (the_same(word, "and") || 
  227.                    the_same(word, "&&"))
  228.            type = AND;
  229.           else if (the_same(word,"?") ||
  230.                the_same(word, "then") || 
  231.                the_same(word, "always")) {
  232.  
  233.         /** shove THIS puppy into the structure and let's continue! **/
  234.  
  235.             if (lasttype == AND) {
  236.           if (outfd != NULL)
  237.                 fprintf(outfd,catgets(elm_msg_cat,
  238.                       FilterSet,FilterErrorReadingRules1,
  239.        "filter (%s): Error reading line %d of rules - badly placed \"and\"\n"),
  240.             username, line);
  241.           return(-1);
  242.             }
  243.  
  244.             if (the_same(word, "always"))
  245.           cond->matchwhat = ALWAYS;    /* so it's a hack... */
  246.         else
  247.           cond->matchwhat = lasttype;
  248.  
  249.             if (relop == NONE) relop = EQ;    /* otherwise can't do -relop */
  250.             cond->relation  = (not_condition? - (relop) : relop);
  251.         cond->regex = NULL;
  252.  
  253.         if (relop != RE)
  254.           for (i=strlen(cond_argument); --i >= 0;)
  255.                 if (cond_argument[i] == '_') cond_argument[i] = ' ';
  256.  
  257.         strcpy(cond->argument1, cond_argument);
  258.             if ((newcond = (struct condition_rec *)
  259.              malloc(sizeof(struct condition_rec))) == NULL) {
  260.           if (outfd != NULL)
  261.                 fprintf(outfd,catgets(elm_msg_cat,
  262.                       FilterSet,FilterCouldntMallocNew ,
  263.                      "filter (%s): Couldn't malloc new cond rec!!\n"),
  264.                     username);
  265.           return(-1);
  266.             }
  267.             cond->next = NULL;
  268.  
  269.             relop = EQ;    /* default relational condition */
  270.  
  271.             state = READING_ACTION;
  272.             if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  273.               continue;
  274.             goto get_outta_loop;
  275.           }
  276.  
  277.           if (type == NONE) {
  278.         if (outfd != NULL)
  279.               fprintf(outfd,catgets(elm_msg_cat,
  280.                     FilterSet,FilterErrorReadingRules2,
  281.       "filter (%s): Error reading line %d of rules - field \"%s\" unknown!\n"),
  282.              username, line, word);
  283.         return(-1);
  284.           }
  285.  
  286.           if (type == AND) {
  287.  
  288.         /** shove THIS puppy into the structure and let's continue! **/
  289.  
  290.         cond->matchwhat = lasttype;
  291.             cond->relation  = (not_condition? - (relop) : relop);
  292.         cond->regex = NULL;
  293.         strcpy(cond->argument1, cond_argument);
  294.             if ((newcond = (struct condition_rec *)
  295.                  malloc(sizeof(struct condition_rec))) == NULL) {
  296.           if (outfd != NULL)
  297.                 fprintf(outfd,catgets(elm_msg_cat,
  298.                       FilterSet,FilterCouldntMallocNew ,
  299.             "filter (%s): Couldn't malloc new cond rec!!\n"),
  300.             username);
  301.           return(-1);
  302.             }
  303.             cond->next = newcond;
  304.         cond = newcond;
  305.         cond->next = NULL;
  306.  
  307.             not_condition = FALSE;
  308.             state = NEXT_CONDITION;
  309.           }
  310.           else {
  311.             state = GETTING_OP;
  312.           }
  313.         }
  314.  
  315. get_outta_loop:     /* jump out when we change state, if needed */
  316.  
  317.         if (state == GETTING_OP) {
  318.  
  319.            if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  320.              continue;
  321.  
  322.            lowercase(word);
  323.  
  324.            relop = NONE;
  325.  
  326.            if (the_same(word, "=") || the_same(word, "in") || 
  327.                    the_same(word, "contains")) {
  328.                  state = READING_ARGUMENT;
  329.              relop = EQ;
  330.            }
  331.            else {
  332.              if (the_same(word, "<="))     relop = LE;
  333.              else if (the_same(word, ">="))    relop = GE;
  334.              else if (the_same(word, ">"))    relop = GT;
  335.              else if (the_same(word, "<>")||
  336.                   the_same(word, "!="))    relop = NE;
  337.              else if (the_same(word, "<"))    relop = LT;
  338.              else if (the_same(word, "~")||
  339.               the_same(word, "matches")) relop = RE;
  340.  
  341.          /* maybe there isn't a relop at all!! */
  342.  
  343.          state=READING_ARGUMENT;
  344.  
  345.            }
  346.         }
  347.          
  348.         if (state == READING_ARGUMENT) {
  349.           if (relop == RE){
  350.         /* Special for regular expressions (enclosed between //) */
  351.         cond_argument[0] = '\0';
  352.         for (;;) {
  353.               if ((word = strtok(str, "/")) == NULL)
  354.                 break;
  355.           strcat(cond_argument, word);
  356.           if (word[strlen(word)-1] == '\\') /* If / was escaped ... */
  357.             strcat(cond_argument, "/");
  358.           else
  359.             break;
  360.         }
  361.         if (word == NULL)
  362.           continue;
  363.  
  364.           } else {
  365.         if (relop != NONE) {
  366.               if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  367.                 continue;
  368.             }
  369.             for (i=strlen(word); --i>=0;)
  370.               if (word[i] == '_') word[i] = ' ';
  371.  
  372.             strcpy(cond_argument, word);
  373.           }
  374.           state = NEXT_CONDITION;
  375.         }
  376.  
  377.         if (state == READING_ACTION) {
  378.           action = NONE;
  379.  
  380.           not_condition = FALSE;
  381.  
  382.           if (the_same(word, "delete"))       action = DELETE_MSG;
  383.           else if (the_same(word, "savec"))   action = SAVECC;
  384.           else if (the_same(word, "save"))    action = SAVE;
  385.           else if (the_same(word, "forwardc")) action = FORWARDC;
  386.           else if (the_same(word, "forward")) action = FORWARD;
  387.           else if (the_same(word, "executec")) action = EXECC;
  388.           else if (the_same(word, "exec"))    action = EXEC;
  389.           else if (the_same(word, "leave"))   action = LEAVE;
  390.           else {
  391.         if (outfd != NULL)
  392.               fprintf(outfd,catgets(elm_msg_cat,
  393.                     FilterSet,FilterErrorReadingRules3 ,
  394.     "filter (%s): Error on line %d of rules - action \"%s\" unknown\n"),
  395.             username, line, word);
  396.           }
  397.  
  398.           if (action == DELETE_MSG || action == LEAVE) {
  399.             /** add this to the rules section and alloc next... **/
  400.  
  401.             rules[total_rules].action = action;
  402.         rules[total_rules].argument2[0] = '\0';    /* nothing! */
  403.             if (++total_rules >= sizeof_rules)
  404.           sizeof_rules = grow(&rules, sizeof_rules, RULESINC);
  405.              
  406.             if ((cond = (struct condition_rec *)
  407.              malloc(sizeof(struct condition_rec))) == NULL) {
  408.           if (outfd != NULL)
  409.                 fprintf(outfd,catgets(elm_msg_cat,
  410.                       FilterSet,FilterCouldntMallocFirst,
  411.             "filter (%s): couldn't malloc first condition rec!\n"),
  412.             username);
  413.               return(-1);
  414.             }
  415.     
  416.             rules[total_rules].condition = cond;    /* hooked in! */
  417.             state = NEXT_CONDITION;    
  418.           }
  419.           else {
  420.             state = ACTION_ARGUMENT;
  421.           }
  422.  
  423.           if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  424.             continue;
  425.  
  426.         }
  427.     
  428.         if (state == ACTION_ARGUMENT) {
  429.           strcpy(action_argument, word);
  430.  
  431.           /** add this to the rules section and alloc next... **/
  432.  
  433.           rules[total_rules].action = action;
  434.           rules[total_rules].line = line;
  435.  
  436.           /** if we are not printing rules we can't expand macros
  437.           until after we applied the rule, due to the regexp macros
  438.           **/
  439.           if (printing_rules)
  440.             expand_macros(action_argument, rules[total_rules].argument2,
  441.                   line, printing_rules);
  442.           else
  443.         strcpy(rules[total_rules].argument2, action_argument);
  444.  
  445.           if (++total_rules >= sizeof_rules)
  446.             sizeof_rules = grow(&rules, sizeof_rules, RULESINC);
  447.  
  448.           if ((cond = (struct condition_rec *)
  449.              malloc(sizeof(struct condition_rec))) == NULL) {
  450.         if (outfd != NULL)
  451.               fprintf(outfd,catgets(elm_msg_cat,
  452.                     FilterSet,FilterCouldntMallocFirst,
  453.                   "filter (%s): couldn't malloc first condition rec!\n"),
  454.               username);
  455.             return(-1);
  456.           }
  457.     
  458.           rules[total_rules].condition = cond;    /* hooked in! */
  459.  
  460.           state = NEXT_CONDITION;
  461.           if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  462.             continue;
  463.         }
  464.       }
  465.     }
  466.  
  467.     return(0);
  468. }
  469.