home *** CD-ROM | disk | FTP | other *** search
-
- static char rcsid[] ="@(#)$Id: parse.c,v 4.1 90/04/28 22:41:58 syd Exp $";
-
- /*******************************************************************************
- * The Elm Mail System - $Revision: 4.1 $ $State: Exp $
- *
- * Copyright (c) 1986, 1987 Dave Taylor
- * Copyright (c) 1988, 1989, 1990 USENET Community Trust
- *******************************************************************************
- * Bug reports, patches, comments, suggestions should be sent to:
- *
- * Syd Weinstein - elm@DSI.COM
- * dsinc!elm
- *
- *******************************************************************************
- * $Log: parse.c,v $
- * Revision 4.1 90/04/28 22:41:58 syd
- * checkin of Elm 2.3 as of Release PL0
- *
- *
- ******************************************************************************/
-
-
- /** This is the parser for the filter program. It accepts a wide variety of
- constructs, building the ruleset table as it goes along. Check the
- data structure in filter.h for more information on how the rules are
- stored. The parser is a cunning state-table based program.
-
- **/
-
- #include <stdio.h>
- #include <ctype.h>
-
- #include "defs.h"
- #include "filter.h"
-
- #define NONE 0
- #define AND 10
-
- #define NEXT_CONDITION 0
- #define GETTING_OP 1
- #define READING_ARGUMENT 2
- #define READING_ACTION 3
- #define ACTION_ARGUMENT 4
-
- char *strtok(), *whatname(), *actionname();
-
- int
- get_filter_rules()
- {
- /** Given the users home directory, open and parse their rules table,
- building the data structure as we go along.
- returns -1 if we hit an error of any sort...
- **/
-
- FILE *fd; /* the file descriptor */
- char buffer[SLEN], /* fd reading buffer */
- *str, /* ptr to read string */
- *word, /* ptr to 'token' */
- filename[SLEN], /* the name of the ruleset */
- action_argument[SLEN], /* action arg, per rule */
- cond_argument[SLEN]; /* cond arg, per condition */
- int not_condition = FALSE, /* are we in a "not" ?? */
- type=NONE, /* what TYPE of condition? */
- lasttype, /* and the previous TYPE? */
- state = NEXT_CONDITION, /* the current state */
- in_single, in_double, /* for handling spaces. */
- i, /* misc integer for loops */
- relop = NONE, /* relational operator */
- action, /* the current action type */
- buflen, /* the length of buffer */
- line = 0; /* line number we're on */
-
- struct condition_rec *cond, *newcond;
-
- sprintf(filename,"%s/%s", home, filterfile);
-
- if ((fd = fopen(filename,"r")) == NULL) {
- if (outfd != NULL)
- fprintf(outfd,"filter (%s): Couldn't read user filter rules file!\n",
- username);
- return(-1);
- }
-
- cond_argument[0] = action_argument[0] = '\0';
-
- /* Now, for each line... **/
-
- if ((cond = (struct condition_rec *)
- malloc(sizeof(struct condition_rec))) == NULL) {
- if (outfd != NULL)
- fprintf(outfd,"filter (%s): couldn't malloc first condition rec!\n",
- username);
- return(-1);
- }
-
- rules[total_rules].condition = cond; /* hooked in! */
-
- while (fgets(buffer, SLEN, fd) != NULL) {
- line++;
-
- if (buffer[0] == '#' || (buflen = strlen(buffer)) < 2)
- continue; /* nothing to look at! */
-
- in_single = in_double = 0;
-
- for (i=0; i < buflen; i++) {
- if (buffer[i] == '"')
- in_double = ! in_double;
- else if (buffer[i] == '\'')
- in_single = ! in_single;
- if ((in_double || in_single) && buffer[i] == ' ')
- buffer[i] = '_';
- }
-
- lasttype = type;
- type = NONE;
- str = (char *) buffer;
-
- /** Three pieces to this loop - get the `field', the 'relop' (if
- there) then, if needed, get the argument to check against (not
- needed for errors or the AND, of course)
- **/
-
- while ((word = strtok(str, " ()[]:\t\n")) != NULL) {
-
- str = (char *) NULL; /* we can start stomping! */
-
- lowercase(word);
-
- if (strcmp(word, "if") == 0) { /* only ONE 'if' allowed */
- if ((word = strtok(str, " ()[]:\t\n")) == NULL) /* NEXT! */
- continue;
- lowercase(word);
- }
-
- if (state == NEXT_CONDITION) {
- lasttype = type;
- type = NONE;
-
- if (the_same(word, "not") || the_same(word, "!")) {
- not_condition = TRUE;
- if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- continue;
- }
-
- if (the_same(word, "from")) type = FROM;
- else if (the_same(word, "to")) type = TO;
- else if (the_same(word, "subject")) type = SUBJECT;
- else if (the_same(word, "lines")) type = LINES;
- else if (the_same(word, "contains")) type = CONTAINS;
- else if (the_same(word, "and") ||
- the_same(word, "&&")) type = AND;
-
- else if (the_same(word,"?") || the_same(word, "then") ||
- the_same(word, "always")) {
-
- /** shove THIS puppy into the structure and let's continue! **/
-
- if (lasttype == AND) {
- if (outfd != NULL)
- fprintf(outfd,
- "filter (%s): Error reading line %d of rules - badly placed \"and\"\n",
- username, line);
- return(-1);
- }
-
- if (the_same(word, "always"))
- cond->matchwhat = ALWAYS; /* so it's a hack... */
- else
- cond->matchwhat = lasttype;
-
- if (relop == NONE) relop = EQ; /* otherwise can't do -relop */
- cond->relation = (not_condition? - (relop) : relop);
-
- for (i=strlen(cond_argument); --i >= 0;)
- if (cond_argument[i] == '_') cond_argument[i] = ' ';
-
- strcpy(cond->argument1, cond_argument);
- if ((newcond = (struct condition_rec *)
- malloc(sizeof(struct condition_rec))) == NULL) {
- if (outfd != NULL)
- fprintf(outfd,
- "filter (%s): Couldn't malloc new cond rec!!\n",
- username);
- return(-1);
- }
- cond->next = NULL;
-
- relop = EQ; /* default relational condition */
-
- state = READING_ACTION;
- if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- continue;
- goto get_outta_loop;
- }
-
- if (type == NONE) {
- if (outfd != NULL)
- fprintf(outfd,
- "filter (%s): Error reading line %d of rules - field \"%s\" unknown!\n",
- username, line, word);
- return(-1);
- }
-
- if (type == AND) {
-
- /** shove THIS puppy into the structure and let's continue! **/
-
- cond->matchwhat = lasttype;
- cond->relation = (not_condition? - (relop) : relop);
- strcpy(cond->argument1, cond_argument);
- if ((newcond = (struct condition_rec *)
- malloc(sizeof(struct condition_rec))) == NULL) {
- if (outfd != NULL)
- fprintf(outfd,
- "filter (%s): Couldn't malloc new cond rec!!\n",
- username);
- return(-1);
- }
- cond->next = newcond;
- cond = newcond;
- cond->next = NULL;
-
- not_condition = FALSE;
- state = NEXT_CONDITION;
- }
- else {
- state = GETTING_OP;
- }
- }
-
- get_outta_loop: /* jump out when we change state, if needed */
-
- if (state == GETTING_OP) {
-
- if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- continue;
-
- lowercase(word);
-
- relop = NONE;
-
- if (the_same(word, "=") || the_same(word, "in") ||
- the_same(word, "contains")) {
- state = READING_ARGUMENT;
- relop = EQ;
- }
- else {
- if (the_same(word, "<=")) relop = LE;
- else if (the_same(word, ">=")) relop = GE;
- else if (the_same(word, ">")) relop = GT;
- else if (the_same(word, "<>")||
- the_same(word, "!=")) relop = NE;
- else if (the_same(word, "<")) relop = LT;
-
- /* maybe there isn't a relop at all!! */
-
- state=READING_ARGUMENT;
-
- }
- }
-
- if (state == READING_ARGUMENT) {
- if (relop != NONE) {
- if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- continue;
- }
- for (i=strlen(word); --i>=0;)
- if (word[i] == '_') word[i] = ' ';
-
- strcpy(cond_argument, word);
- state = NEXT_CONDITION;
- }
-
- if (state == READING_ACTION) {
- action = NONE;
-
- not_condition = FALSE;
-
- if (the_same(word, "delete")) action = DELETE_MSG;
- else if (the_same(word, "savec")) action = SAVECC;
- else if (the_same(word, "save")) action = SAVE;
- else if (the_same(word, "forward")) action = FORWARD;
- else if (the_same(word, "exec")) action = EXEC;
- else if (the_same(word, "leave")) action = LEAVE;
- else {
- if (outfd != NULL)
- fprintf(outfd,
- "filter (%s): Error on line %d of rules - action \"%s\" unknown\n",
- username, line, word);
- }
-
- if (action == DELETE_MSG || action == LEAVE) {
- /** add this to the rules section and alloc next... **/
-
- rules[total_rules].action = action;
- rules[total_rules].argument2[0] = '\0'; /* nothing! */
- total_rules++;
-
- if ((cond = (struct condition_rec *)
- malloc(sizeof(struct condition_rec))) == NULL) {
- if (outfd != NULL)
- fprintf(outfd,
- "filter (%s): couldn't malloc first condition rec!\n",
- username);
- return(-1);
- }
-
- rules[total_rules].condition = cond; /* hooked in! */
- state = NEXT_CONDITION;
- }
- else {
- state = ACTION_ARGUMENT;
- }
-
- if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- continue;
-
- }
-
- if (state == ACTION_ARGUMENT) {
- strcpy(action_argument, word);
-
- /** add this to the rules section and alloc next... **/
-
- rules[total_rules].action = action;
- expand_macros(action_argument, rules[total_rules].argument2,line,
- printing_rules);
- total_rules++;
-
- if ((cond = (struct condition_rec *)
- malloc(sizeof(struct condition_rec))) == NULL) {
- if (outfd != NULL)
- fprintf(outfd,
- "filter (%s): couldn't malloc first condition rec!\n",
- username);
- return(-1);
- }
-
- rules[total_rules].condition = cond; /* hooked in! */
-
- state = NEXT_CONDITION;
- if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
- continue;
- }
- }
- }
-
- return(0);
- }
-