Rewrite scripting support in maidag.
* include/mailutils/guile.h (mu_guile_init, mu_guile_load) (mu_guile_eval, mu_guile_mailbox_apply, mu_guile_message_apply) (mu_guile_safe_exec, mu_guile_safe_proc_call): New protos. * libmu_scm/Makefile.am: Add mu_guile.c * libmu_scm/mu_guile.c: New file. * libmu_scm/mu_mailbox.c (struct mu_mailbox): Kludge: new member noclose. (mu_scm_mailbox_free): Do not close/destroy mailbox if it is marked noclose. (mu_scm_mailbox_create0): Kludge: new function. * libmu_scm/mu_message.c (mu_scm_message_print): Bugfix. * maidag/Makefile.am: Add guile.c and sieve.c. * maidag/deliver.c (maidag_stdio_delivery) [WITH_GUILE]: Remove block. (deliver_url): Call script_apply, instead of sieve_test. * maidag/maidag.c: Rewrite scripting support in a modular way. Remove options: --sieve, --source (and the corresponding config statements). Add options: --language, --script. Add configure statement: filter (block). * maidag/maidag.h (progfile_pattern, sieve_pattern): Remove. (script_list, sieve_debug_flags, message_id_header, sieve_enable_log): New prototypes. [WITH_GUILE]: Remove. (maidag_script_fun, struct maidag_script): New data type. (script_handler): New extern. (script_lang_handler, script_suffix_handler) (script_register, script_apply): New protos. (scheme_check_msg, sieve_check_msg): New protos. * maidag/script.c: Rewrite. Provide general-purpose serialized script support. * guimb/guimb.h (struct guimb_data): Remove. * guimb/main.c: Rewrite in a cleaner way, using functions from mu_guile.c. * guimb/collect.c (guimb_catch_body, guimb_catch_handler) (guimb_exit): Remove. * guimb/scm/sieve-core.scm (sieve-current-message, sieve-mailbox): Public. (sieve-run-current-message): New public function. (sieve-run): Call sieve-run-current-message for each message. * guimb/scm/sieve.scm.in (sieve-save-program): Change code generation to suit both per-mailbox and per-message invocation. This kicks mail.local out of whack. * maidag/guile.c: New file. * maidag/sieve.c: New file.
Showing
18 changed files
with
727 additions
and
367 deletions
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2000, 2001, 2002, 2005, | 2 | Copyright (C) 1999, 2000, 2001, 2002, 2005, |
3 | 2007 Free Software Foundation, Inc. | 3 | 2007, 2009 Free Software Foundation, Inc. |
4 | 4 | ||
5 | GNU Mailutils is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -191,31 +191,3 @@ collect_drop_mailbox () | ... | @@ -191,31 +191,3 @@ collect_drop_mailbox () |
191 | } | 191 | } |
192 | } | 192 | } |
193 | 193 | ||
194 | SCM | ||
195 | guimb_catch_body (void *data, mu_mailbox_t unused) | ||
196 | { | ||
197 | struct guimb_data *gd = data; | ||
198 | if (gd->program_file) | ||
199 | scm_primitive_load (scm_makfrom0str (gd->program_file)); | ||
200 | |||
201 | if (gd->program_expr) | ||
202 | scm_c_eval_string (gd->program_expr); | ||
203 | |||
204 | return SCM_BOOL_F; | ||
205 | } | ||
206 | |||
207 | SCM | ||
208 | guimb_catch_handler (void *unused, SCM tag, SCM throw_args) | ||
209 | { | ||
210 | collect_drop_mailbox (); | ||
211 | return scm_handle_by_message ("guimb", tag, throw_args); | ||
212 | } | ||
213 | |||
214 | int | ||
215 | guimb_exit (void *unused1, mu_mailbox_t unused2) | ||
216 | { | ||
217 | int rc = collect_output (); | ||
218 | collect_drop_mailbox (); | ||
219 | return rc; | ||
220 | } | ||
221 | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2000, 2001, 2002, 2005, | 2 | Copyright (C) 1999, 2000, 2001, 2002, 2005, |
3 | 2007 Free Software Foundation, Inc. | 3 | 2007, 2009 Free Software Foundation, Inc. |
4 | 4 | ||
5 | GNU Mailutils is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -67,12 +67,3 @@ int collect_output (void); | ... | @@ -67,12 +67,3 @@ int collect_output (void); |
67 | void util_error (const char *fmt, ...) MU_PRINTFLIKE(1, 2); | 67 | void util_error (const char *fmt, ...) MU_PRINTFLIKE(1, 2); |
68 | int util_tempfile (char **namep); | 68 | int util_tempfile (char **namep); |
69 | 69 | ||
70 | struct guimb_data | ||
71 | { | ||
72 | char *program_file; | ||
73 | char *program_expr; | ||
74 | }; | ||
75 | |||
76 | SCM guimb_catch_body (void *data, mu_mailbox_t unused); | ||
77 | SCM guimb_catch_handler (void *unused, SCM tag, SCM throw_args); | ||
78 | int guimb_exit (void *unused1, mu_mailbox_t unused2); | ... | ... |
... | @@ -146,18 +146,20 @@ static const char *guimb_argp_capa[] = { | ... | @@ -146,18 +146,20 @@ static const char *guimb_argp_capa[] = { |
146 | NULL | 146 | NULL |
147 | }; | 147 | }; |
148 | 148 | ||
149 | const char *main_sym = "mailutils-main"; | ||
150 | |||
149 | int | 151 | int |
150 | main (int argc, char *argv[]) | 152 | main (int argc, char *argv[]) |
151 | { | 153 | { |
154 | int rc; | ||
152 | int c = argc; | 155 | int c = argc; |
153 | int index; | 156 | int index; |
154 | mu_guimb_param_t param; | ||
155 | struct guimb_data gd; | ||
156 | 157 | ||
157 | /* Native Language Support */ | 158 | /* Native Language Support */ |
158 | MU_APP_INIT_NLS (); | 159 | MU_APP_INIT_NLS (); |
159 | 160 | ||
160 | append_arg (""); | 161 | /* Register the desired formats. */ |
162 | mu_register_all_formats (); | ||
161 | 163 | ||
162 | mu_argp_init (program_version, NULL); | 164 | mu_argp_init (program_version, NULL); |
163 | if (mu_app_init (&argp, guimb_argp_capa, NULL, argc, argv, 0, &index, &c)) | 165 | if (mu_app_init (&argp, guimb_argp_capa, NULL, argc, argv, 0, &index, &c)) |
... | @@ -169,17 +171,12 @@ main (int argc, char *argv[]) | ... | @@ -169,17 +171,12 @@ main (int argc, char *argv[]) |
169 | if (!user_name) | 171 | if (!user_name) |
170 | user_name = who_am_i (); | 172 | user_name = who_am_i (); |
171 | 173 | ||
172 | if (program_file) | 174 | if (!program_file && !program_expr) |
173 | g_argv[0] = program_file; | ||
174 | else if (!program_expr) | ||
175 | { | 175 | { |
176 | mu_error (_("At least one of -fecs must be used. Try guimb --help for more info.")); | 176 | mu_error (_("At least one of -fecs must be used. Try guimb --help for more info.")); |
177 | exit (0); | 177 | exit (1); |
178 | } | 178 | } |
179 | 179 | ||
180 | /* Register the desired formats. */ | ||
181 | mu_register_all_formats (); | ||
182 | |||
183 | if (!argv[index]) | 180 | if (!argv[index]) |
184 | { | 181 | { |
185 | if (default_mailbox) | 182 | if (default_mailbox) |
... | @@ -202,27 +199,42 @@ main (int argc, char *argv[]) | ... | @@ -202,27 +199,42 @@ main (int argc, char *argv[]) |
202 | collect_append_file ("-"); | 199 | collect_append_file ("-"); |
203 | } | 200 | } |
204 | 201 | ||
205 | append_arg (NULL); | ||
206 | g_argc--; | ||
207 | |||
208 | /* Finish creating input mailbox */ | 202 | /* Finish creating input mailbox */ |
209 | collect_create_mailbox (); | 203 | collect_create_mailbox (); |
210 | 204 | ||
211 | gd.program_file = program_file; | 205 | mu_guile_init (debug_guile); |
212 | gd.program_expr = program_expr; | 206 | if (program_file) |
213 | 207 | mu_guile_load (program_file, g_argc, g_argv); | |
214 | param.debug_guile = debug_guile; | 208 | if (program_expr) |
215 | param.mbox = mbox; | 209 | mu_guile_eval (program_expr); |
216 | param.user_name = user_name; | 210 | |
217 | param.init = NULL; | 211 | rc = mu_guile_mailbox_apply (mbox, main_sym); |
218 | param.catch_body = guimb_catch_body; | 212 | switch (rc) |
219 | param.catch_handler = guimb_catch_handler; | 213 | { |
220 | param.next = NULL; | 214 | case 0: |
221 | param.exit = guimb_exit; | 215 | collect_output (); |
222 | param.data = &gd; | 216 | break; |
223 | mu_process_mailbox (g_argc, g_argv, ¶m); | 217 | |
224 | /*NOTREACHED*/ | 218 | case MU_ERR_NOENT: |
225 | return 0; | 219 | mu_error (_("%s not defined"), main_sym); |
220 | break; | ||
221 | |||
222 | case EINVAL: | ||
223 | mu_error (_("%s is not a procedure object"), main_sym); | ||
224 | break; | ||
225 | |||
226 | case MU_ERR_FAILURE: | ||
227 | mu_error (_("execution of %s failed"), main_sym); | ||
228 | break; | ||
229 | |||
230 | default: | ||
231 | mu_error (_("unrecognized error")); | ||
232 | break; | ||
233 | } | ||
234 | |||
235 | collect_drop_mailbox (); | ||
236 | |||
237 | return !!rc; | ||
226 | } | 238 | } |
227 | 239 | ||
228 | char * | 240 | char * | ... | ... |
... | @@ -457,8 +457,15 @@ | ... | @@ -457,8 +457,15 @@ |
457 | (lambda args #f))) | 457 | (lambda args #f))) |
458 | 458 | ||
459 | ;;; Sieve-main | 459 | ;;; Sieve-main |
460 | (define sieve-mailbox #f) | 460 | (define-public sieve-mailbox #f) |
461 | (define sieve-current-message #f) | 461 | (define-public sieve-current-message #f) |
462 | |||
463 | (define-public (sieve-run-current-message thunk) | ||
464 | (and (catch 'sieve-stop | ||
465 | thunk | ||
466 | (lambda args | ||
467 | #f)) | ||
468 | (sieve-verbose-print "IMPLICIT KEEP"))) | ||
462 | 469 | ||
463 | (define (sieve-run thunk) | 470 | (define (sieve-run thunk) |
464 | (if (not sieve-my-email) | 471 | (if (not sieve-my-email) |
... | @@ -470,11 +477,7 @@ | ... | @@ -470,11 +477,7 @@ |
470 | ((> n count) #f) | 477 | ((> n count) #f) |
471 | (set! sieve-current-message | 478 | (set! sieve-current-message |
472 | (mu-mailbox-get-message sieve-mailbox n)) | 479 | (mu-mailbox-get-message sieve-mailbox n)) |
473 | (and (catch 'sieve-stop | 480 | (sieve-run-current-message thunk)) |
474 | thunk | ||
475 | (lambda args | ||
476 | #f)) | ||
477 | (sieve-verbose-print "IMPLICIT KEEP"))) | ||
478 | (sieve-close-mailboxes))) | 481 | (sieve-close-mailboxes))) |
479 | 482 | ||
480 | (define (sieve-command-line) | 483 | (define (sieve-command-line) | ... | ... |
1 | #! %GUILE_BINDIR%/guile -s | 1 | #! %GUILE_BINDIR%/guile -s |
2 | # Emacs, its -*- scheme -*- | 2 | # Emacs, it's -*- scheme -*- |
3 | !# | 3 | !# |
4 | ;;;; GNU Mailutils -- a suite of utilities for electronic mail | 4 | ;;;; GNU Mailutils -- a suite of utilities for electronic mail |
5 | ;;;; Copyright (C) 1999, 2000, 2001, 2006, 2007 Free Software Foundation, Inc. | 5 | ;;;; Copyright (C) 1999, 2000, 2001, 2006, 2007, |
6 | ;;;; 2009 Free Software Foundation, Inc. | ||
6 | ;;;; | 7 | ;;;; |
7 | ;;;; GNU Mailutils is free software; you can redistribute it and/or modify | 8 | ;;;; GNU Mailutils is free software; you can redistribute it and/or modify |
8 | ;;;; it under the terms of the GNU General Public License as published by | 9 | ;;;; it under the terms of the GNU General Public License as published by |
... | @@ -931,11 +932,15 @@ | ... | @@ -931,11 +932,15 @@ |
931 | outfile | 932 | outfile |
932 | (lambda () | 933 | (lambda () |
933 | (display "#! ") | 934 | (display "#! ") |
934 | (if guimb-header | 935 | (cond |
935 | (display "/home/gray/alpha/bin/guimb -s\n") | 936 | (guimb-header |
936 | (display "/usr/bin/guile -s\n")) | 937 | (display "/home/gray/alpha/bin/guimb -s\n")) |
938 | (else | ||
939 | (display "/bin/sh\n\ | ||
940 | # aside from this initial boilerplate, this is actually -*- scheme -*- code\n\ | ||
941 | exec ${GUILE-guile} -l $0 -c '(mailutils-main)'\n"))) | ||
937 | (display (string-append | 942 | (display (string-append |
938 | "# Guile mailbox parser made from " filename)) | 943 | "# This Guile mailbox parser was made from " filename)) |
939 | (newline) | 944 | (newline) |
940 | (display "# by sieve.scm, GNU %PACKAGE% %VERSION%\n!#") | 945 | (display "# by sieve.scm, GNU %PACKAGE% %VERSION%\n!#") |
941 | (newline) | 946 | (newline) |
... | @@ -958,12 +963,22 @@ | ... | @@ -958,12 +963,22 @@ |
958 | (newline) | 963 | (newline) |
959 | (if request-verbose | 964 | (if request-verbose |
960 | (display "(set! sieve-verbose #t)\n")) | 965 | (display "(set! sieve-verbose #t)\n")) |
961 | (display "(sieve-main ") | 966 | (display "(define (sieve-filter-thunk) ") |
967 | |||
968 | (sieve-code-print-list (car sieve-code-list)) | ||
969 | (display ")\n\n") | ||
970 | |||
971 | (display "(define (mailutils-main . rest)\n") | ||
972 | (display " (sieve-main sieve-filter-thunk))\n\n") | ||
973 | |||
974 | (display "(define (mailutils-check-message msg)\n\ | ||
975 | (set! sieve-current-message msg)\n\ | ||
976 | (sieve-run-current-message sieve-filter-thunk))\n") | ||
962 | 977 | ||
963 | (sieve-code-print-list | 978 | (display "\n\ |
964 | (append '(lambda ()) | 979 | ;;;; Local Variables:\n\ |
965 | sieve-code-list)) | 980 | ;;;; buffer-read-only: t\n\ |
966 | (display ")")))) | 981 | ;;;; End:\n")))) |
967 | 982 | ||
968 | ;;;; | 983 | ;;;; |
969 | 984 | ... | ... |
... | @@ -69,9 +69,19 @@ extern SCM mu_port_make_from_stream (SCM msg, mu_stream_t stream, long mode); | ... | @@ -69,9 +69,19 @@ extern SCM mu_port_make_from_stream (SCM msg, mu_stream_t stream, long mode); |
69 | extern void mu_scm_mime_init (void); | 69 | extern void mu_scm_mime_init (void); |
70 | extern void mu_scm_message_add_owner (SCM MESG, SCM owner); | 70 | extern void mu_scm_message_add_owner (SCM MESG, SCM owner); |
71 | 71 | ||
72 | extern void mu_scm_mutil_init (void); | ||
73 | |||
72 | extern void mu_process_mailbox (int argc, char *argv[], mu_guimb_param_t *param); | 74 | extern void mu_process_mailbox (int argc, char *argv[], mu_guimb_param_t *param); |
73 | 75 | ||
74 | extern void mu_scm_mutil_init (void); | 76 | extern void mu_guile_init (int debug); |
77 | extern int mu_guile_load (char *filename, int argc, char **argv); | ||
78 | extern int mu_guile_eval (const char *string); | ||
79 | extern int mu_guile_mailbox_apply (mu_mailbox_t mbx, char *funcname); | ||
80 | extern int mu_guile_message_apply (mu_message_t msg, char *funcname); | ||
81 | |||
82 | extern int mu_guile_safe_exec (SCM (*handler) (void *data), void *data, | ||
83 | SCM *result); | ||
84 | extern int mu_guile_safe_proc_call (SCM proc, SCM arglist, SCM *presult); | ||
75 | 85 | ||
76 | #ifdef __cplusplus | 86 | #ifdef __cplusplus |
77 | } | 87 | } | ... | ... |
... | @@ -26,6 +26,7 @@ EXTRA_LTLIBRARIES=libmu_scm.la | ... | @@ -26,6 +26,7 @@ EXTRA_LTLIBRARIES=libmu_scm.la |
26 | C_SRCS=\ | 26 | C_SRCS=\ |
27 | mu_address.c\ | 27 | mu_address.c\ |
28 | mu_body.c\ | 28 | mu_body.c\ |
29 | mu_guile.c\ | ||
29 | mu_guimb.c\ | 30 | mu_guimb.c\ |
30 | mu_mailbox.c\ | 31 | mu_mailbox.c\ |
31 | mu_message.c\ | 32 | mu_message.c\ | ... | ... |
libmu_scm/mu_guile.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2009 Free Software Foundation, Inc. | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Lesser General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 3 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Lesser General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Lesser General | ||
15 | Public License along with this library; if not, write to the | ||
16 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
17 | Boston, MA 02110-1301 USA */ | ||
18 | |||
19 | #include "mu_scm.h" | ||
20 | |||
21 | static SCM | ||
22 | eval_catch_body (void *list) | ||
23 | { | ||
24 | return scm_primitive_eval ((SCM)list); | ||
25 | } | ||
26 | |||
27 | static SCM | ||
28 | eval_catch_handler (void *data, SCM tag, SCM throw_args) | ||
29 | { | ||
30 | scm_handle_by_message_noexit ("mailutils", tag, throw_args); | ||
31 | longjmp (*(jmp_buf*)data, 1); | ||
32 | } | ||
33 | |||
34 | struct scheme_exec_data | ||
35 | { | ||
36 | SCM (*handler) (void *data); | ||
37 | void *data; | ||
38 | SCM result; | ||
39 | }; | ||
40 | |||
41 | static SCM | ||
42 | scheme_safe_exec_body (void *data) | ||
43 | { | ||
44 | struct scheme_exec_data *ed = data; | ||
45 | ed->result = ed->handler (ed->data); | ||
46 | return SCM_BOOL_F; | ||
47 | } | ||
48 | |||
49 | int | ||
50 | mu_guile_safe_exec (SCM (*handler) (void *data), void *data, SCM *result) | ||
51 | { | ||
52 | jmp_buf jmp_env; | ||
53 | struct scheme_exec_data ed; | ||
54 | |||
55 | if (setjmp (jmp_env)) | ||
56 | return 1; | ||
57 | ed.handler = handler; | ||
58 | ed.data = data; | ||
59 | scm_internal_lazy_catch (SCM_BOOL_T, | ||
60 | scheme_safe_exec_body, (void*)&ed, | ||
61 | eval_catch_handler, &jmp_env); | ||
62 | if (result) | ||
63 | *result = ed.result; | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | |||
68 | |||
69 | SCM | ||
70 | lookup_handler (void *data) | ||
71 | { | ||
72 | const char *symbol = (const char *)data; | ||
73 | return MU_SCM_SYMBOL_VALUE (symbol); | ||
74 | } | ||
75 | |||
76 | int | ||
77 | mu_guile_sym_lookup (const char *symbol, SCM *result) | ||
78 | { | ||
79 | return mu_guile_safe_exec (lookup_handler, (void*) symbol, result); | ||
80 | } | ||
81 | |||
82 | |||
83 | int | ||
84 | mu_guile_safe_proc_call (SCM proc, SCM arglist, SCM *presult) | ||
85 | { | ||
86 | jmp_buf jmp_env; | ||
87 | SCM cell, result; | ||
88 | |||
89 | if (setjmp (jmp_env)) | ||
90 | return 1; | ||
91 | |||
92 | cell = scm_cons (proc, arglist); | ||
93 | result = scm_internal_lazy_catch (SCM_BOOL_T, | ||
94 | eval_catch_body, cell, | ||
95 | eval_catch_handler, &jmp_env); | ||
96 | if (presult) | ||
97 | *presult = result; | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | |||
102 | |||
103 | void | ||
104 | mu_guile_init (int debug) | ||
105 | { | ||
106 | scm_init_guile (); | ||
107 | scm_load_goops (); | ||
108 | |||
109 | if (debug) | ||
110 | { | ||
111 | SCM_DEVAL_P = 1; | ||
112 | SCM_BACKTRACE_P = 1; | ||
113 | SCM_RECORD_POSITIONS_P = 1; | ||
114 | SCM_RESET_DEBUG_MODE; | ||
115 | } | ||
116 | mu_scm_init (); | ||
117 | } | ||
118 | |||
119 | |||
120 | struct load_closure | ||
121 | { | ||
122 | char *filename; | ||
123 | int argc; | ||
124 | char **argv; | ||
125 | }; | ||
126 | |||
127 | static SCM | ||
128 | load_path_handler (void *data) | ||
129 | { | ||
130 | struct load_closure *lp = data; | ||
131 | |||
132 | scm_set_program_arguments (lp->argc, lp->argv, lp->filename); | ||
133 | scm_primitive_load (scm_makfrom0str (lp->filename)); | ||
134 | return SCM_UNDEFINED; | ||
135 | } | ||
136 | |||
137 | int | ||
138 | mu_guile_load (char *filename, int argc, char **argv) | ||
139 | { | ||
140 | struct load_closure lc; | ||
141 | lc.filename = filename; | ||
142 | lc.argc = argc; | ||
143 | lc.argv = argv; | ||
144 | return mu_guile_safe_exec (load_path_handler, &lc, NULL); | ||
145 | } | ||
146 | |||
147 | static SCM | ||
148 | eval_handler (void *data) | ||
149 | { | ||
150 | const char *string = data; | ||
151 | scm_c_eval_string (string); | ||
152 | return SCM_UNDEFINED; | ||
153 | } | ||
154 | |||
155 | int | ||
156 | mu_guile_eval (const char *string) | ||
157 | { | ||
158 | return mu_guile_safe_exec (eval_handler, (void*) string, NULL); | ||
159 | } | ||
160 | |||
161 | |||
162 | /* See comment on this function in mu_mailbox.c */ | ||
163 | extern SCM mu_scm_mailbox_create0 (mu_mailbox_t mbox, int noclose); | ||
164 | |||
165 | int | ||
166 | mu_guile_mailbox_apply (mu_mailbox_t mbx, char *funcname) | ||
167 | { | ||
168 | SCM proc; | ||
169 | |||
170 | if (mu_guile_sym_lookup (funcname, &proc)) | ||
171 | return MU_ERR_NOENT; | ||
172 | if (scm_procedure_p (proc) != SCM_BOOL_T) | ||
173 | return EINVAL; | ||
174 | |||
175 | if (mu_guile_safe_proc_call (proc, | ||
176 | scm_list_1 (mu_scm_mailbox_create0 (mbx, 1)), | ||
177 | NULL)) | ||
178 | return MU_ERR_FAILURE; | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | int | ||
184 | mu_guile_message_apply (mu_message_t msg, char *funcname) | ||
185 | { | ||
186 | SCM proc; | ||
187 | |||
188 | if (mu_guile_sym_lookup (funcname, &proc)) | ||
189 | return MU_ERR_NOENT; | ||
190 | if (scm_procedure_p (proc) != SCM_BOOL_T) | ||
191 | return EINVAL; | ||
192 | |||
193 | if (mu_guile_safe_proc_call (proc, | ||
194 | scm_list_1 (mu_scm_message_create (SCM_BOOL_F, msg)), | ||
195 | NULL)) | ||
196 | return MU_ERR_FAILURE; | ||
197 | |||
198 | return 0; | ||
199 | } |
... | @@ -25,6 +25,7 @@ long mailbox_tag; | ... | @@ -25,6 +25,7 @@ long mailbox_tag; |
25 | struct mu_mailbox | 25 | struct mu_mailbox |
26 | { | 26 | { |
27 | mu_mailbox_t mbox; /* Mailbox */ | 27 | mu_mailbox_t mbox; /* Mailbox */ |
28 | int noclose; | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | /* SMOB functions: */ | 31 | /* SMOB functions: */ |
... | @@ -38,8 +39,11 @@ static scm_sizet | ... | @@ -38,8 +39,11 @@ static scm_sizet |
38 | mu_scm_mailbox_free (SCM mailbox_smob) | 39 | mu_scm_mailbox_free (SCM mailbox_smob) |
39 | { | 40 | { |
40 | struct mu_mailbox *mum = (struct mu_mailbox *) SCM_CDR (mailbox_smob); | 41 | struct mu_mailbox *mum = (struct mu_mailbox *) SCM_CDR (mailbox_smob); |
42 | if (!mum->noclose) | ||
43 | { | ||
41 | mu_mailbox_close (mum->mbox); | 44 | mu_mailbox_close (mum->mbox); |
42 | mu_mailbox_destroy (&mum->mbox); | 45 | mu_mailbox_destroy (&mum->mbox); |
46 | } | ||
43 | free (mum); | 47 | free (mum); |
44 | /* NOTE: Currently there is no way for this function to return the | 48 | /* NOTE: Currently there is no way for this function to return the |
45 | amount of memory *actually freed* by mu_mailbox_destroy */ | 49 | amount of memory *actually freed* by mu_mailbox_destroy */ |
... | @@ -85,16 +89,38 @@ mu_scm_mailbox_print (SCM mailbox_smob, SCM port, scm_print_state * pstate) | ... | @@ -85,16 +89,38 @@ mu_scm_mailbox_print (SCM mailbox_smob, SCM port, scm_print_state * pstate) |
85 | 89 | ||
86 | /* Internal functions */ | 90 | /* Internal functions */ |
87 | 91 | ||
92 | /* There are two C interfaces for creating mailboxes in Scheme. | ||
93 | The first one, mu_scm_mailbox_create0, allows to set `noclose' | ||
94 | bit, which disables closing and releasing the underlying mu_mailbox_t | ||
95 | after the hosting SCM object is freed. Use this, if this mailbox | ||
96 | is referenced elsewhere. | ||
97 | |||
98 | Another one, mu_scm_mailbox_create, always create an object that | ||
99 | will cause closing the mu_mailbox_t object and releasing its memory | ||
100 | after the hosting SCM object is swept away by GC. This is the only | ||
101 | official one. | ||
102 | |||
103 | The mu_scm_mailbox_create0 function is a kludge, needed because | ||
104 | mu_mailbox_t objects don't have reference counters. When it is fixed in | ||
105 | the library, the interface will be removed. */ | ||
106 | |||
88 | SCM | 107 | SCM |
89 | mu_scm_mailbox_create (mu_mailbox_t mbox) | 108 | mu_scm_mailbox_create0 (mu_mailbox_t mbox, int noclose) |
90 | { | 109 | { |
91 | struct mu_mailbox *mum; | 110 | struct mu_mailbox *mum; |
92 | 111 | ||
93 | mum = scm_gc_malloc (sizeof (struct mu_mailbox), "mailbox"); | 112 | mum = scm_gc_malloc (sizeof (struct mu_mailbox), "mailbox"); |
94 | mum->mbox = mbox; | 113 | mum->mbox = mbox; |
114 | mum->noclose = noclose; | ||
95 | SCM_RETURN_NEWSMOB (mailbox_tag, mum); | 115 | SCM_RETURN_NEWSMOB (mailbox_tag, mum); |
96 | } | 116 | } |
97 | 117 | ||
118 | SCM | ||
119 | mu_scm_mailbox_create (mu_mailbox_t mbox) | ||
120 | { | ||
121 | return mu_scm_mailbox_create0 (mbox, 0); | ||
122 | } | ||
123 | |||
98 | int | 124 | int |
99 | mu_scm_is_mailbox (SCM scm) | 125 | mu_scm_is_mailbox (SCM scm) |
100 | { | 126 | { | ... | ... |
... | @@ -103,7 +103,7 @@ mu_scm_message_print (SCM message_smob, SCM port, scm_print_state * pstate) | ... | @@ -103,7 +103,7 @@ mu_scm_message_print (SCM message_smob, SCM port, scm_print_state * pstate) |
103 | else | 103 | else |
104 | scm_puts ("UNKNOWN", port); | 104 | scm_puts ("UNKNOWN", port); |
105 | 105 | ||
106 | if (mu_envelope_sget_date (env, &buffer) == 0 | 106 | if (mu_envelope_sget_date (env, &p) == 0 |
107 | && mu_parse_ctime_date_time (&p, &tm, &tz) == 0) | 107 | && mu_parse_ctime_date_time (&p, &tm, &tz) == 0) |
108 | { | 108 | { |
109 | strftime (datebuf, sizeof (datebuf), "%a %b %e %H:%M", &tm); | 109 | strftime (datebuf, sizeof (datebuf), "%a %b %e %H:%M", &tm); | ... | ... |
... | @@ -21,11 +21,13 @@ sbin_PROGRAMS=maidag | ... | @@ -21,11 +21,13 @@ sbin_PROGRAMS=maidag |
21 | maidag_SOURCES=\ | 21 | maidag_SOURCES=\ |
22 | deliver.c\ | 22 | deliver.c\ |
23 | forward.c\ | 23 | forward.c\ |
24 | guile.c\ | ||
24 | lmtp.c\ | 25 | lmtp.c\ |
25 | maidag.c\ | 26 | maidag.c\ |
26 | maidag.h\ | 27 | maidag.h\ |
27 | mailtmp.c\ | 28 | mailtmp.c\ |
28 | mailquota.c\ | 29 | mailquota.c\ |
30 | sieve.c\ | ||
29 | script.c\ | 31 | script.c\ |
30 | util.c | 32 | util.c |
31 | 33 | ... | ... |
... | @@ -72,19 +72,6 @@ maidag_stdio_delivery (int argc, char **argv) | ... | @@ -72,19 +72,6 @@ maidag_stdio_delivery (int argc, char **argv) |
72 | if (multiple_delivery) | 72 | if (multiple_delivery) |
73 | multiple_delivery = argc > 1; | 73 | multiple_delivery = argc > 1; |
74 | 74 | ||
75 | #ifdef WITH_GUILE | ||
76 | if (progfile_pattern) | ||
77 | { | ||
78 | struct mda_data mda_data; | ||
79 | |||
80 | memset (&mda_data, 0, sizeof mda_data); | ||
81 | mda_data.mbox = mbox; | ||
82 | mda_data.argv = argv; | ||
83 | mda_data.progfile_pattern = progfile_pattern; | ||
84 | return prog_mda (&mda_data); | ||
85 | } | ||
86 | #endif | ||
87 | |||
88 | for (; *argv; argv++) | 75 | for (; *argv; argv++) |
89 | mda (mbox, *argv); | 76 | mda (mbox, *argv); |
90 | return exit_code; | 77 | return exit_code; |
... | @@ -323,7 +310,7 @@ deliver_url (mu_url_t url, mu_message_t msg, const char *name, char **errp) | ... | @@ -323,7 +310,7 @@ deliver_url (mu_url_t url, mu_message_t msg, const char *name, char **errp) |
323 | if (current_uid) | 310 | if (current_uid) |
324 | auth->change_uid = 0; | 311 | auth->change_uid = 0; |
325 | 312 | ||
326 | if (!sieve_test (auth, msg)) | 313 | if (script_apply (msg, auth)) |
327 | { | 314 | { |
328 | exit_code = EX_OK; | 315 | exit_code = EX_OK; |
329 | mu_auth_data_free (auth); | 316 | mu_auth_data_free (auth); | ... | ... |
maidag/guile.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000, 2001, 2002, 2005, | ||
3 | 2007, 2009 Free Software 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, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
18 | MA 02110-1301 USA */ | ||
19 | |||
20 | #include "maidag.h" | ||
21 | |||
22 | #ifdef WITH_GUILE | ||
23 | #include <mailutils/guile.h> | ||
24 | |||
25 | int debug_guile; | ||
26 | static int initialized; | ||
27 | |||
28 | int | ||
29 | scheme_check_msg (mu_message_t msg, struct mu_auth_data *auth, | ||
30 | const char *prog) | ||
31 | { | ||
32 | if (!initialized) | ||
33 | { | ||
34 | mu_guile_init (debug_guile); | ||
35 | initialized = 1; | ||
36 | } | ||
37 | mu_guile_load (prog, 0, NULL); | ||
38 | mu_guile_message_apply (msg, "mailutils-check-message"); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | #endif | ||
43 |
... | @@ -30,8 +30,10 @@ char *quotadbname = NULL; /* Name of mailbox quota database */ | ... | @@ -30,8 +30,10 @@ char *quotadbname = NULL; /* Name of mailbox quota database */ |
30 | char *quota_query = NULL; /* SQL query to retrieve mailbox quota */ | 30 | char *quota_query = NULL; /* SQL query to retrieve mailbox quota */ |
31 | 31 | ||
32 | char *sender_address = NULL; | 32 | char *sender_address = NULL; |
33 | char *progfile_pattern = NULL; | 33 | |
34 | char *sieve_pattern = NULL; | 34 | maidag_script_fun script_handler; |
35 | |||
36 | mu_list_t script_list; | ||
35 | 37 | ||
36 | char *forward_file = NULL; | 38 | char *forward_file = NULL; |
37 | int forward_file_checks = FWD_ALL; | 39 | int forward_file_checks = FWD_ALL; |
... | @@ -73,28 +75,40 @@ static char args_doc[] = N_("[recipient...]"); | ... | @@ -73,28 +75,40 @@ static char args_doc[] = N_("[recipient...]"); |
73 | 75 | ||
74 | static struct argp_option options[] = | 76 | static struct argp_option options[] = |
75 | { | 77 | { |
76 | { "foreground", FOREGROUND_OPTION, 0, 0, N_("Remain in foreground."), 0 }, | 78 | #define GRID 0 |
77 | { "inetd", 'i', 0, 0, N_("Run in inetd mode"), 0 }, | 79 | { NULL, 0, NULL, 0, |
80 | N_("General options"), GRID }, | ||
81 | |||
82 | { "foreground", FOREGROUND_OPTION, 0, 0, N_("Remain in foreground."), | ||
83 | GRID + 1 }, | ||
84 | { "inetd", 'i', 0, 0, N_("Run in inetd mode"), GRID + 1 }, | ||
78 | { "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL, | 85 | { "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL, |
79 | N_("Runs in daemon mode with a maximum of NUMBER children"), 0 }, | 86 | N_("Runs in daemon mode with a maximum of NUMBER children"), GRID + 1 }, |
80 | { "url", URL_OPTION, 0, 0, N_("Deliver to given URLs"), 0 }, | 87 | { "url", URL_OPTION, 0, 0, N_("Deliver to given URLs"), GRID + 1 }, |
81 | { "from", 'f', N_("EMAIL"), 0, | 88 | { "from", 'f', N_("EMAIL"), 0, |
82 | N_("Specify the sender's name") }, | 89 | N_("Specify the sender's name"), GRID + 1 }, |
83 | { NULL, 'r', NULL, OPTION_ALIAS, NULL }, | 90 | { NULL, 'r', NULL, OPTION_ALIAS, NULL }, |
84 | { "sieve", 'S', N_("PATTERN"), 0, | ||
85 | N_("Set name pattern for user-defined Sieve mail filters"), 0 }, | ||
86 | { "message-id-header", MESSAGE_ID_HEADER_OPTION, N_("STRING"), 0, | ||
87 | N_("Identify messages by the value of this header when logging Sieve actions"), 0 }, | ||
88 | #ifdef WITH_GUILE | ||
89 | { "source", 's', N_("PATTERN"), 0, | ||
90 | N_("Set name pattern for user-defined Scheme mail filters"), 0 }, | ||
91 | #endif | ||
92 | { "lmtp", LMTP_OPTION, N_("URL"), OPTION_ARG_OPTIONAL, | 91 | { "lmtp", LMTP_OPTION, N_("URL"), OPTION_ARG_OPTIONAL, |
93 | N_("Operate in LMTP mode"), 0 }, | 92 | N_("Operate in LMTP mode"), GRID + 1 }, |
94 | { "debug", 'x', N_("FLAGS"), 0, | 93 | { "debug", 'x', N_("FLAGS"), 0, |
95 | N_("Enable debugging"), 0 }, | 94 | N_("Enable debugging"), GRID + 1 }, |
96 | { "stderr", STDERR_OPTION, NULL, 0, | 95 | { "stderr", STDERR_OPTION, NULL, 0, |
97 | N_("Log to standard error"), 0 }, | 96 | N_("Log to standard error"), GRID + 1 }, |
97 | #undef GRID | ||
98 | |||
99 | #define GRID 2 | ||
100 | { NULL, 0, NULL, 0, | ||
101 | N_("Scripting options"), GRID }, | ||
102 | |||
103 | { "language", 'l', N_("STRING"), 0, | ||
104 | N_("Define scripting language for the next --script option"), | ||
105 | GRID + 1 }, | ||
106 | { "script", 's', N_("PATTERN"), 0, | ||
107 | N_("Set name pattern for user-defined mail filter"), GRID + 1 }, | ||
108 | { "message-id-header", MESSAGE_ID_HEADER_OPTION, N_("STRING"), 0, | ||
109 | N_("Use this header to identify messages when logging Sieve actions"), | ||
110 | GRID + 1 }, | ||
111 | #undef GRID | ||
98 | { NULL, 0, NULL, 0, NULL, 0 } | 112 | { NULL, 0, NULL, 0, NULL, 0 } |
99 | }; | 113 | }; |
100 | 114 | ||
... | @@ -201,21 +215,30 @@ parse_opt (int key, char *arg, struct argp_state *state) | ... | @@ -201,21 +215,30 @@ parse_opt (int key, char *arg, struct argp_state *state) |
201 | case 'r': | 215 | case 'r': |
202 | case 'f': | 216 | case 'f': |
203 | if (sender_address != NULL) | 217 | if (sender_address != NULL) |
204 | { | ||
205 | argp_error (state, _("Multiple --from options")); | 218 | argp_error (state, _("Multiple --from options")); |
206 | return EX_USAGE; | ||
207 | } | ||
208 | sender_address = arg; | 219 | sender_address = arg; |
209 | break; | 220 | break; |
210 | 221 | ||
211 | #ifdef WITH_GUILE | 222 | case 'l': |
223 | script_handler = script_lang_handler (arg); | ||
224 | if (!script_handler) | ||
225 | argp_error (state, _("Unknown or unsupported language: %s"), | ||
226 | arg); | ||
227 | break; | ||
228 | |||
212 | case 's': | 229 | case 's': |
213 | mu_argp_node_list_new (&lst, "guile-filter", arg); | 230 | switch (script_register (arg)) |
231 | { | ||
232 | case 0: | ||
214 | break; | 233 | break; |
215 | #endif | ||
216 | 234 | ||
217 | case 'S': | 235 | case EINVAL: |
218 | mu_argp_node_list_new (&lst, "sieve-filter", arg); | 236 | argp_error (state, _("%s has unknown file suffix"), arg); |
237 | break; | ||
238 | |||
239 | default: | ||
240 | argp_error (state, _("error registering script")); | ||
241 | } | ||
219 | break; | 242 | break; |
220 | 243 | ||
221 | case 'x': | 244 | case 'x': |
... | @@ -329,6 +352,54 @@ cb_forward_file_checks (mu_debug_t debug, void *data, mu_config_value_t *arg) | ... | @@ -329,6 +352,54 @@ cb_forward_file_checks (mu_debug_t debug, void *data, mu_config_value_t *arg) |
329 | return mu_cfg_string_value_cb (debug, arg, cb2_forward_file_checks, data); | 352 | return mu_cfg_string_value_cb (debug, arg, cb2_forward_file_checks, data); |
330 | } | 353 | } |
331 | 354 | ||
355 | static int | ||
356 | cb_script_language (mu_debug_t debug, void *data, mu_config_value_t *val) | ||
357 | { | ||
358 | if (mu_cfg_assert_value_type (val, MU_CFG_STRING, debug)) | ||
359 | return 1; | ||
360 | script_handler = script_lang_handler (val->v.string); | ||
361 | if (!script_handler) | ||
362 | { | ||
363 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
364 | _("Unsupported language: %s"), | ||
365 | val->v.string); | ||
366 | return 1; | ||
367 | } | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int | ||
372 | cb_script_pattern (mu_debug_t debug, void *data, mu_config_value_t *val) | ||
373 | { | ||
374 | if (mu_cfg_assert_value_type (val, MU_CFG_STRING, debug)) | ||
375 | return 1; | ||
376 | |||
377 | switch (script_register (val->v.string)) | ||
378 | { | ||
379 | case 0: | ||
380 | break; | ||
381 | |||
382 | case EINVAL: | ||
383 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
384 | _("%s has unknown file suffix"), | ||
385 | val->v.string); | ||
386 | break; | ||
387 | |||
388 | default: | ||
389 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
390 | _("error registering script")); | ||
391 | } | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | struct mu_cfg_param filter_cfg_param[] = { | ||
396 | { "language", mu_cfg_callback, NULL, 0, cb_script_language, | ||
397 | N_("Set script language.") }, | ||
398 | { "pattern", mu_cfg_callback, NULL, 0, cb_script_pattern, | ||
399 | N_("Set script pattern.") }, | ||
400 | { NULL } | ||
401 | }; | ||
402 | |||
332 | struct mu_cfg_param maidag_cfg_param[] = { | 403 | struct mu_cfg_param maidag_cfg_param[] = { |
333 | { "exit-multiple-delivery-success", mu_cfg_bool, &multiple_delivery, 0, NULL, | 404 | { "exit-multiple-delivery-success", mu_cfg_bool, &multiple_delivery, 0, NULL, |
334 | N_("In case of multiple delivery, exit with code 0 if at least one " | 405 | N_("In case of multiple delivery, exit with code 0 if at least one " |
... | @@ -347,18 +418,10 @@ struct mu_cfg_param maidag_cfg_param[] = { | ... | @@ -347,18 +418,10 @@ struct mu_cfg_param maidag_cfg_param[] = { |
347 | "sql { ... } instead."), | 418 | "sql { ... } instead."), |
348 | N_("query") }, | 419 | N_("query") }, |
349 | #endif | 420 | #endif |
350 | { "sieve-filter", mu_cfg_string, &sieve_pattern, 0, NULL, | ||
351 | N_("File name or name pattern for Sieve filter file."), | ||
352 | N_("file-or-pattern") }, | ||
353 | { "message-id-header", mu_cfg_string, &message_id_header, 0, NULL, | 421 | { "message-id-header", mu_cfg_string, &message_id_header, 0, NULL, |
354 | N_("When logging Sieve actions, identify messages by the value of " | 422 | N_("When logging Sieve actions, identify messages by the value of " |
355 | "this header."), | 423 | "this header."), |
356 | N_("name") }, | 424 | N_("name") }, |
357 | #ifdef WITH_GUILE | ||
358 | { "guile-filter", mu_cfg_string, &progfile_pattern, 0, NULL, | ||
359 | N_("File name or name pattern for Guile filter file."), | ||
360 | N_("file-or-pattern") }, | ||
361 | #endif | ||
362 | { "debug", mu_cfg_callback, NULL, 0, cb_debug, | 425 | { "debug", mu_cfg_callback, NULL, 0, cb_debug, |
363 | N_("Set maidag debug level. Debug level consists of one or more " | 426 | N_("Set maidag debug level. Debug level consists of one or more " |
364 | "of the following letters:\n" | 427 | "of the following letters:\n" |
... | @@ -388,138 +451,23 @@ struct mu_cfg_param maidag_cfg_param[] = { | ... | @@ -388,138 +451,23 @@ struct mu_cfg_param maidag_cfg_param[] = { |
388 | N_("url") }, | 451 | N_("url") }, |
389 | { "reuse-address", mu_cfg_bool, &reuse_lmtp_address, 0, NULL, | 452 | { "reuse-address", mu_cfg_bool, &reuse_lmtp_address, 0, NULL, |
390 | N_("Reuse existing address (LMTP mode). Default is \"yes\".") }, | 453 | N_("Reuse existing address (LMTP mode). Default is \"yes\".") }, |
454 | { "filter", mu_cfg_section, NULL, 0, NULL, | ||
455 | N_("Add a message filter") }, | ||
391 | { ".server", mu_cfg_section, NULL, 0, NULL, | 456 | { ".server", mu_cfg_section, NULL, 0, NULL, |
392 | N_("LMTP server configuration.") }, | 457 | N_("LMTP server configuration.") }, |
393 | TCP_WRAPPERS_CONFIG | 458 | TCP_WRAPPERS_CONFIG |
394 | { NULL } | 459 | { NULL } |
395 | }; | 460 | }; |
396 | 461 | ||
397 | |||
398 | /* Logging */ | ||
399 | |||
400 | static int | ||
401 | _sieve_debug_printer (void *unused, const char *fmt, va_list ap) | ||
402 | { | ||
403 | mu_diag_vprintf (MU_DIAG_DEBUG, fmt, ap); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static void | 462 | static void |
408 | _sieve_action_log (void *user_name, | 463 | maidag_cfg_init () |
409 | const mu_sieve_locus_t *locus, size_t msgno, | ||
410 | mu_message_t msg, | ||
411 | const char *action, const char *fmt, va_list ap) | ||
412 | { | ||
413 | int pfx = 0; | ||
414 | mu_debug_t debug; | ||
415 | |||
416 | mu_diag_get_debug (&debug); | ||
417 | mu_debug_set_locus (debug, locus->source_file, locus->source_line); | ||
418 | |||
419 | mu_diag_printf (MU_DIAG_NOTICE, _("(user %s) "), (char*) user_name); | ||
420 | if (message_id_header) | ||
421 | { | ||
422 | mu_header_t hdr = NULL; | ||
423 | char *val = NULL; | ||
424 | mu_message_get_header (msg, &hdr); | ||
425 | if (mu_header_aget_value (hdr, message_id_header, &val) == 0 | ||
426 | || mu_header_aget_value (hdr, MU_HEADER_MESSAGE_ID, &val) == 0) | ||
427 | { | ||
428 | pfx = 1; | ||
429 | mu_diag_printf (MU_DIAG_NOTICE, _("%s on msg %s"), action, val); | ||
430 | free (val); | ||
431 | } | ||
432 | } | ||
433 | |||
434 | if (!pfx) | ||
435 | { | ||
436 | size_t uid = 0; | ||
437 | mu_message_get_uid (msg, &uid); | ||
438 | mu_diag_printf (MU_DIAG_NOTICE, _("%s on msg uid %d"), action, uid); | ||
439 | } | ||
440 | |||
441 | if (fmt && strlen (fmt)) | ||
442 | { | ||
443 | mu_diag_printf (MU_DIAG_NOTICE, "; "); | ||
444 | mu_diag_vprintf (MU_DIAG_NOTICE, fmt, ap); | ||
445 | } | ||
446 | mu_diag_printf (MU_DIAG_NOTICE, "\n"); | ||
447 | mu_debug_set_locus (debug, NULL, 0); | ||
448 | } | ||
449 | |||
450 | static int | ||
451 | _sieve_parse_error (void *user_name, const char *filename, int lineno, | ||
452 | const char *fmt, va_list ap) | ||
453 | { | ||
454 | mu_debug_t debug; | ||
455 | |||
456 | mu_diag_get_debug (&debug); | ||
457 | if (filename) | ||
458 | mu_debug_set_locus (debug, filename, lineno); | ||
459 | |||
460 | mu_diag_printf (MU_DIAG_ERROR, _("(user %s) "), (char*) user_name); | ||
461 | mu_diag_vprintf (MU_DIAG_ERROR, fmt, ap); | ||
462 | mu_diag_printf (MU_DIAG_ERROR, "\n"); | ||
463 | mu_debug_set_locus (debug, NULL, 0); | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | int | ||
468 | sieve_test (struct mu_auth_data *auth, mu_message_t msg) | ||
469 | { | 464 | { |
470 | int rc = 1; | 465 | struct mu_cfg_section *section; |
471 | char *progfile; | 466 | if (mu_create_canned_section ("filter", §ion) == 0) |
472 | |||
473 | if (!sieve_pattern) | ||
474 | return 1; | ||
475 | |||
476 | progfile = mu_expand_path_pattern (sieve_pattern, auth->name); | ||
477 | if (access (progfile, R_OK)) | ||
478 | { | ||
479 | if (debug_level > 2) | ||
480 | mu_diag_output (MU_DIAG_DEBUG, _("Access to %s failed: %m"), progfile); | ||
481 | } | ||
482 | else | ||
483 | { | ||
484 | mu_sieve_machine_t mach; | ||
485 | rc = mu_sieve_machine_init (&mach, auth->name); | ||
486 | if (rc) | ||
487 | { | 467 | { |
488 | mu_error (_("Cannot initialize sieve machine: %s"), | 468 | section->docstring = N_("Add new message filter."); |
489 | mu_strerror (rc)); | 469 | mu_cfg_section_add_params (section, filter_cfg_param); |
490 | } | ||
491 | else | ||
492 | { | ||
493 | mu_sieve_set_debug (mach, _sieve_debug_printer); | ||
494 | mu_sieve_set_debug_level (mach, sieve_debug_flags); | ||
495 | mu_sieve_set_parse_error (mach, _sieve_parse_error); | ||
496 | if (sieve_enable_log) | ||
497 | mu_sieve_set_logger (mach, _sieve_action_log); | ||
498 | |||
499 | rc = mu_sieve_compile (mach, progfile); | ||
500 | if (rc == 0) | ||
501 | { | ||
502 | mu_attribute_t attr; | ||
503 | |||
504 | mu_message_get_attribute (msg, &attr); | ||
505 | mu_attribute_unset_deleted (attr); | ||
506 | if (switch_user_id (auth, 1) == 0) | ||
507 | { | ||
508 | chdir (auth->dir); | ||
509 | |||
510 | rc = mu_sieve_message (mach, msg); | ||
511 | if (rc == 0) | ||
512 | rc = mu_attribute_is_deleted (attr) == 0; | ||
513 | |||
514 | switch_user_id (auth, 0); | ||
515 | chdir ("/"); | ||
516 | } | ||
517 | mu_sieve_machine_destroy (&mach); | ||
518 | } | ||
519 | } | ||
520 | } | 470 | } |
521 | free (progfile); | ||
522 | return rc; | ||
523 | } | 471 | } |
524 | 472 | ||
525 | 473 | ||
... | @@ -557,6 +505,7 @@ main (int argc, char *argv[]) | ... | @@ -557,6 +505,7 @@ main (int argc, char *argv[]) |
557 | mu_tcpwrapper_cfg_init (); | 505 | mu_tcpwrapper_cfg_init (); |
558 | mu_acl_cfg_init (); | 506 | mu_acl_cfg_init (); |
559 | mu_m_server_cfg_init (); | 507 | mu_m_server_cfg_init (); |
508 | maidag_cfg_init (); | ||
560 | 509 | ||
561 | /* Parse command line */ | 510 | /* Parse command line */ |
562 | mu_argp_init (program_version, NULL); | 511 | mu_argp_init (program_version, NULL); | ... | ... |
... | @@ -129,8 +129,10 @@ extern char *forward_file; | ... | @@ -129,8 +129,10 @@ extern char *forward_file; |
129 | extern int forward_file_checks; | 129 | extern int forward_file_checks; |
130 | 130 | ||
131 | extern char *sender_address; | 131 | extern char *sender_address; |
132 | extern char *progfile_pattern; | 132 | extern mu_list_t script_list; |
133 | extern char *sieve_pattern; | 133 | extern char *message_id_header; |
134 | extern int sieve_debug_flags; | ||
135 | extern int sieve_enable_log; | ||
134 | 136 | ||
135 | extern mu_m_server_t server; | 137 | extern mu_m_server_t server; |
136 | extern int lmtp_mode; | 138 | extern int lmtp_mode; |
... | @@ -157,20 +159,6 @@ int deliver (mu_message_t msg, char *name, char **errp); | ... | @@ -157,20 +159,6 @@ int deliver (mu_message_t msg, char *name, char **errp); |
157 | int sieve_test (struct mu_auth_data *auth, mu_message_t msg); | 159 | int sieve_test (struct mu_auth_data *auth, mu_message_t msg); |
158 | int check_quota (struct mu_auth_data *auth, mu_off_t size, mu_off_t *rest); | 160 | int check_quota (struct mu_auth_data *auth, mu_off_t size, mu_off_t *rest); |
159 | 161 | ||
160 | #ifdef WITH_GUILE | ||
161 | struct mda_data | ||
162 | { | ||
163 | mu_mailbox_t mbox; | ||
164 | char *progfile; | ||
165 | char *progfile_pattern; | ||
166 | char **argv; | ||
167 | }; | ||
168 | |||
169 | int prog_mda (struct mda_data *data); | ||
170 | |||
171 | extern int debug_guile; | ||
172 | #endif | ||
173 | |||
174 | struct mail_tmp; | 162 | struct mail_tmp; |
175 | int mail_tmp_begin (struct mail_tmp **pmtmp, const char *from); | 163 | int mail_tmp_begin (struct mail_tmp **pmtmp, const char *from); |
176 | int mail_tmp_add_line (struct mail_tmp *mtmp, char *buf, size_t buflen); | 164 | int mail_tmp_add_line (struct mail_tmp *mtmp, char *buf, size_t buflen); |
... | @@ -188,3 +176,31 @@ enum maidag_forward_result | ... | @@ -188,3 +176,31 @@ enum maidag_forward_result |
188 | enum maidag_forward_result maidag_forward (mu_message_t msg, | 176 | enum maidag_forward_result maidag_forward (mu_message_t msg, |
189 | struct mu_auth_data *auth, | 177 | struct mu_auth_data *auth, |
190 | char *fwfile); | 178 | char *fwfile); |
179 | |||
180 | /* Scripting support */ | ||
181 | typedef int (*maidag_script_fun) (mu_message_t msg, | ||
182 | struct mu_auth_data *auth, | ||
183 | const char *prog); | ||
184 | |||
185 | extern maidag_script_fun script_handler; | ||
186 | |||
187 | struct maidag_script | ||
188 | { | ||
189 | maidag_script_fun fun; /* Handler function */ | ||
190 | const char *pat; /* Script name pattern */ | ||
191 | }; | ||
192 | |||
193 | maidag_script_fun script_lang_handler (const char *lang); | ||
194 | maidag_script_fun script_suffix_handler (const char *name); | ||
195 | int script_register (const char *pattern); | ||
196 | int script_apply (mu_message_t msg, struct mu_auth_data *auth); | ||
197 | |||
198 | /* guile.c */ | ||
199 | extern int debug_guile; | ||
200 | int scheme_check_msg (mu_message_t msg, struct mu_auth_data *auth, | ||
201 | const char *prog); | ||
202 | |||
203 | /* sieve.c */ | ||
204 | int sieve_check_msg (mu_message_t msg, struct mu_auth_data *auth, | ||
205 | const char *prog); | ||
206 | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2000, 2001, 2002, 2005, | 2 | Copyright (C) 1999, 2000, 2001, 2002, 2005, |
3 | 2007 Free Software Foundation, Inc. | 3 | 2007, 2009 Free Software Foundation, Inc. |
4 | 4 | ||
5 | GNU Mailutils is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -19,129 +19,149 @@ | ... | @@ -19,129 +19,149 @@ |
19 | 19 | ||
20 | #include "maidag.h" | 20 | #include "maidag.h" |
21 | 21 | ||
22 | #ifdef WITH_GUILE | 22 | struct script_tab |
23 | #include <mailutils/guile.h> | 23 | { |
24 | 24 | char *lang; | |
25 | int debug_guile; | 25 | char *suf; |
26 | maidag_script_fun fun; | ||
27 | }; | ||
26 | 28 | ||
27 | SCM mda_catch_body (void *data, mu_mailbox_t mbox); | 29 | struct script_tab script_tab[] = { |
28 | SCM mda_catch_handler (void *unused, SCM tag, SCM throw_args); | 30 | { "sieve", "sv\0siv\0sieve\0", sieve_check_msg }, |
29 | int mda_next (void *data, mu_mailbox_t mbox); | 31 | #ifdef WITH_GUILE |
30 | int mda_exit (void *data, mu_mailbox_t mbox); | 32 | { "scheme", "scm\0", scheme_check_msg }, |
31 | int mda_init (void *data); | 33 | #endif |
34 | { NULL } | ||
35 | }; | ||
32 | 36 | ||
33 | int | 37 | maidag_script_fun |
34 | prog_mda (struct mda_data *data) | 38 | script_lang_handler (const char *lang) |
35 | { | 39 | { |
36 | char *x_argv[2]; | 40 | struct script_tab *p; |
37 | mu_guimb_param_t param; | ||
38 | |||
39 | x_argv[0] = "maidag"; | ||
40 | x_argv[1] = NULL; | ||
41 | |||
42 | param.debug_guile = debug_guile; | ||
43 | param.mbox = data->mbox; | ||
44 | param.user_name = NULL; | ||
45 | param.init = mda_init; | ||
46 | param.catch_body = mda_catch_body; | ||
47 | param.catch_handler = mda_catch_handler; | ||
48 | param.next = mda_next; | ||
49 | param.exit = mda_exit; | ||
50 | param.data = data; | ||
51 | |||
52 | mu_process_mailbox (1, x_argv, ¶m); | ||
53 | return EX_UNAVAILABLE; | ||
54 | } | ||
55 | 41 | ||
56 | int | 42 | for (p = script_tab; p->lang; p++) |
57 | mda_init (void *data) | 43 | if (strcmp (p->lang, lang) == 0) |
58 | { | 44 | return p->fun; |
59 | struct mda_data *md = data; | 45 | return NULL; |
60 | md->progfile = mu_expand_path_pattern (md->progfile_pattern, md->argv[0]); | ||
61 | return 0; | ||
62 | } | 46 | } |
63 | 47 | ||
64 | static void | 48 | maidag_script_fun |
65 | mda_switch_to_user (struct mda_data *md) | 49 | script_suffix_handler (const char *name) |
66 | { | 50 | { |
67 | struct mu_auth_data *auth = NULL; | 51 | struct script_tab *p; |
52 | char *suf; | ||
68 | 53 | ||
69 | if (md && *md->argv != NULL) | 54 | suf = strrchr (name, '.'); |
70 | auth = mu_get_auth_by_name (*md->argv); | 55 | if (!suf) |
56 | return NULL; | ||
57 | suf++; | ||
71 | 58 | ||
72 | if (auth) | 59 | for (p = script_tab; p->lang; p++) |
73 | { | 60 | { |
74 | switch_user_id (auth, 1); | 61 | char *s; |
75 | chdir (auth->dir); | 62 | |
76 | mu_auth_data_free (auth); | 63 | for (s = p->suf; *s; s += strlen (s) + 1) |
77 | } | 64 | if (strcmp (s, suf) == 0) |
78 | else | 65 | return p->fun; |
79 | { | ||
80 | switch_user_id (auth, 0); | ||
81 | chdir ("/"); | ||
82 | } | 66 | } |
67 | return NULL; | ||
83 | } | 68 | } |
84 | 69 | ||
85 | SCM | 70 | |
86 | mda_catch_body (void *data, mu_mailbox_t mbox) | 71 | |
72 | int | ||
73 | script_register (const char *pattern) | ||
87 | { | 74 | { |
88 | struct mda_data *md = data; | 75 | maidag_script_fun fun; |
89 | mu_message_t mesg = NULL; | 76 | struct maidag_script *scr; |
90 | mu_attribute_t attr = NULL; | ||
91 | 77 | ||
92 | if (access (md->progfile, R_OK)) | 78 | if (script_handler) |
79 | fun = script_handler; | ||
80 | else | ||
93 | { | 81 | { |
94 | if (debug_level > 2) | 82 | fun = script_suffix_handler (pattern); |
95 | mu_diag_output (MU_DIAG_DEBUG, _("Access to %s failed: %m"), md->progfile); | 83 | if (!fun) |
84 | return EINVAL; | ||
96 | } | 85 | } |
97 | else | 86 | |
87 | scr = malloc (sizeof (*scr)); | ||
88 | if (!scr) | ||
89 | return MU_ERR_FAILURE; | ||
90 | |||
91 | scr->fun = fun; | ||
92 | scr->pat = pattern; | ||
93 | |||
94 | if (!script_list) | ||
98 | { | 95 | { |
99 | mda_switch_to_user (md); | 96 | if (mu_list_create (&script_list)) |
100 | scm_primitive_load (scm_makfrom0str (md->progfile)); | 97 | return MU_ERR_FAILURE; |
101 | } | 98 | } |
102 | 99 | ||
103 | mu_mailbox_get_message (mbox, 1, &mesg); | 100 | if (mu_list_append (script_list, scr)) |
104 | mu_message_get_attribute (mesg, &attr); | 101 | return MU_ERR_FAILURE; |
105 | if (mu_attribute_is_deleted (attr)) | ||
106 | return SCM_BOOL_F; | ||
107 | 102 | ||
108 | mda_switch_to_user (NULL); | 103 | return 0; |
109 | mda (md->mbox, md->argv[0]); | ||
110 | return SCM_BOOL_F; | ||
111 | } | 104 | } |
112 | 105 | ||
113 | SCM | 106 | |
114 | mda_catch_handler (void *data, SCM tag, SCM throw_args) | 107 | struct apply_script_closure |
115 | { | 108 | { |
116 | exit_code = EX_TEMPFAIL; | 109 | struct mu_auth_data *auth; |
117 | return scm_handle_by_message_noexit ("mail.local", tag, throw_args); | 110 | mu_message_t msg; |
118 | } | 111 | }; |
119 | 112 | ||
120 | int | 113 | static int |
121 | mda_next (void *data, mu_mailbox_t mbox) | 114 | apply_script (void *item, void *data) |
122 | { | 115 | { |
123 | struct mda_data *md = data; | 116 | struct maidag_script *scr = item; |
124 | mu_message_t mesg = NULL; | 117 | struct apply_script_closure *clos = data; |
125 | mu_attribute_t attr = NULL; | 118 | char *progfile; |
119 | int rc; | ||
126 | 120 | ||
127 | md->argv++; | 121 | progfile = mu_expand_path_pattern (scr->pat, clos->auth->name); |
128 | if (*md->argv == NULL) | 122 | if (access (progfile, R_OK)) |
123 | { | ||
124 | if (debug_level > 2) | ||
125 | mu_diag_output (MU_DIAG_DEBUG, _("Access to %s failed: %m"), progfile); | ||
126 | free (progfile); | ||
129 | return 0; | 127 | return 0; |
130 | if (md->progfile) | 128 | } |
131 | free (md->progfile); | ||
132 | md->progfile = mu_expand_path_pattern (md->progfile_pattern, *md->argv); | ||
133 | 129 | ||
134 | mu_mailbox_get_message (mbox, 1, &mesg); | 130 | rc = scr->fun (clos->msg, clos->auth, progfile); |
135 | mu_message_get_attribute (mesg, &attr); | 131 | free (progfile); |
136 | mu_attribute_unset_deleted (attr); | 132 | |
133 | if (rc == 0) | ||
134 | { | ||
135 | mu_attribute_t attr; | ||
136 | mu_message_get_attribute (clos->msg, &attr); | ||
137 | rc = mu_attribute_is_deleted (attr); | ||
138 | } | ||
137 | 139 | ||
138 | return md->progfile != NULL; | 140 | return rc; |
139 | } | 141 | } |
140 | 142 | ||
141 | int | 143 | int |
142 | mda_exit (void *data, mu_mailbox_t mbox) | 144 | script_apply (mu_message_t msg, struct mu_auth_data *auth) |
143 | { | 145 | { |
144 | return exit_code; | 146 | int rc = 0; |
145 | } | ||
146 | 147 | ||
147 | #endif | 148 | if (script_list) |
149 | { | ||
150 | mu_attribute_t attr; | ||
151 | struct apply_script_closure clos; | ||
152 | |||
153 | clos.auth = auth; | ||
154 | clos.msg = msg; | ||
155 | |||
156 | mu_message_get_attribute (msg, &attr); | ||
157 | mu_attribute_unset_deleted (attr); | ||
158 | if (switch_user_id (auth, 1) == 0) | ||
159 | { | ||
160 | chdir (auth->dir); | ||
161 | rc = mu_list_do (script_list, apply_script, &clos); | ||
162 | chdir ("/"); | ||
163 | switch_user_id (auth, 0); | ||
164 | } | ||
165 | } | ||
166 | return rc; | ||
167 | } | ... | ... |
maidag/sieve.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000, 2001, 2002, 2005, | ||
3 | 2007, 2009 Free Software 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, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
18 | MA 02110-1301 USA */ | ||
19 | |||
20 | #include "maidag.h" | ||
21 | |||
22 | static int | ||
23 | _sieve_debug_printer (void *unused, const char *fmt, va_list ap) | ||
24 | { | ||
25 | mu_diag_vprintf (MU_DIAG_DEBUG, fmt, ap); | ||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | static void | ||
30 | _sieve_action_log (void *user_name, | ||
31 | const mu_sieve_locus_t *locus, size_t msgno, | ||
32 | mu_message_t msg, | ||
33 | const char *action, const char *fmt, va_list ap) | ||
34 | { | ||
35 | int pfx = 0; | ||
36 | mu_debug_t debug; | ||
37 | |||
38 | mu_diag_get_debug (&debug); | ||
39 | mu_debug_set_locus (debug, locus->source_file, locus->source_line); | ||
40 | |||
41 | mu_diag_printf (MU_DIAG_NOTICE, _("(user %s) "), (char*) user_name); | ||
42 | if (message_id_header) | ||
43 | { | ||
44 | mu_header_t hdr = NULL; | ||
45 | char *val = NULL; | ||
46 | mu_message_get_header (msg, &hdr); | ||
47 | if (mu_header_aget_value (hdr, message_id_header, &val) == 0 | ||
48 | || mu_header_aget_value (hdr, MU_HEADER_MESSAGE_ID, &val) == 0) | ||
49 | { | ||
50 | pfx = 1; | ||
51 | mu_diag_printf (MU_DIAG_NOTICE, _("%s on msg %s"), action, val); | ||
52 | free (val); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | if (!pfx) | ||
57 | { | ||
58 | size_t uid = 0; | ||
59 | mu_message_get_uid (msg, &uid); | ||
60 | mu_diag_printf (MU_DIAG_NOTICE, _("%s on msg uid %d"), action, uid); | ||
61 | } | ||
62 | |||
63 | if (fmt && strlen (fmt)) | ||
64 | { | ||
65 | mu_diag_printf (MU_DIAG_NOTICE, "; "); | ||
66 | mu_diag_vprintf (MU_DIAG_NOTICE, fmt, ap); | ||
67 | } | ||
68 | mu_diag_printf (MU_DIAG_NOTICE, "\n"); | ||
69 | mu_debug_set_locus (debug, NULL, 0); | ||
70 | } | ||
71 | |||
72 | static int | ||
73 | _sieve_parse_error (void *user_name, const char *filename, int lineno, | ||
74 | const char *fmt, va_list ap) | ||
75 | { | ||
76 | mu_debug_t debug; | ||
77 | |||
78 | mu_diag_get_debug (&debug); | ||
79 | if (filename) | ||
80 | mu_debug_set_locus (debug, filename, lineno); | ||
81 | |||
82 | mu_diag_printf (MU_DIAG_ERROR, _("(user %s) "), (char*) user_name); | ||
83 | mu_diag_vprintf (MU_DIAG_ERROR, fmt, ap); | ||
84 | mu_diag_printf (MU_DIAG_ERROR, "\n"); | ||
85 | mu_debug_set_locus (debug, NULL, 0); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | int | ||
90 | sieve_check_msg (mu_message_t msg, struct mu_auth_data *auth, const char *prog) | ||
91 | { | ||
92 | int rc; | ||
93 | mu_sieve_machine_t mach; | ||
94 | |||
95 | rc = mu_sieve_machine_init (&mach, auth->name); | ||
96 | if (rc) | ||
97 | { | ||
98 | mu_error (_("Cannot initialize sieve machine: %s"), | ||
99 | mu_strerror (rc)); | ||
100 | } | ||
101 | else | ||
102 | { | ||
103 | mu_sieve_set_debug (mach, _sieve_debug_printer); | ||
104 | mu_sieve_set_debug_level (mach, sieve_debug_flags); | ||
105 | mu_sieve_set_parse_error (mach, _sieve_parse_error); | ||
106 | if (sieve_enable_log) | ||
107 | mu_sieve_set_logger (mach, _sieve_action_log); | ||
108 | |||
109 | rc = mu_sieve_compile (mach, prog); | ||
110 | if (rc == 0) | ||
111 | mu_sieve_message (mach, msg); | ||
112 | } | ||
113 | return 0; | ||
114 | } | ||
115 |
-
Please register or sign in to post a comment