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

  1.  
  2. static char rcsid[] ="@(#)$Id: filter.c,v 5.3 1992/11/15 01:40:43 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.3 $   $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: filter.c,v $
  17.  * Revision 5.3  1992/11/15  01:40:43  syd
  18.  * Add regexp processing to filter.
  19.  * Add execc operator
  20.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  21.  *
  22.  * Revision 5.2  1992/11/07  16:20:56  syd
  23.  * The first is that when doing a summary, macros are expanded when printing the
  24.  * rule. IMHO they should be printed as with the -r option (i.e. %t is
  25.  * printed as "<time>" and so on).
  26.  *
  27.  * The second one is that the summary printed "applied n time" regardless of
  28.  * the value of n, not "applied n times" when n > 1.
  29.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  30.  *
  31.  * Revision 5.1  1992/10/03  22:18:09  syd
  32.  * Initial checkin as of 2.4 Release at PL0
  33.  *
  34.  *
  35.  ******************************************************************************/
  36.  
  37.  
  38. /** This program is used as a filter within the users ``.forward'' file
  39.     and allows intelligent preprocessing of mail at the point between
  40.     when it shows up on the machine and when it is actually put in the
  41.     mailbox.
  42.  
  43.     The program allows selection based on who the message is FROM, TO, or
  44.     what the subject is.  Acceptable actions are for the program to DELETE_MSG
  45.     the message, SAVE the message in a specified folder, FORWARD the message
  46.     to a specified user, SAVE the message in a folder, but add a copy to the
  47.     users mailbox anyway, or simply add the message to the incoming mail.
  48.  
  49.     Filter also keeps a log of what it does as it goes along, and at the
  50.     end of each `quantum' mails a summary of actions, if any, to the user.
  51.  
  52.     Uses the files: $HOME/.elm/filter for instructions to this program, and
  53.     $HOME/.elm/filterlog for a list of what has been done since last summary.
  54.  
  55. **/
  56.  
  57. #include <stdio.h>
  58. #include <pwd.h>
  59. #include <ctype.h>
  60. #include "defs.h"
  61. #ifdef I_TIME
  62. #  include <time.h>
  63. #endif
  64. #ifdef I_SYSTIME
  65. #  include <sys/time.h>
  66. #endif
  67. #include <fcntl.h>
  68.  
  69. #define  MAIN_ROUTINE            /* for the filter.h file, of course! */
  70. #include "filter.h"
  71. #include "s_filter.h"
  72.  
  73.  
  74. main(argc, argv)
  75. int argc;
  76. char *argv[];
  77. {
  78.     extern char *optarg;
  79.     FILE   *fd;                /* for output to temp file! */
  80.     struct passwd  *passwd_entry;
  81. #ifndef    _POSIX_SOURCE
  82.     struct passwd  *getpwuid();        /* for /etc/passwd          */
  83. #endif
  84.     char filename[SLEN],            /* name of the temp file    */
  85.          action_argument[SLEN],         /* action arg, per rule    */
  86.          buffer[MAX_LINE_LEN];        /* input buffer space       */
  87.     int  in_header = TRUE,            /* for header parsing       */
  88.          in_to     = FALSE,            /* are we on 'n' line To: ? */
  89.          summary   = FALSE,            /* a summary is requested?  */
  90.          c;                    /* var for getopt routine   */
  91.  
  92. #ifdef I_LOCALE
  93.         setlocale(LC_ALL, "");
  94. #endif
  95.  
  96.         elm_msg_cat = catopen("elm2.4", 0);
  97.  
  98.         
  99.     /* first off, let's get the info from /etc/passwd */ 
  100.     
  101.     if ((passwd_entry = getpwuid(getuid())) == NULL) 
  102.       leave(catgets(elm_msg_cat,FilterSet,FilterCantGetPasswdEntry,
  103.         "Cannot get password entry for this uid!"));
  104.  
  105.     strcpy(home, passwd_entry->pw_dir);
  106.     strcpy(username, passwd_entry->pw_name);
  107.     user_uid = passwd_entry->pw_uid;
  108.     user_gid = passwd_entry->pw_gid;
  109.     
  110.     /* nothing read in yet, right? */
  111.     outfname[0] = to[0] = filterfile[0] = '\0';
  112.     
  113.     
  114. #ifdef HOSTCOMPILED
  115.     strncpy(hostname, HOSTNAME, sizeof(hostname));
  116. #else
  117.     gethostname(hostname, sizeof(hostname));
  118. #endif
  119.  
  120.     /* now parse the starting arguments... */
  121.  
  122.     while ((c = getopt(argc, argv, "clno:qrSsvf:")) != EOF)
  123.     {
  124.           switch (c) {
  125.            case 'c' :
  126.             clear_logs = TRUE;
  127.             break;
  128.            case 'f' :
  129.             strcpy(filterfile,optarg);
  130.             break;
  131.            case 'l' :
  132.             log_actions_only = TRUE;
  133.             break;
  134.            case 'n' :
  135.             show_only = TRUE;
  136.             break;
  137.            case 'o' :
  138.             strcpy(outfname, optarg);
  139.             break;
  140.            case 'q' :
  141.             logging = FALSE;
  142.             break;
  143.            case 'r' :
  144.             printing_rules = TRUE;
  145.             break;
  146.            case 's' :
  147.             summary = TRUE;
  148.             break;
  149.            case 'S' :
  150.             long_summary = TRUE;
  151.             break;
  152.            case 'v' :
  153.             verbose = TRUE;
  154.             break;
  155.            case '?' :
  156.             default  :
  157.             fprintf(stderr, 
  158.                    catgets(elm_msg_cat,FilterSet,FilterUsage,
  159.   "Usage: | filter [-nrvlq] [-f rules] [-o file]\n\
  160. \tor: filter [-c] -[s|S]\n"));
  161.                      exit(1);
  162.       }
  163.     }
  164.  
  165.     if (c < 0) {
  166.     }
  167.  
  168.     /* use default filter file name if none specified */
  169.     if (!*filterfile)
  170.          sprintf(filterfile,"%s/%s",home,FILTERFILE);
  171.     
  172.     
  173.     /* let's open our outfd logfile as needed... */
  174.  
  175.     if (outfname[0] == '\0')     /* default is stdout */
  176.       outfd = stdout;
  177.     else 
  178.       if ((outfd = fopen(outfname, "a")) == NULL) {
  179.         if (isatty(fileno(stderr)))
  180.           fprintf(stderr,
  181.               catgets(elm_msg_cat,FilterSet,FilterCouldntOpenLogFile,
  182.           "filter (%s): couldn't open log file %s\n"),
  183.               username, outfname);
  184.       }
  185.  
  186.     if (summary || long_summary) {
  187.           if (get_filter_rules() == -1) {
  188.         if (outfd != NULL) fclose(outfd);
  189.         exit(1);
  190.       }
  191.       printing_rules = TRUE;
  192.       show_summary();
  193.       if (outfd != NULL) fclose(outfd);
  194.       exit(0);
  195.     }
  196.  
  197.     if (printing_rules) {
  198.           if (get_filter_rules() == -1)
  199.         fprintf(outfd,catgets(elm_msg_cat,FilterSet,FilterCouldntGetRules,
  200.           "filter (%s): Couldn't get rules!\n"), username);
  201.           else
  202.         print_rules();
  203.       if (outfd != NULL) fclose(outfd);
  204.           exit(0);
  205.     }
  206.  
  207.     /* next, create the tempfile and save the incoming message */
  208.  
  209.     sprintf(filename, "%s.%d", filter_temp, getpid());
  210.  
  211.     if ((fd = fopen(filename,"w")) == NULL)
  212.       {
  213.         sprintf(buffer,
  214.             catgets(elm_msg_cat,FilterSet,
  215.                 FilterCantOpenTempFileLeave,
  216.             "Cannot open temporary file %s"),
  217.                 filename);
  218.         leave(buffer);
  219.       }
  220.     
  221.  
  222.     while (fgets(buffer, MAX_LINE_LEN, stdin) != NULL) {
  223.  
  224.       remove_return(buffer);
  225.  
  226.       if (in_header) {
  227.  
  228.         if (! whitespace(buffer[0])) 
  229.         in_to = FALSE;
  230.  
  231.         if (the_same(buffer, "From ")) 
  232.           save_from(buffer);
  233.         else if (the_same(buffer, "Subject:")) 
  234.           save_subject(buffer);
  235.         else if (the_same(buffer, "Sender:")) 
  236.           save_sender(buffer);
  237.         else if (the_same(buffer, "To:") || the_same(buffer, "Cc:") ||
  238.              the_same(buffer, "Apparently-To:")) {
  239.           in_to++;
  240.           save_to(buffer);
  241.         }
  242.         else if (the_same(buffer, "X-Filtered-By:")) 
  243.           already_been_forwarded++;    /* could be a loop here! */
  244. #ifdef USE_EMBEDDED_ADDRESSES
  245.         else if (the_same(buffer, "From:"))
  246.           save_embedded_address(buffer, "From:");
  247.         else if (the_same(buffer, "Reply-To:"))
  248.           save_embedded_address(buffer, "Reply-To:");
  249. #endif
  250.         else if (strlen(buffer) < 2) 
  251.           in_header = 0;
  252.         else if (whitespace(buffer[0]) && in_to)
  253.           strcat(to, buffer);
  254.       }
  255.     
  256.           fprintf(fd, "%s\n", buffer);    /* and save it regardless! */
  257.       fflush(fd);
  258.       lines++;
  259.     }
  260.  
  261.     fclose(fd);
  262.  
  263.     /** next let's see if the user HAS a filter file, and if so what's in
  264.             it (and so on) **/
  265.  
  266.     if (get_filter_rules() == -1)
  267.       mail_message(username);
  268.     else {
  269.       int action = action_from_ruleset();
  270.  
  271.       if (rule_choosen >= 0) {
  272.         expand_macros(rules[rule_choosen].argument2, action_argument,
  273.             rules[rule_choosen].line, printing_rules);
  274.         /* Got to do this because log_msg() uses argument2 in rules[] */
  275.         strcpy(rules[rule_choosen].argument2, action_argument);
  276.       }
  277.  
  278.       switch (action) {
  279.  
  280.         case DELETE_MSG : if (verbose && outfd != NULL)
  281.                 fprintf(outfd,
  282.                     catgets(elm_msg_cat,FilterSet,
  283.                         FilterMessageDeleted,
  284.                         "filter (%s): Message deleted\n"),
  285.                     username);
  286.               log_msg(DELETE_MSG);                break;
  287.  
  288.         case SAVE   : if (save_message(rules[rule_choosen].argument2)) {
  289.                 mail_message(username);
  290.                 log_msg(FAILED_SAVE);
  291.               }
  292.               else
  293.                  log_msg(SAVE);
  294.                       break;
  295.  
  296.         case SAVECC : if (save_message(rules[rule_choosen].argument2))
  297.                 log_msg(FAILED_SAVE);
  298.               else
  299.                     log_msg(SAVECC);
  300.               mail_message(username);
  301.                       break;
  302.  
  303.         case FORWARDC:mail_message(username);
  304.                   mail_message(rules[rule_choosen].argument2);
  305.               log_msg(FORWARDC);
  306.                       break;
  307.         case FORWARD: mail_message(rules[rule_choosen].argument2);
  308.               log_msg(FORWARD);
  309.                       break;
  310.  
  311.         case EXECC    : mail_message(username);
  312.                   execute(rules[rule_choosen].argument2);
  313.               log_msg(EXECC);
  314.                       break;
  315.  
  316.         case EXEC   : execute(rules[rule_choosen].argument2);
  317.               log_msg(EXEC);
  318.                       break;
  319.  
  320.         case LEAVE  : mail_message(username);
  321.               log_msg(LEAVE);
  322.                       break;
  323.       }
  324.     }
  325.  
  326.     (void) unlink(filename);    /* remove the temp file, please! */
  327.     if (outfd != NULL)
  328.       fclose(outfd);
  329.     exit(0);
  330. }
  331.  
  332. save_from(buffer)
  333. char *buffer;
  334. {
  335.     /** save the SECOND word of this string as FROM **/
  336.  
  337.     register char *f = from;
  338.  
  339.     while (*buffer != ' ')
  340.       buffer++;                /* get to word     */
  341.  
  342.     for (buffer++; *buffer != ' ' && *buffer; buffer++, f++) 
  343.       *f = *buffer;                /* copy it and     */
  344.  
  345.     *f = '\0';                /* Null terminate! */
  346. }
  347.  
  348. save_subject(buffer)
  349. char *buffer;
  350. {
  351.     /** save all but the word "Subject:" for the subject **/
  352.  
  353.     register int skip = 8;  /* skip "Subject:" initially */
  354.  
  355.     while (buffer[skip] == ' ') skip++;
  356.  
  357.     strcpy(subject, (char *) buffer + skip);
  358. }
  359.  
  360. save_sender(buffer)
  361. char *buffer;
  362. {
  363.     /** save all but the word "Sender:" for the sender **/
  364.  
  365.     register int skip = 7;  /* skip "Sender:" initially */
  366.  
  367.     while (buffer[skip] == ' ') skip++;
  368.  
  369.     strcpy(sender, (char *) buffer + skip);
  370. }
  371.  
  372. save_to(buffer)
  373. char *buffer;
  374. {
  375.     /** save all but the word "To:" or "Cc:" or
  376.         "Apparently-To:" for the to list **/
  377.  
  378.     register int skip = 0;
  379.  
  380.     while (buffer[skip] != ' ') skip++;
  381.     while (buffer[skip] == ' ') skip++;
  382.  
  383.     if (*to)
  384.         strcat(to, " "); /* place one blank between items */
  385.  
  386.     strcat(to, (char *) buffer + skip);
  387. }
  388.  
  389. #ifdef USE_EMBEDDED_ADDRESSES
  390.  
  391. save_embedded_address(buffer, fieldname)
  392. char *buffer, *fieldname;
  393. {
  394.     /** this will replace the 'from' address with the one given, 
  395.         unless the address is from a 'reply-to' field (which overrides 
  396.         the From: field).  The buffer given to this routine can have one 
  397.             of three forms:
  398.         fieldname: username <address>
  399.         fieldname: address (username)
  400.         fieldname: address
  401.     **/
  402.     
  403.     static int processed_a_reply_to = 0;
  404.     char address[LONG_STRING];
  405.     register int i, j = 0;
  406.  
  407.     /** first let's extract the address from this line.. **/
  408.  
  409.     if (buffer[strlen(buffer)-1] == '>') {    /* case #1 */
  410.       for (i=strlen(buffer)-1; buffer[i] != '<' && i > 0; i--)
  411.         /* nothing - just move backwards .. */ ;
  412.       i++;    /* skip the leading '<' symbol */
  413.       while (buffer[i] != '>')
  414.         address[j++] = buffer[i++];
  415.       address[j] = '\0';
  416.     }
  417.     else {    /* get past "from:" and copy until white space or paren hit */
  418.       for (i=strlen(fieldname); whitespace(buffer[i]); i++)
  419.          /* skip past that... */ ;
  420.       while (buffer[i] != '(' && ! whitespace(buffer[i]) && buffer[i]!='\0')
  421.         address[j++] = buffer[i++];
  422.       address[j] = '\0';
  423.     }
  424.  
  425.     /** now let's see if we should overwrite the existing from address
  426.         with this one or not.. **/
  427.  
  428.     if (processed_a_reply_to)
  429.       return;    /* forget it! */
  430.  
  431.     strcpy(from, address);            /* replaced!! */
  432.  
  433.     if (istrcmp(fieldname, "Reply-To:") == 0)
  434.       processed_a_reply_to++;
  435. }
  436. #endif
  437.  
  438.