masqmail

view src/deliver.c @ 347:53cf6be5843a

Minor refactoring
author markus schnalke <meillo@marmaro.de>
date Thu, 14 Jul 2011 11:15:27 +0200
parents 9149d893eb52
children 332999b1303f
line source
1 /* MasqMail
2 Copyright (C) 1999-2002 Oliver Kurth
3 Copyright (C) 2008, 2010 markus schnalke <meillo@marmaro.de>
5 This program 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 2 of the License, or
8 (at your option) any later version.
10 This program 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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
20 #include <fnmatch.h>
21 #include <sysexits.h>
22 #include <netdb.h>
24 #include "masqmail.h"
25 #include "smtp_out.h"
27 /* collect failed/defered rcpts for failure/warning messages */
28 /* returns TRUE if either there are no failures or a failure message has been successfully sent */
29 gboolean
30 delivery_failures(message * msg, GList * rcpt_list, gchar * err_fmt, ...)
31 {
32 gboolean ok_fail = TRUE, ok_warn = TRUE;
33 time_t now = time(NULL);
35 GList *failed_list = NULL, *defered_list = NULL, *rcpt_node;
36 va_list args;
37 va_start(args, err_fmt);
39 foreach(rcpt_list, rcpt_node) {
40 address *rcpt = (address *) (rcpt_node->data);
42 if (addr_is_defered(rcpt)) {
43 if ((now - msg->received_time) >= conf.max_defer_time) {
44 addr_mark_failed(rcpt);
45 } else {
46 defered_list = g_list_prepend(defered_list, rcpt);
47 }
48 }
49 if (addr_is_failed(rcpt)) {
50 failed_list = g_list_prepend(failed_list, rcpt);
51 }
52 }
53 if (failed_list) {
54 ok_fail = fail_msg(msg, conf.errmsg_file, failed_list, err_fmt, args);
55 g_list_free(failed_list);
56 }
57 if (defered_list) {
58 ok_warn = warn_msg(msg, conf.warnmsg_file, defered_list, err_fmt, args);
59 g_list_free(defered_list);
60 }
61 va_end(args);
62 return ok_fail && ok_warn;
63 }
65 static gint
66 _g_list_strcasecmp(gconstpointer a, gconstpointer b)
67 {
68 return (gint) strcasecmp(a, b);
69 }
71 gboolean
72 deliver_local_mbox(message* msg, GList* hdr_list, address* rcpt, address* env_addr)
73 {
74 DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
75 if (append_file(msg, hdr_list, rcpt->local_part)) {
76 if (env_addr != rcpt) {
77 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);
78 } else {
79 logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n", msg->uid, rcpt->local_part, rcpt->domain);
80 }
81 addr_mark_delivered(rcpt);
82 return TRUE;
83 }
85 /* prevents 'Resource temporarily unavailable (11)' */
86 if (errno != EAGAIN) {
87 addr_mark_failed(rcpt);
88 } else {
89 addr_mark_defered(rcpt);
90 }
91 return FALSE;
92 }
94 gboolean
95 deliver_local_pipe(message* msg, GList* hdr_list, address* rcpt, address* env_addr)
96 {
97 guint flags;
99 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
101 flags = (conf.pipe_fromline) ? MSGSTR_FROMLINE : 0;
102 flags |= (conf.pipe_fromhack) ? MSGSTR_FROMHACK : 0;
103 if (pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]), flags)) {
104 logwrite(LOG_NOTICE, "%s => %s <%s@%s> with pipe\n",
105 msg->uid, rcpt->local_part, env_addr->local_part, env_addr->domain);
106 addr_mark_delivered(rcpt);
107 return TRUE;
108 }
110 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
111 addr_mark_failed(rcpt);
112 } else {
113 addr_mark_defered(rcpt);
114 /* has no effect yet, except that mail remains in spool */
115 }
116 return FALSE;
117 }
119 gboolean
120 deliver_local_mda(message* msg, GList* hdr_list, address* rcpt, address* env_addr)
121 {
122 gboolean ok = FALSE;
123 gchar *cmd = g_malloc(256);
124 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
125 guint flags;
127 DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
129 if (!expand(var_table, conf.mda, cmd, 256)) {
130 logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
131 destroy_table(var_table);
132 return FALSE;
133 }
135 flags = (conf.mda_fromline) ? MSGSTR_FROMLINE : 0;
136 flags |= (conf.mda_fromhack) ? MSGSTR_FROMHACK : 0;
137 if (pipe_out(msg, hdr_list, rcpt, cmd, flags)) {
138 logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
139 msg->uid, rcpt->local_part, rcpt->domain, cmd);
140 addr_mark_delivered(rcpt);
141 ok = TRUE;
142 } else if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
143 addr_mark_failed(rcpt);
144 } else {
145 addr_mark_defered(rcpt);
146 /* has no effect yet, except that mail remains in spool */
147 }
149 destroy_table(var_table);
150 return ok;
151 }
153 gboolean
154 deliver_local(msg_out * msgout)
155 {
156 message *msg = msgout->msg;
157 GList *rcpt_list = msgout->rcpt_list;
158 GList *rcpt_node;
159 gboolean ok = FALSE, flag = FALSE, ok_fail = FALSE;
161 DEBUG(5) debugf("deliver_local entered\n");
163 flag = (msg->data_list == NULL);
164 if (flag && !spool_read_data(msg)) {
165 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
166 return FALSE;
167 }
169 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
170 GList *hdr_list;
171 address *rcpt = (address *) (rcpt_node->data);
172 address *env_addr = addr_find_ancestor(rcpt);
173 address *ret_path = msg->return_path;
174 header *retpath_hdr, *envto_hdr;
176 /* we need a private copy of the hdr list because we add headers
177 here that belong to the rcpt only. g_list_copy copies only
178 the nodes, so it is safe to g_list_free it */
179 hdr_list = g_list_copy(msg->hdr_list);
180 retpath_hdr = create_header(HEAD_ENVELOPE_TO, "Envelope-to: %s\n", addr_string(env_addr));
181 envto_hdr = create_header(HEAD_RETURN_PATH, "Return-path: %s\n", addr_string(ret_path));
183 hdr_list = g_list_prepend(hdr_list, envto_hdr);
184 hdr_list = g_list_prepend(hdr_list, retpath_hdr);
186 if (rcpt->local_part[0] == '|') {
187 /* probably for expanded aliases, but why not done
188 like with the mda? //meillo 2010-12-06 */
189 if (deliver_local_pipe(msg, hdr_list, rcpt, env_addr)) {
190 ok = TRUE;
191 }
192 } else {
193 /* figure out which mailbox type should be used for this user */
194 gchar *user = rcpt->local_part;
195 gchar *mbox_type = conf.mbox_default;
197 if (g_list_find_custom (conf.mbox_users, user, _g_list_strcasecmp)) {
198 mbox_type = "mbox";
199 } else if (g_list_find_custom (conf.mda_users, user, _g_list_strcasecmp)) {
200 mbox_type = "mda";
201 }
203 if (strcmp(mbox_type, "mbox") == 0) {
204 if (deliver_local_mbox(msg, hdr_list, rcpt, env_addr)) {
205 ok = TRUE;
206 }
207 } else if (strcmp(mbox_type, "mda") == 0) {
208 if (conf.mda) {
209 if (deliver_local_mda(msg, hdr_list, rcpt, env_addr)) {
210 ok = TRUE;
211 }
212 } else {
213 logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n");
214 }
216 } else {
217 logwrite(LOG_ALERT, "unknown mbox type '%s'\n", mbox_type);
218 }
219 }
221 destroy_header(retpath_hdr);
222 destroy_header(envto_hdr);
224 g_list_free(hdr_list);
225 }
226 ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)", ext_strerror(errno), errno);
228 if (flag) {
229 msg_free_data(msg);
230 }
231 if (ok || ok_fail) {
232 deliver_finish(msgout);
233 }
235 return ok;
236 }
238 /* make a list of rcpt's of a message that are local
239 return a new copy of the list */
240 void
241 msg_rcptlist_local(GList * rcpt_list, GList ** p_local_list, GList ** p_nonlocal_list)
242 {
243 GList *rcpt_node;
245 foreach(rcpt_list, rcpt_node) {
246 address *rcpt = (address *) (rcpt_node->data);
247 GList *dom_node;
249 DEBUG(5) debugf("checking address %s\n", rcpt->address);
251 /* search for local host list: */
252 foreach(conf.local_hosts, dom_node) {
253 if (strcasecmp(dom_node->data, rcpt->domain) == 0) {
254 *p_local_list = g_list_append(*p_local_list, rcpt);
255 DEBUG(5) debugf("<%s@%s> is local\n", rcpt->local_part, rcpt->domain);
256 break;
257 } else {
258 *p_nonlocal_list = g_list_append(*p_nonlocal_list, rcpt);
259 }
260 }
261 }
262 }
264 gboolean
265 deliver_msglist_host_pipe(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
266 {
267 gboolean ok = TRUE;
268 GList *msgout_node;
270 DEBUG(5) debugf("deliver_msglist_host_pipe entered\n");
272 foreach(msgout_list, msgout_node) {
273 msg_out *msgout = (msg_out *) (msgout_node->data);
274 gboolean flag, ok_fail = FALSE;
275 message *msg = msgout->msg;
276 GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
278 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
280 flag = (msg->data_list == NULL);
281 if (flag && !spool_read_data(msg)) {
282 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
283 continue;
284 }
286 ok = FALSE;
287 foreach(rcpt_list, rcpt_node) {
288 address *rcpt = (address *) (rcpt_node->data);
289 gchar *cmd = g_malloc(256);
290 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
292 DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n",
293 msg->uid, rcpt->local_part, rcpt->domain);
295 if (!expand(var_table, route->pipe, cmd, 256)) {
296 logwrite(LOG_ALERT, "could not expand string `%s'\n", route->pipe);
297 destroy_table(var_table);
298 continue;
299 }
301 if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0)
302 | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
303 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n",
304 msg->uid, rcpt->local_part, rcpt->domain, cmd);
305 addr_mark_delivered(rcpt);
306 ok = TRUE;
307 } else {
308 logwrite(LOG_ALERT, "pipe_out '%s' failed\n", route->pipe);
310 if (route->connect_error_fail) {
311 addr_mark_failed(rcpt);
312 } else {
313 addr_mark_defered(rcpt);
314 }
315 }
317 destroy_table(var_table);
318 }
319 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
321 if (flag) {
322 msg_free_data(msg);
323 }
324 if (ok || ok_fail) {
325 deliver_finish(msgout);
326 }
327 }
329 return ok;
330 }
332 /* deliver list of messages to one host and finishes them if the message was
333 delivered to at least one rcpt.
334 Returns TRUE if at least one msg was delivered to at least one rcpt.
335 */
336 gboolean
337 deliver_msglist_host_smtp(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
338 {
339 gboolean ok = FALSE;
340 GList *msgout_node;
341 smtp_base *psb;
342 gint port = 25;
344 /* paranoid check: */
345 if (!msgout_list) {
346 logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n");
347 return FALSE;
348 }
350 if (!host) {
351 /* XXX: what if mail_host isn't set? Is this possible? */
352 host = route->mail_host->address;
353 port = route->mail_host->port;
354 }
356 if (route->wrapper) {
357 psb = smtp_out_open_child(route->wrapper, host);
358 } else {
359 psb = smtp_out_open(host, port, res_list);
360 }
362 if (!psb) {
363 /* smtp_out_open() failed */
364 foreach(msgout_list, msgout_node) {
365 msg_out *msgout = (msg_out *) (msgout_node->data);
366 GList *rcpt_node;
368 for (rcpt_node = g_list_first(msgout->rcpt_list);
369 rcpt_node;
370 rcpt_node = g_list_next(rcpt_node)) {
371 address *rcpt = (address *) (rcpt_node->data);
372 gboolean ret = FALSE;
374 addr_unmark_delivered(rcpt);
375 if (route->connect_error_fail) {
376 addr_mark_failed(rcpt);
377 } else {
378 addr_mark_defered(rcpt);
379 }
380 if (route->wrapper) {
381 ret = delivery_failures(msgout->msg, msgout->rcpt_list, "could not open wrapper:\n\t%s", strerror(errno));
382 } else {
383 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));
384 }
385 if (ret) {
386 deliver_finish(msgout);
387 }
388 }
389 }
390 return ok;
391 }
393 set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
395 #ifdef ENABLE_AUTH
396 if (route->auth_name && route->auth_login && route->auth_secret) {
397 set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
398 }
399 #endif
400 if (!smtp_out_init(psb, route->instant_helo)) {
401 /* smtp_out_init() failed */
402 if ((psb->error==smtp_fail) || (psb->error==smtp_trylater) || (psb->error==smtp_syntax)) {
403 smtp_out_quit(psb);
405 foreach(msgout_list, msgout_node) {
406 msg_out *msgout = (msg_out *) (msgout_node->data);
407 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
409 if (delivery_failures(msgout->msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", host, psb->buffer)) {
410 deliver_finish(msgout);
411 }
412 }
413 }
414 destroy_smtpbase(psb);
415 return ok;
416 }
418 if (!route->do_pipelining) {
419 psb->use_pipelining = FALSE;
420 }
422 foreach(msgout_list, msgout_node) {
423 msg_out *msgout = (msg_out *) (msgout_node->data);
424 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
425 message *msg = msgout->msg;
427 /* we may have to read the data at this point and remember if we did */
428 flag = (msg->data_list == NULL);
429 if (flag && !spool_read_data(msg)) {
430 logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
431 break;
432 }
434 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
436 ok_fail = delivery_failures(msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", host, psb->buffer);
438 if ((psb->error == smtp_eof) || (psb->error == smtp_timeout)) {
439 /* connection lost */
440 break;
441 } else if (psb->error != smtp_ok) {
442 if (g_list_next(msgout_node) && !smtp_out_rset(psb)) {
443 break;
444 }
445 }
446 ok_msg = (psb->error == smtp_ok);
448 if (flag) {
449 msg_free_data(msg);
450 }
451 if (ok_msg) {
452 ok = TRUE;
453 }
454 if (ok_msg || ok_fail) {
455 deliver_finish(msgout);
456 }
457 }
458 if (psb->error == smtp_ok || (psb->error == smtp_fail)
459 || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
460 smtp_out_quit(psb);
461 }
462 destroy_smtpbase(psb);
463 return ok;
464 }
466 gboolean
467 deliver_msglist_host(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
468 {
470 if (route->pipe) {
471 DEBUG(5) debugf("with pipe\n");
472 return deliver_msglist_host_pipe(route, msgout_list, host, res_list);
473 } else {
474 DEBUG(5) debugf("with smtp\n");
475 return deliver_msglist_host_smtp(route, msgout_list, host, res_list);
476 }
477 }
479 /*
480 delivers messages in msgout_list using route
481 */
482 gboolean
483 deliver_route_msgout_list(connect_route * route, GList * msgout_list)
484 {
485 gboolean ok = FALSE;
486 GList *mo_ph_list;
487 GList *mo_ph_node;
489 DEBUG(5) debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name);
491 if (route->mail_host) {
492 /* this is easy... deliver everything to a smart host for relay */
493 return deliver_msglist_host(route, msgout_list, NULL, route->resolve_list);
494 }
496 /* this is not easy... */
498 mo_ph_list = route_msgout_list(route, msgout_list);
499 /* okay, now we have ordered our messages by the hosts. */
500 if (!mo_ph_list) {
501 return FALSE;
502 }
504 /* TODO: It would be nice to be able to fork for each host.
505 We cannot do that yet because of complications with finishing the
506 messages. Threads could be a solution because they use the same
507 memory. But we are not thread safe yet...
508 */
509 foreach(mo_ph_list, mo_ph_node) {
510 msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
511 if (deliver_msglist_host(route, mo_ph->msgout_list, mo_ph->host, route->resolve_list)) {
512 ok = TRUE;
513 }
514 destroy_msgout_perhost(mo_ph);
515 }
516 g_list_free(mo_ph_list);
517 return ok;
518 }
520 /*
521 calls route_prepare_msg()
522 delivers messages in msg_list using route by calling deliver_route_msgout_list()
523 */
524 gboolean
525 deliver_route_msg_list(connect_route * route, GList * msgout_list)
526 {
527 GList *msgout_list_deliver = NULL;
528 GList *msgout_node;
529 gboolean ok = TRUE;
531 DEBUG(6) debugf("deliver_route_msg_list()\n");
533 foreach(msgout_list, msgout_node) {
534 msg_out *msgout = (msg_out *) (msgout_node->data);
535 msg_out *msgout_cloned = clone_msg_out(msgout);
536 GList *rcpt_list_non_delivered = NULL;
537 GList *rcpt_node;
539 /* we have to delete already delivered rcpt's because a
540 previous route may have delivered to it */
541 foreach(msgout_cloned->rcpt_list, rcpt_node) {
542 address *rcpt = (address *) (rcpt_node->data);
543 /* failed addresses already have been bounced;
544 there should be a better way to handle those. */
545 if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt)
546 && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE)) {
547 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
548 }
549 }
550 g_list_free(msgout_cloned->rcpt_list);
551 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
553 if (!msgout_cloned->rcpt_list) {
554 destroy_msg_out(msgout_cloned);
555 continue;
556 }
558 /* filter by allowed envelope sender */
559 if (!route_sender_is_allowed(route, msgout->msg->return_path)) {
560 destroy_msg_out(msgout_cloned);
561 continue;
562 }
564 /* filter by allowed envelope rcpts */
565 GList* rcpt_list_allowed = NULL;
566 GList* rcpt_list_notallowed = NULL;
567 route_split_rcpts(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
568 if (!rcpt_list_allowed) {
569 destroy_msg_out(msgout_cloned);
570 continue;
571 }
573 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
575 g_list_free(msgout_cloned->rcpt_list);
576 msgout_cloned->rcpt_list = rcpt_list_allowed;
578 if (route->last_route) {
579 GList *rcpt_node;
580 foreach(msgout_cloned->rcpt_list, rcpt_node) {
581 address *rcpt = (address *) (rcpt_node->data);
582 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
583 }
584 }
586 route_prepare_msgout(route, msgout_cloned);
587 msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
588 }
590 if (msgout_list_deliver) {
591 if (deliver_route_msgout_list(route, msgout_list_deliver)) {
592 ok = TRUE;
593 }
594 destroy_msg_out_list(msgout_list_deliver);
595 }
596 return ok;
597 }
599 /* copy pointers of delivered addresses to the msg's non_rcpt_list,
600 to make sure that they will not be delivered again.
601 */
602 void
603 update_non_rcpt_list(msg_out * msgout)
604 {
605 GList *rcpt_node;
606 message *msg = msgout->msg;
608 foreach(msgout->rcpt_list, rcpt_node) {
609 address *rcpt = (address *) (rcpt_node->data);
610 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt)) {
611 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
612 }
613 }
614 }
616 /* after delivery attempts, we check if there are any rcpt addresses left in
617 the message. If all addresses have been completed, the spool files will be
618 deleted, otherwise the header spool will be written back. We never changed
619 the data spool, so there is no need to write that back.
621 returns TRUE if all went well.
622 */
623 gboolean
624 deliver_finish(msg_out * msgout)
625 {
626 GList *rcpt_node;
627 message *msg = msgout->msg;
628 gboolean finished = TRUE;
630 update_non_rcpt_list(msgout);
632 /* we NEVER made copies of the addresses, flags affecting addresses
633 were always set on the original address structs */
634 foreach(msg->rcpt_list, rcpt_node) {
635 address *rcpt = (address *) (rcpt_node->data);
636 if (!addr_is_finished_children(rcpt)) {
637 finished = FALSE;
638 } else {
639 /* if ALL children have been delivered, mark parent as
640 delivered. if there is one or more not delivered,
641 it must have failed, we mark the parent as failed
642 as well.
643 */
644 if (addr_is_delivered_children(rcpt)) {
645 addr_mark_delivered(rcpt);
646 } else {
647 addr_mark_failed(rcpt);
648 }
649 }
650 }
652 if (finished) {
653 if (spool_delete_all(msg)) {
654 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
655 return TRUE;
656 }
657 return FALSE;
658 }
660 /* one not delivered address was found */
661 if (!spool_write(msg, FALSE)) {
662 logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
663 return FALSE;
664 }
666 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
667 return TRUE;
668 }
670 gboolean
671 deliver_finish_list(GList * msgout_list)
672 {
673 gboolean ok = TRUE;
674 GList *msgout_node;
675 foreach(msgout_list, msgout_node) {
676 msg_out *msgout = (msg_out *) (msgout_node->data);
677 if (!deliver_finish(msgout)) {
678 ok = FALSE;
679 }
680 }
681 return ok;
682 }
684 gboolean
685 deliver_msgout_list_online(GList * msgout_list)
686 {
687 GList *rf_list = NULL;
688 gchar *connect_name = NULL;
689 gboolean ok = FALSE;
690 GList *route_node;
691 GList *route_list;
693 connect_name = online_query();
694 if (!connect_name) {
695 DEBUG(5) debugf("online query returned false\n");
696 return FALSE;
697 }
699 /* we are online! */
700 DEBUG(5) debugf("processing query_routes\n");
701 logwrite(LOG_NOTICE, "detected online configuration `%s'\n", connect_name);
703 rf_list = (GList *) table_find(conf.connect_routes, connect_name);
704 if (!rf_list) {
705 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
706 return FALSE;
707 }
709 route_list = read_route_list(rf_list, FALSE);
710 if (!route_list) {
711 logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
712 return FALSE;
713 }
715 foreach(route_list, route_node) {
716 connect_route *route = (connect_route *) (route_node->data);
717 /* TODO: ok gets overwritten */
718 ok = deliver_route_msg_list(route, msgout_list);
719 }
720 destroy_route_list(route_list);
722 return ok;
723 }
725 /*
726 This function searches in the list of rcpt addresses
727 for local and 'local net' addresses. Remote addresses
728 which are reachable only when online are treated specially
729 in another function.
730 */
731 gboolean
732 deliver_msg_list(GList * msg_list, guint flags)
733 {
734 GList *msgout_list = NULL;
735 GList *msg_node;
736 GList *local_msgout_list = NULL;
737 GList *localnet_msgout_list = NULL;
738 GList *other_msgout_list = NULL;
739 GList *msgout_node;
740 GList *alias_table = NULL;
741 gboolean ok = TRUE;
743 /* create msgout_list */
744 foreach(msg_list, msg_node) {
745 message *msg = (message *) msg_node->data;
746 msgout_list = g_list_append(msgout_list, create_msg_out(msg));
747 }
750 if (conf.alias_file) {
751 alias_table = table_read(conf.alias_file, ':');
752 }
754 /* sort messages for different deliveries */
755 foreach(msgout_list, msgout_node) {
756 msg_out *msgout = (msg_out *) (msgout_node->data);
757 GList *rcpt_list;
758 GList *local_rcpt_list = NULL;
759 GList *localnet_rcpt_list = NULL;
760 GList *other_rcpt_list = NULL;
762 if (!spool_lock(msgout->msg->uid)) {
763 DEBUG(5) debugf("spool_lock(%s) failed.\n", msgout->msg->uid);
764 continue;
765 }
766 DEBUG(5) debugf("spool_lock(%s)\n", msgout->msg->uid);
768 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
769 if (conf.log_user) {
770 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
771 if (addr) {
772 rcpt_list = g_list_prepend(rcpt_list, addr);
773 } else {
774 logwrite(LOG_ALERT, "invalid log_user address `%s', ignoring\n", conf.log_user);
775 }
776 }
777 if (alias_table) {
778 GList *aliased_rcpt_list;
779 aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list);
780 g_list_free(rcpt_list);
781 rcpt_list = aliased_rcpt_list;
782 }
784 split_rcpts(rcpt_list, conf.local_nets, &local_rcpt_list, &localnet_rcpt_list, &other_rcpt_list);
785 g_list_free(rcpt_list);
787 /* local recipients */
788 if ((flags & DLVR_LOCAL) && local_rcpt_list) {
789 msg_out *local_msgout = clone_msg_out(msgout);
790 local_msgout->rcpt_list = local_rcpt_list;
791 local_msgout_list = g_list_append(local_msgout_list, local_msgout);
792 }
794 /* local net recipients */
795 if ((flags & DLVR_LAN) && localnet_rcpt_list) {
796 msg_out *localnet_msgout = clone_msg_out(msgout);
797 localnet_msgout->rcpt_list = localnet_rcpt_list;
798 localnet_msgout_list = g_list_append(localnet_msgout_list, localnet_msgout);
799 }
801 /* remote recipients (the rest), requires online delivery */
802 if ((flags & DLVR_ONLINE) && other_rcpt_list) {
803 msg_out *other_msgout = clone_msg_out(msgout);
804 other_msgout->rcpt_list = other_rcpt_list;
805 other_msgout_list = g_list_append(other_msgout_list, other_msgout);
806 }
807 }
809 if (alias_table) {
810 destroy_table(alias_table);
811 }
813 /* actual delivery */
815 if (local_msgout_list) {
816 DEBUG(5) debugf("local_msgout_list\n");
817 foreach(local_msgout_list, msgout_node) {
818 msg_out *msgout = (msg_out *) (msgout_node->data);
819 if (!deliver_local(msgout)) {
820 ok = FALSE;
821 }
822 }
823 destroy_msg_out_list(local_msgout_list);
824 }
826 if (localnet_msgout_list) {
827 GList *route_list = NULL;
828 GList *route_node;
830 DEBUG(5) debugf("localnet_msgout_list\n");
831 if (conf.local_net_routes) {
832 route_list = read_route_list(conf.local_net_routes, TRUE);
833 } else {
834 route_list = g_list_append(NULL, create_local_route());
835 }
837 foreach(route_list, route_node) {
838 connect_route *route = (connect_route *) (route_node->data);
839 if (!deliver_route_msg_list(route, localnet_msgout_list)) {
840 ok = FALSE;
841 }
842 }
843 destroy_msg_out_list(localnet_msgout_list);
844 destroy_route_list(route_list);
845 }
847 if (other_msgout_list) {
848 DEBUG(5) debugf("other_msgout_list\n");
849 if (!deliver_msgout_list_online(other_msgout_list)) {
850 ok = FALSE;
851 }
852 destroy_msg_out_list(other_msgout_list);
853 }
855 /* unlock spool files */
856 foreach(msgout_list, msgout_node) {
857 msg_out *msgout = (msg_out *) (msgout_node->data);
858 if (spool_unlock(msgout->msg->uid)) {
859 DEBUG(5) debugf("spool_unlock(%s)\n", msgout->msg->uid);
860 } else {
861 DEBUG(5) debugf("spool_unlock(%s) failed.\n", msgout->msg->uid);
862 }
863 }
864 destroy_msg_out_list(msgout_list);
866 return ok;
867 }
869 /*
870 deliver() is called when a message has just been received
871 (mode_accept and smtp_in) and should be delivered immediately
872 (neither -odq nor do_queue). Only this one message will be tried to
873 deliver then.
874 */
875 gboolean
876 deliver(message * msg)
877 {
878 gboolean ok;
879 GList *msg_list = g_list_append(NULL, msg);
881 ok = deliver_msg_list(msg_list, DLVR_ALL);
882 g_list_free(msg_list);
884 return ok;
885 }