Commit 836d8ad1 836d8ad109de5517ff1aa5ef61a557f5ed240081 by Sergey Poznyakoff

Add scripting capability to mh/inc.

This patch adds a convenience library libmuscript that provides scripting
capability easy to use in MU applications. Currently used by maidag and
inc.

* include/mailutils/util.h (mu_stpcpy): 2nd arg is const.
* libmailutils/string/stpcpy.c: Likewise.

* lib/.gitignore: Update.
* lib/Makefile.am: New library libmuscript.a
* lib/muscript.h: New file.
* lib/muscript_priv.h: New file.
* lib/script.c: New file.
* maidag/guile.c: Rename to ...
* lib/guile.c: ... this
* maidag/python.c: Rename to ...
* lib/python.c: ... this
* maidag/sieve.c: Rename to ...
* lib/sieve.c: ... this

* maidag/Makefile.am (maidag_LDADD): Add libmuscript.a
(maidag_SOURCES): Update.
* maidag/maidag.c (script_handler): Change type to mu_script_t.
* maidag/maidag.h: Include muscript.h
* maidag/script.c: Rewrite via libmuscript

* mh/Makefile.am (inc_LDADD): New variable.
* mh/inc.c (options): New options --language and --script.
(mh_option): New options -language and -script.
(incdat) <handler,descr>: New members.
(incmbx): Optionally process each message through a script. If it is
marked as deleted upon return, don't incorporate it.
(main): Set mh as the default mailbox scheme.
Initialize scripting subsystem and deallocate it when finished.
* mh/mh_getopt.h (ARG_LANG, ARG_SCRIPT): New constants.
1 parent 835cf591
......@@ -34,7 +34,7 @@ extern "C" {
unsigned long mu_hex2ul (char hex);
size_t mu_hexstr2ul (unsigned long* ul, const char* hex, size_t len);
size_t mu_cpystr (char *dst, const char *src, size_t size);
char *mu_stpcpy (char *p, char *q);
char *mu_stpcpy (char *p, const char *q);
int mu_string_unfold (char *text, size_t *plen);
int mu_true_answer_p (const char *p);
int mu_unre_set_regex (const char *str, int caseflag, char **errp);
......
......@@ -17,8 +17,14 @@
SUBDIRS = gnu .
AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I${top_srcdir}/lib/gnu -I${top_builddir}/lib/gnu
noinst_LIBRARIES = libmuaux.a
AM_CPPFLAGS = \
@MU_LIB_COMMON_INCLUDES@\
-I${top_srcdir}/lib/gnu\
-I${top_builddir}/lib/gnu\
@GUILE_INCLUDES@\
@PYTHON_INCLUDES@
noinst_LIBRARIES = libmuaux.a libmuscript.a
libmuaux_a_SOURCES = \
argp_base.c\
daemon.c\
......@@ -35,8 +41,21 @@ libmuaux_a_LIBADD=gnu/*.o
noinst_HEADERS =\
mailcap.h\
muaux.h\
muscript.h\
muscript_priv.h\
tcpwrap.h
EXTRA_DIST = utmp.c
libmuscript_a_SOURCES = \
script.c\
sieve.c
if MU_COND_LIBMU_SCM
libmuscript_a_SOURCES += guile.c
endif
if MU_COND_PYTHON
libmuscript_a_SOURCES += python.c
endif
......
......@@ -15,21 +15,18 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#include "maidag.h"
#ifdef WITH_GUILE
#include "muscript.h"
#include "muscript_priv.h"
#include <mailutils/guile.h>
int debug_guile;
static int initialized;
int
scheme_check_msg (mu_message_t msg, struct mu_auth_data *auth,
const char *prog)
static int
scheme_init (const char *prog, mu_script_descr_t *pdescr)
{
if (!initialized)
{
mu_guile_init (debug_guile);
mu_guile_init (mu_script_debug_guile);
if (mu_log_syslog)
{
SCM port;
......@@ -42,9 +39,21 @@ scheme_check_msg (mu_message_t msg, struct mu_auth_data *auth,
initialized = 1;
}
mu_guile_load (prog, 0, NULL);
mu_guile_message_apply (msg, "mailutils-check-message");
return 0;
}
#endif
static int
scheme_proc (mu_script_descr_t descr, mu_message_t msg)
{
mu_guile_message_apply (msg, "mailutils-check-message");
return 0;
}
struct mu_script_fun mu_script_scheme = {
"scheme",
"scm\0",
scheme_init,
NULL,
scheme_proc,
NULL
};
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999-2002, 2005, 2007, 2009-2012, 2014 Free Software
Foundation, Inc.
GNU Mailutils 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.
GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#if defined(HAVE_CONFIG_H)
# include <config.h>
#endif
#include <mailutils/sieve.h>
#include <mailutils/diag.h>
#include <mailutils/errno.h>
#include <mailutils/error.h>
typedef struct mu_script_fun *mu_script_t;
typedef struct mu_script_descr *mu_script_descr_t;
mu_script_t mu_script_lang_handler (const char *lang);
mu_script_t mu_script_suffix_handler (const char *name);
int mu_script_init (mu_script_t scr, const char *name, mu_script_descr_t *);
int mu_script_done (mu_script_t, mu_script_descr_t);
int mu_script_process_msg (mu_script_t, mu_script_descr_t, mu_message_t msg);
void mu_script_log_enable (mu_script_t scr, mu_script_descr_t descr,
const char *name, const char *hdr);
int mu_script_debug_flags (const char *arg, char **endp);
extern int mu_script_debug_guile;
extern int mu_script_debug_sieve;
extern int mu_script_sieve_log;
struct mu_script_fun
{
char *lang;
char *suf;
int (*script_init) (const char *, mu_script_descr_t *);
int (*script_done) (mu_script_descr_t);
int (*script_process) (mu_script_descr_t, mu_message_t);
int (*script_log_enable) (mu_script_descr_t descr, const char *name,
const char *hdr);
};
extern struct mu_script_fun mu_script_python;
extern struct mu_script_fun mu_script_sieve;
extern struct mu_script_fun mu_script_scheme;
......@@ -14,26 +14,37 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#include "maidag.h"
#ifdef WITH_PYTHON
#include "muscript.h"
#include "muscript_priv.h"
#include <mailutils/python.h>
#include <string.h>
static int
python_init (const char *prog, mu_script_descr_t *pdescr)
{
*pdescr = (mu_script_descr_t) strdup (prog);
if (!*pdescr)
return errno;
return 0;
}
static int
python_done (mu_script_descr_t descr)
{
free (descr);
}
int
python_check_msg (mu_message_t msg, struct mu_auth_data *auth,
const char *prog)
static int
python_proc (mu_script_descr_t descr, mu_message_t msg)
{
PyMessage *py_msg;
mu_py_dict dict[2];
mu_py_script_data data[1];
char *argv[] = { "maidag", NULL };
char *argv[] = { NULL, NULL };
mu_py_script_init (1, argv);
argv[0] = mu_program_name;
if (!log_to_stderr)
{
/* FIXME */
}
mu_py_script_init (1, argv);
py_msg = PyMessage_NEW ();
py_msg->msg = msg;
......@@ -41,14 +52,21 @@ python_check_msg (mu_message_t msg, struct mu_auth_data *auth,
dict[0].name = "message";
dict[0].obj = (PyObject *)py_msg;
dict[1].name = NULL;
data[0].module_name = "maidag";
data[0].module_name = mu_program_name;
data[0].attrs = dict;
dict[1].name = NULL;
mu_py_script_run (prog, data);
mu_py_script_run ((char*)descr, data);
mu_py_script_finish ();
return 0;
}
#endif /* WITH_PYTHON */
struct mu_script_fun mu_script_python = {
"python",
"py\0pyc\0",
python_init,
python_done,
python_proc,
NULL
};
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999-2002, 2005, 2007, 2009-2012, 2014 Free Software
Foundation, Inc.
GNU Mailutils 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.
GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#include "muscript.h"
#include "muscript_priv.h"
int mu_script_debug_sieve;
int mu_script_debug_guile;
int mu_script_sieve_log;
struct mu_script_fun *script_tab[] = {
&mu_script_sieve,
#ifdef WITH_PYTHON
&mu_script_python,
#endif
#ifdef WITH_GUILE
&mu_script_scheme,
#endif
NULL
};
int
mu_script_debug_flags (const char *arg, char **endp)
{
for (; *arg; arg++)
{
switch (*arg)
{
case 'g':
mu_script_debug_guile = 1;
break;
case 't':
mu_script_debug_sieve |= MU_SIEVE_DEBUG_TRACE;
break;
case 'i':
mu_script_debug_sieve |= MU_SIEVE_DEBUG_INSTR;
break;
case 'l':
mu_script_sieve_log = 1;
break;
default:
if (endp)
*endp = (char*) arg;
return 1;
}
}
return 0;
}
mu_script_t
mu_script_lang_handler (const char *lang)
{
int i;
for (i = 0; script_tab[i]; i++)
if (strcmp (script_tab[i]->lang, lang) == 0)
return script_tab[i];
return NULL;
}
mu_script_t
mu_script_suffix_handler (const char *name)
{
int i;
char *suf;
suf = strrchr (name, '.');
if (!suf)
return NULL;
suf++;
for (i = 0; script_tab[i]; i++)
{
char *s;
for (s = script_tab[i]->suf; *s; s += strlen (s) + 1)
if (strcmp (s, suf) == 0)
return script_tab[i];
}
return NULL;
}
int
mu_script_init (mu_script_t scr, const char *name, mu_script_descr_t *pdescr)
{
return scr->script_init ? scr->script_init (name, pdescr) : 0;
}
int
mu_script_done (mu_script_t scr, mu_script_descr_t descr)
{
return scr->script_done ? scr->script_done (descr) : 0;
}
void
mu_script_log_enable (mu_script_t scr, mu_script_descr_t descr,
const char *name, const char *hdr)
{
if (scr->script_log_enable)
scr->script_log_enable (descr, name, hdr);
}
int
mu_script_process_msg (mu_script_t scr, mu_script_descr_t descr,
mu_message_t msg)
{
return scr->script_process (descr, msg);
}
......@@ -15,24 +15,35 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#include "maidag.h"
#include "muscript.h"
#include "muscript_priv.h"
struct sieve_log_data
{
char *user;
char *hdr;
};
static void
_sieve_action_log (void *user_name,
_sieve_action_log (void *data,
mu_stream_t stream, size_t msgno,
mu_message_t msg,
const char *action, const char *fmt, va_list ap)
{
struct sieve_log_data *ldat = data;
int pfx = 0;
mu_stream_printf (stream, "\033s<%d>", MU_LOG_NOTICE);
mu_stream_printf (stream, _("(user %s) "), (char*) user_name);
if (message_id_header)
if (ldat)
{
if (ldat->user)
mu_stream_printf (stream, _("(user %s) "), ldat->user);
if (ldat->hdr)
{
mu_header_t hdr = NULL;
char *val = NULL;
mu_message_get_header (msg, &hdr);
if (mu_header_aget_value (hdr, message_id_header, &val) == 0
if (mu_header_aget_value (hdr, ldat->hdr, &val) == 0
|| mu_header_aget_value (hdr, MU_HEADER_MESSAGE_ID, &val) == 0)
{
pfx = 1;
......@@ -40,6 +51,7 @@ _sieve_action_log (void *user_name,
free (val);
}
}
}
if (!pfx)
{
......@@ -57,29 +69,82 @@ _sieve_action_log (void *user_name,
mu_stream_printf (stream, "\n");
}
int
sieve_check_msg (mu_message_t msg, struct mu_auth_data *auth, const char *prog)
static int
sieve_init (const char *prog, mu_script_descr_t *pdescr)
{
int rc;
mu_sieve_machine_t mach;
rc = mu_sieve_machine_init (&mach);
if (rc)
if (rc == 0)
{
mu_sieve_set_debug_level (mach, mu_script_debug_sieve);
if (mu_script_sieve_log)
mu_sieve_set_logger (mach, _sieve_action_log);
rc = mu_sieve_compile (mach, prog);
}
*pdescr = (mu_script_descr_t) mach;
return rc;
}
static int
sieve_log_enable (mu_script_descr_t descr, const char *name, const char *hdr)
{
mu_sieve_machine_t mach = (mu_sieve_machine_t) descr;
struct sieve_log_data *ldat;
size_t size = 0;
char *p;
if (name)
size += strlen (name) + 1;
if (hdr)
size += strlen (hdr) + 1;
if (size)
{
mu_error (_("Cannot initialize sieve machine: %s"),
mu_strerror (rc));
ldat = calloc (1, sizeof (*ldat) + size);
if (!ldat)
return ENOMEM;
p = (char *) (ldat + 1);
if (name)
{
ldat->user = p;
p = mu_stpcpy (p, name) + 1;
}
else
if (hdr)
{
mu_sieve_set_data (mach, auth->name);
if (sieve_enable_log)
ldat->hdr = p;
strcpy (p, hdr);
}
mu_sieve_set_data (mach, ldat);
}
mu_sieve_set_logger (mach, _sieve_action_log);
return 0;
}
rc = mu_sieve_compile (mach, prog);
if (rc == 0)
mu_sieve_message (mach, msg);
static int
sieve_done (mu_script_descr_t descr)
{
mu_sieve_machine_t mach = (mu_sieve_machine_t) descr;
void *p = mu_sieve_get_data (mach);
free (p);
mu_sieve_machine_destroy (&mach);
}
return 0;
}
static int
sieve_proc (mu_script_descr_t descr, mu_message_t msg)
{
return mu_sieve_message ((mu_sieve_machine_t) descr, msg);
}
struct mu_script_fun mu_script_sieve = {
"sieve",
"sv\0siv\0sieve\0",
sieve_init,
sieve_done,
sieve_proc,
sieve_log_enable
};
......
......@@ -23,7 +23,7 @@
#include <mailutils/util.h>
char *
mu_stpcpy (char *p, char *q)
mu_stpcpy (char *p, const char *q)
{
if (q)
while ((*p = *q++))
......
......@@ -19,13 +19,10 @@ sbin_PROGRAMS=maidag
maidag_SOURCES=\
deliver.c\
forward.c\
guile.c\
lmtp.c\
maidag.c\
maidag.h\
mailquota.c\
python.c\
sieve.c\
script.c\
util.c
......@@ -34,6 +31,7 @@ if MU_COND_DBM
endif
maidag_LDADD = \
../lib/libmuscript.a\
@LIBMU_SCM@ @GUILE_LIBS@\
@LIBMU_SCM_DEPS@\
@MU_LIB_PY@ @PYTHON_LIBS@\
......
......@@ -30,7 +30,7 @@ char *quota_query = NULL; /* SQL query to retrieve mailbox quota */
char *sender_address = NULL;
maidag_script_fun script_handler;
mu_script_t script_handler;
mu_list_t script_list;
......@@ -62,7 +62,7 @@ static char doc[] =
N_("GNU maidag -- the mail delivery agent.")
"\v"
N_("Debug flags are:\n\
g - guimb stack traces\n\
g - guile stack traces\n\
t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\
i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n\
l - sieve action logs\n\
......@@ -143,47 +143,28 @@ static const char *maidag_argp_capa[] = {
NULL
};
#define D_DEFAULT "9,s"
static void
set_debug_flags (const char *arg)
{
while (*arg)
{
if (mu_isdigit (*arg))
if (mu_script_debug_flags (arg, (char**)&arg) == 0)
break;
else if (mu_isdigit (*arg))
debug_level = strtoul (arg, (char**)&arg, 10);
else
for (; *arg && *arg != ','; arg++)
{
switch (*arg)
{
case 'g':
#ifdef WITH_GUILE
debug_guile = 1;
#endif
break;
case 't':
sieve_debug_flags |= MU_SIEVE_DEBUG_TRACE;
break;
case 'i':
sieve_debug_flags |= MU_SIEVE_DEBUG_INSTR;
break;
case 'l':
sieve_enable_log = 1;
break;
default:
mu_error (_("%c is not a valid debug flag"), *arg);
break;
}
}
if (*arg == ',')
arg++;
else if (*arg)
{
mu_error (_("expected comma, but found %c"), *arg);
exit (1);
}
}
}
......@@ -234,7 +215,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case 'l':
script_handler = script_lang_handler (arg);
script_handler = mu_script_lang_handler (arg);
if (!script_handler)
argp_error (state, _("unknown or unsupported language: %s"),
arg);
......@@ -256,7 +237,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case 'x':
mu_argp_node_list_new (lst, "debug", arg ? arg : D_DEFAULT);
mu_argp_node_list_new (lst, "debug", arg);
break;
case STDERR_OPTION:
......@@ -353,7 +334,7 @@ cb_script_language (void *data, mu_config_value_t *val)
{
if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
return 1;
script_handler = script_lang_handler (val->v.string);
script_handler = mu_script_lang_handler (val->v.string);
if (!script_handler)
{
mu_error (_("unsupported language: %s"), val->v.string);
......@@ -457,7 +438,7 @@ struct mu_cfg_param maidag_cfg_param[] = {
{ "debug", mu_cfg_callback, NULL, 0, cb_debug,
N_("Set maidag debug level. Debug level consists of one or more "
"of the following letters:\n"
" g - guimb stack traces\n"
" g - guile stack traces\n"
" t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n"
" i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n"
" l - sieve action logs\n") },
......
......@@ -94,6 +94,7 @@
#include "mailutils/libargp.h"
#include "tcpwrap.h"
#include "muscript.h"
/* Debug */
extern int debug_level;
......@@ -177,11 +178,11 @@ typedef int (*maidag_script_fun) (mu_message_t msg,
struct mu_auth_data *auth,
const char *prog);
extern maidag_script_fun script_handler;
extern mu_script_t script_handler;
struct maidag_script
{
maidag_script_fun fun; /* Handler function */
mu_script_t scr; /* Handler script */
const char *pat; /* Script name pattern */
};
......
......@@ -17,80 +17,27 @@
#include "maidag.h"
struct script_tab
{
char *lang;
char *suf;
maidag_script_fun fun;
};
struct script_tab script_tab[] = {
#ifdef WITH_PYTHON
{ "python", "py\0pyc\0", python_check_msg },
#endif
{ "sieve", "sv\0siv\0sieve\0", sieve_check_msg },
#ifdef WITH_GUILE
{ "scheme", "scm\0", scheme_check_msg },
#endif
{ NULL }
};
maidag_script_fun
script_lang_handler (const char *lang)
{
struct script_tab *p;
for (p = script_tab; p->lang; p++)
if (strcmp (p->lang, lang) == 0)
return p->fun;
return NULL;
}
maidag_script_fun
script_suffix_handler (const char *name)
{
struct script_tab *p;
char *suf;
suf = strrchr (name, '.');
if (!suf)
return NULL;
suf++;
for (p = script_tab; p->lang; p++)
{
char *s;
for (s = p->suf; *s; s += strlen (s) + 1)
if (strcmp (s, suf) == 0)
return p->fun;
}
return NULL;
}
int
script_register (const char *pattern)
{
maidag_script_fun fun;
struct maidag_script *scr;
mu_script_t scr;
struct maidag_script *p;
if (script_handler)
fun = script_handler;
scr = script_handler;
else
{
fun = script_suffix_handler (pattern);
if (!fun)
scr = mu_script_suffix_handler (pattern);
if (!scr)
return EINVAL;
}
scr = malloc (sizeof (*scr));
if (!scr)
p = malloc (sizeof (*p));
if (!p)
return MU_ERR_FAILURE;
scr->fun = fun;
scr->pat = pattern;
p->scr = scr;
p->pat = pattern;
if (!script_list)
{
......@@ -98,7 +45,7 @@ script_register (const char *pattern)
return MU_ERR_FAILURE;
}
if (mu_list_append (script_list, scr))
if (mu_list_append (script_list, p))
return MU_ERR_FAILURE;
return 0;
......@@ -119,6 +66,7 @@ apply_script (void *item, void *data)
char *progfile;
int rc;
struct stat st;
mu_script_descr_t sd;
progfile = mu_expand_path_pattern (scr->pat, clos->auth->name);
if (stat (progfile, &st))
......@@ -131,7 +79,21 @@ apply_script (void *item, void *data)
return 0;
}
rc = scr->fun (clos->msg, clos->auth, progfile);
rc = mu_script_init (scr->scr, progfile, &sd);
if (rc)
mu_error (_("initialization of script %s failed: %s"),
progfile, mu_strerror (rc));
else
{
if (sieve_enable_log)
mu_script_log_enable (scr->scr, sd, clos->auth->name,
message_id_header);
rc = mu_script_process_msg (scr->scr, sd, clos->msg);
if (rc)
mu_error (_("script %s failed: %s"), progfile, mu_strerror (rc));
mu_script_done (scr->scr, sd);
}
free (progfile);
if (rc == 0)
......
......@@ -125,6 +125,27 @@ pick_SOURCES = pick.c pick.h pick-gram.c pick-gram.h
YLWRAP = $(SHELL) $(mu_aux_dir)/gylwrap
AM_YFLAGS=-vt
inc_LDADD = \
./libmh.a\
../lib/libmuaux.a\
../lib/libmuscript.a\
@LIBMU_SCM@ @GUILE_LIBS@\
@LIBMU_SCM_DEPS@\
@MU_LIB_PY@ @PYTHON_LIBS@\
${MU_LIB_SIEVE}\
${MU_LIB_MBOX}\
${MU_LIB_IMAP}\
${MU_LIB_POP}\
${MU_LIB_MH}\
${MU_LIB_NNTP}\
${MU_LIB_MAILDIR}\
${MU_LIB_MAILER}\
${MU_LIB_AUTH}\
@MU_AUTHLIBS@\
${MU_LIB_MAILUTILS}\
@MU_COMMON_LIBRARIES@
pick-gram.c pick-gram.h: $(srcdir)/pick.y
$(YLWRAP) "$(YACC) $(AM_YFLAGS) -d" $< \
y.tab.c pick-gram.c y.tab.h pick-gram.h \
......
......@@ -18,9 +18,15 @@
/* MH inc command */
#include <mh.h>
#include "muscript.h"
static char doc[] = N_("GNU MH inc")"\v"
N_("Use -help to obtain the list of traditional MH options.");
N_("Debug flags are:\n\
g - guile stack traces\n\
t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\
i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n\
l - sieve action logs\n\n\
Use -help to obtain the list of traditional MH options.");
static char args_doc[] = N_("[+FOLDER]");
/* GNU options */
......@@ -51,6 +57,12 @@ static struct argp_option options[] = {
N_("be quiet")},
{"notify", ARG_NOTIFY,N_("BOOL"), OPTION_ARG_OPTIONAL,
N_("enable biff notification"), },
{"language",ARG_LANG, N_("LANG"), 0,
N_("set language for the --script option") },
{"script", ARG_SCRIPT,N_("FILE"), 0,
N_("filter incoming messages using script FILE") },
{"debug", ARG_DEBUG, N_("FLAGS"), 0,
N_("enable debugging") },
{ 0 }
};
......@@ -67,6 +79,9 @@ struct mh_option mh_option[] = {
{ "width", MH_OPT_ARG, "number" },
{ "notify", MH_OPT_BOOL },
{ "quiet" },
{ "language", MH_OPT_ARG, "lang" },
{ "script", MH_OPT_ARG, "file" },
{ "debug", MH_OPT_ARG, "flags" },
{ NULL }
};
......@@ -81,11 +96,14 @@ static int quiet = 0;
static int notify = 0;
static const char *append_folder;
static const char *move_to_mailbox;
static const char *script_file;
static const char *script_lang;
static error_t
opt_handler (int key, char *arg, struct argp_state *state)
{
int rc;
char *p;
switch (key)
{
......@@ -106,6 +124,11 @@ opt_handler (int key, char *arg, struct argp_state *state)
changecur = is_true (arg);
break;
case ARG_DEBUG:
if (mu_script_debug_flags (arg, &p))
argp_error (state, _("invalid debug flag near %s"), p);
break;
case ARG_NOCHANGECUR:
changecur = 0;
break;
......@@ -170,6 +193,14 @@ opt_handler (int key, char *arg, struct argp_state *state)
notify = is_true (arg);;
break;
case ARG_LANG:
script_lang = arg;
break;
case ARG_SCRIPT:
script_file = arg;
break;
default:
return ARGP_ERR_UNKNOWN;
}
......@@ -196,6 +227,8 @@ struct incdat
mu_mailbox_t output;
size_t lastmsg;
mh_format_t format;
mu_script_t handler;
mu_script_descr_t descr;
};
static int
......@@ -294,6 +327,23 @@ incmbx (void *item, void *data)
continue;
}
if (dp->handler)
{
mu_attribute_t attr;
if (mu_script_process_msg (dp->handler, dp->descr, imsg))
{
mu_error (_("%lu: filter failed: %s"),
(unsigned long) n, mu_strerror (rc));
continue;
}
mu_message_get_attribute (imsg, &attr);
if (mu_attribute_is_deleted (attr))
continue;
}
if ((rc = mu_mailbox_append_message (dp->output, imsg)) != 0)
{
mu_error (_("%lu: error appending message: %s"),
......@@ -383,6 +433,8 @@ main (int argc, char **argv)
mh_argp_init ();
mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
opt_handler, NULL, NULL);
mu_registrar_set_default_scheme ("mh");
/* Inc sets missing cur to 1 */
mh_mailbox_cur_default = 1;
......@@ -395,6 +447,38 @@ main (int argc, char **argv)
incdat.output = mh_open_folder (append_folder,
MU_STREAM_READ|MU_STREAM_APPEND|MU_STREAM_CREAT);
if (script_file)
{
if (script_lang)
{
incdat.handler = mu_script_lang_handler (script_lang);
if (!incdat.handler)
{
mu_error (_("unknown or unsupported language: %s"),
script_lang);
exit (1);
}
}
else
{
incdat.handler = mu_script_suffix_handler (script_file);
if (!incdat.handler)
{
mu_error (_("unknown or unsupported language: %s"),
script_file);
exit (1);
}
}
rc = mu_script_init (incdat.handler, script_file, &incdat.descr);
if (rc)
{
mu_error (_("script initialization failed: %s"),
mu_strerror (rc));
exit (1);
}
}
if (notify)
{
rc = mu_mailbox_set_notify (incdat.output, NULL);
......@@ -424,6 +508,9 @@ main (int argc, char **argv)
else
mu_list_foreach (input_file_list, incmbx, &incdat);
if (script_file)
mu_script_done (incdat.handler, incdat.descr);
unseen_seq = mh_global_profile_get ("Unseen-Sequence", NULL);
if (unseen_seq && lastseen < incdat.lastmsg)
{
......
......@@ -87,6 +87,7 @@ enum mh_arg {
ARG_HOST,
ARG_INPLACE,
ARG_INTERACTIVE,
ARG_LANG,
ARG_LBRACE,
ARG_LENGTH,
ARG_LIMIT,
......@@ -166,6 +167,7 @@ enum mh_arg {
ARG_RECURSIVE,
ARG_REORDER,
ARG_REVERSE,
ARG_SCRIPT,
ARG_SEQUENCE,
ARG_SERIALONLY,
ARG_SHOW,
......