Commit 43088a1c 43088a1c350b70b627edeb98d927beca3bcd7708 by Sergey Poznyakoff

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.
1 parent 303823bd
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);
......
...@@ -145,19 +145,21 @@ static const char *guimb_argp_capa[] = { ...@@ -145,19 +145,21 @@ static const char *guimb_argp_capa[] = {
145 "license", 145 "license",
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)
207 mu_guile_load (program_file, g_argc, g_argv);
208 if (program_expr)
209 mu_guile_eval (program_expr);
210
211 rc = mu_guile_mailbox_apply (mbox, main_sym);
212 switch (rc)
213 {
214 case 0:
215 collect_output ();
216 break;
217
218 case MU_ERR_NOENT:
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 ();
213 236
214 param.debug_guile = debug_guile; 237 return !!rc;
215 param.mbox = mbox;
216 param.user_name = user_name;
217 param.init = NULL;
218 param.catch_body = guimb_catch_body;
219 param.catch_handler = guimb_catch_handler;
220 param.next = NULL;
221 param.exit = guimb_exit;
222 param.data = &gd;
223 mu_process_mailbox (g_argc, g_argv, &param);
224 /*NOTREACHED*/
225 return 0;
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,39 +932,53 @@ ...@@ -931,39 +932,53 @@
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"))
937 (display (string-append 938 (else
938 "# Guile mailbox parser made from " filename)) 939 (display "/bin/sh\n\
939 (newline) 940 # aside from this initial boilerplate, this is actually -*- scheme -*- code\n\
940 (display "# by sieve.scm, GNU %PACKAGE% %VERSION%\n!#") 941 exec ${GUILE-guile} -l $0 -c '(mailutils-main)'\n")))
941 (newline) 942 (display (string-append
942 943 "# This Guile mailbox parser was made from " filename))
943 (display 944 (newline)
944 "(if (not (member \"%GUILE_SITE%\" %load-path))\n 945 (display "# by sieve.scm, GNU %PACKAGE% %VERSION%\n!#")
946 (newline)
947
948 (display
949 "(if (not (member \"%GUILE_SITE%\" %load-path))\n
945 (set! %load-path (cons \"%GUILE_SITE%\" %load-path)))\n") 950 (set! %load-path (cons \"%GUILE_SITE%\" %load-path)))\n")
946 951
947 (display "(use-modules (mailutils sieve-core))\n") 952 (display "(use-modules (mailutils sieve-core))\n")
948 (display (string-append 953 (display (string-append
949 "(set! sieve-source \"" filename "\")")) 954 "(set! sieve-source \"" filename "\")"))
950 (newline) 955 (newline)
951 956
952 (for-each 957 (for-each
953 (lambda (file) 958 (lambda (file)
954 (display (string-append 959 (display (string-append
955 "(load \"" file "\")")) 960 "(load \"" file "\")"))
956 (newline)) 961 (newline))
957 sieve-load-files) 962 sieve-load-files)
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) ")
962 967
963 (sieve-code-print-list 968 (sieve-code-print-list (car sieve-code-list))
964 (append '(lambda ()) 969 (display ")\n\n")
965 sieve-code-list)) 970
966 (display ")")))) 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")
977
978 (display "\n\
979 ;;;; Local Variables:\n\
980 ;;;; buffer-read-only: t\n\
981 ;;;; End:\n"))))
967 982
968 ;;;; 983 ;;;;
969 984
......
...@@ -69,10 +69,20 @@ extern SCM mu_port_make_from_stream (SCM msg, mu_stream_t stream, long mode); ...@@ -69,10 +69,20 @@ 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);
75 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);
85
76 #ifdef __cplusplus 86 #ifdef __cplusplus
77 } 87 }
78 #endif 88 #endif
......
...@@ -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\
......
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);
41 mu_mailbox_close (mum->mbox); 42 if (!mum->noclose)
42 mu_mailbox_destroy (&mum->mbox); 43 {
44 mu_mailbox_close (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);
......
...@@ -49,4 +49,3 @@ ...@@ -49,4 +49,3 @@
49 49
50 #include <mailutils/guile.h> 50 #include <mailutils/guile.h>
51 51
52
......
...@@ -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;
...@@ -322,8 +309,8 @@ deliver_url (mu_url_t url, mu_message_t msg, const char *name, char **errp) ...@@ -322,8 +309,8 @@ deliver_url (mu_url_t url, mu_message_t msg, const char *name, char **errp)
322 309
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);
......
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 { 218 argp_error (state, _("Multiple --from options"));
205 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':
212 case 's': 223 script_handler = script_lang_handler (arg);
213 mu_argp_node_list_new (&lst, "guile-filter", arg); 224 if (!script_handler)
225 argp_error (state, _("Unknown or unsupported language: %s"),
226 arg);
214 break; 227 break;
215 #endif 228
229 case 's':
230 switch (script_register (arg))
231 {
232 case 0:
233 break;
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", &section) == 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 { 467 {
484 mu_sieve_machine_t mach; 468 section->docstring = N_("Add new message filter.");
485 rc = mu_sieve_machine_init (&mach, auth->name); 469 mu_cfg_section_add_params (section, filter_cfg_param);
486 if (rc)
487 {
488 mu_error (_("Cannot initialize sieve machine: %s"),
489 mu_strerror (rc));
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 struct script_tab
23 {
24 char *lang;
25 char *suf;
26 maidag_script_fun fun;
27 };
28
29 struct script_tab script_tab[] = {
30 { "sieve", "sv\0siv\0sieve\0", sieve_check_msg },
22 #ifdef WITH_GUILE 31 #ifdef WITH_GUILE
23 #include <mailutils/guile.h> 32 { "scheme", "scm\0", scheme_check_msg },
33 #endif
34 { NULL }
35 };
24 36
25 int debug_guile; 37 maidag_script_fun
38 script_lang_handler (const char *lang)
39 {
40 struct script_tab *p;
26 41
27 SCM mda_catch_body (void *data, mu_mailbox_t mbox); 42 for (p = script_tab; p->lang; p++)
28 SCM mda_catch_handler (void *unused, SCM tag, SCM throw_args); 43 if (strcmp (p->lang, lang) == 0)
29 int mda_next (void *data, mu_mailbox_t mbox); 44 return p->fun;
30 int mda_exit (void *data, mu_mailbox_t mbox); 45 return NULL;
31 int mda_init (void *data); 46 }
32 47
33 int 48 maidag_script_fun
34 prog_mda (struct mda_data *data) 49 script_suffix_handler (const char *name)
35 { 50 {
36 char *x_argv[2]; 51 struct script_tab *p;
37 mu_guimb_param_t param; 52 char *suf;
38 53
39 x_argv[0] = "maidag"; 54 suf = strrchr (name, '.');
40 x_argv[1] = NULL; 55 if (!suf)
41 56 return NULL;
42 param.debug_guile = debug_guile; 57 suf++;
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 58
52 mu_process_mailbox (1, x_argv, &param); 59 for (p = script_tab; p->lang; p++)
53 return EX_UNAVAILABLE; 60 {
54 } 61 char *s;
55 62
56 int 63 for (s = p->suf; *s; s += strlen (s) + 1)
57 mda_init (void *data) 64 if (strcmp (s, suf) == 0)
58 { 65 return p->fun;
59 struct mda_data *md = data; 66 }
60 md->progfile = mu_expand_path_pattern (md->progfile_pattern, md->argv[0]); 67 return NULL;
61 return 0;
62 } 68 }
63 69
64 static void 70
65 mda_switch_to_user (struct mda_data *md) 71
72 int
73 script_register (const char *pattern)
66 { 74 {
67 struct mu_auth_data *auth = NULL; 75 maidag_script_fun fun;
76 struct maidag_script *scr;
68 77
69 if (md && *md->argv != NULL) 78 if (script_handler)
70 auth = mu_get_auth_by_name (*md->argv); 79 fun = script_handler;
71 80 else
72 if (auth)
73 { 81 {
74 switch_user_id (auth, 1); 82 fun = script_suffix_handler (pattern);
75 chdir (auth->dir); 83 if (!fun)
76 mu_auth_data_free (auth); 84 return EINVAL;
77 } 85 }
78 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)
79 { 95 {
80 switch_user_id (auth, 0); 96 if (mu_list_create (&script_list))
81 chdir ("/"); 97 return MU_ERR_FAILURE;
82 } 98 }
99
100 if (mu_list_append (script_list, scr))
101 return MU_ERR_FAILURE;
102
103 return 0;
83 } 104 }
84 105
85 SCM 106
86 mda_catch_body (void *data, mu_mailbox_t mbox) 107 struct apply_script_closure
87 { 108 {
88 struct mda_data *md = data; 109 struct mu_auth_data *auth;
89 mu_message_t mesg = NULL; 110 mu_message_t msg;
90 mu_attribute_t attr = NULL; 111 };
91 112
92 if (access (md->progfile, R_OK)) 113 static int
114 apply_script (void *item, void *data)
115 {
116 struct maidag_script *scr = item;
117 struct apply_script_closure *clos = data;
118 char *progfile;
119 int rc;
120
121 progfile = mu_expand_path_pattern (scr->pat, clos->auth->name);
122 if (access (progfile, R_OK))
93 { 123 {
94 if (debug_level > 2) 124 if (debug_level > 2)
95 mu_diag_output (MU_DIAG_DEBUG, _("Access to %s failed: %m"), md->progfile); 125 mu_diag_output (MU_DIAG_DEBUG, _("Access to %s failed: %m"), progfile);
126 free (progfile);
127 return 0;
96 } 128 }
97 else 129
130 rc = scr->fun (clos->msg, clos->auth, progfile);
131 free (progfile);
132
133 if (rc == 0)
98 { 134 {
99 mda_switch_to_user (md); 135 mu_attribute_t attr;
100 scm_primitive_load (scm_makfrom0str (md->progfile)); 136 mu_message_get_attribute (clos->msg, &attr);
137 rc = mu_attribute_is_deleted (attr);
101 } 138 }
102 139
103 mu_mailbox_get_message (mbox, 1, &mesg); 140 return rc;
104 mu_message_get_attribute (mesg, &attr);
105 if (mu_attribute_is_deleted (attr))
106 return SCM_BOOL_F;
107
108 mda_switch_to_user (NULL);
109 mda (md->mbox, md->argv[0]);
110 return SCM_BOOL_F;
111 }
112
113 SCM
114 mda_catch_handler (void *data, SCM tag, SCM throw_args)
115 {
116 exit_code = EX_TEMPFAIL;
117 return scm_handle_by_message_noexit ("mail.local", tag, throw_args);
118 } 141 }
119
120 int
121 mda_next (void *data, mu_mailbox_t mbox)
122 {
123 struct mda_data *md = data;
124 mu_message_t mesg = NULL;
125 mu_attribute_t attr = NULL;
126
127 md->argv++;
128 if (*md->argv == NULL)
129 return 0;
130 if (md->progfile)
131 free (md->progfile);
132 md->progfile = mu_expand_path_pattern (md->progfile_pattern, *md->argv);
133
134 mu_mailbox_get_message (mbox, 1, &mesg);
135 mu_message_get_attribute (mesg, &attr);
136 mu_attribute_unset_deleted (attr);
137 142
138 return md->progfile != NULL;
139 }
140
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;
147
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;
145 } 167 }
146
147 #endif
......
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