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 / rules.c < prev    next >
C/C++ Source or Header  |  1993-01-12  |  14KB  |  532 lines

  1.  
  2. static char rcsid[] ="@(#)$Id: rules.c,v 5.5 1992/12/11 01:45:04 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.5 $   $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: rules.c,v $
  17.  * Revision 5.5  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.4  1992/11/22  00:06:45  syd
  23.  * Fix when expanding the macro '%S', the subject line is scanned for a
  24.  * 'Re:', and if nothing is found, a '"Re: ' is added. But when a 'Re:'
  25.  * *is* found, then nothing is added, not even the '"'.
  26.  * From: Sigmund Austigard <austig@solan.unit.no>
  27.  *
  28.  * Revision 5.3  1992/11/17  04:10:01  syd
  29.  * The changes to filter/regexp.c are to correct compiler warnings about
  30.  * unreachable statements.
  31.  *
  32.  * The changes to filter/rules.c are to correct the fact that we are passing
  33.  * a pointer to a condition_rec structore to a function expecting a pointer to
  34.  * a character string.
  35.  * From: Tom Moore <tmoore@fievel.DaytonOH.NCR.COM>
  36.  *
  37.  * Revision 5.2  1992/11/15  01:40:43  syd
  38.  * Add regexp processing to filter.
  39.  * Add execc operator
  40.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  41.  *
  42.  * Revision 5.1  1992/10/03  22:18:09  syd
  43.  * Initial checkin as of 2.4 Release at PL0
  44.  *
  45.  *
  46.  ******************************************************************************/
  47.  
  48. /** This file contains all the rule routines, including those that apply the
  49.     specified rules and the routine to print the rules out.
  50.  
  51. **/
  52.  
  53. #include <stdio.h>
  54. #include "defs.h"
  55. #include <pwd.h>
  56. #include <ctype.h>
  57. #ifdef I_TIME
  58. #  include <time.h>
  59. #endif
  60. #ifdef I_SYSTIME
  61. #  include <sys/time.h>
  62. #endif
  63. #include <fcntl.h>
  64.  
  65. #include "filter.h"
  66. #include "s_filter.h"
  67.  
  68. char *listrule();
  69.  
  70. static struct regexp *last_regexp = NULL;
  71.  
  72. static int
  73. matches(str, relation, cond)
  74. char *str;
  75. int relation;
  76. struct condition_rec *cond;
  77. {
  78.     if (relation == RE) {
  79.       if (cond->regex == NULL) cond->regex = regcomp(cond->argument1);
  80.       if (regexec(cond->regex, str)) {
  81.         last_regexp = cond->regex;
  82.         return TRUE;
  83.       } else {
  84.         return FALSE;
  85.       }
  86.     } else {
  87.       return contains(str, cond->argument1);
  88.     }
  89. }
  90.  
  91. void
  92. regerror(s)
  93. char *s;
  94. {
  95.     if (outfd != NULL)
  96.       fprintf(outfd,
  97.         catgets(elm_msg_cat,
  98.             FilterSet,FilterCantCompileRegexp,
  99.             "filter (%s): Error: can't compile regexp: \"%s\"\n"),
  100.          username, s);
  101.     if (outfd != NULL) fclose(outfd);
  102.     exit(1);         
  103. }
  104.  
  105. int
  106. action_from_ruleset()
  107. {
  108.     /** Given the set of rules we've read in and the current to, from, 
  109.         and subject, try to match one.  Return the ACTION of the match
  110.             or LEAVE if none found that apply.
  111.     **/
  112.  
  113.     register int iindex = 0, not, relation, try_next_rule, x;
  114.     struct condition_rec *cond;
  115.  
  116.     while (iindex < total_rules) {
  117.       cond = rules[iindex].condition;
  118.       try_next_rule = 0;
  119.  
  120.       while (cond != NULL && ! try_next_rule) {
  121.         
  122.         not = (cond->relation < 0);
  123.         relation = abs(cond->relation);
  124.     
  125.         switch (cond->matchwhat) {
  126.  
  127.           case TO     : x = matches(to, relation, cond);        break;
  128.           case FROM   : x = matches(from, relation, cond);         break;
  129.           case SENDER : x = matches(sender, relation, cond);    break;
  130.           case SUBJECT: x = matches(subject, relation, cond);    break;
  131.           case LINES  : x = compare(lines, relation, cond);        break;
  132.                
  133.           case CONTAINS: if (outfd != NULL) fprintf(outfd,
  134.                 catgets(elm_msg_cat,
  135.                     FilterSet,FilterContainsNotImplemented,
  136.        "filter (%s): Error: rules based on 'contains' are not implemented!\n"),
  137.                 username);
  138.                 if (outfd != NULL) fclose(outfd);
  139.                 exit(0);         
  140.  
  141.           case ALWAYS: not = FALSE; x = TRUE;            break;
  142.         }
  143.  
  144.         if ((not && x) || ((! not) && (! x))) /* this test failed (LISP?) */
  145.           try_next_rule++;
  146.         else
  147.           cond = cond->next;          /* next condition, if any?  */
  148.       }
  149.  
  150.       if (! try_next_rule) {
  151.         rule_choosen = iindex;
  152.          return(rules[rule_choosen].action);
  153.       }
  154.       iindex++;
  155.     }
  156.  
  157.     rule_choosen = -1;
  158.     return(LEAVE);
  159. }
  160.  
  161. #define get_the_time()    if (!gotten_time) {           \
  162.                thetime = time( (time_t *) 0);   \
  163.                timerec = localtime(&thetime); \
  164.                gotten_time++;           \
  165.             }
  166.  
  167. static struct {
  168.     int    id;
  169.     char    *str;
  170. } regmessage[] = {
  171.     FilterWholeRegsub,    "<match>",
  172.     FilterRegsubOne,    "<submatch-1>",
  173.     FilterRegsubTwo,    "<submatch-2>",
  174.     FilterRegsubThree,    "<submatch-3>",
  175.     FilterRegsubFour,    "<submatch-4>",
  176.     FilterRegsubFive,    "<submatch-5>",
  177.     FilterRegsubSix,    "<submatch-6>",
  178.     FilterRegsubSeven,    "<submatch-7>",
  179.     FilterRegsubEight,    "<submatch-8>",
  180.     FilterRegsubNine,    "<submatch-9>",
  181. };
  182.  
  183. expand_macros(word, buffer, line, display)
  184. char *word, *buffer;
  185. int  line, display;
  186. {
  187.     /** expand the allowable macros in the word;
  188.         %d    = day of the month  
  189.         %D    = day of the week  
  190.             %h    = hour (0-23)     
  191.         %m    = month of the year
  192.         %n      = sender of message
  193.         %r    = return address of sender
  194.            %s    = subject of message
  195.            %S    = "Re: subject of message"  (only add Re: if not there)
  196.         %t    = hour:minute     
  197.         %y    = year          
  198.         %&    = the whole string that matched last regexp
  199.         %1-%9    = matched subexpressions in last regexp
  200.         or simply copies word into buffer. If "display" is set then
  201.         instead it puts "<day-of-month>" etc. etc. in the output.
  202.     **/
  203.  
  204. #ifndef    _POSIX_SOURCE
  205.     struct tm *localtime();
  206.     time_t    time();
  207. #endif
  208.     struct tm *timerec;
  209.     time_t    thetime;
  210.     register int i, j=0, gotten_time = 0, reading_a_percent_sign = 0,
  211.                      len, backslashed=0, regsub;
  212.  
  213.     for (i = 0, len = strlen(word); i < len; i++) {
  214.       if (reading_a_percent_sign) {
  215.         reading_a_percent_sign = 0;
  216.         switch (word[i]) {
  217.  
  218.           case 'n' : buffer[j] = '\0';
  219.              if (display)
  220.                strcat(buffer,catgets(elm_msg_cat,
  221.                          FilterSet,FilterSender,
  222.                          "<sender>"));
  223.              else {
  224.                strcat(buffer, "\"");
  225.                strcat(buffer, sender);
  226.                strcat(buffer, "\"");
  227.              }
  228.              j = strlen(buffer);
  229.              break;
  230.  
  231.           case 'r' : buffer[j] = '\0';
  232.              if (display)
  233.                 strcat(buffer,catgets(elm_msg_cat,
  234.                          FilterSet,FilterReturnAddress,
  235.                          "<return-address>"));
  236.              else
  237.                strcat(buffer, from);
  238.                      j = strlen(buffer);
  239.              break;
  240.  
  241.           case 's' : buffer[j] = '\0';
  242.              if (display)
  243.                 strcat(buffer,catgets(elm_msg_cat,
  244.                         FilterSet,FilterSubject,
  245.                          "<subject>"));
  246.              else {
  247.                strcat(buffer, "\"");
  248.                strcat(buffer, subject);
  249.                strcat(buffer, "\"");
  250.              }
  251.                      j = strlen(buffer);
  252.              break;
  253.  
  254.           case 'S' : buffer[j] = '\0';
  255.              if (display)
  256.                 strcat(buffer,catgets(elm_msg_cat,
  257.                          FilterSet,FilterReSubject,
  258.                          "<Re: subject>"));
  259.              else {
  260.                strcat(buffer, "\"");
  261.                if (! the_same(subject, "Re:")) 
  262.                  strcat(buffer, "Re: ");
  263.                strcat(buffer, subject);
  264.                strcat(buffer, "\"");
  265.              }
  266.                      j = strlen(buffer);
  267.              break;
  268.  
  269.           case 'd' : get_the_time(); buffer[j] = '\0';
  270.              if (display)
  271.                strcat(buffer,catgets(elm_msg_cat,
  272.                          FilterSet,FilterDayOfMonth,
  273.                          "<day-of-month>"));
  274.              else
  275.                strcat(buffer, itoa(timerec->tm_mday,FALSE));
  276.                      j = strlen(buffer);
  277.              break;
  278.  
  279.           case 'D' : get_the_time(); buffer[j] = '\0';
  280.              if (display)
  281.                strcat(buffer,catgets(elm_msg_cat,
  282.                          FilterSet,FilterDayOfWeek,
  283.                          "<day-of-week>"));
  284.              else
  285.                strcat(buffer, itoa(timerec->tm_wday,FALSE));
  286.                      j = strlen(buffer);
  287.              break;
  288.  
  289.           case 'm' : get_the_time(); buffer[j] = '\0';
  290.              if (display)
  291.                strcat(buffer,catgets(elm_msg_cat,
  292.                          FilterSet,FilterMonth,
  293.                          "<month>"));
  294.              else
  295.                sprintf(&buffer[j],"%2.2d",timerec->tm_mon+1);
  296.                      j = strlen(buffer);
  297.              break;
  298.  
  299.           case 'y' : get_the_time(); buffer[j] = '\0';
  300.              if (display)
  301.                strcat(buffer,catgets(elm_msg_cat,
  302.                          FilterSet,FilterYear,
  303.                          "<year>"));
  304.              else
  305.                strcat(buffer, itoa(timerec->tm_year,FALSE));
  306.                      j = strlen(buffer);
  307.              break;
  308.  
  309.           case 'h' : get_the_time(); buffer[j] = '\0';
  310.              if (display)
  311.                strcat(buffer,catgets(elm_msg_cat,
  312.                          FilterSet,FilterHour,
  313.                          "<hour>"));
  314.              else
  315.                strcat(buffer, itoa(timerec->tm_hour,FALSE));
  316.                      j = strlen(buffer);
  317.              break;
  318.  
  319.           case 't' : get_the_time(); buffer[j] = '\0';
  320.              if (display)
  321.                strcat(buffer,catgets(elm_msg_cat,
  322.                          FilterSet,FilterTime,
  323.                          "<time>"));
  324.                  else {
  325.                strcat(buffer, itoa(timerec->tm_hour,FALSE));
  326.                strcat(buffer, ":");
  327.                strcat(buffer, itoa(timerec->tm_min,TRUE));
  328.              }
  329.                      j = strlen(buffer);
  330.              break;
  331.  
  332.           case '&': case '1': case '2': case '3': case '4':
  333.           case '5': case '6': case '7': case '8': case '9':
  334.  
  335.              if (word[i] == '&') regsub = 0;
  336.              else regsub = word[i] - '0';
  337.  
  338.              if (display) {
  339.                strcat(buffer,catgets(elm_msg_cat,
  340.                          FilterSet,
  341.                          regmessage[regsub].id,
  342.                          regmessage[regsub].str));
  343.                j = strlen(buffer);
  344.              } else {
  345.                if (last_regexp != NULL) {
  346.                  char *sp = last_regexp->startp[regsub];
  347.                  char *ep = last_regexp->endp[regsub];
  348.                  if (sp != NULL && ep != NULL && ep > sp)
  349.                    while (sp < ep) buffer[j++] = *sp++;
  350.                }
  351.              }
  352.              break;
  353.  
  354.           default  : if (outfd != NULL) fprintf(outfd,
  355.                 catgets(elm_msg_cat,
  356.                     FilterSet,FilterErrorTranslatingMacro,
  357.    "filter (%s): Error on line %d translating %%%c macro in word \"%s\"!\n"),
  358.                      username, line, word[i], word);
  359.              if (outfd != NULL) fclose(outfd);
  360.              exit(1);
  361.         }
  362.       }
  363.       else if (word[i] == '%') {
  364.         if (backslashed) {
  365.                  buffer[j++] = '%';
  366.                  backslashed = 0;
  367.             } else {
  368.              reading_a_percent_sign++;
  369.         }
  370.       } else if (word[i] == '\\') {
  371.         if (backslashed) {
  372.          buffer[j++] = '\\';
  373.          backslashed = 0;
  374.         } else {
  375.          backslashed++;
  376.         }
  377.       } else {
  378.         buffer[j++] = (word[i] == '_' ? ' ' : word[i]);
  379.         backslashed = 0;
  380.       }
  381.     }
  382.     buffer[j] = '\0';
  383. }
  384.  
  385. print_rules()
  386. {
  387.     /** print the rules out.  A double check, of course! **/
  388.  
  389.     register int i = -1;
  390.     char     *whatname(), *actionname();
  391.     struct   condition_rec *cond;
  392.  
  393.     if (outfd == NULL) return;    /* why are we here, then? */
  394.  
  395.     while (++i < total_rules) {
  396.       if (rules[i].condition->matchwhat == ALWAYS) {
  397.         fprintf(outfd,catgets(elm_msg_cat,FilterSet,FilterAlways,
  398.             "\nRule %d:  ** always ** \n\t%s %s\n"), i+1,
  399.          actionname(rules[i].action), listrule(rules[i].argument2));
  400.         continue;
  401.       }
  402.  
  403.       fprintf(outfd,catgets(elm_msg_cat,FilterSet,FilterRuleIf,
  404.                 "\nRule %d:  if ("), i+1);
  405.  
  406.       cond = rules[i].condition;
  407.  
  408.       while (cond != NULL) {
  409.         if (cond->relation < 0)
  410.           fprintf(outfd,catgets(elm_msg_cat,FilterSet,FilterNot,
  411.                     "not %s %s %s%s%s"), 
  412.               whatname(cond->matchwhat),
  413.               relationname(- (cond->relation)),
  414.               quoteit(cond->matchwhat),
  415.               cond->argument1,
  416.               quoteit(cond->matchwhat));
  417.         else
  418.           fprintf(outfd, "%s %s %s%s%s",
  419.               whatname(cond->matchwhat),
  420.               relationname(cond->relation),
  421.               quoteit(cond->matchwhat),
  422.               cond->argument1,
  423.               quoteit(cond->matchwhat));
  424.  
  425.         cond = cond->next;
  426.  
  427.         if (cond != NULL)
  428.           fprintf(outfd,catgets(elm_msg_cat,
  429.                     FilterSet,FilterAnd,
  430.                     " and "));
  431.       }
  432.         
  433.       fprintf(outfd,catgets(elm_msg_cat,FilterSet,FilterThen,
  434.                 ") then\n\t  %s %s\n"), 
  435.          actionname(rules[i].action), 
  436.          listrule(rules[i].argument2));
  437.     }
  438.     fprintf(outfd, "\n");
  439. }
  440.  
  441. char *whatname(n)
  442. int n;
  443. {
  444.     static char buffer[10];
  445.  
  446.     switch(n) {
  447.       case FROM   : return("from");
  448.       case TO     : return("to");
  449.       case SENDER : return("sender");
  450.       case SUBJECT: return("subject");
  451.       case LINES  : return ("lines");
  452.       case CONTAINS: return("contains");
  453.       default     : sprintf(buffer, "?%d?", n); return((char *)buffer);
  454.     }
  455. }
  456.  
  457. char *actionname(n)
  458. int n;
  459. {
  460.     switch(n) {
  461.       case DELETE_MSG : return(catgets(elm_msg_cat,
  462.                        FilterSet,FilterDelete,
  463.                        "Delete"));
  464.       case SAVE       : return(catgets(elm_msg_cat,
  465.                        FilterSet,FilterSave,
  466.                        "Save"));
  467.       case SAVECC     : return(catgets(elm_msg_cat,
  468.                        FilterSet,FilterCopyAndSave,
  469.                        "Copy and Save"));
  470.       case FORWARD    : return(catgets(elm_msg_cat,
  471.                        FilterSet,FilterForward,
  472.                        "Forward"));
  473.       case FORWARDC   : return(catgets(elm_msg_cat,
  474.                        FilterSet,FilterCopyAndForward,
  475.                        "Copy and Forward"));
  476.       case LEAVE      : return(catgets(elm_msg_cat,
  477.                        FilterSet,FilterLeave,
  478.                        "Leave")); 
  479.       case EXEC       : return(catgets(elm_msg_cat,
  480.                        FilterSet,FilterExecute,
  481.                        "Execute"));
  482.       case EXECC       : return(catgets(elm_msg_cat,
  483.                        FilterSet,FilterExecuteAndSave,
  484.                        "Execute and Save"));
  485.       default         : return(catgets(elm_msg_cat,
  486.                        FilterSet,FilterAction,
  487.                        "?action?"));
  488.     }
  489. }
  490.  
  491. int
  492. compare(line, relop, cond)
  493. int line, relop;
  494. struct condition_rec *cond;
  495. {
  496.     /** Given the actual number of lines in the message, the relop
  497.         relation, and the number of lines in the rule, as a string (!),
  498.            return TRUE or FALSE according to which is correct.
  499.     **/
  500.  
  501.     int rule_lines;
  502.  
  503.     rule_lines = atoi(cond->argument1);
  504.  
  505.     switch (relop) {
  506.       case LE: return(line <= rule_lines);
  507.       case LT: return(line <  rule_lines);
  508.       case GE: return(line >= rule_lines);
  509.       case GT: return(line >  rule_lines);
  510.       case NE: return(line != rule_lines);
  511.       case EQ: return(line == rule_lines);
  512.     }
  513.     return(-1);
  514. }
  515.  
  516. char *listrule(rule)
  517. char *rule;
  518. {
  519.     /** simply translates all underscores into spaces again on the
  520.         way past... **/
  521.  
  522.     static char buffer[SLEN];
  523.     register int i;
  524.  
  525.     i = strlen(rule);
  526.     buffer[i] = '\0';
  527.     while (--i >= 0)
  528.       buffer[i] = (rule[i] == '_' ? ' ' : rule[i]);
  529.  
  530.     return( (char *) buffer);
  531. }
  532.