/* This file is part of Mailfromd. -*- c -*-
Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
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 3, 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, see . */
#include
#define MF_SIEVE_LOG 0x01
#define MF_SIEVE_DEBUG_TRACE 0x02
#define MF_SIEVE_DEBUG_INSTR 0x04
#define MF_SIEVE_DEBUG_MAILUTILS 0x08
#define MF_SIEVE_DEBUG_PROT 0x10
static int
_mu_debug_printer(void *unused, mu_log_level_t level, const char *msg)
{
logmsg((level == MU_DEBUG_ERROR) ? LOG_ERR : LOG_DEBUG, "%s", msg);
return 0;
}
static int
_sieve_debug_printer (void *unused, const char *fmt, va_list ap)
{
vlogmsg(LOG_DEBUG, fmt, ap);
return 0;
}
static void
_sieve_action_log (void *unused,
const mu_sieve_locus_t *locus, size_t msgno,
mu_message_t msg,
const char *action, const char *fmt, va_list ap)
{
logmsg(LOG_INFO, "%s:%lu: %s",
locus->source_file, (unsigned long) locus->source_line,
action);
}
static int
_sieve_parse_error (void *unused, const char *filename, int lineno,
const char *fmt, va_list ap)
{
if (filename) {
char *newfmt = NULL;
asprintf(&newfmt, "%s:%lu: %s",
filename, (unsigned long)lineno, fmt);
vlogmsg(LOG_ERR, newfmt, ap);
free(newfmt);
} else
vlogmsg(LOG_ERR, fmt, ap);
return 0;
}
/* FIXME (mailutils): Cannot use mu_stream_to_message because it ignores
envelope line */
int
mf_stream_to_message(mu_stream_t stream, mu_message_t *msg)
{
int rc;
mu_mailbox_t mbox;
size_t n;
mu_stream_flush (stream);
rc = mu_mailbox_create (&mbox, "/dev/null");
if (rc)
return rc;
rc = mu_mailbox_open (mbox, MU_STREAM_RDWR);
if (rc)
return rc;
mu_stream_seek(stream, 0, SEEK_SET);
rc = mu_mailbox_set_stream (mbox, stream);
if (rc)
return rc;
rc = mu_mailbox_messages_count (mbox, &n);
if (rc)
return rc;
return mu_mailbox_get_message (mbox, 1, msg);
}
MF_STATE(eom)
MF_CAPTURE
MF_DEFUN(sieve, NUMBER, STRING script, OPTIONAL, NUMBER dbg)
{
mu_sieve_machine_t mach;
mu_debug_t mudebug = NULL;
mu_log_level_t debug_flags = 0; /* FIXME: Init */
int sieve_debug_flags = 0;
int sieve_log = 0;
int rc = mu_sieve_machine_init(&mach, NULL);
int retval = 0;
int f = MF_OPTVAL(dbg);
MF_ASSERT(rc == 0, mfe_failure,
_("Failed to initialize sieve machine: %s"),
mu_strerror(rc));
mu_sieve_set_debug(mach, _sieve_debug_printer);
if (f) {
if (f & MF_SIEVE_DEBUG_TRACE)
sieve_debug_flags |= MU_SIEVE_DEBUG_TRACE;
if (f & MF_SIEVE_DEBUG_INSTR)
sieve_debug_flags |= MU_SIEVE_DEBUG_INSTR;
if (f & MF_SIEVE_DEBUG_MAILUTILS)
debug_flags |= MU_DEBUG_TRACE;
if (f & MF_SIEVE_DEBUG_PROT)
debug_flags |= MU_DEBUG_PROT;
if (f & MF_SIEVE_LOG)
sieve_log = 1;
}
if (debug_flags) {
rc = mu_debug_create(&mudebug, NULL);
MF_ASSERT(rc == 0, mfe_failure,
_("Cannot create debug object: %s"),
mu_strerror(rc));
mu_debug_set_level(mudebug, debug_flags);
mu_debug_set_print(mudebug, _mu_debug_printer, NULL);
}
mu_sieve_set_debug_level(mach, sieve_debug_flags);
mu_sieve_set_debug_object(mach, mudebug);
mu_sieve_set_parse_error(mach, _sieve_parse_error);
if (sieve_log)
mu_sieve_set_logger(mach, _sieve_action_log);
rc = mu_sieve_compile(mach, script);
if (rc == 0) {
mu_stream_t mstr = env_get_stream(env);
mu_attribute_t attr;
mu_message_t msg;
rc = mf_stream_to_message(mstr, &msg);
if (rc) {
mu_sieve_machine_destroy(&mach);
MF_THROW(mfe_failure,
_("Cannot translate stream to message: %s"),
mu_strerror (rc));
}
mu_message_get_attribute(msg, &attr);
mu_attribute_unset_deleted(attr);
rc = mu_sieve_message(mach, msg);
if (rc == 0)
retval = !(mu_attribute_is_deleted(attr) == 0);
/* FIXME: Cannot destroy msg because this will cause
destroying its stream (mstr).
Need a workaround. */
/*mu_message_destroy(&msg, mu_message_get_owner(msg));*/
if (rc) {
mu_sieve_machine_destroy(&mach);
MF_THROW(mfe_failure,
_("Sieving failed: %s"),
mu_strerror(rc));
}
} else {
MF_THROW(mfe_failure,
_("Compilation of Sieve script %s failed"),
script);
}
mu_sieve_machine_destroy(&mach);
MF_RETURN(retval);
}
END
MF_INIT