home *** CD-ROM | disk | FTP | other *** search
/ ftp.shrubbery.net / 2015-02-07.ftp.shrubbery.net.tar / ftp.shrubbery.net / pub / foad / foad-0.3.tar.gz / foad-0.3.tar / foad-0.3 / foad.c < prev    next >
C/C++ Source or Header  |  2003-09-22  |  10KB  |  457 lines

  1. #include "foad.h"
  2.  
  3. char    version[] = "0.2";
  4. #define FOADRC    ".foadrc"
  5. int    debug = 0,
  6.     egrepbcc = 0,
  7.     egrepfrom = 0,
  8.     negate = 0,
  9.     testconf = 0;
  10. char    *foadrc,
  11.     *progname,
  12.     *c_bcc = NULL,
  13.     *c_from = NULL,
  14.     *c_cc = NULL,
  15.     *c_to = NULL;
  16.  
  17. struct     s_addresses    addresses,
  18.             bcc,
  19.             from,
  20.             cc,
  21.             to;
  22.  
  23. #if STDC_HEADERS
  24. int    main(int, char **);
  25. int    read_conf(char *);
  26. void    usage(void);
  27. #endif
  28.  
  29. int
  30. main(int argc, char **argv)
  31. {
  32.     register int    op;
  33.     char        *home;
  34.     extern char        *optarg;
  35.     extern int        optind, opterr;
  36.     node        *next;
  37.  
  38.     if ((progname = strrchr(argv[0], '/')) != NULL)
  39.     progname++;
  40.     else
  41.     progname = argv[0];
  42.  
  43.     while ((op = getopt(argc, argv, "bdfhntvc:")) != -1)
  44.     switch (op) {
  45.  
  46.         case 'b':
  47.         ++egrepbcc;
  48.         break;
  49.         case 'c':            /* alt .foadrc */
  50.         foadrc = optarg;
  51.         break;
  52.         case 'd':
  53.         ++debug;
  54.         break;
  55.         case 'f':
  56.         ++egrepfrom;
  57.         break;
  58.         case 'n':
  59.         negate = 1;
  60.         break;
  61.         case 'v':
  62.         fprintf(stderr, "%s version %s\n", progname, version);
  63.         exit(0);
  64.         case 't':
  65.         ++testconf;
  66.         break;
  67.         default:
  68.         usage();
  69.     }
  70.  
  71.     if (foadrc == NULL) {
  72.     if ((home = getenv("HOME")) == NULL) {
  73.         fprintf(stderr, "%s: could not find $HOME in environment\n",
  74.         progname);
  75.         return(1 ^ negate);
  76.     }
  77.     if ((foadrc = (char *) malloc(strlen(home)+strlen(FOADRC)+2)) == NULL) {
  78.         fprintf(stderr, "%s: malloc failed: %s\n", progname,
  79.         strerror(errno));
  80.         return(1 ^ negate);
  81.     }
  82.     strcpy(foadrc, home); strcat(foadrc, "/"); strcat(foadrc, FOADRC);
  83.     }
  84.  
  85.     if (debug)
  86.     fprintf(stderr, "\n%s: reading config file: %s\n", progname, foadrc);
  87.  
  88.     if (read_conf(foadrc)) {
  89.     if (debug)
  90.         fprintf(stderr, "%s: config error: exit code %d\n\n",
  91.         progname, 1 ^ negate);
  92.     return(1 ^ negate);
  93.     }
  94.  
  95.     if (testconf) {            /* just read the .foadrc and exit */
  96.     if (debug) {
  97.         node    *next = addresses.next;
  98.  
  99.         fprintf(stderr, "%s: read the following regex's:\n", progname);
  100.         while (next) {
  101.         fprintf(stderr, "%s: \t%s\n", progname, next->addr);
  102.         next = next->next;
  103.         }
  104.         fprintf(stderr, "%s: exit code %d\n\n", progname, 0 ^ negate);
  105.     }
  106.     return(0 ^ negate);
  107.     }
  108.  
  109.     if (read_header()) {
  110.     if (debug)
  111.         fprintf(stderr, "%s: header error: exit code %d\n\n",
  112.         progname, 1 ^ negate);
  113.     return(1 ^ negate);
  114.     }
  115.  
  116.     if (debug) {
  117.     if (from.next) {
  118.         next = from.next;
  119.         fprintf(stderr, "%s: FROM: ", progname);
  120.         while (next) {
  121.         fprintf(stderr, "%s", next->addr);
  122.         next = next->next;
  123.         if (next)
  124.             fprintf(stderr, ",");
  125.         }
  126.         fprintf(stderr, "\n");
  127.     } else
  128.         fprintf(stderr, "%s: FROM: (null)\n", progname);
  129.     if (to.next) {
  130.         next = to.next;
  131.         fprintf(stderr, "%s: TO: ", progname);
  132.         while (next) {
  133.         fprintf(stderr, "%s", next->addr);
  134.         next = next->next;
  135.         if (next)
  136.             fprintf(stderr, ",");
  137.         }
  138.         fprintf(stderr, "\n");
  139.     } else
  140.         fprintf(stderr, "%s: TO: (null)\n", progname);
  141.     if (cc.next) {
  142.         next = cc.next;
  143.         fprintf(stderr, "%s: CC: ", progname);
  144.         while (next) {
  145.         fprintf(stderr, "%s", next->addr);
  146.         next = next->next;
  147.         if (next)
  148.             fprintf(stderr, ",");
  149.         }
  150.         fprintf(stderr, "\n");
  151.     } else
  152.         fprintf(stderr, "%s: CC: (null)\n", progname);
  153.     if (bcc.next) {
  154.         next = bcc.next;
  155.         fprintf(stderr, "%s: BCC: ", progname);
  156.         while (next) {
  157.         fprintf(stderr, "%s", next->addr);
  158.         next = next->next;
  159.         if (next)
  160.             fprintf(stderr, ",");
  161.         }
  162.         fprintf(stderr, "\n");
  163.     } else
  164.         fprintf(stderr, "%s: BCC: (null)\n", progname);
  165.     }
  166.  
  167.     if (match()) {
  168.     if (debug)
  169.         fprintf(stderr, "%s: exit code %d\n\n", progname, 1 ^ negate);
  170.     return(1 ^ negate);
  171.     }
  172.  
  173.     if (debug)
  174.     fprintf(stderr, "%s: exit code %d\n\n", progname, 0 ^ negate);
  175.     return(0 ^ negate);
  176. }
  177.  
  178. /*
  179.       function: int read_conf(* foadrc)
  180.    description: read config file, ie: list of addresses
  181.        returns: non-zero on error
  182.  */     
  183. int
  184. read_conf(char *foadrc)
  185. {
  186.     FILE    *fp;
  187.     char    buf[LINE_MAX];
  188.     int        line = 0,
  189.         error = 0;
  190.  
  191.     if ((fp = fopen(foadrc, "r")) == NULL) {
  192.     fprintf(stderr, "%s: could not open rc file %s: %s\n",
  193.         progname, foadrc, strerror(errno));
  194.     return(1);
  195.     }
  196.  
  197.     do {
  198.     if (fgets(buf, LINE_MAX, fp) == NULL) {
  199.         if (feof(fp))
  200.         break;
  201.         fprintf(stderr, "%s: error reading %s line %d: %s\n", progname,
  202.         foadrc, line, strerror(errno));
  203.         error++; break;
  204.     }
  205.     line++;
  206.     if (strlen(buf) == LINE_MAX -1 && buf[LINE_MAX-1] != '\n') {
  207.         fprintf(stderr, "%s: %s: line %d exeeds max length of %d\n",
  208.         progname, foadrc, line, LINE_MAX);
  209.         error++; break;
  210.     }
  211.     if (*buf == '#')
  212.         continue;
  213.     error += dequote(buf);
  214.     if (add_addr(buf, line)) { error++; break; }
  215.     } while (1);
  216.  
  217.     fclose(fp);
  218.     return(error);
  219. }
  220.  
  221. /*
  222.       function: int add_addr(address)
  223.    description: add address to linked list
  224.        returns: non-zero on error
  225.  */     
  226. int
  227. add_addr(char *addr, int line)
  228. {
  229.     node    *next = addresses.next,
  230.         *new;
  231.     char    errbuf[LINE_MAX] = "";
  232.     int        errcode;
  233.  
  234.     if (addr == NULL)
  235.     return(1);
  236.  
  237.     if ((new = (node *) malloc(sizeof(node))) == NULL) {
  238.     fprintf(stderr, "%s: malloc failed: %s\n", progname, strerror(errno));
  239.     return(1);
  240.     }
  241.     bzero(new, sizeof(node));
  242.  
  243.     new->line = line;
  244.     if ((new->addr = strdup(addr)) == NULL) {
  245.     fprintf(stderr, "%s: malloc failed: %s\n", progname, strerror(errno));
  246.     return(1);
  247.     }
  248.     if ((errcode = regcomp(&new->preg, new->addr,
  249.                 REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
  250.     regerror(errcode, &new->preg, errbuf, LINE_MAX);
  251.     fprintf(stderr, "%s: regex compile failed for %s line %d: %s\n",
  252.         progname, foadrc, line, errbuf);
  253.     free(new->addr);
  254.     free(new);
  255.     return(1);
  256.     }
  257.  
  258.     if (addresses.next == NULL)
  259.     addresses.next = new;
  260.     else
  261.     while (next) {
  262.         if (next->next == NULL) {
  263.         next->next = new; break;
  264.         }
  265.         next = next->next;
  266.     }
  267.  
  268.     return(0);
  269. }
  270.  
  271. /*
  272.       function: int dequote(string)
  273.    description: remove leading/trailing spaces from a string
  274.        returns: non-zero on error
  275.  */     
  276. int
  277. dequote(register char *s)
  278. {
  279.     static regex_t    *preg1, *preg2;
  280.     regmatch_t        pmatch[2];
  281.     size_t        nmatch = 2;
  282.     char        buf[256];
  283.     int            err;
  284.  
  285.     if (s == NULL)
  286.     return(0);
  287.  
  288.     if (!preg1) {            /* remove trailing spaces */
  289.     if ((preg1 = malloc(sizeof(regex_t))) == NULL) {
  290.         fprintf(stderr, "%s: malloc failed: %s\n", progname,
  291.         strerror(errno));
  292.         return(1);
  293.     }
  294.     if ((err = regcomp(preg1, "([ \t]*)\n?$", REG_EXTENDED))) {
  295.         regerror(err, preg1, buf, 256);
  296.         fprintf(stderr, "%s: regex compile failed: %s\n", progname, buf);
  297.         return(1);
  298.     }
  299.     }
  300.  
  301.     if ((err = regexec(preg1, s, nmatch, pmatch, 0))) {
  302.     if (err != REG_NOMATCH) {
  303.         regerror(err, preg1, buf, 256);
  304.         fprintf(stderr, "%s: regexec failed: %s\n", progname, buf);
  305.     }
  306.     return(1);
  307.     } else
  308.     *(s+ pmatch[1].rm_so) = '\0';
  309.  
  310.     if (!preg2) {            /* remove leading spaces */
  311.     if ((preg2 = malloc(sizeof(regex_t))) == NULL) {
  312.         fprintf(stderr, "%s: malloc failed: %s\n", progname,
  313.         strerror(errno));
  314.         return(1);
  315.     }
  316.     if ((err = regcomp(preg2, "^([ \t]*)", REG_EXTENDED))) {
  317.         regerror(err, preg2, buf, 256);
  318.         fprintf(stderr, "%s: regex compile failed: %s\n", progname, buf);
  319.         return(1);
  320.     }
  321.     }
  322.  
  323.     if ((err = regexec(preg2, s, nmatch, pmatch, 0))) {
  324.     if (err != REG_NOMATCH) {
  325.         regerror(err, preg2, buf, 256);
  326.         fprintf(stderr, "%s: regexec failed: %s\n", progname, buf);
  327.     }
  328.     return(1);
  329.     } else
  330.     strcpy(s, s + pmatch[1].rm_eo);
  331.  
  332.     return(0);
  333. }
  334.  
  335. /*
  336.       function: int match()
  337.    description: match address against the to and cc (etc) until one matches or
  338.         we hit the end of the list.
  339.        returns: non-zero if there is a match, zero if no match
  340.  */     
  341. int
  342. match(void)
  343. {
  344.     node    *addr,
  345.         *h_addr;
  346.  
  347.     /* if -f option and a from: header was found, match .foadrc entries */
  348.     if (egrepfrom && from.next) {
  349.     addr = addresses.next;
  350.     while (addr) {
  351.         if (debug)
  352.         fprintf(stderr, "%s: %s : ", progname, addr->addr);
  353.         if (listmatch(&addr->preg, &from)) {
  354.         if (debug)
  355.             fprintf(stderr, "%s: match from: %s\n", progname,
  356.             addr->addr);
  357.         return(1);
  358.         }
  359.         addr = addr->next;
  360.     }
  361.     }
  362.  
  363.     /* match .foadrc entries against to: header, if one existed */
  364.     if (to.next) {
  365.     addr = addresses.next;
  366.     while (addr) {
  367.         if (debug)
  368.         fprintf(stderr, "%s: %s : ", progname, addr->addr);
  369.         if (listmatch(&addr->preg, &to)) {
  370.         if (debug)
  371.             fprintf(stderr, "%s: match to: %s\n", progname, addr->addr);
  372.         return(1);
  373.         }
  374.         addr = addr->next;
  375.     }
  376.     }
  377.  
  378.     /* match .foadrc entries against cc: header, if one existed */
  379.     if (cc.next) {
  380.     addr = addresses.next;
  381.     while (addr) {
  382.         if (debug)
  383.         fprintf(stderr, "%s: %s : ", progname, addr->addr);
  384.         if (listmatch(&addr->preg, &cc)) {
  385.         if (debug)
  386.             fprintf(stderr, "%s: match cc: %s\n", progname, addr->addr);
  387.         return(1);
  388.         }
  389.         addr = addr->next;
  390.     }
  391.     }
  392.  
  393.     /* if -b option and a bcc: header was found, match .foadrc entries */
  394.     if (egrepbcc && bcc.next) {
  395.     addr = addresses.next;
  396.     while (addr) {
  397.         if (debug)
  398.         fprintf(stderr, "%s: %s : ", progname, addr->addr);
  399.         if (listmatch(&addr->preg, &bcc)) {
  400.         if (debug)
  401.             fprintf(stderr, "%s: match bcc: %s\n", progname,
  402.             addr->addr);
  403.         return(1);
  404.         }
  405.         addr = addr->next;
  406.     }
  407.     }
  408.  
  409.     if (debug)
  410.     fprintf(stderr, "%s: no match\n", progname);
  411.  
  412.     return(0);
  413. }
  414.  
  415. /*
  416.       function: int listmatch()
  417.    description: match .foadrc address against the elements of a linked list
  418.         from split mail headers (from/to/cc/bcc)
  419.        returns: non-zero if there is a match, zero if no match
  420.  */     
  421. int
  422. listmatch(regex_t *preg, s_addresses *list)
  423. {
  424.     node    *next = list->next;
  425.  
  426.     while (next) {
  427.     /* use preg, compiled when .foadrc was read, for match */
  428.     if (!regexec(preg, next->addr, 0, NULL, 0)) {
  429.         if (debug)
  430.         fprintf(stderr, "%s\n", next->addr);
  431.         return(1);
  432.     }
  433.     next = next->next;
  434.     }
  435.  
  436.     if (debug)
  437.     fprintf(stderr, "no match\n");
  438.  
  439.     return(0);
  440. }
  441.  
  442.  
  443. void
  444. usage(void)
  445. {
  446.     fprintf(stderr, "usage: %s [-bhntv] [-c .foadrc]\n"
  447.         "\t-b  egrep Bcc: and Resent-Bcc: headers\n"
  448.         "\t-c  alternate .foadrc location (dflt: $HOME/%s)\n"
  449.         "\t-f  egrep From: header\n"
  450.         "\t-h  print this help msg\n"
  451.         "\t-n  negate (complement of) exit code\n"
  452.         "\t-t  read the $HOME/%s and exit non-zero on error\n"
  453.         "\t-v  version info\n",
  454.     progname, FOADRC, FOADRC);
  455.     exit(1);
  456. }
  457.