/*
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 <string.h>
#include <sys/types.h>
#include <regex.h>
#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
*
****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1