home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / elm23-2.zip / filter / filter.c < prev    next >
C/C++ Source or Header  |  1994-08-16  |  10KB  |  349 lines

  1.  
  2. static char rcsid[] ="@(#)$Id: filter.c,v 4.1.1.1 90/10/24 16:11:44 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1.1.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:    filter.c,v $
  17.  * Revision 4.1.1.1  90/10/24  16:11:44  syd
  18.  * Fix out of order lines
  19.  * From: Steve Campbell
  20.  *
  21.  * Revision 4.1  90/04/28  22:41:55  syd
  22.  * checkin of Elm 2.3 as of Release PL0
  23.  *
  24.  *
  25.  ******************************************************************************/
  26.  
  27.  
  28. /** This program is used as a filter within the users ``.forward'' file
  29.     and allows intelligent preprocessing of mail at the point between
  30.     when it shows up on the machine and when it is actually put in the
  31.     mailbox.
  32.  
  33.     The program allows selection based on who the message is FROM, TO, or
  34.     what the subject is.  Acceptable actions are for the program to DELETE_MSG
  35.     the message, SAVE the message in a specified folder, FORWARD the message
  36.     to a specified user, SAVE the message in a folder, but add a copy to the
  37.     users mailbox anyway, or simply add the message to the incoming mail.
  38.  
  39.     Filter also keeps a log of what it does as it goes along, and at the
  40.     end of each `quantum' mails a summary of actions, if any, to the user.
  41.  
  42.     Uses the files: $HOME/.filter for instructions to this program, and
  43.     $HOME/.filterlog for a list of what has been done since last summary.
  44.  
  45. **/
  46.  
  47. #include <stdio.h>
  48. #include <pwd.h>
  49. #include <ctype.h>
  50. #include "defs.h"
  51. #ifdef I_TIME
  52. #  include <time.h>
  53. #endif
  54. #ifdef I_SYSTIME
  55. #  include <sys/time.h>
  56. #endif
  57. #include <fcntl.h>
  58.  
  59. #define  MAIN_ROUTINE            /* for the filter.h file, of course! */
  60. #include "filter.h"
  61.  
  62. #undef fflush
  63.  
  64. main(argc, argv)
  65. int argc;
  66. char *argv[];
  67. {
  68.     extern char *optarg;
  69.     FILE   *fd;                /* for output to temp file! */
  70.     struct passwd  *passwd_entry;
  71. #ifndef    _POSIX_SOURCE
  72.     struct passwd  *getpwuid();        /* for /etc/passwd          */
  73. #endif
  74.     char filename[SLEN],            /* name of the temp file    */
  75.          buffer[MAX_LINE_LEN];        /* input buffer space       */
  76.     int  in_header = TRUE,            /* for header parsing       */
  77.          in_to     = FALSE,            /* are we on 'n' line To: ? */
  78.          summary   = FALSE,            /* a summary is requested?  */
  79.          c;                    /* var for getopt routine   */
  80.  
  81.         initpaths();
  82.  
  83.     outfname[0] = to[0] = '\0';    /* nothing read in yet, right? */
  84.  
  85. #ifdef HOSTCOMPILED
  86.     strncpy(hostname, HOSTNAME, sizeof(hostname));
  87. #else
  88.     gethostname(hostname, sizeof(hostname));
  89. #endif
  90.  
  91. #ifdef OS2
  92.     getfromdomain(hostfromname, sizeof(hostfromname));
  93. #else
  94.     strcpy(hostfromname, hostname);
  95. #endif
  96.  
  97.     /* now parse the starting arguments... */
  98.  
  99.     while ((c = getopt(argc, argv, "clno:rSsu:v")) != EOF) {
  100.       switch (c) {
  101.         case 'c' : clear_logs = TRUE;            break;
  102.         case 'l' : log_actions_only = TRUE;            break;
  103.         case 'o' : strcpy(outfname, optarg);        break;
  104.         case 'r' : printing_rules = TRUE;            break;
  105.  
  106.         case 's' : summary = TRUE;                break;
  107.         case 'S' : long_summary = TRUE;            break;
  108.  
  109.         case 'n' : show_only = TRUE;            break;
  110.         case 'u' : strcpy(username, optarg);        break;
  111.         case 'v' : verbose = TRUE;                break;
  112.         case '?' : usage(argv[0]);
  113.       }
  114.     }
  115.  
  116.     /* first off, let's get the info from /etc/passwd */
  117.     passwd_entry = username[0] ? getpwnam(username) : getpwuid(getuid());
  118.     if (passwd_entry == NULL)
  119.       leave("Cannot get password entry for this uid!");
  120.  
  121.     strcpy(home, passwd_entry->pw_dir);
  122.     strcpy(username, passwd_entry->pw_name);
  123.  
  124.     if (isatty(0) && !summary && !long_summary && !printing_rules)
  125.           usage(argv[0]);
  126.  
  127.     /* let's open our outfd logfile as needed... */
  128.  
  129.     if (outfname[0] == '\0')     /* default is stdout */
  130.       outfd = stdout;
  131.     else
  132.       if ((outfd = fopen(outfname, "a")) == NULL) {
  133.         if (isatty(fileno(stderr)))
  134.           fprintf(stderr,"filter (%s): couldn't open log file %s\n",
  135.               username, outfname);
  136.       }
  137.  
  138.     if (summary || long_summary) {
  139.           if (get_filter_rules() == -1) {
  140.         if (outfd != NULL) fclose(outfd);
  141.         exit(1);
  142.       }
  143.       show_summary();
  144.       if (outfd != NULL) fclose(outfd);
  145.       exit(0);
  146.     }
  147.  
  148.     if (printing_rules) {
  149.           if (get_filter_rules() == -1)
  150.         fprintf(outfd,"filter (%s): Couldn't get rules!\n", username);
  151.           else
  152.         print_rules();
  153.       if (outfd != NULL) fclose(outfd);
  154.           exit(0);
  155.     }
  156.  
  157.     /* next, create the tempfile and save the incoming message */
  158.  
  159.     sprintf(filename, "%s%d.fil", tempdir, getpid());
  160.  
  161.     if ((fd = fopen(filename,"w")) == NULL)
  162.       leave("Cannot open temporary file!");
  163.  
  164.     while (fgets(buffer, MAX_LINE_LEN, stdin) != NULL) {
  165.  
  166.       remove_return(buffer);
  167.  
  168.       if (in_header) {
  169.  
  170.         if (! whitespace(buffer[0]))
  171.         in_to = FALSE;
  172.  
  173.         if (the_same(buffer, "From "))
  174.           save_from(buffer);
  175.         else if (the_same(buffer, "Subject:"))
  176.           save_subject(buffer);
  177.         else if (the_same(buffer, "To:") || the_same(buffer, "Cc:")) {
  178.           in_to++;
  179.           save_to(buffer);
  180.         }
  181.         else if (the_same(buffer, "X-Filtered-By:"))
  182.           already_been_forwarded++;    /* could be a loop here! */
  183. #ifdef USE_EMBEDDED_ADDRESSES
  184.         else if (the_same(buffer, "From:"))
  185.           save_embedded_address(buffer, "From:");
  186.         else if (the_same(buffer, "Reply-To:"))
  187.           save_embedded_address(buffer, "Reply-To:");
  188. #endif
  189.         else if (strlen(buffer) < 2)
  190.           in_header = 0;
  191.         else if (whitespace(buffer[0]) && in_to)
  192.           strcat(to, buffer);
  193.       }
  194.  
  195.           fprintf(fd, "%s\n", buffer);    /* and save it regardless! */
  196.       fflush(fd);
  197.       lines++;
  198.     }
  199.  
  200.     fclose(fd);
  201.  
  202.     /** next let's see if the user HAS a filter file, and if so what's in
  203.             it (and so on) **/
  204.  
  205.     if (get_filter_rules() == -1)
  206.       mail_message(username);
  207.     else {
  208.       switch (action_from_ruleset()) {
  209.  
  210.         case DELETE_MSG : if (verbose && outfd != NULL)
  211.                 fprintf(outfd, "filter (%s): Message deleted\n",
  212.                     username);
  213.               log(DELETE_MSG);                break;
  214.  
  215.         case SAVE   : if (save_message(rules[rule_choosen].argument2)) {
  216.                 mail_message(username);
  217.                 log(FAILED_SAVE);
  218.               }
  219.               else
  220.                  log(SAVE);                    break;
  221.  
  222.         case SAVECC : if (save_message(rules[rule_choosen].argument2))
  223.                 log(FAILED_SAVE);
  224.               else
  225.                     log(SAVECC);
  226.               mail_message(username);            break;
  227.  
  228.         case FORWARD: mail_message(rules[rule_choosen].argument2);
  229.               log(FORWARD);                    break;
  230.  
  231.         case EXEC   : execute(rules[rule_choosen].argument2);
  232.               log(EXEC);                    break;
  233.  
  234.         case LEAVE  : mail_message(username);
  235.               log(LEAVE);                    break;
  236.       }
  237.     }
  238.  
  239.     (void) unlink(filename);    /* remove the temp file, please! */
  240.     if (outfd != NULL) fclose(outfd);
  241.     exit(0);
  242. }
  243.  
  244.  
  245. usage(name)
  246. char *name;
  247. {
  248.   printf("\nUsage: filter [-nrv] [-o output] [-u user]"
  249.          "\n   or: filter [-s|-S] [-c] [-o output] [-u user]\n"
  250.          "\nWhere: -n   not really, only output what would happen"
  251.          "\n       -v   be verbose for each message filtered"
  252.          "\n       -r   list rules currently beeing used"
  253.          "\n       -s   list summary of message filtered log"
  254.          "\n       -S   list more verbose summary that -s"
  255.          "\n       -c   clear log files after summarizing with -s or -S"
  256.          "\n       -o output    redirect log message to 'output'"
  257.      "\n       -u user      work under user ID 'user'\n");
  258.   exit(1);
  259. }
  260.  
  261. save_from(buffer)
  262. char *buffer;
  263. {
  264.     /** save the SECOND word of this string as FROM **/
  265.  
  266.     register char *f = from;
  267.  
  268.     while (*buffer != ' ')
  269.       buffer++;                /* get to word     */
  270.  
  271.     for (buffer++; *buffer != ' ' && *buffer; buffer++, f++)
  272.       *f = *buffer;                /* copy it and     */
  273.  
  274.     *f = '\0';                /* Null terminate! */
  275. }
  276.  
  277. save_subject(buffer)
  278. char *buffer;
  279. {
  280.     /** save all but the word "Subject:" for the subject **/
  281.  
  282.     register int skip = 8;  /* skip "Subject:" initially */
  283.  
  284.     while (buffer[skip] == ' ') skip++;
  285.  
  286.     strcpy(subject, (char *) buffer + skip);
  287. }
  288.  
  289. save_to(buffer)
  290. char *buffer;
  291. {
  292.     /** save all but the word "To:" or "Cc:" for the to list **/
  293.  
  294.     register int skip = 3;    /* skip "To:" or "Cc:" initially */
  295.  
  296.     while (buffer[skip] == ' ') skip++;
  297.  
  298.     strcat(to, (char *) buffer + skip);
  299. }
  300.  
  301. #ifdef USE_EMBEDDED_ADDRESSES
  302.  
  303. save_embedded_address(buffer, fieldname)
  304. char *buffer, *fieldname;
  305. {
  306.     /** this will replace the 'from' address with the one given,
  307.         unless the address is from a 'reply-to' field (which overrides
  308.         the From: field).  The buffer given to this routine can have one
  309.             of three forms:
  310.         fieldname: username <address>
  311.         fieldname: address (username)
  312.         fieldname: address
  313.     **/
  314.  
  315.     static int processed_a_reply_to = 0;
  316.     char address[LONG_STRING];
  317.     register int i, j = 0;
  318.  
  319.     /** first let's extract the address from this line.. **/
  320.  
  321.     if (buffer[strlen(buffer)-1] == '>') {    /* case #1 */
  322.       for (i=strlen(buffer)-1; buffer[i] != '<' && i > 0; i--)
  323.         /* nothing - just move backwards .. */ ;
  324.       i++;    /* skip the leading '<' symbol */
  325.       while (buffer[i] != '>')
  326.         address[j++] = buffer[i++];
  327.       address[j] = '\0';
  328.     }
  329.     else {    /* get past "from:" and copy until white space or paren hit */
  330.       for (i=strlen(fieldname); whitespace(buffer[i]); i++)
  331.          /* skip past that... */ ;
  332.       while (buffer[i] != '(' && ! whitespace(buffer[i]) && buffer[i]!='\0')
  333.         address[j++] = buffer[i++];
  334.       address[j] = '\0';
  335.     }
  336.  
  337.     /** now let's see if we should overwrite the existing from address
  338.         with this one or not.. **/
  339.  
  340.     if (processed_a_reply_to)
  341.       return;    /* forget it! */
  342.  
  343.     strcpy(from, address);            /* replaced!! */
  344.  
  345.     if (strcmp(fieldname, "Reply-To:") == 0)
  346.       processed_a_reply_to++;
  347. }
  348. #endif
  349.