masqmail

view src/deliver.c @ 378:5781ba87df95

Removed ident. This had been discussed on the mailing list in Oct 2011. Ident is hardly useful in typical setups for masqmail. Probably Oliver had used it in his setup; that would make sense. Now, I know of nobody who needs it.
author markus schnalke <meillo@marmaro.de>
date Sat, 14 Jan 2012 21:36:58 +0100
parents a96bb42f597d
children a408411ff8df
line source
1 /*
2 ** MasqMail
3 ** Copyright (C) 1999-2002 Oliver Kurth
4 ** Copyright (C) 2008, 2010 markus schnalke <meillo@marmaro.de>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
21 #include <fnmatch.h>
22 #include <sysexits.h>
23 #include <netdb.h>
25 #include "masqmail.h"
26 #include "smtp_out.h"
28 /*
29 ** collect failed/defered rcpts for failure/warning messages
30 ** returns TRUE if either there are no failures or a failure message has
31 ** been successfully sent
32 */
33 gboolean
34 delivery_failures(message *msg, GList *rcpt_list, gchar *err_fmt, ...)
35 {
36 gboolean ok_fail = TRUE, ok_warn = TRUE;
37 time_t now = time(NULL);
39 GList *failed_list = NULL, *defered_list = NULL, *rcpt_node;
40 va_list args;
41 va_start(args, err_fmt);
43 foreach(rcpt_list, rcpt_node) {
44 address *rcpt = (address *) (rcpt_node->data);
46 if (addr_is_defered(rcpt)) {
47 if ((now - msg->received_time) >= conf.max_defer_time) {
48 addr_mark_failed(rcpt);
49 } else {
50 defered_list = g_list_prepend(defered_list, rcpt);
51 }
52 }
53 if (addr_is_failed(rcpt)) {
54 failed_list = g_list_prepend(failed_list, rcpt);
55 }
56 }
57 if (failed_list) {
58 ok_fail = fail_msg(msg, conf.errmsg_file, failed_list, err_fmt, args);
59 g_list_free(failed_list);
60 }
61 if (defered_list) {
62 ok_warn = warn_msg(msg, conf.warnmsg_file, defered_list, err_fmt, args);
63 g_list_free(defered_list);
64 }
65 va_end(args);
66 return ok_fail && ok_warn;
67 }
69 static gint
70 _g_list_strcasecmp(gconstpointer a, gconstpointer b)
71 {
72 return (gint) strcasecmp(a, b);
73 }
75 gboolean
76 deliver_local_mbox(message *msg, GList *hdr_list, address *rcpt, address *env_addr)
77 {
78 DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
79 if (append_file(msg, hdr_list, rcpt->local_part)) {
80 if (env_addr != rcpt) {
81 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with mbox\n", msg->uid, rcpt->local_part, rcpt->domain, env_addr->local_part, env_addr->domain);
82 } else {
83 logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n", msg->uid, rcpt->local_part, rcpt->domain);
84 }
85 addr_mark_delivered(rcpt);
86 return TRUE;
87 }
89 /* prevents 'Resource temporarily unavailable (11)' */
90 if (errno != EAGAIN) {
91 addr_mark_failed(rcpt);
92 } else {
93 addr_mark_defered(rcpt);
94 }
95 return FALSE;
96 }
98 gboolean
99 deliver_local_pipe(message *msg, GList *hdr_list, address *rcpt, address *env_addr)
100 {
101 guint flags;
103 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
105 flags = (conf.pipe_fromline) ? MSGSTR_FROMLINE : 0;
106 flags |= (conf.pipe_fromhack) ? MSGSTR_FROMHACK : 0;
107 if (pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]), flags)) {
108 logwrite(LOG_NOTICE, "%s => %s <%s@%s> with pipe\n",
109 msg->uid, rcpt->local_part, env_addr->local_part, env_addr->domain);
110 addr_mark_delivered(rcpt);
111 return TRUE;
112 }
114 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
115 addr_mark_failed(rcpt);
116 } else {
117 addr_mark_defered(rcpt);
118 /* has no effect yet, except that mail remains in spool */
119 }
120 return FALSE;
121 }
123 gboolean
124 deliver_local_mda(message *msg, GList *hdr_list, address *rcpt, address *env_addr)
125 {
126 gboolean ok = FALSE;
127 gchar *cmd = g_malloc(256);
128 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
129 guint flags;
131 DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
133 if (!expand(var_table, conf.mda, cmd, 256)) {
134 logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
135 destroy_table(var_table);
136 return FALSE;
137 }
139 flags = (conf.mda_fromline) ? MSGSTR_FROMLINE : 0;
140 flags |= (conf.mda_fromhack) ? MSGSTR_FROMHACK : 0;
141 if (pipe_out(msg, hdr_list, rcpt, cmd, flags)) {
142 logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
143 msg->uid, rcpt->local_part, rcpt->domain, cmd);
144 addr_mark_delivered(rcpt);
145 ok = TRUE;
146 } else if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
147 addr_mark_failed(rcpt);
148 } else {
149 addr_mark_defered(rcpt);
150 /* has no effect yet, except that mail remains in spool */
151 }
153 destroy_table(var_table);
154 return ok;
155 }
157 gboolean
158 deliver_local(msg_out *msgout)
159 {
160 message *msg = msgout->msg;
161 GList *rcpt_list = msgout->rcpt_list;
162 GList *rcpt_node;
163 gboolean ok = FALSE, flag = FALSE, ok_fail = FALSE;
165 DEBUG(5) debugf("deliver_local entered\n");
167 flag = (msg->data_list == NULL);
168 if (flag && !spool_read_data(msg)) {
169 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
170 return FALSE;
171 }
173 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
174 GList *hdr_list;
175 address *rcpt = (address *) (rcpt_node->data);
176 address *env_addr = addr_find_ancestor(rcpt);
177 address *ret_path = msg->return_path;
178 header *retpath_hdr, *envto_hdr;
180 /*
181 ** we need a private copy of the hdr list because we add
182 ** headers here that belong to the rcpt only. g_list_copy
183 ** copies only the nodes, so it is safe to g_list_free it
184 */
185 hdr_list = g_list_copy(msg->hdr_list);
186 retpath_hdr = create_header(HEAD_ENVELOPE_TO, "Envelope-to: %s\n", addr_string(env_addr));
187 envto_hdr = create_header(HEAD_RETURN_PATH, "Return-path: %s\n", addr_string(ret_path));
189 hdr_list = g_list_prepend(hdr_list, envto_hdr);
190 hdr_list = g_list_prepend(hdr_list, retpath_hdr);
192 if (rcpt->local_part[0] == '|') {
193 /*
194 ** probably for expanded aliases, but why not done
195 ** like with the mda? //meillo 2010-12-06
196 */
197 if (deliver_local_pipe(msg, hdr_list, rcpt, env_addr)) {
198 ok = TRUE;
199 }
200 } else {
201 /* figure out which mailbox type should be used for this user */
202 gchar *user = rcpt->local_part;
203 gchar *mbox_type = conf.mbox_default;
205 if (g_list_find_custom (conf.mbox_users, user, _g_list_strcasecmp)) {
206 mbox_type = "mbox";
207 } else if (g_list_find_custom (conf.mda_users, user, _g_list_strcasecmp)) {
208 mbox_type = "mda";
209 }
211 if (strcmp(mbox_type, "mbox") == 0) {
212 if (deliver_local_mbox(msg, hdr_list, rcpt, env_addr)) {
213 ok = TRUE;
214 }
215 } else if (strcmp(mbox_type, "mda") == 0) {
216 if (conf.mda) {
217 if (deliver_local_mda(msg, hdr_list, rcpt, env_addr)) {
218 ok = TRUE;
219 }
220 } else {
221 logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n");
222 }
224 } else {
225 logwrite(LOG_ALERT, "unknown mbox type '%s'\n", mbox_type);
226 }
227 }
229 destroy_header(retpath_hdr);
230 destroy_header(envto_hdr);
232 g_list_free(hdr_list);
233 }
234 ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)", ext_strerror(errno), errno);
236 if (flag) {
237 msg_free_data(msg);
238 }
239 if (ok || ok_fail) {
240 deliver_finish(msgout);
241 }
243 return ok;
244 }
246 /*
247 ** make a list of rcpt's of a message that are local
248 ** return a new copy of the list
249 */
250 void
251 msg_rcptlist_local(GList *rcpt_list, GList **p_local_list,
252 GList **p_nonlocal_list)
253 {
254 GList *rcpt_node;
256 foreach(rcpt_list, rcpt_node) {
257 address *rcpt = (address *) (rcpt_node->data);
258 GList *dom_node;
260 DEBUG(5) debugf("checking address %s\n", rcpt->address);
262 /* search for local host list: */
263 foreach(conf.local_hosts, dom_node) {
264 if (fnmatch(dom_node->data, rcpt->domain, FNM_CASEFOLD)==0) {
265 *p_local_list = g_list_append(*p_local_list, rcpt);
266 DEBUG(5) debugf("<%s@%s> is local\n", rcpt->local_part, rcpt->domain);
267 break;
268 } else {
269 *p_nonlocal_list = g_list_append(*p_nonlocal_list, rcpt);
270 }
271 }
272 }
273 }
275 gboolean
276 deliver_msglist_host_pipe(connect_route *route, GList *msgout_list,
277 gchar *host, GList *res_list)
278 {
279 gboolean ok = TRUE;
280 GList *msgout_node;
282 DEBUG(5) debugf("deliver_msglist_host_pipe entered\n");
284 foreach(msgout_list, msgout_node) {
285 msg_out *msgout = (msg_out *) (msgout_node->data);
286 gboolean flag, ok_fail = FALSE;
287 message *msg = msgout->msg;
288 GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
290 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
292 flag = (msg->data_list == NULL);
293 if (flag && !spool_read_data(msg)) {
294 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
295 continue;
296 }
298 ok = FALSE;
299 foreach(rcpt_list, rcpt_node) {
300 address *rcpt = (address *) (rcpt_node->data);
301 gchar *cmd = g_malloc(256);
302 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
304 DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n",
305 msg->uid, rcpt->local_part, rcpt->domain);
307 if (!expand(var_table, route->pipe, cmd, 256)) {
308 logwrite(LOG_ALERT, "could not expand string `%s'\n", route->pipe);
309 destroy_table(var_table);
310 continue;
311 }
313 if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0)
314 | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
315 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n",
316 msg->uid, rcpt->local_part, rcpt->domain, cmd);
317 addr_mark_delivered(rcpt);
318 ok = TRUE;
319 } else {
320 logwrite(LOG_ALERT, "pipe_out '%s' failed\n", route->pipe);
322 if (route->connect_error_fail) {
323 addr_mark_failed(rcpt);
324 } else {
325 addr_mark_defered(rcpt);
326 }
327 }
329 destroy_table(var_table);
330 }
331 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
333 if (flag) {
334 msg_free_data(msg);
335 }
336 if (ok || ok_fail) {
337 deliver_finish(msgout);
338 }
339 }
341 return ok;
342 }
344 /*
345 ** deliver list of messages to one host and finishes them if the message was
346 ** delivered to at least one rcpt.
347 ** Returns TRUE if at least one msg was delivered to at least one rcpt.
348 */
349 gboolean
350 deliver_msglist_host_smtp(connect_route *route, GList *msgout_list,
351 gchar *host, GList *res_list)
352 {
353 gboolean ok = FALSE;
354 GList *msgout_node;
355 smtp_base *psb;
356 gint port = 25;
358 /* paranoid check: */
359 if (!msgout_list) {
360 logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n");
361 return FALSE;
362 }
364 if (!host) {
365 /* XXX: what if mail_host isn't set? Is this possible? */
366 host = route->mail_host->address;
367 port = route->mail_host->port;
368 }
370 if (route->wrapper) {
371 psb = smtp_out_open_child(route->wrapper);
372 if (psb) {
373 psb->remote_host = host;
374 }
375 } else {
376 psb = smtp_out_open(host, port, res_list);
377 }
379 if (!psb) {
380 /* smtp_out_open() failed */
381 foreach(msgout_list, msgout_node) {
382 msg_out *msgout = (msg_out *) (msgout_node->data);
383 GList *rcpt_node;
385 for (rcpt_node = g_list_first(msgout->rcpt_list);
386 rcpt_node;
387 rcpt_node = g_list_next(rcpt_node)) {
388 address *rcpt = (address *) (rcpt_node->data);
389 gboolean ret = FALSE;
391 addr_unmark_delivered(rcpt);
392 if (route->connect_error_fail) {
393 addr_mark_failed(rcpt);
394 } else {
395 addr_mark_defered(rcpt);
396 }
397 if (route->wrapper) {
398 ret = delivery_failures(msgout->msg, msgout->rcpt_list, "could not open wrapper:\n\t%s", strerror(errno));
399 } else {
400 ret = delivery_failures(msgout->msg, msgout->rcpt_list, "could not open connection to %s:%d :\n\t%s", host, port, h_errno != 0 ? hstrerror(h_errno) : strerror(errno));
401 }
402 if (ret) {
403 deliver_finish(msgout);
404 }
405 }
406 }
407 return ok;
408 }
410 set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
412 #ifdef ENABLE_AUTH
413 if (route->auth_name && route->auth_login && route->auth_secret) {
414 set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
415 }
416 #endif
417 if (!smtp_out_init(psb, route->instant_helo)) {
418 /* smtp_out_init() failed */
419 if ((psb->error==smtp_fail) || (psb->error==smtp_trylater) || (psb->error==smtp_syntax)) {
420 smtp_out_quit(psb);
422 foreach(msgout_list, msgout_node) {
423 msg_out *msgout = (msg_out *) (msgout_node->data);
424 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
426 if (delivery_failures(msgout->msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", (route->wrapper) ? "<wrapper>" : host, psb->buffer)) {
427 deliver_finish(msgout);
428 }
429 }
430 }
431 destroy_smtpbase(psb);
432 return ok;
433 }
435 if (!route->do_pipelining) {
436 psb->use_pipelining = FALSE;
437 }
439 foreach(msgout_list, msgout_node) {
440 msg_out *msgout = (msg_out *) (msgout_node->data);
441 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
442 message *msg = msgout->msg;
444 /* we may have to read the data at this point and remember if we did */
445 flag = (msg->data_list == NULL);
446 if (flag && !spool_read_data(msg)) {
447 logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
448 break;
449 }
451 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
453 ok_fail = delivery_failures(msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", (route->wrapper) ? "<wrapper>" : host, psb->buffer);
455 if ((psb->error == smtp_eof) || (psb->error == smtp_timeout)) {
456 /* connection lost */
457 break;
458 } else if (psb->error != smtp_ok) {
459 if (g_list_next(msgout_node) && !smtp_out_rset(psb)) {
460 break;
461 }
462 }
463 ok_msg = (psb->error == smtp_ok);
465 if (flag) {
466 msg_free_data(msg);
467 }
468 if (ok_msg) {
469 ok = TRUE;
470 }
471 if (ok_msg || ok_fail) {
472 deliver_finish(msgout);
473 }
474 }
475 if (psb->error == smtp_ok || (psb->error == smtp_fail)
476 || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
477 smtp_out_quit(psb);
478 }
479 destroy_smtpbase(psb);
480 return ok;
481 }
483 gboolean
484 deliver_msglist_host(connect_route *route, GList *msgout_list, gchar *host,
485 GList *res_list)
486 {
488 if (route->pipe) {
489 DEBUG(5) debugf("with pipe\n");
490 return deliver_msglist_host_pipe(route, msgout_list, host, res_list);
491 } else {
492 DEBUG(5) debugf("with smtp\n");
493 return deliver_msglist_host_smtp(route, msgout_list, host, res_list);
494 }
495 }
497 /*
498 ** delivers messages in msgout_list using route
499 */
500 gboolean
501 deliver_route_msgout_list(connect_route *route, GList *msgout_list)
502 {
503 gboolean ok = FALSE;
504 GList *mo_ph_list;
505 GList *mo_ph_node;
507 DEBUG(5) debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name);
509 if (route->mail_host) {
510 /* this is easy... deliver everything to a smart host for relay */
511 return deliver_msglist_host(route, msgout_list, NULL,
512 route->resolve_list);
513 }
515 /* this is not easy... */
517 mo_ph_list = route_msgout_list(route, msgout_list);
518 /* okay, now we have ordered our messages by the hosts. */
519 if (!mo_ph_list) {
520 return FALSE;
521 }
523 /*
524 ** TODO: It would be nice to be able to fork for each host.
525 ** We cannot do that yet because of complications with finishing the
526 ** messages. Threads could be a solution because they use the same
527 ** memory. But we are not thread safe yet...
528 */
529 foreach(mo_ph_list, mo_ph_node) {
530 msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
531 if (deliver_msglist_host(route, mo_ph->msgout_list,
532 mo_ph->host, route->resolve_list)) {
533 ok = TRUE;
534 }
535 destroy_msgout_perhost(mo_ph);
536 }
537 g_list_free(mo_ph_list);
538 return ok;
539 }
541 /*
542 ** calls route_prepare_msg()
543 ** delivers messages in msg_list using route by calling
544 ** deliver_route_msgout_list()
545 */
546 gboolean
547 deliver_route_msg_list(connect_route *route, GList *msgout_list)
548 {
549 GList *msgout_list_deliver = NULL;
550 GList *msgout_node;
551 gboolean ok = TRUE;
553 DEBUG(6) debugf("deliver_route_msg_list()\n");
555 foreach(msgout_list, msgout_node) {
556 msg_out *msgout = (msg_out *) (msgout_node->data);
557 msg_out *msgout_cloned = clone_msg_out(msgout);
558 GList *rcpt_list_non_delivered = NULL;
559 GList *rcpt_node;
561 /*
562 ** we have to delete already delivered rcpt's because a
563 ** previous route may have delivered to it
564 */
565 foreach(msgout_cloned->rcpt_list, rcpt_node) {
566 address *rcpt = (address *) (rcpt_node->data);
567 /*
568 ** failed addresses already have been bounced;
569 ** there should be a better way to handle those.
570 */
571 if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt)
572 && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE)) {
573 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
574 }
575 }
576 g_list_free(msgout_cloned->rcpt_list);
577 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
579 if (!msgout_cloned->rcpt_list) {
580 destroy_msg_out(msgout_cloned);
581 continue;
582 }
584 /* filter by allowed envelope sender */
585 if (!route_sender_is_allowed(route, msgout->msg->return_path)) {
586 DEBUG(6) debugf("sender `%s' is not allowed for this route\n", msgout->msg->return_path);
587 destroy_msg_out(msgout_cloned);
588 continue;
589 }
591 /* filter by allowed envelope rcpts */
592 GList *rcpt_list_allowed = NULL;
593 GList *rcpt_list_notallowed = NULL;
594 route_split_rcpts(route, msgout_cloned->rcpt_list,
595 &rcpt_list_allowed, &rcpt_list_notallowed);
596 if (!rcpt_list_allowed) {
597 destroy_msg_out(msgout_cloned);
598 continue;
599 }
601 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid,
602 route->name);
604 g_list_free(msgout_cloned->rcpt_list);
605 msgout_cloned->rcpt_list = rcpt_list_allowed;
607 if (route->last_route) {
608 GList *rcpt_node;
609 foreach(msgout_cloned->rcpt_list, rcpt_node) {
610 address *rcpt = (address *) (rcpt_node->data);
611 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
612 }
613 }
615 route_prepare_msgout(route, msgout_cloned);
616 msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
617 }
619 if (msgout_list_deliver) {
620 if (deliver_route_msgout_list(route, msgout_list_deliver)) {
621 ok = TRUE;
622 }
623 destroy_msg_out_list(msgout_list_deliver);
624 }
625 return ok;
626 }
628 /*
629 ** copy pointers of delivered addresses to the msg's non_rcpt_list,
630 ** to make sure that they will not be delivered again.
631 */
632 void
633 update_non_rcpt_list(msg_out *msgout)
634 {
635 GList *rcpt_node;
636 message *msg = msgout->msg;
638 foreach(msgout->rcpt_list, rcpt_node) {
639 address *rcpt = (address *) (rcpt_node->data);
640 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt)) {
641 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
642 }
643 }
644 }
646 /*
647 ** after delivery attempts, we check if there are any rcpt addresses left in
648 ** the message. If all addresses have been completed, the spool files will be
649 ** deleted, otherwise the header spool will be written back. We never changed
650 ** the data spool, so there is no need to write that back.
651 **
652 ** returns TRUE if all went well.
653 */
654 gboolean
655 deliver_finish(msg_out *msgout)
656 {
657 GList *rcpt_node;
658 message *msg = msgout->msg;
659 gboolean finished = TRUE;
661 update_non_rcpt_list(msgout);
663 /*
664 ** we NEVER made copies of the addresses, flags affecting addresses
665 ** were always set on the original address structs
666 */
667 foreach(msg->rcpt_list, rcpt_node) {
668 address *rcpt = (address *) (rcpt_node->data);
669 if (!addr_is_finished_children(rcpt)) {
670 finished = FALSE;
671 } else {
672 /*
673 ** if ALL children have been delivered, mark parent as
674 ** delivered. if there is one or more not delivered,
675 ** it must have failed, we mark the parent as failed
676 ** as well.
677 */
678 if (addr_is_delivered_children(rcpt)) {
679 addr_mark_delivered(rcpt);
680 } else {
681 addr_mark_failed(rcpt);
682 }
683 }
684 }
686 if (finished) {
687 if (spool_delete_all(msg)) {
688 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
689 return TRUE;
690 }
691 return FALSE;
692 }
694 /* one not delivered address was found */
695 if (!spool_write(msg, FALSE)) {
696 logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
697 return FALSE;
698 }
700 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
701 return TRUE;
702 }
704 int
705 deliver_remote(GList *remote_msgout_list)
706 {
707 int ok = TRUE;
708 GList *route_list = NULL;
709 GList *route_node;
710 GList *rf_list = NULL;
711 gchar *connect_name = NULL;
713 if (!remote_msgout_list) {
714 return FALSE;
715 }
717 /* perma routes */
718 if (conf.perma_routes) {
719 DEBUG(5) debugf("processing perma_routes\n");
721 route_list = read_route_list(conf.perma_routes, TRUE);
722 foreach(route_list, route_node) {
723 connect_route *route = (connect_route *) (route_node->data);
724 if (!deliver_route_msg_list(route, remote_msgout_list)) {
725 ok = FALSE;
726 }
727 }
728 destroy_route_list(route_list);
729 }
731 /* query routes */
732 connect_name = online_query();
733 if (!connect_name) {
734 DEBUG(5) debugf("online query returned false\n");
735 return FALSE;
736 }
738 /* we are online! */
739 DEBUG(5) debugf("processing query_routes\n");
740 logwrite(LOG_NOTICE, "detected online configuration `%s'\n", connect_name);
742 rf_list = (GList *) table_find(conf.query_routes, connect_name);
743 if (!rf_list) {
744 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
745 return FALSE;
746 }
748 route_list = read_route_list(rf_list, FALSE);
749 if (!route_list) {
750 logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
751 return FALSE;
752 }
754 foreach(route_list, route_node) {
755 connect_route *route = (connect_route *) (route_node->data);
756 /* TODO: ok gets overwritten */
757 ok = deliver_route_msg_list(route, remote_msgout_list);
758 }
759 destroy_route_list(route_list);
761 return ok;
762 }
764 /*
765 ** This function splits the list of rcpt addresses
766 ** into local and remote addresses and processes them accordingly.
767 */
768 gboolean
769 deliver_msg_list(GList *msg_list, guint flags)
770 {
771 GList *msgout_list = NULL;
772 GList *msg_node;
773 GList *local_msgout_list = NULL;
774 GList *remote_msgout_list = NULL;
775 GList *msgout_node;
776 GList *alias_table = NULL;
777 gboolean ok = TRUE;
779 /* create msgout_list */
780 foreach(msg_list, msg_node) {
781 message *msg = (message *) msg_node->data;
782 msgout_list = g_list_append(msgout_list, create_msg_out(msg));
783 }
785 if (conf.alias_file) {
786 alias_table = table_read(conf.alias_file, ':');
787 }
789 /* sort messages for different deliveries */
790 foreach(msgout_list, msgout_node) {
791 msg_out *msgout = (msg_out *) (msgout_node->data);
792 GList *rcpt_list;
793 GList *local_rcpt_list = NULL;
794 GList *other_rcpt_list = NULL;
796 if (!spool_lock(msgout->msg->uid)) {
797 DEBUG(5) debugf("spool_lock(%s) failed.\n", msgout->msg->uid);
798 continue;
799 }
800 DEBUG(5) debugf("spool_lock(%s)\n", msgout->msg->uid);
802 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
803 if (conf.log_user) {
804 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
805 if (addr) {
806 rcpt_list = g_list_prepend(rcpt_list, addr);
807 } else {
808 logwrite(LOG_ALERT, "invalid log_user address `%s', ignoring\n", conf.log_user);
809 }
810 }
811 if (alias_table) {
812 GList *aliased_rcpt_list;
813 aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list);
814 g_list_free(rcpt_list);
815 rcpt_list = aliased_rcpt_list;
816 }
818 /* split_rcpts(rcpt_list, NULL, &local_rcpt_list, NULL, &other_rcpt_list); */
819 local_rcpt_list = local_rcpts(rcpt_list);
820 other_rcpt_list = remote_rcpts(rcpt_list);
821 g_list_free(rcpt_list);
823 /* local recipients */
824 if ((flags & DLVR_LOCAL) && local_rcpt_list) {
825 msg_out *local_msgout = clone_msg_out(msgout);
826 local_msgout->rcpt_list = local_rcpt_list;
827 local_msgout_list = g_list_append(local_msgout_list, local_msgout);
828 }
830 /* remote recipients, requires online delivery */
831 if ((flags & DLVR_ONLINE) && other_rcpt_list) {
832 msg_out *remote_msgout = clone_msg_out(msgout);
833 remote_msgout->rcpt_list = other_rcpt_list;
834 remote_msgout_list = g_list_append(remote_msgout_list, remote_msgout);
835 }
836 }
838 if (alias_table) {
839 destroy_table(alias_table);
840 }
842 /* process local/remote msgout lists -> delivery */
844 if (local_msgout_list) {
845 DEBUG(5) debugf("local_msgout_list\n");
846 foreach(local_msgout_list, msgout_node) {
847 msg_out *msgout = (msg_out *) (msgout_node->data);
848 if (!deliver_local(msgout)) {
849 ok = FALSE;
850 }
851 }
852 destroy_msg_out_list(local_msgout_list);
853 }
855 if (remote_msgout_list) {
856 DEBUG(5) debugf("remote_msgout_list\n");
857 deliver_remote(remote_msgout_list);
858 destroy_msg_out_list(remote_msgout_list);
859 }
861 /* unlock spool files */
862 foreach(msgout_list, msgout_node) {
863 msg_out *msgout = (msg_out *) (msgout_node->data);
864 if (spool_unlock(msgout->msg->uid)) {
865 DEBUG(5) debugf("spool_unlock(%s)\n", msgout->msg->uid);
866 } else {
867 DEBUG(5) debugf("spool_unlock(%s) failed.\n", msgout->msg->uid);
868 }
869 }
870 destroy_msg_out_list(msgout_list);
872 return ok;
873 }
875 /*
876 ** deliver() is called when a message has just been received
877 ** (mode_accept and smtp_in) and should be delivered immediately
878 ** (neither -odq nor do_queue). Only this one message will be tried to
879 ** deliver then.
880 */
881 gboolean
882 deliver(message *msg)
883 {
884 gboolean ok;
885 GList *msg_list = g_list_append(NULL, msg);
887 ok = deliver_msg_list(msg_list, DLVR_ALL);
888 g_list_free(msg_list);
890 return ok;
891 }