/* elmo - ELectronic Mail Operator Copyright (C) 2003 rzyjontko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ---------------------------------------------------------------------- */ /**************************************************************************** * IMPLEMENTATION HEADERS ****************************************************************************/ #include #include #include #include "procmail.h" #include "debug.h" #include "xmalloc.h" #include "rarray.h" #include "error.h" #include "mail.h" #include "mybox.h" #include "file.h" #include "misc.h" /**************************************************************************** * IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS ****************************************************************************/ enum field { FIELD_INVALID, FIELD_TO, FIELD_FROM, FIELD_SUBJECT, FIELD_CC, FIELD_TOCC, }; /**************************************************************************** * IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES ****************************************************************************/ struct constraint { enum field field; regex_t re; }; struct rule { struct rule *next; char *name; rarray_t *constraints; char *action; int stop; }; /**************************************************************************** * IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID) ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE DATA ****************************************************************************/ /* These two variables define a list of rules. Last is used to append to the end of the list instead of prepending. */ struct rule *rules = NULL; struct rule *last = NULL; /* This variable holds a new rule, while it is parsed in config file. */ struct rule *prepared = NULL; struct constraint *constraint = NULL; /**************************************************************************** * INTERFACE DATA ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES ****************************************************************************/ /**************************************************************************** * IMPLEMENTATION PRIVATE FUNCTIONS ****************************************************************************/ static void destroy_constraint (struct constraint *c) { regfree (& c->re); xfree (c); } static void destroy_constraints (rarray_t *c) { int i; for (i = 0; i < c->count; i++){ destroy_constraint ((struct constraint *) c->array[i]); } rarray_destroy (c); } static void destroy_rule (struct rule *rule) { if (rule == NULL) return; destroy_rule (rule->next); if (rule->name) xfree (rule->name); if (rule->constraints) destroy_constraints (rule->constraints); if (rule->action) xfree (rule->action); xfree (rule); } static void store (void) { if (rules == NULL){ rules = prepared; last = prepared; } else { last->next = prepared; last = prepared; } prepared = NULL; } static int str_match (struct constraint *c, char *str) { int ret; if (str == NULL) return 0; ret = regexec (& c->re, str, 0, NULL, 0); if (ret && ret != REG_NOMATCH){ error_regex (ret, & c->re, NULL); } return ! ret; } static int addr_match (struct constraint *c, address_t *addr) { if (addr == NULL || addr->full == NULL) return 0; return str_match (c, addr->full); } static int raddr_match (struct constraint *c, raddress_t *ptr) { int i; if (ptr == NULL) return 0; for (i = 0; i < ptr->count; i++){ if (addr_match (c, ptr->array[i])) return 1; } return 0; } static int condition_met (struct constraint *c, mail_t *mail) { switch (c->field){ case FIELD_INVALID: return 0; case FIELD_TO: return raddr_match (c, mail->to); case FIELD_FROM: return addr_match (c, mail->from); case FIELD_SUBJECT: return str_match (c, mail->subject); case FIELD_CC: return raddr_match (c, mail->cc); case FIELD_TOCC: return raddr_match (c, mail->to) || raddr_match (c, mail->cc); } return 0; } static char * find_rule (struct rule *rule, mail_t *mail) { int i; struct constraint *c; if (rule == NULL) return NULL; for (i = 0; i < rule->constraints->count; i++){ c = (struct constraint *) rule->constraints->array[i]; if (! condition_met (c, mail)) break; } if (i == rule->constraints->count) return rule->action; return find_rule (rule->next, mail); } /**************************************************************************** * INTERFACE FUNCTIONS ****************************************************************************/ void procmail_free_resources (void) { destroy_rule (rules); destroy_rule (prepared); if (constraint) destroy_constraint (constraint); rules = NULL; last = NULL; prepared = NULL; constraint = NULL; } void procmail_setup_name (char *name) { if (prepared != NULL) destroy_rule (prepared); prepared = xmalloc (sizeof (struct rule)); prepared->next = NULL; prepared->name = xstrdup (name); prepared->constraints = rarray_create_size (3); prepared->action = NULL; prepared->stop = 0; } void procmail_setup_header (char *header) { if (prepared == NULL) return; if (constraint != NULL) destroy_constraint (constraint); constraint = xmalloc (sizeof (struct constraint)); if (strcmp (header, "SUBJECT") == 0) constraint->field = FIELD_SUBJECT; else if (strcmp (header, "TO") == 0) constraint->field = FIELD_TO; else if (strcmp (header, "FROM") == 0) constraint->field = FIELD_FROM; else if (strcmp (header, "CC") == 0) constraint->field = FIELD_CC; else if (strcmp (header, "TOCC") == 0) constraint->field = FIELD_TOCC; else constraint->field = FIELD_INVALID; } void procmail_setup_re (char *re) { int ret; if (prepared == NULL || constraint == NULL) return; ret = regcomp (& constraint->re, re, REG_NOSUB | REG_NEWLINE); if (ret){ error_regex (ret, & constraint->re, re); destroy_constraint (constraint); destroy_rule (prepared); constraint = NULL; prepared = NULL; return; } rarray_add (prepared->constraints, constraint); constraint = NULL; } void procmail_setup_str (char *str) { char *re = misc_re_from_str (str); procmail_setup_re (re); xfree (re); } void procmail_setup_action (char *action, int stop) { if (prepared == NULL) return; prepared->action = xstrdup (action); prepared->stop = stop; store (); } char * procmail_box (mail_t *mail) { char *box = find_rule (rules, mail); if (box) return file_with_dir (mybox_dir, box); return mybox_inbox (); } /**************************************************************************** * INTERFACE CLASS BODIES ****************************************************************************/ /**************************************************************************** * * END MODULE procmail.c * ****************************************************************************/