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" { ...@@ -34,7 +34,7 @@ extern "C" {
34 unsigned long mu_hex2ul (char hex); 34 unsigned long mu_hex2ul (char hex);
35 size_t mu_hexstr2ul (unsigned long* ul, const char* hex, size_t len); 35 size_t mu_hexstr2ul (unsigned long* ul, const char* hex, size_t len);
36 size_t mu_cpystr (char *dst, const char *src, size_t size); 36 size_t mu_cpystr (char *dst, const char *src, size_t size);
37 char *mu_stpcpy (char *p, char *q); 37 char *mu_stpcpy (char *p, const char *q);
38 int mu_string_unfold (char *text, size_t *plen); 38 int mu_string_unfold (char *text, size_t *plen);
39 int mu_true_answer_p (const char *p); 39 int mu_true_answer_p (const char *p);
40 int mu_unre_set_regex (const char *str, int caseflag, char **errp); 40 int mu_unre_set_regex (const char *str, int caseflag, char **errp);
......
...@@ -17,8 +17,14 @@ ...@@ -17,8 +17,14 @@
17 17
18 SUBDIRS = gnu . 18 SUBDIRS = gnu .
19 19
20 AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I${top_srcdir}/lib/gnu -I${top_builddir}/lib/gnu 20 AM_CPPFLAGS = \
21 noinst_LIBRARIES = libmuaux.a 21 @MU_LIB_COMMON_INCLUDES@\
22 -I${top_srcdir}/lib/gnu\
23 -I${top_builddir}/lib/gnu\
24 @GUILE_INCLUDES@\
25 @PYTHON_INCLUDES@
26
27 noinst_LIBRARIES = libmuaux.a libmuscript.a
22 libmuaux_a_SOURCES = \ 28 libmuaux_a_SOURCES = \
23 argp_base.c\ 29 argp_base.c\
24 daemon.c\ 30 daemon.c\
...@@ -35,8 +41,21 @@ libmuaux_a_LIBADD=gnu/*.o ...@@ -35,8 +41,21 @@ libmuaux_a_LIBADD=gnu/*.o
35 noinst_HEADERS =\ 41 noinst_HEADERS =\
36 mailcap.h\ 42 mailcap.h\
37 muaux.h\ 43 muaux.h\
44 muscript.h\
45 muscript_priv.h\
38 tcpwrap.h 46 tcpwrap.h
39 47
40 EXTRA_DIST = utmp.c 48 EXTRA_DIST = utmp.c
41 49
50 libmuscript_a_SOURCES = \
51 script.c\
52 sieve.c
53
54 if MU_COND_LIBMU_SCM
55 libmuscript_a_SOURCES += guile.c
56 endif
57
58 if MU_COND_PYTHON
59 libmuscript_a_SOURCES += python.c
60 endif
42 61
......
...@@ -15,21 +15,18 @@ ...@@ -15,21 +15,18 @@
15 You should have received a copy of the GNU General Public License 15 You should have received a copy of the GNU General Public License
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ 16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17 17
18 #include "maidag.h" 18 #include "muscript.h"
19 19 #include "muscript_priv.h"
20 #ifdef WITH_GUILE
21 #include <mailutils/guile.h> 20 #include <mailutils/guile.h>
22 21
23 int debug_guile;
24 static int initialized; 22 static int initialized;
25 23
26 int 24 static int
27 scheme_check_msg (mu_message_t msg, struct mu_auth_data *auth, 25 scheme_init (const char *prog, mu_script_descr_t *pdescr)
28 const char *prog)
29 { 26 {
30 if (!initialized) 27 if (!initialized)
31 { 28 {
32 mu_guile_init (debug_guile); 29 mu_guile_init (mu_script_debug_guile);
33 if (mu_log_syslog) 30 if (mu_log_syslog)
34 { 31 {
35 SCM port; 32 SCM port;
...@@ -42,9 +39,21 @@ scheme_check_msg (mu_message_t msg, struct mu_auth_data *auth, ...@@ -42,9 +39,21 @@ scheme_check_msg (mu_message_t msg, struct mu_auth_data *auth,
42 initialized = 1; 39 initialized = 1;
43 } 40 }
44 mu_guile_load (prog, 0, NULL); 41 mu_guile_load (prog, 0, NULL);
45 mu_guile_message_apply (msg, "mailutils-check-message");
46 return 0; 42 return 0;
47 } 43 }
48 44
49 #endif 45 static int
46 scheme_proc (mu_script_descr_t descr, mu_message_t msg)
47 {
48 mu_guile_message_apply (msg, "mailutils-check-message");
49 return 0;
50 }
50 51
52 struct mu_script_fun mu_script_scheme = {
53 "scheme",
54 "scm\0",
55 scheme_init,
56 NULL,
57 scheme_proc,
58 NULL
59 };
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2002, 2005, 2007, 2009-2012, 2014 Free Software
3 Foundation, Inc.
4
5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9
10 GNU Mailutils is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17
18 #if defined(HAVE_CONFIG_H)
19 # include <config.h>
20 #endif
21 #include <mailutils/sieve.h>
22 #include <mailutils/diag.h>
23 #include <mailutils/errno.h>
24 #include <mailutils/error.h>
25
26
27 typedef struct mu_script_fun *mu_script_t;
28 typedef struct mu_script_descr *mu_script_descr_t;
29
30 mu_script_t mu_script_lang_handler (const char *lang);
31 mu_script_t mu_script_suffix_handler (const char *name);
32
33 int mu_script_init (mu_script_t scr, const char *name, mu_script_descr_t *);
34 int mu_script_done (mu_script_t, mu_script_descr_t);
35 int mu_script_process_msg (mu_script_t, mu_script_descr_t, mu_message_t msg);
36 void mu_script_log_enable (mu_script_t scr, mu_script_descr_t descr,
37 const char *name, const char *hdr);
38
39 int mu_script_debug_flags (const char *arg, char **endp);
40
41 extern int mu_script_debug_guile;
42 extern int mu_script_debug_sieve;
43 extern int mu_script_sieve_log;
44
45
1 struct mu_script_fun
2 {
3 char *lang;
4 char *suf;
5 int (*script_init) (const char *, mu_script_descr_t *);
6 int (*script_done) (mu_script_descr_t);
7 int (*script_process) (mu_script_descr_t, mu_message_t);
8 int (*script_log_enable) (mu_script_descr_t descr, const char *name,
9 const char *hdr);
10 };
11
12 extern struct mu_script_fun mu_script_python;
13 extern struct mu_script_fun mu_script_sieve;
14 extern struct mu_script_fun mu_script_scheme;
...@@ -14,26 +14,37 @@ ...@@ -14,26 +14,37 @@
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ 15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16 16
17 #include "maidag.h" 17 #include "muscript.h"
18 18 #include "muscript_priv.h"
19 #ifdef WITH_PYTHON
20 #include <mailutils/python.h> 19 #include <mailutils/python.h>
20 #include <string.h>
21
22 static int
23 python_init (const char *prog, mu_script_descr_t *pdescr)
24 {
25 *pdescr = (mu_script_descr_t) strdup (prog);
26 if (!*pdescr)
27 return errno;
28 return 0;
29 }
30
31 static int
32 python_done (mu_script_descr_t descr)
33 {
34 free (descr);
35 }
21 36
22 int 37 static int
23 python_check_msg (mu_message_t msg, struct mu_auth_data *auth, 38 python_proc (mu_script_descr_t descr, mu_message_t msg)
24 const char *prog)
25 { 39 {
26 PyMessage *py_msg; 40 PyMessage *py_msg;
27 mu_py_dict dict[2]; 41 mu_py_dict dict[2];
28 mu_py_script_data data[1]; 42 mu_py_script_data data[1];
29 char *argv[] = { "maidag", NULL }; 43 char *argv[] = { NULL, NULL };
30 44
31 mu_py_script_init (1, argv); 45 argv[0] = mu_program_name;
32 46
33 if (!log_to_stderr) 47 mu_py_script_init (1, argv);
34 {
35 /* FIXME */
36 }
37 48
38 py_msg = PyMessage_NEW (); 49 py_msg = PyMessage_NEW ();
39 py_msg->msg = msg; 50 py_msg->msg = msg;
...@@ -41,14 +52,21 @@ python_check_msg (mu_message_t msg, struct mu_auth_data *auth, ...@@ -41,14 +52,21 @@ python_check_msg (mu_message_t msg, struct mu_auth_data *auth,
41 52
42 dict[0].name = "message"; 53 dict[0].name = "message";
43 dict[0].obj = (PyObject *)py_msg; 54 dict[0].obj = (PyObject *)py_msg;
44 dict[1].name = NULL; 55 data[0].module_name = mu_program_name;
45 data[0].module_name = "maidag";
46 data[0].attrs = dict; 56 data[0].attrs = dict;
57 dict[1].name = NULL;
47 58
48 mu_py_script_run (prog, data); 59 mu_py_script_run ((char*)descr, data);
49 mu_py_script_finish (); 60 mu_py_script_finish ();
50 return 0; 61 return 0;
51 } 62 }
52 63
53 #endif /* WITH_PYTHON */ 64 struct mu_script_fun mu_script_python = {
65 "python",
66 "py\0pyc\0",
67 python_init,
68 python_done,
69 python_proc,
70 NULL
71 };
54 72
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2002, 2005, 2007, 2009-2012, 2014 Free Software
3 Foundation, Inc.
4
5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9
10 GNU Mailutils is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17
18 #include "muscript.h"
19 #include "muscript_priv.h"
20
21 int mu_script_debug_sieve;
22 int mu_script_debug_guile;
23 int mu_script_sieve_log;
24
25 struct mu_script_fun *script_tab[] = {
26 &mu_script_sieve,
27 #ifdef WITH_PYTHON
28 &mu_script_python,
29 #endif
30 #ifdef WITH_GUILE
31 &mu_script_scheme,
32 #endif
33 NULL
34 };
35
36 int
37 mu_script_debug_flags (const char *arg, char **endp)
38 {
39 for (; *arg; arg++)
40 {
41 switch (*arg)
42 {
43 case 'g':
44 mu_script_debug_guile = 1;
45 break;
46
47 case 't':
48 mu_script_debug_sieve |= MU_SIEVE_DEBUG_TRACE;
49 break;
50
51 case 'i':
52 mu_script_debug_sieve |= MU_SIEVE_DEBUG_INSTR;
53 break;
54
55 case 'l':
56 mu_script_sieve_log = 1;
57 break;
58
59 default:
60 if (endp)
61 *endp = (char*) arg;
62 return 1;
63 }
64 }
65 return 0;
66 }
67
68 mu_script_t
69 mu_script_lang_handler (const char *lang)
70 {
71 int i;
72
73 for (i = 0; script_tab[i]; i++)
74 if (strcmp (script_tab[i]->lang, lang) == 0)
75 return script_tab[i];
76 return NULL;
77 }
78
79 mu_script_t
80 mu_script_suffix_handler (const char *name)
81 {
82 int i;
83 char *suf;
84
85 suf = strrchr (name, '.');
86 if (!suf)
87 return NULL;
88 suf++;
89
90 for (i = 0; script_tab[i]; i++)
91 {
92 char *s;
93
94 for (s = script_tab[i]->suf; *s; s += strlen (s) + 1)
95 if (strcmp (s, suf) == 0)
96 return script_tab[i];
97 }
98 return NULL;
99 }
100
101 int
102 mu_script_init (mu_script_t scr, const char *name, mu_script_descr_t *pdescr)
103 {
104 return scr->script_init ? scr->script_init (name, pdescr) : 0;
105 }
106
107 int
108 mu_script_done (mu_script_t scr, mu_script_descr_t descr)
109 {
110 return scr->script_done ? scr->script_done (descr) : 0;
111 }
112
113 void
114 mu_script_log_enable (mu_script_t scr, mu_script_descr_t descr,
115 const char *name, const char *hdr)
116 {
117 if (scr->script_log_enable)
118 scr->script_log_enable (descr, name, hdr);
119 }
120
121 int
122 mu_script_process_msg (mu_script_t scr, mu_script_descr_t descr,
123 mu_message_t msg)
124 {
125 return scr->script_process (descr, msg);
126 }
127
...@@ -15,24 +15,35 @@ ...@@ -15,24 +15,35 @@
15 You should have received a copy of the GNU General Public License 15 You should have received a copy of the GNU General Public License
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ 16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17 17
18 #include "maidag.h" 18 #include "muscript.h"
19 #include "muscript_priv.h"
20
21 struct sieve_log_data
22 {
23 char *user;
24 char *hdr;
25 };
19 26
20 static void 27 static void
21 _sieve_action_log (void *user_name, 28 _sieve_action_log (void *data,
22 mu_stream_t stream, size_t msgno, 29 mu_stream_t stream, size_t msgno,
23 mu_message_t msg, 30 mu_message_t msg,
24 const char *action, const char *fmt, va_list ap) 31 const char *action, const char *fmt, va_list ap)
25 { 32 {
33 struct sieve_log_data *ldat = data;
26 int pfx = 0; 34 int pfx = 0;
27 35
28 mu_stream_printf (stream, "\033s<%d>", MU_LOG_NOTICE); 36 mu_stream_printf (stream, "\033s<%d>", MU_LOG_NOTICE);
29 mu_stream_printf (stream, _("(user %s) "), (char*) user_name); 37 if (ldat)
30 if (message_id_header) 38 {
39 if (ldat->user)
40 mu_stream_printf (stream, _("(user %s) "), ldat->user);
41 if (ldat->hdr)
31 { 42 {
32 mu_header_t hdr = NULL; 43 mu_header_t hdr = NULL;
33 char *val = NULL; 44 char *val = NULL;
34 mu_message_get_header (msg, &hdr); 45 mu_message_get_header (msg, &hdr);
35 if (mu_header_aget_value (hdr, message_id_header, &val) == 0 46 if (mu_header_aget_value (hdr, ldat->hdr, &val) == 0
36 || mu_header_aget_value (hdr, MU_HEADER_MESSAGE_ID, &val) == 0) 47 || mu_header_aget_value (hdr, MU_HEADER_MESSAGE_ID, &val) == 0)
37 { 48 {
38 pfx = 1; 49 pfx = 1;
...@@ -40,6 +51,7 @@ _sieve_action_log (void *user_name, ...@@ -40,6 +51,7 @@ _sieve_action_log (void *user_name,
40 free (val); 51 free (val);
41 } 52 }
42 } 53 }
54 }
43 55
44 if (!pfx) 56 if (!pfx)
45 { 57 {
...@@ -57,29 +69,82 @@ _sieve_action_log (void *user_name, ...@@ -57,29 +69,82 @@ _sieve_action_log (void *user_name,
57 mu_stream_printf (stream, "\n"); 69 mu_stream_printf (stream, "\n");
58 } 70 }
59 71
60 int 72 static int
61 sieve_check_msg (mu_message_t msg, struct mu_auth_data *auth, const char *prog) 73 sieve_init (const char *prog, mu_script_descr_t *pdescr)
62 { 74 {
63 int rc; 75 int rc;
64 mu_sieve_machine_t mach; 76 mu_sieve_machine_t mach;
65 77
66 rc = mu_sieve_machine_init (&mach); 78 rc = mu_sieve_machine_init (&mach);
67 if (rc) 79 if (rc == 0)
80 {
81 mu_sieve_set_debug_level (mach, mu_script_debug_sieve);
82 if (mu_script_sieve_log)
83 mu_sieve_set_logger (mach, _sieve_action_log);
84 rc = mu_sieve_compile (mach, prog);
85 }
86 *pdescr = (mu_script_descr_t) mach;
87 return rc;
88 }
89
90 static int
91 sieve_log_enable (mu_script_descr_t descr, const char *name, const char *hdr)
92 {
93 mu_sieve_machine_t mach = (mu_sieve_machine_t) descr;
94 struct sieve_log_data *ldat;
95 size_t size = 0;
96 char *p;
97
98 if (name)
99 size += strlen (name) + 1;
100 if (hdr)
101 size += strlen (hdr) + 1;
102
103 if (size)
68 { 104 {
69 mu_error (_("Cannot initialize sieve machine: %s"), 105 ldat = calloc (1, sizeof (*ldat) + size);
70 mu_strerror (rc)); 106 if (!ldat)
107 return ENOMEM;
108 p = (char *) (ldat + 1);
109 if (name)
110 {
111 ldat->user = p;
112 p = mu_stpcpy (p, name) + 1;
71 } 113 }
72 else 114 if (hdr)
73 { 115 {
74 mu_sieve_set_data (mach, auth->name); 116 ldat->hdr = p;
75 if (sieve_enable_log) 117 strcpy (p, hdr);
118 }
119
120 mu_sieve_set_data (mach, ldat);
121 }
76 mu_sieve_set_logger (mach, _sieve_action_log); 122 mu_sieve_set_logger (mach, _sieve_action_log);
123 return 0;
124 }
77 125
78 rc = mu_sieve_compile (mach, prog); 126 static int
79 if (rc == 0) 127 sieve_done (mu_script_descr_t descr)
80 mu_sieve_message (mach, msg); 128 {
129 mu_sieve_machine_t mach = (mu_sieve_machine_t) descr;
130 void *p = mu_sieve_get_data (mach);
131 free (p);
81 mu_sieve_machine_destroy (&mach); 132 mu_sieve_machine_destroy (&mach);
82 }
83 return 0; 133 return 0;
84 } 134 }
85 135
136 static int
137 sieve_proc (mu_script_descr_t descr, mu_message_t msg)
138 {
139 return mu_sieve_message ((mu_sieve_machine_t) descr, msg);
140 }
141
142 struct mu_script_fun mu_script_sieve = {
143 "sieve",
144 "sv\0siv\0sieve\0",
145 sieve_init,
146 sieve_done,
147 sieve_proc,
148 sieve_log_enable
149 };
150
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
23 #include <mailutils/util.h> 23 #include <mailutils/util.h>
24 24
25 char * 25 char *
26 mu_stpcpy (char *p, char *q) 26 mu_stpcpy (char *p, const char *q)
27 { 27 {
28 if (q) 28 if (q)
29 while ((*p = *q++)) 29 while ((*p = *q++))
......
...@@ -19,13 +19,10 @@ sbin_PROGRAMS=maidag ...@@ -19,13 +19,10 @@ sbin_PROGRAMS=maidag
19 maidag_SOURCES=\ 19 maidag_SOURCES=\
20 deliver.c\ 20 deliver.c\
21 forward.c\ 21 forward.c\
22 guile.c\
23 lmtp.c\ 22 lmtp.c\
24 maidag.c\ 23 maidag.c\
25 maidag.h\ 24 maidag.h\
26 mailquota.c\ 25 mailquota.c\
27 python.c\
28 sieve.c\
29 script.c\ 26 script.c\
30 util.c 27 util.c
31 28
...@@ -34,6 +31,7 @@ if MU_COND_DBM ...@@ -34,6 +31,7 @@ if MU_COND_DBM
34 endif 31 endif
35 32
36 maidag_LDADD = \ 33 maidag_LDADD = \
34 ../lib/libmuscript.a\
37 @LIBMU_SCM@ @GUILE_LIBS@\ 35 @LIBMU_SCM@ @GUILE_LIBS@\
38 @LIBMU_SCM_DEPS@\ 36 @LIBMU_SCM_DEPS@\
39 @MU_LIB_PY@ @PYTHON_LIBS@\ 37 @MU_LIB_PY@ @PYTHON_LIBS@\
......
...@@ -30,7 +30,7 @@ char *quota_query = NULL; /* SQL query to retrieve mailbox quota */ ...@@ -30,7 +30,7 @@ char *quota_query = NULL; /* SQL query to retrieve mailbox quota */
30 30
31 char *sender_address = NULL; 31 char *sender_address = NULL;
32 32
33 maidag_script_fun script_handler; 33 mu_script_t script_handler;
34 34
35 mu_list_t script_list; 35 mu_list_t script_list;
36 36
...@@ -62,7 +62,7 @@ static char doc[] = ...@@ -62,7 +62,7 @@ static char doc[] =
62 N_("GNU maidag -- the mail delivery agent.") 62 N_("GNU maidag -- the mail delivery agent.")
63 "\v" 63 "\v"
64 N_("Debug flags are:\n\ 64 N_("Debug flags are:\n\
65 g - guimb stack traces\n\ 65 g - guile stack traces\n\
66 t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\ 66 t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\
67 i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n\ 67 i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n\
68 l - sieve action logs\n\ 68 l - sieve action logs\n\
...@@ -143,47 +143,28 @@ static const char *maidag_argp_capa[] = { ...@@ -143,47 +143,28 @@ static const char *maidag_argp_capa[] = {
143 NULL 143 NULL
144 }; 144 };
145 145
146 #define D_DEFAULT "9,s"
147
148 static void 146 static void
149 set_debug_flags (const char *arg) 147 set_debug_flags (const char *arg)
150 { 148 {
151 while (*arg) 149 while (*arg)
152 { 150 {
153 if (mu_isdigit (*arg)) 151 if (mu_script_debug_flags (arg, (char**)&arg) == 0)
152 break;
153 else if (mu_isdigit (*arg))
154 debug_level = strtoul (arg, (char**)&arg, 10); 154 debug_level = strtoul (arg, (char**)&arg, 10);
155 else 155 else
156 for (; *arg && *arg != ','; arg++)
157 {
158 switch (*arg)
159 { 156 {
160 case 'g':
161 #ifdef WITH_GUILE
162 debug_guile = 1;
163 #endif
164 break;
165
166 case 't':
167 sieve_debug_flags |= MU_SIEVE_DEBUG_TRACE;
168 break;
169
170 case 'i':
171 sieve_debug_flags |= MU_SIEVE_DEBUG_INSTR;
172 break;
173
174 case 'l':
175 sieve_enable_log = 1;
176 break;
177
178 default:
179 mu_error (_("%c is not a valid debug flag"), *arg); 157 mu_error (_("%c is not a valid debug flag"), *arg);
180 break; 158 break;
181 } 159 }
182 } 160
183 if (*arg == ',') 161 if (*arg == ',')
184 arg++; 162 arg++;
185 else if (*arg) 163 else if (*arg)
164 {
186 mu_error (_("expected comma, but found %c"), *arg); 165 mu_error (_("expected comma, but found %c"), *arg);
166 exit (1);
167 }
187 } 168 }
188 } 169 }
189 170
...@@ -234,7 +215,7 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -234,7 +215,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
234 break; 215 break;
235 216
236 case 'l': 217 case 'l':
237 script_handler = script_lang_handler (arg); 218 script_handler = mu_script_lang_handler (arg);
238 if (!script_handler) 219 if (!script_handler)
239 argp_error (state, _("unknown or unsupported language: %s"), 220 argp_error (state, _("unknown or unsupported language: %s"),
240 arg); 221 arg);
...@@ -256,7 +237,7 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -256,7 +237,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
256 break; 237 break;
257 238
258 case 'x': 239 case 'x':
259 mu_argp_node_list_new (lst, "debug", arg ? arg : D_DEFAULT); 240 mu_argp_node_list_new (lst, "debug", arg);
260 break; 241 break;
261 242
262 case STDERR_OPTION: 243 case STDERR_OPTION:
...@@ -353,7 +334,7 @@ cb_script_language (void *data, mu_config_value_t *val) ...@@ -353,7 +334,7 @@ cb_script_language (void *data, mu_config_value_t *val)
353 { 334 {
354 if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) 335 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
355 return 1; 336 return 1;
356 script_handler = script_lang_handler (val->v.string); 337 script_handler = mu_script_lang_handler (val->v.string);
357 if (!script_handler) 338 if (!script_handler)
358 { 339 {
359 mu_error (_("unsupported language: %s"), val->v.string); 340 mu_error (_("unsupported language: %s"), val->v.string);
...@@ -457,7 +438,7 @@ struct mu_cfg_param maidag_cfg_param[] = { ...@@ -457,7 +438,7 @@ struct mu_cfg_param maidag_cfg_param[] = {
457 { "debug", mu_cfg_callback, NULL, 0, cb_debug, 438 { "debug", mu_cfg_callback, NULL, 0, cb_debug,
458 N_("Set maidag debug level. Debug level consists of one or more " 439 N_("Set maidag debug level. Debug level consists of one or more "
459 "of the following letters:\n" 440 "of the following letters:\n"
460 " g - guimb stack traces\n" 441 " g - guile stack traces\n"
461 " t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n" 442 " t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n"
462 " i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n" 443 " i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n"
463 " l - sieve action logs\n") }, 444 " l - sieve action logs\n") },
......
...@@ -94,6 +94,7 @@ ...@@ -94,6 +94,7 @@
94 #include "mailutils/libargp.h" 94 #include "mailutils/libargp.h"
95 95
96 #include "tcpwrap.h" 96 #include "tcpwrap.h"
97 #include "muscript.h"
97 98
98 /* Debug */ 99 /* Debug */
99 extern int debug_level; 100 extern int debug_level;
...@@ -177,11 +178,11 @@ typedef int (*maidag_script_fun) (mu_message_t msg, ...@@ -177,11 +178,11 @@ typedef int (*maidag_script_fun) (mu_message_t msg,
177 struct mu_auth_data *auth, 178 struct mu_auth_data *auth,
178 const char *prog); 179 const char *prog);
179 180
180 extern maidag_script_fun script_handler; 181 extern mu_script_t script_handler;
181 182
182 struct maidag_script 183 struct maidag_script
183 { 184 {
184 maidag_script_fun fun; /* Handler function */ 185 mu_script_t scr; /* Handler script */
185 const char *pat; /* Script name pattern */ 186 const char *pat; /* Script name pattern */
186 }; 187 };
187 188
......
...@@ -17,80 +17,27 @@ ...@@ -17,80 +17,27 @@
17 17
18 #include "maidag.h" 18 #include "maidag.h"
19 19
20 struct script_tab
21 {
22 char *lang;
23 char *suf;
24 maidag_script_fun fun;
25 };
26
27 struct script_tab script_tab[] = {
28 #ifdef WITH_PYTHON
29 { "python", "py\0pyc\0", python_check_msg },
30 #endif
31 { "sieve", "sv\0siv\0sieve\0", sieve_check_msg },
32 #ifdef WITH_GUILE
33 { "scheme", "scm\0", scheme_check_msg },
34 #endif
35 { NULL }
36 };
37
38 maidag_script_fun
39 script_lang_handler (const char *lang)
40 {
41 struct script_tab *p;
42
43 for (p = script_tab; p->lang; p++)
44 if (strcmp (p->lang, lang) == 0)
45 return p->fun;
46 return NULL;
47 }
48
49 maidag_script_fun
50 script_suffix_handler (const char *name)
51 {
52 struct script_tab *p;
53 char *suf;
54
55 suf = strrchr (name, '.');
56 if (!suf)
57 return NULL;
58 suf++;
59
60 for (p = script_tab; p->lang; p++)
61 {
62 char *s;
63
64 for (s = p->suf; *s; s += strlen (s) + 1)
65 if (strcmp (s, suf) == 0)
66 return p->fun;
67 }
68 return NULL;
69 }
70
71
72
73 int 20 int
74 script_register (const char *pattern) 21 script_register (const char *pattern)
75 { 22 {
76 maidag_script_fun fun; 23 mu_script_t scr;
77 struct maidag_script *scr; 24 struct maidag_script *p;
78 25
79 if (script_handler) 26 if (script_handler)
80 fun = script_handler; 27 scr = script_handler;
81 else 28 else
82 { 29 {
83 fun = script_suffix_handler (pattern); 30 scr = mu_script_suffix_handler (pattern);
84 if (!fun) 31 if (!scr)
85 return EINVAL; 32 return EINVAL;
86 } 33 }
87 34
88 scr = malloc (sizeof (*scr)); 35 p = malloc (sizeof (*p));
89 if (!scr) 36 if (!p)
90 return MU_ERR_FAILURE; 37 return MU_ERR_FAILURE;
91 38
92 scr->fun = fun; 39 p->scr = scr;
93 scr->pat = pattern; 40 p->pat = pattern;
94 41
95 if (!script_list) 42 if (!script_list)
96 { 43 {
...@@ -98,7 +45,7 @@ script_register (const char *pattern) ...@@ -98,7 +45,7 @@ script_register (const char *pattern)
98 return MU_ERR_FAILURE; 45 return MU_ERR_FAILURE;
99 } 46 }
100 47
101 if (mu_list_append (script_list, scr)) 48 if (mu_list_append (script_list, p))
102 return MU_ERR_FAILURE; 49 return MU_ERR_FAILURE;
103 50
104 return 0; 51 return 0;
...@@ -119,6 +66,7 @@ apply_script (void *item, void *data) ...@@ -119,6 +66,7 @@ apply_script (void *item, void *data)
119 char *progfile; 66 char *progfile;
120 int rc; 67 int rc;
121 struct stat st; 68 struct stat st;
69 mu_script_descr_t sd;
122 70
123 progfile = mu_expand_path_pattern (scr->pat, clos->auth->name); 71 progfile = mu_expand_path_pattern (scr->pat, clos->auth->name);
124 if (stat (progfile, &st)) 72 if (stat (progfile, &st))
...@@ -131,7 +79,21 @@ apply_script (void *item, void *data) ...@@ -131,7 +79,21 @@ apply_script (void *item, void *data)
131 return 0; 79 return 0;
132 } 80 }
133 81
134 rc = scr->fun (clos->msg, clos->auth, progfile); 82 rc = mu_script_init (scr->scr, progfile, &sd);
83 if (rc)
84 mu_error (_("initialization of script %s failed: %s"),
85 progfile, mu_strerror (rc));
86 else
87 {
88 if (sieve_enable_log)
89 mu_script_log_enable (scr->scr, sd, clos->auth->name,
90 message_id_header);
91 rc = mu_script_process_msg (scr->scr, sd, clos->msg);
92 if (rc)
93 mu_error (_("script %s failed: %s"), progfile, mu_strerror (rc));
94 mu_script_done (scr->scr, sd);
95 }
96
135 free (progfile); 97 free (progfile);
136 98
137 if (rc == 0) 99 if (rc == 0)
......
...@@ -125,6 +125,27 @@ pick_SOURCES = pick.c pick.h pick-gram.c pick-gram.h ...@@ -125,6 +125,27 @@ pick_SOURCES = pick.c pick.h pick-gram.c pick-gram.h
125 YLWRAP = $(SHELL) $(mu_aux_dir)/gylwrap 125 YLWRAP = $(SHELL) $(mu_aux_dir)/gylwrap
126 AM_YFLAGS=-vt 126 AM_YFLAGS=-vt
127 127
128 inc_LDADD = \
129 ./libmh.a\
130 ../lib/libmuaux.a\
131 ../lib/libmuscript.a\
132 @LIBMU_SCM@ @GUILE_LIBS@\
133 @LIBMU_SCM_DEPS@\
134 @MU_LIB_PY@ @PYTHON_LIBS@\
135 ${MU_LIB_SIEVE}\
136 ${MU_LIB_MBOX}\
137 ${MU_LIB_IMAP}\
138 ${MU_LIB_POP}\
139 ${MU_LIB_MH}\
140 ${MU_LIB_NNTP}\
141 ${MU_LIB_MAILDIR}\
142 ${MU_LIB_MAILER}\
143 ${MU_LIB_AUTH}\
144 @MU_AUTHLIBS@\
145 ${MU_LIB_MAILUTILS}\
146 @MU_COMMON_LIBRARIES@
147
148
128 pick-gram.c pick-gram.h: $(srcdir)/pick.y 149 pick-gram.c pick-gram.h: $(srcdir)/pick.y
129 $(YLWRAP) "$(YACC) $(AM_YFLAGS) -d" $< \ 150 $(YLWRAP) "$(YACC) $(AM_YFLAGS) -d" $< \
130 y.tab.c pick-gram.c y.tab.h pick-gram.h \ 151 y.tab.c pick-gram.c y.tab.h pick-gram.h \
......
...@@ -18,9 +18,15 @@ ...@@ -18,9 +18,15 @@
18 /* MH inc command */ 18 /* MH inc command */
19 19
20 #include <mh.h> 20 #include <mh.h>
21 #include "muscript.h"
21 22
22 static char doc[] = N_("GNU MH inc")"\v" 23 static char doc[] = N_("GNU MH inc")"\v"
23 N_("Use -help to obtain the list of traditional MH options."); 24 N_("Debug flags are:\n\
25 g - guile stack traces\n\
26 t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\
27 i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n\
28 l - sieve action logs\n\n\
29 Use -help to obtain the list of traditional MH options.");
24 static char args_doc[] = N_("[+FOLDER]"); 30 static char args_doc[] = N_("[+FOLDER]");
25 31
26 /* GNU options */ 32 /* GNU options */
...@@ -51,6 +57,12 @@ static struct argp_option options[] = { ...@@ -51,6 +57,12 @@ static struct argp_option options[] = {
51 N_("be quiet")}, 57 N_("be quiet")},
52 {"notify", ARG_NOTIFY,N_("BOOL"), OPTION_ARG_OPTIONAL, 58 {"notify", ARG_NOTIFY,N_("BOOL"), OPTION_ARG_OPTIONAL,
53 N_("enable biff notification"), }, 59 N_("enable biff notification"), },
60 {"language",ARG_LANG, N_("LANG"), 0,
61 N_("set language for the --script option") },
62 {"script", ARG_SCRIPT,N_("FILE"), 0,
63 N_("filter incoming messages using script FILE") },
64 {"debug", ARG_DEBUG, N_("FLAGS"), 0,
65 N_("enable debugging") },
54 { 0 } 66 { 0 }
55 }; 67 };
56 68
...@@ -67,6 +79,9 @@ struct mh_option mh_option[] = { ...@@ -67,6 +79,9 @@ struct mh_option mh_option[] = {
67 { "width", MH_OPT_ARG, "number" }, 79 { "width", MH_OPT_ARG, "number" },
68 { "notify", MH_OPT_BOOL }, 80 { "notify", MH_OPT_BOOL },
69 { "quiet" }, 81 { "quiet" },
82 { "language", MH_OPT_ARG, "lang" },
83 { "script", MH_OPT_ARG, "file" },
84 { "debug", MH_OPT_ARG, "flags" },
70 { NULL } 85 { NULL }
71 }; 86 };
72 87
...@@ -81,11 +96,14 @@ static int quiet = 0; ...@@ -81,11 +96,14 @@ static int quiet = 0;
81 static int notify = 0; 96 static int notify = 0;
82 static const char *append_folder; 97 static const char *append_folder;
83 static const char *move_to_mailbox; 98 static const char *move_to_mailbox;
99 static const char *script_file;
100 static const char *script_lang;
84 101
85 static error_t 102 static error_t
86 opt_handler (int key, char *arg, struct argp_state *state) 103 opt_handler (int key, char *arg, struct argp_state *state)
87 { 104 {
88 int rc; 105 int rc;
106 char *p;
89 107
90 switch (key) 108 switch (key)
91 { 109 {
...@@ -106,6 +124,11 @@ opt_handler (int key, char *arg, struct argp_state *state) ...@@ -106,6 +124,11 @@ opt_handler (int key, char *arg, struct argp_state *state)
106 changecur = is_true (arg); 124 changecur = is_true (arg);
107 break; 125 break;
108 126
127 case ARG_DEBUG:
128 if (mu_script_debug_flags (arg, &p))
129 argp_error (state, _("invalid debug flag near %s"), p);
130 break;
131
109 case ARG_NOCHANGECUR: 132 case ARG_NOCHANGECUR:
110 changecur = 0; 133 changecur = 0;
111 break; 134 break;
...@@ -170,6 +193,14 @@ opt_handler (int key, char *arg, struct argp_state *state) ...@@ -170,6 +193,14 @@ opt_handler (int key, char *arg, struct argp_state *state)
170 notify = is_true (arg);; 193 notify = is_true (arg);;
171 break; 194 break;
172 195
196 case ARG_LANG:
197 script_lang = arg;
198 break;
199
200 case ARG_SCRIPT:
201 script_file = arg;
202 break;
203
173 default: 204 default:
174 return ARGP_ERR_UNKNOWN; 205 return ARGP_ERR_UNKNOWN;
175 } 206 }
...@@ -196,6 +227,8 @@ struct incdat ...@@ -196,6 +227,8 @@ struct incdat
196 mu_mailbox_t output; 227 mu_mailbox_t output;
197 size_t lastmsg; 228 size_t lastmsg;
198 mh_format_t format; 229 mh_format_t format;
230 mu_script_t handler;
231 mu_script_descr_t descr;
199 }; 232 };
200 233
201 static int 234 static int
...@@ -294,6 +327,23 @@ incmbx (void *item, void *data) ...@@ -294,6 +327,23 @@ incmbx (void *item, void *data)
294 continue; 327 continue;
295 } 328 }
296 329
330 if (dp->handler)
331 {
332 mu_attribute_t attr;
333
334 if (mu_script_process_msg (dp->handler, dp->descr, imsg))
335 {
336 mu_error (_("%lu: filter failed: %s"),
337 (unsigned long) n, mu_strerror (rc));
338 continue;
339 }
340
341 mu_message_get_attribute (imsg, &attr);
342 if (mu_attribute_is_deleted (attr))
343 continue;
344 }
345
346
297 if ((rc = mu_mailbox_append_message (dp->output, imsg)) != 0) 347 if ((rc = mu_mailbox_append_message (dp->output, imsg)) != 0)
298 { 348 {
299 mu_error (_("%lu: error appending message: %s"), 349 mu_error (_("%lu: error appending message: %s"),
...@@ -383,6 +433,8 @@ main (int argc, char **argv) ...@@ -383,6 +433,8 @@ main (int argc, char **argv)
383 mh_argp_init (); 433 mh_argp_init ();
384 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, 434 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
385 opt_handler, NULL, NULL); 435 opt_handler, NULL, NULL);
436 mu_registrar_set_default_scheme ("mh");
437
386 /* Inc sets missing cur to 1 */ 438 /* Inc sets missing cur to 1 */
387 mh_mailbox_cur_default = 1; 439 mh_mailbox_cur_default = 1;
388 440
...@@ -395,6 +447,38 @@ main (int argc, char **argv) ...@@ -395,6 +447,38 @@ main (int argc, char **argv)
395 447
396 incdat.output = mh_open_folder (append_folder, 448 incdat.output = mh_open_folder (append_folder,
397 MU_STREAM_READ|MU_STREAM_APPEND|MU_STREAM_CREAT); 449 MU_STREAM_READ|MU_STREAM_APPEND|MU_STREAM_CREAT);
450
451 if (script_file)
452 {
453 if (script_lang)
454 {
455 incdat.handler = mu_script_lang_handler (script_lang);
456 if (!incdat.handler)
457 {
458 mu_error (_("unknown or unsupported language: %s"),
459 script_lang);
460 exit (1);
461 }
462 }
463 else
464 {
465 incdat.handler = mu_script_suffix_handler (script_file);
466 if (!incdat.handler)
467 {
468 mu_error (_("unknown or unsupported language: %s"),
469 script_file);
470 exit (1);
471 }
472 }
473 rc = mu_script_init (incdat.handler, script_file, &incdat.descr);
474 if (rc)
475 {
476 mu_error (_("script initialization failed: %s"),
477 mu_strerror (rc));
478 exit (1);
479 }
480 }
481
398 if (notify) 482 if (notify)
399 { 483 {
400 rc = mu_mailbox_set_notify (incdat.output, NULL); 484 rc = mu_mailbox_set_notify (incdat.output, NULL);
...@@ -424,6 +508,9 @@ main (int argc, char **argv) ...@@ -424,6 +508,9 @@ main (int argc, char **argv)
424 else 508 else
425 mu_list_foreach (input_file_list, incmbx, &incdat); 509 mu_list_foreach (input_file_list, incmbx, &incdat);
426 510
511 if (script_file)
512 mu_script_done (incdat.handler, incdat.descr);
513
427 unseen_seq = mh_global_profile_get ("Unseen-Sequence", NULL); 514 unseen_seq = mh_global_profile_get ("Unseen-Sequence", NULL);
428 if (unseen_seq && lastseen < incdat.lastmsg) 515 if (unseen_seq && lastseen < incdat.lastmsg)
429 { 516 {
......
...@@ -87,6 +87,7 @@ enum mh_arg { ...@@ -87,6 +87,7 @@ enum mh_arg {
87 ARG_HOST, 87 ARG_HOST,
88 ARG_INPLACE, 88 ARG_INPLACE,
89 ARG_INTERACTIVE, 89 ARG_INTERACTIVE,
90 ARG_LANG,
90 ARG_LBRACE, 91 ARG_LBRACE,
91 ARG_LENGTH, 92 ARG_LENGTH,
92 ARG_LIMIT, 93 ARG_LIMIT,
...@@ -166,6 +167,7 @@ enum mh_arg { ...@@ -166,6 +167,7 @@ enum mh_arg {
166 ARG_RECURSIVE, 167 ARG_RECURSIVE,
167 ARG_REORDER, 168 ARG_REORDER,
168 ARG_REVERSE, 169 ARG_REVERSE,
170 ARG_SCRIPT,
169 ARG_SEQUENCE, 171 ARG_SEQUENCE,
170 ARG_SERIALONLY, 172 ARG_SERIALONLY,
171 ARG_SHOW, 173 ARG_SHOW,
......