summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2002-11-19 13:58:05 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2002-11-19 13:58:05 +0000
commite2e5a90391f4c96f17e4fd436b047356b081f02b (patch)
tree1e46d807871a16f1ec8075376896f25e2ae3fdd0
parent3474b31fbd90f896400fe3937862cf10952855ca (diff)
downloadmailutils-e2e5a90391f4c96f17e4fd436b047356b081f02b.tar.gz
mailutils-e2e5a90391f4c96f17e4fd436b047356b081f02b.tar.bz2
Support for user-defined sieve filters. Improved debugging.
-rw-r--r--mail.local/main.c279
1 files changed, 247 insertions, 32 deletions
diff --git a/mail.local/main.c b/mail.local/main.c
index fd2abb054..79bef09e6 100644
--- a/mail.local/main.c
+++ b/mail.local/main.c
@@ -17,7 +17,6 @@
#include <mail.local.h>
-int debug_level;
int multiple_delivery;
int ex_quota_tempfail;
int exit_code = EX_OK;
@@ -25,6 +24,13 @@ uid_t uid;
char *quotadbname = NULL;
int lock_timeout = 300;
+/* Debuggig options */
+int debug_level;
+int debug_flags;
+int sieve_debug_flags;
+int sieve_enable_log;
+mu_debug_t mudebug;
+
#define MAXFD 64
#define EX_QUOTA() (ex_quota_tempfail ? EX_TEMPFAIL : EX_UNAVAILABLE)
@@ -36,7 +42,17 @@ void mailer_err (char *fmt, ...);
void notify_biff (mailbox_t mbox, char *name, size_t size);
const char *argp_program_version = "mail.local (" PACKAGE_STRING ")";
-static char doc[] = "GNU mail.local -- the local MDA";
+static char doc[] =
+"GNU mail.local -- the local MDA"
+"\v"
+"Debug flags are:\n"
+" g - guimb stack traces\n"
+" T - mailutil traces (MU_DEBUG_TRACE)\n"
+" P - network protocols (MU_DEBUG_PROT)\n"
+" t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n"
+" l - sieve action logs\n"
+" 0-9 - Set mail.local debugging level\n";
+
static char args_doc[] = "recipient [recipient ...]";
#define ARG_MULTIPLE_DELIVERY 1
@@ -55,17 +71,13 @@ static struct argp_option options[] =
{ "quota-db", 'q', "FILE", 0,
"Specify path to quota database", 0 },
#endif
+ { "sieve", 'S', "PATTERN", 0,
+ "Set name pattern for user-defined sieve mail filters", 0 },
#ifdef WITH_GUILE
{ "source", 's', "PATTERN", 0,
"Set name pattern for user-defined mail filters", 0 },
#endif
- { "debug", 'x',
-#ifdef WITH_GUILE
- "{NUMBER|guile}",
-#else
- "NUMBER",
-#endif
- 0,
+ { "debug", 'x', "FLAGS", 0,
"Enable debugging", 0 },
{ "timeout", 't', "NUMBER", 0,
"Set timeout for acquiring the lockfile" },
@@ -94,6 +106,10 @@ static const char *argp_capa[] = {
char *from = NULL;
char *progfile_pattern = NULL;
+char *sieve_pattern = NULL;
+message_t sieve_msg = NULL;
+
+#define D_DEFAULT "9s"
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
@@ -117,7 +133,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
}
from = arg;
break;
-
+
#ifdef USE_DBM
case 'q':
quotadbname = arg;
@@ -125,34 +141,59 @@ parse_opt (int key, char *arg, struct argp_state *state)
#endif
#ifdef WITH_GUILE
- case 's':
- progfile_pattern = optarg;
- break;
+ case 's':
+ progfile_pattern = optarg;
+ break;
#endif
+
+ case 'S':
+ sieve_pattern = optarg;
+ break;
+
+ case 't':
+ lock_timeout = strtoul (optarg, NULL, 0);
+ break;
- case 't':
- lock_timeout = strtoul (optarg, NULL, 0);
- break;
-
- case 'x':
- if (optarg)
- {
+ case 'x':
+ do
+ {
+ if (!optarg)
+ optarg = D_DEFAULT;
+ switch (*optarg)
+ {
+ case 'g':
#ifdef WITH_GUILE
- if (strcmp (optarg, "guile") == 0)
debug_guile = 1;
- else
-#endif
- debug_level = strtoul (optarg, NULL, 0);
- }
- else
- {
- debug_level = 9;
-#ifdef WITH_GUILE
- debug_guile = 1;
#endif
- }
- break;
+ break;
+ case 't':
+ sieve_debug_flags |= MU_SIEVE_DEBUG_TRACE;
+ break;
+
+ case 'l':
+ sieve_enable_log = 1;
+ break;
+
+ case 'T':
+ debug_flags |= MU_DEBUG_TRACE;
+ break;
+
+ case 'P':
+ debug_flags |= MU_DEBUG_PROT;
+ break;
+
+ default:
+ if (isdigit (*optarg))
+ debug_level = *optarg - '0';
+ else
+ argp_error (state, "%c is not a valid debug flag", *arg);
+ break;
+ }
+ }
+ while (*++optarg);
+ break;
+
default:
return ARGP_ERR_UNKNOWN;
@@ -162,6 +203,64 @@ parse_opt (int key, char *arg, struct argp_state *state)
return 0;
}
+
+static int
+_mu_debug_printer (mu_debug_t unused, size_t level, const char *fmt,
+ va_list ap)
+{
+ vsyslog ((level == MU_DEBUG_ERROR) ? LOG_ERR : LOG_DEBUG, fmt, ap);
+ return 0;
+}
+
+static int
+_sieve_debug_printer (void *unused, const char *fmt, va_list ap)
+{
+ vsyslog (LOG_DEBUG, fmt, ap);
+ return 0;
+}
+
+static void
+_sieve_action_log (void *user_name,
+ const char *script, size_t msgno, message_t msg,
+ const char *action, const char *fmt, va_list ap)
+{
+ size_t uid = 0;
+ char *text = NULL;
+
+ message_get_uid (msg, &uid);
+
+ asprintf (&text, "%s on msg uid %d", action, uid);
+ if (fmt && strlen (fmt))
+ {
+ char *diag = NULL;
+ asprintf (&diag, fmt, ap);
+ syslog (LOG_NOTICE, "(user %s) %s: %s", (char*) user_name, text, diag);
+ free (diag);
+ }
+ else
+ syslog (LOG_NOTICE, "(user %s) %s", (char*) user_name, text);
+ free (text);
+}
+
+static int
+_sieve_parse_error (void *user_name, const char *filename, int lineno,
+ const char *fmt, va_list ap)
+{
+ char *text;
+ vasprintf (&text, fmt, ap);
+ if (filename)
+ {
+ char *loc;
+ asprintf (&loc, "%s:%d: ", filename, lineno);
+ syslog (LOG_ERR, "%s: %s", loc, text);
+ free (loc);
+ }
+ else
+ syslog (LOG_ERR, "(user %s) %s", user_name, text);
+ free (text);
+ return 0;
+}
+
int
main (int argc, char *argv[])
{
@@ -180,6 +279,28 @@ main (int argc, char *argv[])
openlog ("mail.local", LOG_PID, log_facility);
mu_error_set_print (mu_syslog_error_printer);
+ if (debug_flags)
+ {
+ int rc;
+
+ if ((rc = mu_debug_create (&mudebug, NULL)))
+ {
+ mu_error ("mu_debug_create failed: %s\n", mu_errstring (rc));
+ exit (EX_TEMPFAIL);
+ }
+ if ((rc = mu_debug_set_level (mudebug, debug_flags)))
+ {
+ mu_error ("mu_debug_set_level failed: %s\n",
+ mu_errstring (rc));
+ exit (EX_TEMPFAIL);
+ }
+ if ((rc = mu_debug_set_print (mudebug, _mu_debug_printer, NULL)))
+ {
+ mu_error ("mu_debug_set_print failed: %s\n",
+ mu_errstring (rc));
+ exit (EX_TEMPFAIL);
+ }
+ }
uid = getuid ();
@@ -204,6 +325,34 @@ main (int argc, char *argv[])
}
fp = make_tmp (from, &tempfile);
+ if (sieve_pattern)
+ {
+ stream_t stream;
+ int status;
+
+ fflush (fp);
+ file_stream_create (&stream, tempfile, MU_STREAM_RDWR);
+ if ((status = stream_open (stream)))
+ {
+ mu_error ("Opening temporary file failed: %s\n",
+ mu_errstring (status));
+ return EX_TEMPFAIL;
+ }
+
+ if ((status = message_create (&sieve_msg, NULL)))
+ {
+ mu_error ("Can't create temporary message: %s\n",
+ mu_errstring (status));
+ return EX_TEMPFAIL;
+ }
+
+ if ((status = message_set_stream (sieve_msg, stream, NULL)))
+ {
+ mu_error ("Can't assign stream to temporary message: %s\n",
+ mu_errstring (status));
+ return EX_TEMPFAIL;
+ }
+ }
if (multiple_delivery)
multiple_delivery = argc > 1;
@@ -229,6 +378,64 @@ main (int argc, char *argv[])
}
int
+sieve_test (struct mu_auth_data *auth)
+{
+ int rc = 1;
+ char *progfile;
+
+ if (!sieve_pattern)
+ return 1;
+
+ progfile = mu_expand_path_pattern (sieve_pattern, auth->name);
+ if (access (progfile, R_OK))
+ {
+ if (debug_level > 2)
+ syslog (LOG_DEBUG, "access to %s failed: %m", progfile);
+ }
+ else
+ {
+ sieve_machine_t mach;
+ rc = sieve_machine_init (&mach, auth->name);
+ if (rc)
+ {
+ mu_error ("can't initialize sieve machine: %s",
+ mu_errstring (rc));
+ }
+ else
+ {
+ sieve_set_debug (mach, _sieve_debug_printer);
+ sieve_set_debug_level (mach, mudebug, sieve_debug_flags);
+ sieve_set_parse_error (mach, _sieve_parse_error);
+ if (sieve_enable_log)
+ sieve_set_logger (mach, _sieve_action_log);
+
+ rc = sieve_compile (mach, progfile);
+ if (rc == 0)
+ {
+ attribute_t attr;
+
+ message_get_attribute (sieve_msg, &attr);
+ attribute_unset_deleted (attr);
+ if (switch_user_id (auth, 1) == 0)
+ {
+ chdir (auth->dir);
+
+ rc = sieve_message (mach, sieve_msg);
+ if (rc == 0)
+ rc = attribute_is_deleted (attr) == 0;
+
+ switch_user_id (auth, 0);
+ chdir ("/");
+ }
+ }
+ sieve_machine_destroy (&mach);
+ }
+ }
+ free (progfile);
+ return rc;
+}
+
+int
mda (FILE *fp, char *username)
{
deliver (fp, username);
@@ -374,11 +581,19 @@ deliver (FILE *fp, char *name)
exit_code = EX_UNAVAILABLE;
return;
}
+
+ if (!sieve_test (auth))
+ {
+ exit_code = EX_OK;
+ mu_auth_data_free (auth);
+ return;
+ }
if ((status = mailbox_create (&mbox, auth->mailbox)) != 0)
{
mailer_err ("can't open mailbox %s: %s",
auth->mailbox, mu_errstring (status));
+ mu_auth_data_free (auth);
return;
}

Return to:

Send suggestions and report system problems to the System administrator.