Commit 966f07cc 966f07ccacdc8b1d13b87e28b1032192ac729fa4 by Sergey Poznyakoff

Initial implementation of a `prog' mailer.

* configure.ac: Enable/disable prog mailer support.
* include/mailutils/progmailer.h: New file.
* include/mailutils/Makefile.am (pkginclude_HEADERS): Add
progmailer.h
* include/mailutils/mailutils.h: Include progmailer.h
* include/mailutils/registrar.h (MU_PROG_PRIO): New define.
(mu_prog_record): New extern.
(mu_register_all_mailer_formats): Register mu_prog_record.
* include/mailutils/types.hin (mu_progmailer_t): New typedef.
* libproto/include/registrar0.h (MU_PROG_SCHEME)
(MU_PROG_SCHEME_LEN): New defines.
* libproto/mailer/prog.c: New file.
* libproto/mailer/Makefile.am (libmu_mailer_la_SOURCES): Add
prog.c
* libproto/mailer/sendmail.c: Rewrite using mu_progmailer_t
* libproto/remote/folder.c (_remote_is_scheme): Remove unused
variable.
* mailbox/progmailer.c: New file
* mailbox/Makefile.am (libmailutils_la_SOURCES): Add progmailer.c

* mailbox/acl.c (_expand_aclno): Add a fixme.
* mail/send.c (msg_to_pipe): Bugfix: use pclose, instead of fclose.
* examples/config/mailutils.schema: Update.
1 parent 5d3f1ff9
1 2008-10-25 Sergey Poznyakoff <gray@gnu.org.ua>
2
3 Initial implementation of a `prog' mailer.
4
5 * configure.ac: Enable/disable prog mailer support.
6 * include/mailutils/progmailer.h: New file.
7 * include/mailutils/Makefile.am (pkginclude_HEADERS): Add
8 progmailer.h
9 * include/mailutils/mailutils.h: Include progmailer.h
10 * include/mailutils/registrar.h (MU_PROG_PRIO): New define.
11 (mu_prog_record): New extern.
12 (mu_register_all_mailer_formats): Register mu_prog_record.
13 * include/mailutils/types.hin (mu_progmailer_t): New typedef.
14 * libproto/include/registrar0.h (MU_PROG_SCHEME)
15 (MU_PROG_SCHEME_LEN): New defines.
16 * libproto/mailer/prog.c: New file.
17 * libproto/mailer/Makefile.am (libmu_mailer_la_SOURCES): Add
18 prog.c
19 * libproto/mailer/sendmail.c: Rewrite using mu_progmailer_t
20 * libproto/remote/folder.c (_remote_is_scheme): Remove unused
21 variable.
22 * mailbox/progmailer.c: New file
23 * mailbox/Makefile.am (libmailutils_la_SOURCES): Add progmailer.c
24
25 * mailbox/acl.c (_expand_aclno): Add a fixme.
26 * mail/send.c (msg_to_pipe): Bugfix: use pclose, instead of fclose.
27 * examples/config/mailutils.schema: Update.
28
1 2008-10-24 Sergey Poznyakoff <gray@gnu.org.ua> 29 2008-10-24 Sergey Poznyakoff <gray@gnu.org.ua>
2 30
3 * examples/config/mailutils.dict: Use GNU OID number. 31 * examples/config/mailutils.dict: Use GNU OID number.
......
...@@ -767,10 +767,13 @@ MU_ENABLE_SUPPORT(nntp) ...@@ -767,10 +767,13 @@ MU_ENABLE_SUPPORT(nntp)
767 767
768 AC_SUBST(BUILD_SMTP_PROGRAMS) 768 AC_SUBST(BUILD_SMTP_PROGRAMS)
769 AC_SUBST(RUN_SMTP_DEJATOOL) 769 AC_SUBST(RUN_SMTP_DEJATOOL)
770
770 MU_ENABLE_SUPPORT(smtp, [BUILD_SMTP_PROGRAMS='$(PROGRAMS_SMTP)' 771 MU_ENABLE_SUPPORT(smtp, [BUILD_SMTP_PROGRAMS='$(PROGRAMS_SMTP)'
771 RUN_SMTP_DEJATOOL='$(SMTP_DEJATOOL)']) 772 RUN_SMTP_DEJATOOL='$(SMTP_DEJATOOL)'])
772 MU_ENABLE_SUPPORT(sendmail) 773 MU_ENABLE_SUPPORT(sendmail)
773 774
775 MU_ENABLE_SUPPORT(prog)
776
774 AC_SUBST(BUILD_MH_PROGRAMS) 777 AC_SUBST(BUILD_MH_PROGRAMS)
775 AC_SUBST(BUILD_MH_LIBRARIES) 778 AC_SUBST(BUILD_MH_LIBRARIES)
776 AC_SUBST(BUILD_MH_EXEC_HOOK) 779 AC_SUBST(BUILD_MH_EXEC_HOOK)
......
1 # This file is part of GNU Mailutils -- a suite of utilities for electronic 1 # This file is part of GNU Mailutils -- a suite of utilities for electronic
2 # mail 2 # mail
3 # Copyright (C) 2008 Free Software Foundation, Inc. 3 # Copyright (C) 2007, 2008 Free Software Foundation, Inc.
4 # 4 #
5 # GNU Mailutils is free software; you can redistribute it and/or 5 # GNU Mailutils is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License as 6 # modify it under the terms of the GNU General Public License as
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
13 # GNU General Public License for more details. 13 # GNU General Public License for more details.
14 # 14 #
15 # You should have received a copy of the GNU General Public License 15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>. 16 # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
17 17
18 # Mailutuls LDAP schema items 18 # Mailutuls LDAP schema items
19 # 19 #
......
...@@ -78,6 +78,7 @@ pkginclude_HEADERS = \ ...@@ -78,6 +78,7 @@ pkginclude_HEADERS = \
78 pam.h\ 78 pam.h\
79 parse822.h\ 79 parse822.h\
80 pop3.h\ 80 pop3.h\
81 progmailer.h\
81 property.h\ 82 property.h\
82 radius.h\ 83 radius.h\
83 refcount.h\ 84 refcount.h\
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
50 #include <mailutils/opool.h> 50 #include <mailutils/opool.h>
51 #include <mailutils/parse822.h> 51 #include <mailutils/parse822.h>
52 #include <mailutils/pop3.h> 52 #include <mailutils/pop3.h>
53 #include <mailutils/progmailer.h>
53 #include <mailutils/property.h> 54 #include <mailutils/property.h>
54 #include <mailutils/refcount.h> 55 #include <mailutils/refcount.h>
55 #include <mailutils/registrar.h> 56 #include <mailutils/registrar.h>
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2008 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 #ifndef _MAILUTILS_PROGMAILER_H
20 #define _MAILUTILS_PROGMAILER_H
21
22 #include <mailutils/types.h>
23
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27
28 int mu_progmailer_create (mu_progmailer_t *pm);
29 int mu_progmailer_set_command (mu_progmailer_t pm, const char *command);
30 int mu_progmailer_sget_command (mu_progmailer_t pm, const char **command);
31 /* FIXME: missing _aget_ and _get_ */
32 int mu_progmailer_set_debug (mu_progmailer_t pm, mu_debug_t debug);
33 int mu_progmailer_open (mu_progmailer_t pm, char **argv);
34 int mu_progmailer_send (mu_progmailer_t pm, mu_message_t msg);
35 int mu_progmailer_close (mu_progmailer_t pm);
36 void mu_progmailer_destroy (mu_progmailer_t *pm);
37
38 #ifdef __cplusplus
39 }
40 #endif
41
42 #endif /* _MAILUTILS_PROGMAILER_H */
43
...@@ -121,12 +121,15 @@ extern mu_record_t mu_remote_mbox_record; ...@@ -121,12 +121,15 @@ extern mu_record_t mu_remote_mbox_record;
121 #define MU_REMOTE_MBOX_PRIO 10000 121 #define MU_REMOTE_MBOX_PRIO 10000
122 #define MU_SMTP_PRIO 10000 122 #define MU_SMTP_PRIO 10000
123 #define MU_SENDMAIL_PRIO 10000 123 #define MU_SENDMAIL_PRIO 10000
124 #define MU_PROG_PRIO 10000
124 125
125 /* SMTP mailer, "smtp://" */ 126 /* SMTP mailer, "smtp://" */
126 extern mu_record_t mu_smtp_record; 127 extern mu_record_t mu_smtp_record;
127 /* Sendmail, "sendmail:" */ 128 /* Sendmail, "sendmail:" */
128 extern mu_record_t mu_sendmail_record; 129 extern mu_record_t mu_sendmail_record;
129 130 /* Program mailer, "prog://", "|" */
131 extern mu_record_t mu_prog_record;
132
130 #define mu_register_all_mbox_formats() do {\ 133 #define mu_register_all_mbox_formats() do {\
131 mu_registrar_record (mu_path_record);\ 134 mu_registrar_record (mu_path_record);\
132 mu_registrar_record (mu_mbox_record);\ 135 mu_registrar_record (mu_mbox_record);\
...@@ -156,6 +159,7 @@ extern mu_record_t mu_sendmail_record; ...@@ -156,6 +159,7 @@ extern mu_record_t mu_sendmail_record;
156 #define mu_register_all_mailer_formats() do {\ 159 #define mu_register_all_mailer_formats() do {\
157 mu_registrar_record (mu_sendmail_record);\ 160 mu_registrar_record (mu_sendmail_record);\
158 mu_registrar_record (mu_smtp_record);\ 161 mu_registrar_record (mu_smtp_record);\
162 mu_registrar_record (mu_prog_record);\
159 } while (0) 163 } while (0)
160 164
161 #define mu_register_extra_formats() do {\ 165 #define mu_register_extra_formats() do {\
......
...@@ -111,7 +111,8 @@ typedef struct _mu_server *mu_server_t; ...@@ -111,7 +111,8 @@ typedef struct _mu_server *mu_server_t;
111 typedef struct _mu_ip_server *mu_ip_server_t; 111 typedef struct _mu_ip_server *mu_ip_server_t;
112 typedef struct _mu_m_server *mu_m_server_t; 112 typedef struct _mu_m_server *mu_m_server_t;
113 typedef struct _mu_opool *mu_opool_t; 113 typedef struct _mu_opool *mu_opool_t;
114 114 typedef struct _mu_progmailer *mu_progmailer_t;
115
115 #define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001 116 #define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001
116 #define MU_FOLDER_ATTRIBUTE_FILE 0x002 117 #define MU_FOLDER_ATTRIBUTE_FILE 0x002
117 118
......
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, 2004, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2000, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
3 3
4 This library is free software; you can redistribute it and/or 4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public 5 modify it under the terms of the GNU Lesser General Public
...@@ -19,10 +19,6 @@ ...@@ -19,10 +19,6 @@
19 #ifndef _REGISTRAR0_H 19 #ifndef _REGISTRAR0_H
20 #define _REGISTRAR0_H 20 #define _REGISTRAR0_H
21 21
22 #ifdef DMALLOC
23 # include <dmalloc.h>
24 #endif
25
26 #include <mailutils/registrar.h> 22 #include <mailutils/registrar.h>
27 23
28 #ifdef __cplusplus 24 #ifdef __cplusplus
...@@ -85,6 +81,9 @@ extern int _mailer_smtp_init (mu_mailer_t); ...@@ -85,6 +81,9 @@ extern int _mailer_smtp_init (mu_mailer_t);
85 extern int _url_sendmail_init (mu_url_t); 81 extern int _url_sendmail_init (mu_url_t);
86 extern int _mailer_sendmail_init (mu_mailer_t); 82 extern int _mailer_sendmail_init (mu_mailer_t);
87 83
84 #define MU_PROG_SCHEME "prog"
85 #define MU_PROG_SCHEME_LEN (sizeof (MU_PROG_SCHEME) - 1)
86
88 #define MU_MH_SCHEME "mh" 87 #define MU_MH_SCHEME "mh"
89 #define MU_MH_SCHEME_LEN (sizeof (MU_MH_SCHEME) - 1) 88 #define MU_MH_SCHEME_LEN (sizeof (MU_MH_SCHEME) - 1)
90 extern int _mailbox_mh_init (mu_mailbox_t mailbox); 89 extern int _mailbox_mh_init (mu_mailbox_t mailbox);
......
1 ## Process this file with GNU Automake to create Makefile.in 1 ## Process this file with GNU Automake to create Makefile.in
2 2
3 ## Copyright (C) 2007 Free Software Foundation, Inc. 3 ## Copyright (C) 2007, 2008 Free Software Foundation, Inc.
4 ## 4 ##
5 ## GNU Mailutils is free software; you can redistribute it and/or 5 ## GNU Mailutils is free software; you can redistribute it and/or
6 ## modify it under the terms of the GNU General Public License as 6 ## modify it under the terms of the GNU General Public License as
...@@ -24,6 +24,7 @@ libmu_mailer_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ ...@@ -24,6 +24,7 @@ libmu_mailer_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
24 libmu_mailer_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@ 24 libmu_mailer_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@
25 25
26 libmu_mailer_la_SOURCES = \ 26 libmu_mailer_la_SOURCES = \
27 prog.c\
27 sendmail.c\ 28 sendmail.c\
28 smtp.c\ 29 smtp.c\
29 url_sendmail.c\ 30 url_sendmail.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2008 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,
16 see <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #ifdef ENABLE_PROG
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <unistd.h>
26
27 #include <mailutils/address.h>
28 #include <mailutils/argcv.h>
29 #include <mailutils/debug.h>
30 #include <mailutils/errno.h>
31 #include <mailutils/header.h>
32 #include <mailutils/message.h>
33 #include <mailutils/observer.h>
34 #include <mailutils/progmailer.h>
35 #include <mailutils/vartab.h>
36
37 #include <url0.h>
38 #include <mailer0.h>
39 #include <registrar0.h>
40
41 static int _url_prog_init (mu_url_t);
42 static int _url_pipe_init (mu_url_t);
43 static int _mailer_prog_init (mu_mailer_t);
44
45 static struct _mu_record _prog_record =
46 {
47 MU_PROG_PRIO,
48 MU_PROG_SCHEME,
49 _url_prog_init, /* url init. */
50 NULL, /* Mailbox entry. */
51 _mailer_prog_init, /* Mailer entry. */
52 NULL, /* Folder entry. */
53 NULL, /* No need for a back pointer. */
54 NULL, /* _is_scheme method. */
55 NULL, /* _get_url method. */
56 NULL, /* _get_mailbox method. */
57 NULL, /* _get_mailer method. */
58 NULL /* _get_folder method. */
59 };
60
61 mu_record_t mu_prog_record = &_prog_record;
62
63
64 static int
65 _url_prog_init (mu_url_t url)
66 {
67 int status = mu_url_init (url, 0, "prog");
68 if (status)
69 return status;
70 /* not valid in a sendmail url */
71 if (url->user || url->passwd || url->auth || url->host || url->port)
72 return EINVAL;
73 if (!url->path)
74 return EINVAL;
75 return 0;
76 }
77
78
79 static void prog_destroy (mu_mailer_t);
80 static int prog_open (mu_mailer_t, int);
81 static int prog_close (mu_mailer_t);
82 static int prog_send_message (mu_mailer_t, mu_message_t, mu_address_t,
83 mu_address_t);
84
85 static int
86 _mailer_prog_init (mu_mailer_t mailer)
87 {
88 int status;
89 mu_progmailer_t pm;
90
91 status = mu_progmailer_create (&pm);
92 if (status)
93 return status;
94
95 mailer->data = pm;
96 mailer->_destroy = prog_destroy;
97 mailer->_open = prog_open;
98 mailer->_close = prog_close;
99 mailer->_send_message = prog_send_message;
100
101 return 0;
102 }
103
104 static void
105 prog_destroy (mu_mailer_t mailer)
106 {
107 mu_progmailer_destroy ((mu_progmailer_t*)&mailer->data);
108 }
109
110 static int
111 prog_open (mu_mailer_t mailer, int flags)
112 {
113 mu_progmailer_t pm = mailer->data;
114 int status;
115 const char *path;
116
117 /* Sanity checks. */
118 if (pm == NULL)
119 return EINVAL;
120
121 mailer->flags = flags;
122
123 if ((status = mu_url_sget_path (mailer->url, &path)))
124 return status;
125
126 if (access (path, X_OK) == -1)
127 return errno;
128
129 mu_progmailer_set_debug (pm, mailer->debug);
130 status = mu_progmailer_set_command (pm, path);
131 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE, "prog (%s)\n", path);
132 return status;
133 }
134
135 static int
136 prog_close (mu_mailer_t mailer)
137 {
138 return mu_progmailer_close (mailer->data);
139 }
140
141 static int
142 _expand_sender (const char *name, void *data, char **p)
143 {
144 mu_address_t addr = data;
145 const char *email;
146 int status = mu_address_sget_email (addr, 1, &email);
147
148 if (status != 0)
149 return status;
150 *(const char**)p = email;
151 return 0;
152 }
153
154 struct ex_rcpt
155 {
156 mu_message_t msg;
157 mu_address_t addr;
158 char *string;
159 };
160
161 static int
162 address_add (mu_address_t *paddr, const char *value)
163 {
164 mu_address_t addr = NULL;
165 int status;
166
167 status = mu_address_create (&addr, value);
168 if (status)
169 return status;
170 status = mu_address_union (paddr, addr);
171 mu_address_destroy (&addr);
172 return status;
173 }
174
175 static int
176 message_read_rcpt (mu_message_t msg, mu_address_t *paddr)
177 {
178 mu_header_t header = NULL;
179 const char *value;
180 int status;
181
182 status = mu_message_get_header (msg, &header);
183 if (status)
184 return status;
185
186 status = mu_header_sget_value (header, MU_HEADER_TO, &value);
187
188 if (status == 0)
189 address_add (paddr, value);
190 else if (status != MU_ERR_NOENT)
191 return status;
192
193 status = mu_header_sget_value (header, MU_HEADER_CC, &value);
194 if (status == 0)
195 address_add (paddr, value);
196 else if (status != MU_ERR_NOENT)
197 return status;
198
199 status = mu_header_sget_value (header, MU_HEADER_BCC, &value);
200 if (status == 0)
201 address_add (paddr, value);
202 else if (status != MU_ERR_NOENT)
203 return status;
204 return 0;
205 }
206
207 static int
208 _expand_rcpt (const char *name, void *data, char **p)
209 {
210 struct ex_rcpt *exrcpt = data;
211 int status;
212
213 if (!exrcpt->string)
214 {
215 size_t i, count = 0;
216 size_t len = 0;
217 char *str;
218 mu_address_t tmp_addr = NULL, addr;
219
220 if (exrcpt->addr)
221 addr = exrcpt->addr;
222 else
223 {
224 status = message_read_rcpt (exrcpt->msg, &tmp_addr);
225 if (status)
226 {
227 mu_address_destroy (&tmp_addr);
228 return status;
229 }
230 addr = tmp_addr;
231 }
232
233 mu_address_get_count (addr, &count);
234 for (i = 1; i <= count; i++)
235 {
236 const char *email;
237 if (i > 1)
238 len++;
239 if ((status = mu_address_sget_email (addr, i, &email)) != 0)
240 {
241 mu_address_destroy (&tmp_addr);
242 return status;
243 }
244 len += strlen (email);
245 }
246
247 str = malloc (len + 1);
248 if (!str)
249 {
250 mu_address_destroy (&tmp_addr);
251 return ENOMEM;
252 }
253 exrcpt->string = str;
254
255 for (i = 1; i <= count; i++)
256 {
257 const char *email;
258 if (i > 1)
259 *str++ = ' ';
260 if (mu_address_sget_email (addr, i, &email))
261 continue;
262 strcpy (str, email);
263 str += strlen (email);
264 }
265 *str = 0;
266 mu_address_destroy (&tmp_addr);
267 }
268 *p = exrcpt->string;
269 return 0;
270 }
271
272 void
273 _free_rcpt (void *data, char *value)
274 {
275 free (value);
276 }
277
278 static int
279 url_to_argv (mu_url_t url, mu_message_t msg,
280 mu_address_t from, mu_address_t to,
281 int *pargc, char ***pargv)
282 {
283 int rc;
284 mu_vartab_t vtab;
285 struct ex_rcpt ex_rcpt;
286 const char *query;
287 char *cmdargs;
288 int argc;
289 char **argv;
290
291 ex_rcpt.msg = msg;
292 ex_rcpt.addr = to;
293 ex_rcpt.string = NULL;
294 mu_vartab_create (&vtab);
295 mu_vartab_define_exp (vtab, "sender", _expand_sender, NULL, from);
296 mu_vartab_define_exp (vtab, "rcpt", _expand_rcpt, _free_rcpt, &ex_rcpt);
297
298 rc = mu_url_sget_query (url, &query);
299 if (rc)
300 return rc;
301
302 rc = mu_vartab_expand (vtab, query, &cmdargs);
303 mu_vartab_destroy (&vtab);
304 if (rc)
305 return rc;
306
307 rc = mu_argcv_get_np (cmdargs, strlen (cmdargs),
308 "&", NULL,
309 0, &argc, &argv, NULL);
310 free (cmdargs);
311 if (rc)
312 return rc;
313 argv = realloc (argv, (argc + 2) * sizeof (argv[0]));
314 memmove (argv + 1, argv, (argc + 1) * sizeof (argv[0]));
315 mu_url_aget_path (url, &argv[0]);
316
317 *pargc = argc + 1;
318 *pargv = argv;
319 return 0;
320 }
321
322 static int
323 prog_send_message (mu_mailer_t mailer, mu_message_t msg, mu_address_t from,
324 mu_address_t to)
325 {
326 mu_progmailer_t pm = mailer->data;
327 int argc;
328 char **argv;
329 int status;
330
331 status = url_to_argv(mailer->url, msg, from, to, &argc, &argv);
332 if (status)
333 {
334 MU_DEBUG1 (mailer->debug, MU_DEBUG_ERROR,
335 "cannot convert URL to command line: %s\n",
336 mu_strerror (status));
337 return status;
338 }
339
340 mu_progmailer_set_debug (pm, mailer->debug);
341 status = mu_progmailer_open (pm, argv);
342 if (status == 0)
343 {
344 status = mu_progmailer_send (pm, msg);
345 if (status == 0)
346 mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT,
347 msg);
348 else
349 MU_DEBUG1 (mailer->debug, MU_DEBUG_ERROR,
350 "progmailer error: %s\n",
351 mu_strerror (status));
352 }
353
354 mu_argcv_free (argc, argv);
355 return status;
356 }
357
358 #else
359 #include <stdio.h>
360 #include <registrar0.h>
361 mu_record_t mu_prog_record = NULL;
362 #endif
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, 2004, 2005, 2 Copyright (C) 1999, 2000, 2001, 2004, 2005,
3 2006, 2007 Free Software Foundation, Inc. 3 2006, 2007, 2008 Free Software Foundation, Inc.
4 4
5 This library is free software; you can redistribute it and/or 5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public 6 modify it under the terms of the GNU Lesser General Public
...@@ -30,19 +30,13 @@ ...@@ -30,19 +30,13 @@
30 #include <string.h> 30 #include <string.h>
31 #include <unistd.h> 31 #include <unistd.h>
32 32
33 #include <sys/types.h>
34 #include <sys/wait.h>
35
36 #include <mailutils/address.h> 33 #include <mailutils/address.h>
37 #include <mailutils/debug.h> 34 #include <mailutils/debug.h>
38 #include <mailutils/message.h>
39 #include <mailutils/observer.h> 35 #include <mailutils/observer.h>
40 #include <mailutils/property.h> 36 #include <mailutils/property.h>
41 #include <mailutils/stream.h>
42 #include <mailutils/url.h> 37 #include <mailutils/url.h>
43 #include <mailutils/header.h>
44 #include <mailutils/body.h>
45 #include <mailutils/errno.h> 38 #include <mailutils/errno.h>
39 #include <mailutils/progmailer.h>
46 40
47 #include <mailer0.h> 41 #include <mailer0.h>
48 #include <registrar0.h> 42 #include <registrar0.h>
...@@ -66,33 +60,23 @@ static struct _mu_record _sendmail_record = ...@@ -66,33 +60,23 @@ static struct _mu_record _sendmail_record =
66 the mailbox, via the register entry/record. */ 60 the mailbox, via the register entry/record. */
67 mu_record_t mu_sendmail_record = &_sendmail_record; 61 mu_record_t mu_sendmail_record = &_sendmail_record;
68 62
69 struct _sendmail
70 {
71 int dsn;
72 char *path;
73 pid_t pid;
74 off_t offset;
75 int fd;
76 enum sendmail_state { SENDMAIL_CLOSED, SENDMAIL_OPEN, SENDMAIL_SEND } state;
77 };
78
79 typedef struct _sendmail * sendmail_t;
80
81 static void sendmail_destroy (mu_mailer_t); 63 static void sendmail_destroy (mu_mailer_t);
82 static int sendmail_open (mu_mailer_t, int); 64 static int sendmail_open (mu_mailer_t, int);
83 static int sendmail_close (mu_mailer_t); 65 static int sendmail_close (mu_mailer_t);
84 static int sendmail_send_message (mu_mailer_t, mu_message_t, mu_address_t, mu_address_t); 66 static int sendmail_send_message (mu_mailer_t, mu_message_t, mu_address_t,
67 mu_address_t);
85 68
86 int 69 int
87 _mailer_sendmail_init (mu_mailer_t mailer) 70 _mailer_sendmail_init (mu_mailer_t mailer)
88 { 71 {
89 sendmail_t sendmail; 72 int status;
73 mu_progmailer_t pm;
90 74
91 /* Allocate memory specific to sendmail mailer. */ 75 status = mu_progmailer_create (&pm);
92 sendmail = mailer->data = calloc (1, sizeof (*sendmail)); 76 if (status)
93 if (mailer->data == NULL) 77 return status;
94 return ENOMEM; 78
95 sendmail->state = SENDMAIL_CLOSED; 79 mailer->data = pm;
96 mailer->_destroy = sendmail_destroy; 80 mailer->_destroy = sendmail_destroy;
97 mailer->_open = sendmail_open; 81 mailer->_open = sendmail_open;
98 mailer->_close = sendmail_close; 82 mailer->_close = sendmail_close;
...@@ -108,61 +92,39 @@ _mailer_sendmail_init (mu_mailer_t mailer) ...@@ -108,61 +92,39 @@ _mailer_sendmail_init (mu_mailer_t mailer)
108 } 92 }
109 93
110 static void 94 static void
111 sendmail_destroy(mu_mailer_t mailer) 95 sendmail_destroy (mu_mailer_t mailer)
112 { 96 {
113 sendmail_t sendmail = mailer->data; 97 mu_progmailer_destroy ((mu_progmailer_t*)&mailer->data);
114 if (sendmail)
115 {
116 if (sendmail->path)
117 free (sendmail->path);
118 free (sendmail);
119 mailer->data = NULL;
120 }
121 } 98 }
122 99
123 static int 100 static int
124 sendmail_open (mu_mailer_t mailer, int flags) 101 sendmail_open (mu_mailer_t mailer, int flags)
125 { 102 {
126 sendmail_t sendmail = mailer->data; 103 mu_progmailer_t pm = mailer->data;
127 int status; 104 int status;
128 char *path; 105 const char *path;
129 106
130 /* Sanity checks. */ 107 /* Sanity checks. */
131 if (sendmail == NULL) 108 if (pm == NULL)
132 return EINVAL; 109 return EINVAL;
133 110
134 mailer->flags = flags; 111 mailer->flags = flags;
135 112
136 if ((status = mu_url_aget_path (mailer->url, &path))) 113 if ((status = mu_url_sget_path (mailer->url, &path)))
137 return status; 114 return status;
138 115
139 if (access (path, X_OK) == -1) 116 if (access (path, X_OK) == -1)
140 { 117 return errno;
141 free (path); 118 mu_progmailer_set_debug (pm, mailer->debug);
142 return errno; 119 status = mu_progmailer_set_command (pm, path);
143 } 120 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE, "sendmail (%s)\n", path);
144 sendmail->path = path; 121 return status;
145 sendmail->state = SENDMAIL_OPEN;
146 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE, "sendmail (%s)\n", sendmail->path);
147 return 0;
148 } 122 }
149 123
150 static int 124 static int
151 sendmail_close (mu_mailer_t mailer) 125 sendmail_close (mu_mailer_t mailer)
152 { 126 {
153 sendmail_t sendmail = mailer->data; 127 return mu_progmailer_close (mailer->data);
154
155 /* Sanity checks. */
156 if (sendmail == NULL)
157 return EINVAL;
158
159 if(sendmail->path)
160 free(sendmail->path);
161
162 sendmail->path = NULL;
163 sendmail->state = SENDMAIL_CLOSED;
164
165 return 0;
166 } 128 }
167 129
168 static int 130 static int
...@@ -174,281 +136,139 @@ mailer_property_is_set (mu_mailer_t mailer, const char *name) ...@@ -174,281 +136,139 @@ mailer_property_is_set (mu_mailer_t mailer, const char *name)
174 return mu_property_is_set (property, name); 136 return mu_property_is_set (property, name);
175 } 137 }
176 138
177
178 /* Close FD unless it is part of pipe P */
179 #define SCLOSE(fd,p) if (p[0]!=fd&&p[1]!=fd) close(fd)
180
181 static int 139 static int
182 sendmail_send_message (mu_mailer_t mailer, mu_message_t msg, mu_address_t from, 140 sendmail_send_message (mu_mailer_t mailer, mu_message_t msg, mu_address_t from,
183 mu_address_t to) 141 mu_address_t to)
184 { 142 {
185 sendmail_t sendmail = mailer->data; 143 mu_progmailer_t pm = mailer->data;
186 int status = 0; 144 int argc = 0;
187 145 const char **argvec = NULL;
188 if (sendmail == NULL || msg == NULL) 146 size_t tocount = 0;
147 const char *emailfrom = NULL;
148 int status;
149
150 if (!pm)
189 return EINVAL; 151 return EINVAL;
152
153 /* Count the length of the arg vec: */
190 154
191 switch (sendmail->state) 155 argc++; /* terminating NULL */
192 { 156 argc++; /* sendmail */
193 case SENDMAIL_CLOSED: 157 argc++; /* -oi (do not treat '.' as message
194 return EINVAL;
195 case SENDMAIL_OPEN:
196 {
197 int tunnel[2];
198 int argc = 0;
199 const char **argvec = NULL;
200 size_t tocount = 0;
201 const char *emailfrom = NULL;
202
203 /* Count the length of the arg vec: */
204
205 argc++; /* terminating NULL */
206 argc++; /* sendmail */
207 argc++; /* -oi (do not treat '.' as message
208 terminator) */ 158 terminator) */
209 159
210 if (from) 160 if (from)
211 { 161 {
212 if ((status = mu_address_sget_email (from, 1, &emailfrom)) != 0) 162 if ((status = mu_address_sget_email (from, 1, &emailfrom)) != 0)
213 goto OPEN_STATE_CLEANUP; 163 {
214 164 MU_DEBUG1 (mailer->debug, MU_DEBUG_ERROR,
215 if (!emailfrom) 165 "cannot get recipient email: %s\n",
216 { 166 mu_strerror (status));
217 /* the address wasn't fully qualified, choke (for now) */
218 status = EINVAL;
219
220 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
221 "envelope from (%s) not fully qualifed\n",
222 emailfrom);
223
224 goto OPEN_STATE_CLEANUP;
225 }
226
227 argc += 2; /* -f from */
228 }
229
230 if (to)
231 {
232 status = mu_address_get_email_count (to, &tocount);
233
234 assert (!status);
235 assert (tocount);
236
237 argc += tocount; /* 1 per to address */
238 }
239
240 argc++; /* -t */
241
242 /* Allocate arg vec: */
243 if ((argvec = calloc (argc, sizeof (*argvec))) == 0)
244 {
245 status = ENOMEM;
246 goto OPEN_STATE_CLEANUP;
247 }
248
249 argc = 0;
250
251 argvec[argc++] = sendmail->path;
252 argvec[argc++] = "-oi";
253
254 if (from)
255 {
256 argvec[argc++] = "-f";
257 argvec[argc++] = emailfrom;
258 }
259
260 if (!to || mailer_property_is_set (mailer, "READ_RECIPIENTS"))
261 {
262 argvec[argc++] = "-t";
263 }
264 else
265 {
266 int i = 1;
267 size_t count = 0;
268
269 mu_address_get_count (to, &count);
270
271 for (; i <= count; i++)
272 {
273 const char *email;
274 if ((status = mu_address_sget_email (to, i, &email)) != 0)
275 goto OPEN_STATE_CLEANUP;
276 if (!email)
277 {
278 /* the address wasn't fully qualified, choke (for now) */
279 status = EINVAL;
280
281 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
282 "envelope to (%s) not fully qualifed\n",
283 email);
284
285 goto OPEN_STATE_CLEANUP;
286 }
287 argvec[argc++] = email;
288 }
289 }
290
291 assert (argvec[argc] == NULL);
292
293 if (pipe (tunnel) == 0)
294 {
295 sendmail->fd = tunnel[1];
296 sendmail->pid = vfork ();
297 if (sendmail->pid == 0) /* Child. */
298 {
299 SCLOSE (STDIN_FILENO, tunnel);
300 SCLOSE (STDOUT_FILENO, tunnel);
301 SCLOSE (STDERR_FILENO, tunnel);
302 close (tunnel[1]);
303 dup2 (tunnel[0], STDIN_FILENO);
304 execv (sendmail->path, (char**) argvec);
305 exit (errno);
306 }
307 else if (sendmail->pid == -1)
308 {
309 status = errno;
310
311 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
312 "vfork() failed: %s\n", strerror (status));
313 }
314 }
315 else
316 {
317 status = errno;
318 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
319 "pipe() failed: %s\n", strerror (status));
320 }
321
322 OPEN_STATE_CLEANUP:
323 MU_DEBUG (mailer->debug, MU_DEBUG_TRACE, "exec argv:");
324 for (argc = 0; argvec && argvec[argc]; argc++)
325 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE, " %s", argvec[argc]);
326 MU_DEBUG (mailer->debug, MU_DEBUG_TRACE, "\n");
327 free (argvec);
328 close (tunnel[0]);
329
330 if (status != 0)
331 {
332 close (sendmail->fd);
333 break;
334 }
335 sendmail->state = SENDMAIL_SEND;
336 }
337
338 case SENDMAIL_SEND:
339 {
340 mu_stream_t stream = NULL;
341 char buffer[512];
342 size_t len = 0;
343 int rc;
344 size_t offset = 0;
345 mu_header_t hdr;
346 mu_body_t body;
347 int found_nl = 0;
348 int exit_status;
349
350 mu_message_get_header (msg, &hdr);
351 mu_header_get_stream (hdr, &stream);
352
353 MU_DEBUG (mailer->debug, MU_DEBUG_TRACE, "Sending headers...\n");
354 while ((status = mu_stream_readline (stream, buffer, sizeof (buffer),
355 offset, &len)) == 0
356 && len != 0)
357 {
358 if (strncasecmp (buffer, MU_HEADER_FCC,
359 sizeof (MU_HEADER_FCC) - 1))
360 {
361 MU_DEBUG1 (mailer->debug, MU_DEBUG_PROT, "Header: %s", buffer);
362 if (write (sendmail->fd, buffer, len) == -1)
363 {
364 status = errno;
365
366 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
367 "write() failed: %s\n", strerror (status));
368
369 break;
370 }
371 }
372 found_nl = (len == 1 && buffer[0] == '\n');
373
374 offset += len;
375 sendmail->offset += len;
376 }
377
378 if (!found_nl)
379 {
380 if (write (sendmail->fd, "\n", 1) == -1)
381 {
382 status = errno;
383
384 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
385 "write() failed: %s\n", strerror (status));
386 }
387 }
388
389 mu_message_get_body (msg, &body);
390 mu_body_get_stream (body, &stream);
391
392 MU_DEBUG (mailer->debug, MU_DEBUG_TRACE, "Sending body...\n");
393 offset = 0;
394 while ((status = mu_stream_read (stream, buffer, sizeof (buffer),
395 offset, &len)) == 0
396 && len != 0)
397 {
398 if (write (sendmail->fd, buffer, len) == -1)
399 {
400 status = errno;
401
402 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
403 "write() failed: %s\n", strerror (status));
404
405 break;
406 }
407 offset += len;
408 sendmail->offset += len;
409 }
410 if (status == EAGAIN)
411 return status; 167 return status;
168 }
169
170 if (!emailfrom)
171 {
172 /* the address wasn't fully qualified, choke (for now) */
173 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
174 "envelope from (%s) not fully qualifed\n",
175 emailfrom);
176 return MU_ERR_BAD_822_FORMAT;
177 }
178
179 argc += 2; /* -f from */
180 }
181
182 if (to)
183 {
184 status = mu_address_get_email_count (to, &tocount);
185 if (status)
186 return status;
187
188 if (tocount == 0)
189 {
190 MU_DEBUG (mailer->debug, MU_DEBUG_TRACE,
191 "missing recipients\n");
192 return MU_ERR_NOENT;
193 }
194
195 argc += tocount; /* 1 per to address */
196 }
412 197
413 close (sendmail->fd); 198 argc++; /* -t */
414 199
415 rc = waitpid (sendmail->pid, &exit_status, 0); 200 /* Allocate arg vec: */
201 if ((argvec = calloc (argc, sizeof (*argvec))) == 0)
202 return ENOMEM;
203
204 argc = 0;
205
206 if (mu_progmailer_sget_command (pm, &argvec[argc]) || argvec[argc] == NULL)
207 {
208 free (argvec);
209 return EINVAL;
210 }
211
212 argc++;
213 argvec[argc++] = "-oi";
416 214
417 if (rc < 0) 215 if (from)
418 { 216 {
419 if (errno == ECHILD) 217 argvec[argc++] = "-f";
420 status = 0; 218 argvec[argc++] = emailfrom;
421 else 219 }
422 {
423 status = errno;
424 MU_DEBUG2 (mailer->debug, MU_DEBUG_TRACE,
425 "waitpid(%d) failed: %s\n",
426 sendmail->pid, strerror (status));
427 }
428 }
429 else if (WIFEXITED (exit_status))
430 {
431 exit_status = WEXITSTATUS (exit_status);
432 MU_DEBUG2 (mailer->debug, MU_DEBUG_TRACE,
433 "%s exited with: %d\n",
434 sendmail->path, exit_status);
435 status = (exit_status == 0) ? 0 : MU_ERR_PROCESS_EXITED;
436 }
437 else if (WIFSIGNALED (exit_status))
438 status = MU_ERR_PROCESS_SIGNALED;
439 else
440 status = MU_ERR_PROCESS_UNKNOWN_FAILURE;
441 220
442 /* Shouldn't this notification only happen on success? */ 221 if (!to || mailer_property_is_set (mailer, "READ_RECIPIENTS"))
443 mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT, 222 {
444 msg); 223 argvec[argc++] = "-t";
445 }
446 default:
447 break;
448 } 224 }
449 225 else
450 sendmail->state = (status == 0) ? SENDMAIL_OPEN : SENDMAIL_CLOSED; 226 {
451 227 size_t i;
228 size_t count = 0;
229
230 mu_address_get_count (to, &count);
231
232 for (i = 1; i <= count; i++)
233 {
234 const char *email;
235 if ((status = mu_address_sget_email (to, i, &email)) != 0)
236 {
237 free (argvec);
238 MU_DEBUG2 (mailer->debug, MU_DEBUG_ERROR,
239 "cannot get email of recipient #%d: %s\n",
240 i, mu_strerror (status));
241 return status;
242 }
243
244 if (!email)
245 {
246 MU_DEBUG1 (mailer->debug, MU_DEBUG_TRACE,
247 "envelope to (%s) not fully qualifed\n",
248 email);
249 free (argvec);
250 return MU_ERR_BAD_822_FORMAT;
251 }
252 argvec[argc++] = email;
253 }
254 }
255 argvec[argc] = NULL;
256
257 mu_progmailer_set_debug (pm, mailer->debug);
258 status = mu_progmailer_open (pm, (char**) argvec);
259 if (status == 0)
260 {
261 status = mu_progmailer_send (pm, msg);
262 if (status == 0)
263 mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT,
264 msg);
265 else
266 MU_DEBUG1 (mailer->debug, MU_DEBUG_ERROR,
267 "progmailer error: %s\n",
268 mu_strerror (status));
269 }
270
271 free (argvec);
452 return status; 272 return status;
453 } 273 }
454 274
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2008 Free Software Foundation, Inc.
3 3
4 This library is free software; you can redistribute it and/or 4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public 5 modify it under the terms of the GNU Lesser General Public
...@@ -46,7 +46,6 @@ _remote_is_scheme (mu_record_t record, mu_url_t url, int flags) ...@@ -46,7 +46,6 @@ _remote_is_scheme (mu_record_t record, mu_url_t url, int flags)
46 { 46 {
47 char *scheme = url->scheme; 47 char *scheme = url->scheme;
48 size_t scheme_len = scheme ? strlen (scheme) : 0; 48 size_t scheme_len = scheme ? strlen (scheme) : 0;
49 int rc;
50 struct _mu_url s_url; 49 struct _mu_url s_url;
51 50
52 if (!scheme 51 if (!scheme
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2002, 2003, 2004, 2 Copyright (C) 1999, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007 Free Software Foundation, Inc. 3 2005, 2006, 2007, 2008 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
...@@ -666,7 +666,7 @@ msg_to_pipe (const char *cmd, mu_message_t msg) ...@@ -666,7 +666,7 @@ msg_to_pipe (const char *cmd, mu_message_t msg)
666 fprintf (fp, "%s", buffer); 666 fprintf (fp, "%s", buffer);
667 off += n; 667 off += n;
668 } 668 }
669 fclose (fp); 669 pclose (fp);
670 } 670 }
671 else 671 else
672 util_error (_("Piping %s failed"), cmd); 672 util_error (_("Piping %s failed"), cmd);
......
...@@ -108,6 +108,7 @@ libmailutils_la_SOURCES = \ ...@@ -108,6 +108,7 @@ libmailutils_la_SOURCES = \
108 opool.c\ 108 opool.c\
109 parse822.c\ 109 parse822.c\
110 parsedate.c\ 110 parsedate.c\
111 progmailer.c\
111 property.c\ 112 property.c\
112 registrar.c\ 113 registrar.c\
113 refcount.c\ 114 refcount.c\
......
...@@ -501,6 +501,7 @@ _expand_aclno (const char *name, void *data, char **p) ...@@ -501,6 +501,7 @@ _expand_aclno (const char *name, void *data, char **p)
501 { 501 {
502 struct run_closure *rp = data; 502 struct run_closure *rp = data;
503 char buf[UINTMAX_STRSIZE_BOUND]; 503 char buf[UINTMAX_STRSIZE_BOUND];
504 /*FIXME: memory leak*/
504 *p = strdup (umaxtostr (rp->idx, buf)); 505 *p = strdup (umaxtostr (rp->idx, buf));
505 return 0; 506 return 0;
506 } 507 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2004, 2005,
3 2006, 2007, 2008 Free Software Foundation, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
9
10 This library 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 GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General
16 Public License along with this library; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sysexits.h>
30
31 #include <sys/types.h>
32 #include <sys/wait.h>
33
34 #include <mailutils/debug.h>
35 #include <mailutils/error.h>
36 #include <mailutils/errno.h>
37 #include <mailutils/stream.h>
38 #include <mailutils/header.h>
39 #include <mailutils/body.h>
40 #include <mailutils/message.h>
41 #include <mailutils/progmailer.h>
42
43 struct _mu_progmailer
44 {
45 int fd;
46 pid_t pid;
47 RETSIGTYPE (*sighandler)();
48 mu_debug_t debug;
49 char *command;
50 };
51
52 /* Close FD unless it is part of pipe P */
53 #define SCLOSE(fd,p) if (p[0]!=fd&&p[1]!=fd) close(fd)
54
55 int
56 mu_progmailer_create (struct _mu_progmailer **ppm)
57 {
58 struct _mu_progmailer *pm = malloc (sizeof (*pm));
59 if (!pm)
60 return ENOMEM;
61 pm->fd = -1;
62 pm->pid = -1;
63 pm->sighandler = SIG_ERR;
64 pm->debug = NULL;
65 pm->command = NULL;
66 *ppm = pm;
67 return 0;
68 }
69
70 int
71 mu_progmailer_set_command (mu_progmailer_t pm, const char *command)
72 {
73 if (!pm)
74 return EINVAL;
75 free (pm->command);
76 if (command)
77 {
78 pm->command = strdup (command);
79 if (!pm->command)
80 return EINVAL;
81 }
82 else
83 pm->command = NULL;
84 return 0;
85 }
86
87 int
88 mu_progmailer_sget_command (mu_progmailer_t pm, const char **command)
89 {
90 if (!pm)
91 return EINVAL;
92 *command = pm->command;
93 return 0;
94 }
95
96 int
97 mu_progmailer_set_debug (mu_progmailer_t pm, mu_debug_t debug)
98 {
99 if (!pm)
100 return EINVAL;
101 pm->debug = debug;
102 }
103
104 void
105 mu_progmailer_destroy (struct _mu_progmailer **ppm)
106 {
107 if (*ppm)
108 {
109 free ((*ppm)->command);
110 free (*ppm);
111 *ppm = NULL;
112 }
113 }
114
115 int
116 mu_progmailer_open (struct _mu_progmailer *pm, char **argv)
117 {
118 int tunnel[2];
119 int status = 0;
120 int i;
121
122 if (!pm || !argv)
123 return EINVAL;
124
125 if ((pm->sighandler = signal (SIGCHLD, SIG_DFL)) == SIG_ERR)
126 {
127 status = errno;
128 MU_DEBUG1 (pm->debug, MU_DEBUG_ERROR,
129 "setting SIGCHLD failed: %s\n", mu_strerror (status));
130 return status;
131 }
132
133 if (pipe (tunnel) == 0)
134 {
135 pm->fd = tunnel[1];
136 pm->pid = fork ();
137 if (pm->pid == 0) /* Child. */
138 {
139 SCLOSE (STDIN_FILENO, tunnel);
140 SCLOSE (STDOUT_FILENO, tunnel);
141 SCLOSE (STDERR_FILENO, tunnel);
142 close (tunnel[1]);
143 dup2 (tunnel[0], STDIN_FILENO);
144 execv (pm->command ? pm->command : argv[0], argv);
145 exit (errno ? EX_CANTCREAT : 0);
146 }
147 else if (pm->pid == -1)
148 {
149 status = errno;
150 MU_DEBUG1 (pm->debug, MU_DEBUG_ERROR,
151 "fork failed: %s\n", mu_strerror (status));
152 }
153 }
154 else
155 {
156 status = errno;
157 MU_DEBUG1 (pm->debug, MU_DEBUG_ERROR,
158 "pipe() failed: %s\n", mu_strerror (status));
159 }
160 MU_DEBUG1 (pm->debug, MU_DEBUG_TRACE, "exec %s argv:", pm->command);
161 for (i = 0; argv[i]; i++)
162 MU_DEBUG1 (pm->debug, MU_DEBUG_TRACE, " %s", argv[i]);
163 MU_DEBUG (pm->debug, MU_DEBUG_TRACE, "\n");
164 close (tunnel[0]);
165
166 if (status != 0)
167 close (pm->fd);
168 return status;
169 }
170
171 int
172 mu_progmailer_send (struct _mu_progmailer *pm, mu_message_t msg)
173 {
174 int status;
175 mu_stream_t stream = NULL;
176 char buffer[512];
177 size_t len = 0;
178 int rc;
179 size_t offset = 0;
180 mu_header_t hdr;
181 mu_body_t body;
182 int found_nl = 0;
183 int exit_status;
184
185 if (!pm || !msg)
186 return EINVAL;
187 mu_message_get_header (msg, &hdr);
188 mu_header_get_stream (hdr, &stream);
189
190 MU_DEBUG (pm->debug, MU_DEBUG_TRACE, "Sending headers...\n");
191 while ((status = mu_stream_readline (stream, buffer, sizeof (buffer),
192 offset, &len)) == 0
193 && len != 0)
194 {
195 if (strncasecmp (buffer, MU_HEADER_FCC, sizeof (MU_HEADER_FCC) - 1))
196 {
197 MU_DEBUG1 (pm->debug, MU_DEBUG_PROT, "Header: %s", buffer);
198 if (write (pm->fd, buffer, len) == -1)
199 {
200 status = errno;
201
202 MU_DEBUG1 (pm->debug, MU_DEBUG_TRACE,
203 "write failed: %s\n", strerror (status));
204 break;
205 }
206 }
207 found_nl = (len == 1 && buffer[0] == '\n');
208
209 offset += len;
210 }
211
212 if (!found_nl)
213 {
214 if (write (pm->fd, "\n", 1) == -1)
215 {
216 status = errno;
217
218 MU_DEBUG1 (pm->debug, MU_DEBUG_TRACE,
219 "write failed: %s\n", strerror (status));
220 }
221 }
222
223 mu_message_get_body (msg, &body);
224 mu_body_get_stream (body, &stream);
225
226 MU_DEBUG (pm->debug, MU_DEBUG_TRACE, "Sending body...\n");
227 offset = 0;
228 while ((status = mu_stream_read (stream, buffer, sizeof (buffer),
229 offset, &len)) == 0
230 && len != 0)
231 {
232 if (write (pm->fd, buffer, len) == -1)
233 {
234 status = errno;
235
236 MU_DEBUG1 (pm->debug, MU_DEBUG_TRACE,
237 "write failed: %s\n", strerror (status));
238 break;
239 }
240 offset += len;
241 }
242
243 close (pm->fd);
244
245 rc = waitpid (pm->pid, &exit_status, 0);
246 if (status == 0)
247 {
248 if (rc < 0)
249 {
250 if (errno == ECHILD)
251 status = 0;
252 else
253 {
254 status = errno;
255 MU_DEBUG2 (pm->debug, MU_DEBUG_TRACE,
256 "waitpid(%lu) failed: %s\n",
257 (unsigned long) pm->pid, strerror (status));
258 }
259 }
260 else if (WIFEXITED (exit_status))
261 {
262 exit_status = WEXITSTATUS (exit_status);
263 MU_DEBUG2 (pm->debug, MU_DEBUG_TRACE,
264 "%s exited with: %d\n",
265 pm->command, exit_status);
266 status = (exit_status == 0) ? 0 : MU_ERR_PROCESS_EXITED;
267 }
268 else if (WIFSIGNALED (exit_status))
269 status = MU_ERR_PROCESS_SIGNALED;
270 else
271 status = MU_ERR_PROCESS_UNKNOWN_FAILURE;
272 }
273 pm->pid = -1;
274 return status;
275 }
276
277 int
278 mu_progmailer_close (struct _mu_progmailer *pm)
279 {
280 int status = 0;
281
282 if (!pm)
283 return EINVAL;
284
285 if (pm->pid > 0)
286 {
287 kill (SIGTERM, pm->pid);
288 pm->pid = -1;
289 }
290
291 if (pm->sighandler != SIG_ERR
292 && signal (SIGCHLD, pm->sighandler) == SIG_ERR)
293 {
294 status = errno;
295 MU_DEBUG1 (pm->debug, MU_DEBUG_ERROR,
296 "resetting SIGCHLD failed: %s\n", mu_strerror (status));
297 }
298 pm->sighandler = SIG_ERR;
299 return status;
300 }