/* $Id: sortsieve.c 1550 2005-01-07 12:23:02Z paul $
Copyright (C) 1999-2004 Aaron Stone aaron at serendipity dot cx
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; either
version 2 of the License, or (at your option) any later
version.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Functions for running user defined sorting rules
* on a message in the temporary store, usually
* just delivering the message to the user's INBOX
* ...unless they have fancy rules defined, that is :-)
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <time.h>
#include <ctype.h>
#include "db.h"
#include "auth.h"
#include "debug.h"
#include "list.h"
#include "dbmail.h"
#include "debug.h"
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "dbmd5.h"
#include "misc.h"
#include "sortsieve.h"
#include "sort.h"
#include <sieve2_interface.h>
extern struct list smtpItems, sysItems;
/* typedef sort_action {
* int method,
* char *destination,
* char *message
* } sort_action_t;
* */
/* Pull up the relevant sieve scripts for this
* user and begin running them against the header
* and possibly the body of the message.
*
* Returns 0 on success, -1 on failure,
* and +1 on success but with memory leaking.
* In the +1 case, if called from a daemon
* such as dbmail-lmtpd, the daemon should
* finish storing the message and restart.
* */
int sortsieve_msgsort(u64_t useridnr, char *header, u64_t headersize,
u64_t messagesize, struct list *actions)
{
sieve2_message_t *m;
sieve2_support_t *p;
sieve2_script_t *s;
sieve2_action_t *a;
sieve2_loader_t scriptloader, msgloader;
char *scriptname = NULL, *script = NULL, *freestr = NULL;
int res = 0, ret = 0;
/* Pass the address of the char *script, and it will come
* back magically allocated. Don't forget to free it later! */
res = db_get_sievescript_active(useridnr, &scriptname);
if (res < 0) {
printf("db_get_sievescript_active() returns %d\n", res);
ret = -1;
goto no_free;
}
printf("Looking up script [%s]\n", scriptname);
res = db_get_sievescript_byname(useridnr, scriptname, &script);
if (res < 0) {
printf("db_get_sievescript_byname() returns %d\n", res);
ret = -1;
goto char_scriptname_free;
}
res = sieve2_action_alloc(&a);
if (res != SIEVE2_OK) {
printf("sieve2_action_alloc() returns %d\n", res);
ret = -1;
goto char_script_free;
}
res = sieve2_support_alloc(&p);
if (res != SIEVE2_OK) {
printf("sieve2_support_alloc() returns %d\n", res);
ret = -1;
goto action_free;
}
res = sieve2_support_register(p, SIEVE2_ACTION_FILEINTO);
res = sieve2_support_register(p, SIEVE2_ACTION_REDIRECT);
res = sieve2_support_register(p, SIEVE2_ACTION_REJECT);
// res = sieve2_support_register(p, SIEVE2_ACTION_NOTIFY);
res = sieve2_script_alloc(&s);
if (res != SIEVE2_OK) {
printf("sieve2_script_alloc() returns %d\n", res);
ret = -1;
goto support_free;
}
res = sieve2_support_bind(p, s);
if (res != SIEVE2_OK) {
printf("sieve2_support_bind() returns %d\n", res);
ret = -1;
goto script_free;
}
res = sieve2_script_parse(s, script);
if (res != SIEVE2_OK) {
printf("sieve2_script_parse() returns %d: %s\n", res,
sieve2_errstr(res, &freestr));
dm_free(freestr);
ret = -1;
goto script_free;
}
res = sieve2_message_alloc(&m);
if (res != SIEVE2_OK) {
printf("sieve2_message_alloc() returns %d\n", res);
ret = -1;
goto script_free;
}
res =
sieve2_message_register(m, &messagesize, SIEVE2_MESSAGE_SIZE);
if (res != SIEVE2_OK) {
printf("sieve2_message_register() returns %d\n", res);
ret = -1;
goto message_free;
}
res = sieve2_message_register(m, header, SIEVE2_MESSAGE_HEADER);
if (res != SIEVE2_OK) {
printf("sieve2_message_register() returns %d\n", res);
ret = -1;
goto message_free;
}
res = sieve2_script_exec(s, m, a);
if (res != SIEVE2_OK) {
printf("sieve2_execute_script() returns %d\n", res);
ret = -1;
goto message_free;
}
res = sortsieve_unroll_action(a, actions);
if (res != SIEVE2_OK && res != SIEVE2_DONE) {
printf("unroll_action() returns %d\n", res);
ret = -1;
goto action_free;
}
message_free:
res = sieve2_message_free(m);
if (res != SIEVE2_OK) {
printf("sieve2_message_free() returns %d\n", res);
ret = 1;
}
script_free:
res = sieve2_script_free(s);
if (res != SIEVE2_OK) {
printf("sieve2_script_free() returns %d\n", res);
ret = 1;
}
support_free:
res = sieve2_support_free(p);
if (res != SIEVE2_OK) {
printf("sieve2_support_free() returns %d\n", res);
ret = 1;
}
action_free:
res = sieve2_action_free(a);
if (res != SIEVE2_OK) {
printf("sieve2_action_free() returns %d\n", res);
ret = 1;
}
/* Good thing we're not forgetting ;-) */
char_script_free:
if (script != NULL)
dm_free(script);
char_scriptname_free:
if (scriptname != NULL)
dm_free(scriptname);
no_free:
return ret;
}
int sortsieve_unroll_action(sieve2_action_t * a, struct list *actions)
{
int res = SIEVE2_OK;
int code;
void *action_context;
/* Working variables to set up
* the struct then nodeadd it */
sort_action_t *tmpsa = NULL;
char *tmpdest = NULL;
char *tmpmsg = NULL;
int tmpmeth = 0;
while (res == SIEVE2_OK) {
if ((tmpsa = malloc(sizeof(sort_action_t))) == NULL)
break;
res = sieve2_action_next(&a, &code, &action_context);
if (res == SIEVE2_DONE) {
printf("We've reached the end.\n");
break;
} else if (res != SIEVE2_OK) {
printf("Error in action list.\n");
break;
}
printf("Action code is: %d\n", code);
switch (code) {
case SIEVE2_ACTION_REDIRECT:
{
sieve2_redirect_context_t *context =
(sieve2_redirect_context_t *)
action_context;
printf("Action is REDIRECT: ");
printf("Destination is %s\n",
context->addr);
tmpmeth = SA_REDIRECT;
tmpdest = dm_strdup(context->addr);
break;
}
case SIEVE2_ACTION_REJECT:
{
sieve2_reject_context_t *context =
(sieve2_reject_context_t *)
action_context;
printf("Action is REJECT: ");
printf("Message is %s\n", context->msg);
tmpmeth = SA_REJECT;
tmpmsg = dm_strdup(context->msg);
break;
}
case SIEVE2_ACTION_DISCARD:
printf("Action is DISCARD\n");
tmpmeth = SA_DISCARD;
break;
case SIEVE2_ACTION_FILEINTO:
{
sieve2_fileinto_context_t *context =
(sieve2_fileinto_context_t *)
action_context;
printf("Action is FILEINTO: ");
printf("Destination is %s\n",
context->mailbox);
tmpmeth = SA_FILEINTO;
tmpdest = dm_strdup(context->mailbox);
break;
}
case SIEVE2_ACTION_NOTIFY:
{
sieve2_notify_context_t *context =
(sieve2_notify_context_t *)
action_context;
printf("Action is NOTIFY: \n");
// FIXME: Prefer to have a function for this?
while (context != NULL) {
printf(" ID \"%s\" is %s\n",
context->id,
(context->
isactive ? "ACTIVE" :
"INACTIVE"));
printf(" Method is %s\n",
context->method);
printf(" Priority is %s\n",
context->priority);
printf(" Message is %s\n",
context->message);
if (context->options != NULL) {
size_t opt = 0;
while (context->
options[opt] !=
NULL) {
printf
(" Options are %s\n",
context->
options[opt]);
opt++;
}
}
context = context->next;
}
break;
}
case SIEVE2_ACTION_KEEP:
printf("Action is KEEP\n");
break;
default:
printf("Unrecognized action code: %d\n", code);
break;
} /* case */
tmpsa->method = tmpmeth;
tmpsa->destination = tmpdest;
tmpsa->message = tmpmsg;
list_nodeadd(actions, tmpsa, sizeof(sort_action_t));
dm_free(tmpsa);
tmpsa = NULL;
} /* while */
if (tmpsa != NULL)
dm_free(tmpsa);
return res;
}
/* Return 0 on script OK, 1 on script error. */
int sortsieve_script_validate(char *script, char **errmsg)
{
if (sieve2_validate(t, s, p, e) == SIEVE2_OK) {
*errmsg = NULL;
return 0;
} else {
*errmsg = "Script error...";
return 1;
}
}
syntax highlighted by Code2HTML, v. 0.9.1