masqmail
view src/deliver.c @ 314:e74ee75453db
small wording change
author | meillo@marmaro.de |
---|---|
date | Mon, 25 Apr 2011 15:14:04 +0200 |
parents | f10a56dc7481 |
children | c98aa884d2cb |
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 return a new copy of the list */
239 void
240 msg_rcptlist_local(GList * rcpt_list, GList ** p_local_list, GList ** p_nonlocal_list)
241 {
242 GList *rcpt_node;
244 foreach(rcpt_list, rcpt_node) {
245 address *rcpt = (address *) (rcpt_node->data);
246 GList *dom_node;
248 DEBUG(5) debugf("checking address %s\n", rcpt->address);
250 /* search for local host list: */
251 foreach(conf.local_hosts, dom_node) {
252 if (strcasecmp(dom_node->data, rcpt->domain) == 0) {
253 *p_local_list = g_list_append(*p_local_list, rcpt);
254 DEBUG(5) debugf("<%s@%s> is local\n", rcpt->local_part, rcpt->domain);
255 break;
256 } else {
257 *p_nonlocal_list = g_list_append(*p_nonlocal_list, rcpt);
258 }
259 }
260 }
261 }
263 gboolean
264 deliver_msglist_host_pipe(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
265 {
266 gboolean ok = TRUE;
267 GList *msgout_node;
269 DEBUG(5) debugf("deliver_msglist_host_pipe entered\n");
271 foreach(msgout_list, msgout_node) {
272 msg_out *msgout = (msg_out *) (msgout_node->data);
273 gboolean flag, ok_fail = FALSE;
274 message *msg = msgout->msg;
275 GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
277 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
279 flag = (msg->data_list == NULL);
280 if (flag && !spool_read_data(msg)) {
281 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
282 continue;
283 }
285 ok = FALSE;
286 foreach(rcpt_list, rcpt_node) {
287 address *rcpt = (address *) (rcpt_node->data);
288 gchar *cmd = g_malloc(256);
289 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
291 DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n", msg->uid, rcpt->local_part, rcpt->domain);
293 if (!expand(var_table, route->pipe, cmd, 256)) {
294 logwrite(LOG_ALERT, "could not expand string %s\n", route->pipe);
295 } else {
297 if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0)
298 | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
299 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n",
300 msg->uid, rcpt->local_part, rcpt->domain, cmd);
301 addr_mark_delivered(rcpt);
302 ok = TRUE;
303 } else {
304 logwrite(LOG_ALERT, "pipe_out '%s' failed\n", route->pipe);
306 if (route->connect_error_fail) {
307 addr_mark_failed(rcpt);
308 } else {
309 addr_mark_defered(rcpt);
310 }
311 }
312 }
314 destroy_table(var_table);
315 }
316 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
318 if (flag) {
319 msg_free_data(msg);
320 }
321 if (ok || ok_fail) {
322 deliver_finish(msgout);
323 }
324 }
326 return ok;
327 }
329 /* deliver list of messages to one host and finishes them if the message was
330 delivered to at least one rcpt.
331 Returns TRUE if at least one msg was delivered to at least one rcpt.
332 */
333 gboolean
334 deliver_msglist_host_smtp(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
335 {
336 gboolean ok = FALSE;
337 GList *msgout_node;
338 smtp_base *psb;
339 gint port = 25;
341 /* paranoid check: */
342 if (!msgout_list) {
343 logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n");
344 return FALSE;
345 }
347 if (!host) {
348 /* XXX: what if mail_host isn't set? Is this possible? */
349 host = route->mail_host->address;
350 port = route->mail_host->port;
351 }
353 if (route->wrapper) {
354 psb = smtp_out_open_child(route->wrapper);
355 } else {
356 psb = smtp_out_open(host, port, res_list);
357 }
359 if (!psb) {
360 /* smtp_out_open() failed */
361 foreach(msgout_list, msgout_node) {
362 msg_out *msgout = (msg_out *) (msgout_node->data);
363 GList *rcpt_node;
365 for (rcpt_node = g_list_first(msgout->rcpt_list);
366 rcpt_node;
367 rcpt_node = g_list_next(rcpt_node)) {
368 address *rcpt = (address *) (rcpt_node->data);
369 gboolean ret = FALSE;
371 addr_unmark_delivered(rcpt);
372 if (route->connect_error_fail) {
373 addr_mark_failed(rcpt);
374 } else {
375 addr_mark_defered(rcpt);
376 }
377 if (route->wrapper) {
378 ret = delivery_failures(msgout->msg, msgout->rcpt_list, "could not open wrapper:\n\t%s", strerror(errno));
379 } else {
380 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));
381 }
382 if (ret) {
383 deliver_finish(msgout);
384 }
385 }
386 }
387 return ok;
388 }
391 if (route->wrapper) {
392 /* it seems as if the remote_host is only set for logging
393 /* XXX: this could probably be moved into smtp_out_open_child() */
394 psb->remote_host = host;
395 }
397 set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
399 #ifdef ENABLE_AUTH
400 if ((route->auth_name) && (route->auth_login) && (route->auth_secret)) {
401 set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
402 }
403 #endif
404 if (!smtp_out_init(psb, route->instant_helo)) {
405 /* smtp_out_init() failed */
406 if ((psb->error==smtp_fail) || (psb->error==smtp_trylater) || (psb->error==smtp_syntax)) {
407 smtp_out_quit(psb);
409 foreach(msgout_list, msgout_node) {
410 msg_out *msgout = (msg_out *) (msgout_node->data);
411 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
413 if (delivery_failures(msgout->msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", host, psb->buffer)) {
414 deliver_finish(msgout);
415 }
416 }
417 }
418 destroy_smtpbase(psb);
419 return ok;
420 }
422 if (!route->do_pipelining) {
423 psb->use_pipelining = FALSE;
424 }
426 foreach(msgout_list, msgout_node) {
427 msg_out *msgout = (msg_out *) (msgout_node->data);
428 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
429 message *msg = msgout->msg;
431 /* we may have to read the data at this point and remember if we did */
432 flag = (msg->data_list == NULL);
433 if (flag && !spool_read_data(msg)) {
434 logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
435 break;
436 }
438 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
440 ok_fail = delivery_failures(msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", host, psb->buffer);
442 if ((psb->error == smtp_eof) || (psb->error == smtp_timeout)) {
443 /* connection lost */
444 break;
445 } else if (psb->error != smtp_ok) {
446 if (g_list_next(msgout_node) && !smtp_out_rset(psb)) {
447 break;
448 }
449 }
450 ok_msg = (psb->error == smtp_ok);
452 if (flag) {
453 msg_free_data(msg);
454 }
455 if (ok_msg) {
456 ok = TRUE;
457 }
458 if (ok_msg || ok_fail) {
459 deliver_finish(msgout);
460 }
461 }
462 if (psb->error == smtp_ok || (psb->error == smtp_fail)
463 || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
464 smtp_out_quit(psb);
465 }
466 destroy_smtpbase(psb);
467 return ok;
468 }
470 gboolean
471 deliver_msglist_host(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
472 {
474 if (route->pipe) {
475 DEBUG(5) debugf("with pipe\n");
476 return deliver_msglist_host_pipe(route, msgout_list, host, res_list);
477 } else {
478 DEBUG(5) debugf("with smtp\n");
479 return deliver_msglist_host_smtp(route, msgout_list, host, res_list);
480 }
481 }
483 /*
484 delivers messages in msgout_list using route
485 */
486 gboolean
487 deliver_route_msgout_list(connect_route * route, GList * msgout_list)
488 {
489 gboolean ok = FALSE;
490 GList *mo_ph_list;
491 GList *mo_ph_node;
493 DEBUG(5) debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name);
495 if (route->mail_host) {
496 /* this is easy... deliver everything to a smart host for relay */
497 return deliver_msglist_host(route, msgout_list, NULL, route->resolve_list);
498 }
500 /* this is not easy... */
502 mo_ph_list = route_msgout_list(route, msgout_list);
503 /* okay, now we have ordered our messages by the hosts. */
504 if (!mo_ph_list) {
505 return FALSE;
506 }
508 /* TODO: It would be nice to be able to fork for each host.
509 We cannot do that yet because of complications with finishing the
510 messages. Threads could be a solution because they use the same
511 memory. But we are not thread safe yet...
512 */
513 foreach(mo_ph_list, mo_ph_node) {
514 msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
515 if (deliver_msglist_host(route, mo_ph->msgout_list, mo_ph->host, route->resolve_list)) {
516 ok = TRUE;
517 }
518 destroy_msgout_perhost(mo_ph);
519 }
520 g_list_free(mo_ph_list);
521 return ok;
522 }
524 /*
525 calls route_prepare_msg()
526 delivers messages in msg_list using route by calling deliver_route_msgout_list()
527 */
528 gboolean
529 deliver_route_msg_list(connect_route * route, GList * msgout_list)
530 {
531 GList *msgout_list_deliver = NULL;
532 GList *msgout_node;
533 gboolean ok = TRUE;
535 DEBUG(6) debugf("deliver_route_msg_list()\n");
537 foreach(msgout_list, msgout_node) {
538 msg_out *msgout = (msg_out *) (msgout_node->data);
539 msg_out *msgout_cloned = clone_msg_out(msgout);
540 GList *rcpt_list_non_delivered = NULL;
541 GList *rcpt_node;
543 /* we have to delete already delivered rcpt's because a
544 previous route may have delivered to it */
545 foreach(msgout_cloned->rcpt_list, rcpt_node) {
546 address *rcpt = (address *) (rcpt_node->data);
547 /* failed addresses already have been bounced;
548 there should be a better way to handle those. */
549 if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt)
550 && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE)) {
551 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
552 }
553 }
554 g_list_free(msgout_cloned->rcpt_list);
555 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
557 if (!msgout_cloned->rcpt_list) {
558 destroy_msg_out(msgout_cloned);
559 continue;
560 }
562 if (!route_is_allowed_mail_local(route, msgout->msg->return_path)
563 || !route_is_allowed_return_path(route, msgout->msg-> return_path)) {
564 destroy_msg_out(msgout_cloned);
565 continue;
566 }
568 GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
569 msg_rcptlist_route(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
571 if (!rcpt_list_allowed) {
572 destroy_msg_out(msgout_cloned);
573 continue;
574 }
575 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
577 g_list_free(msgout_cloned->rcpt_list);
578 msgout_cloned->rcpt_list = rcpt_list_allowed;
580 if (route->last_route) {
581 GList *rcpt_node;
582 foreach(msgout_cloned->rcpt_list, rcpt_node) {
583 address *rcpt = (address *) (rcpt_node->data);
584 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
585 }
586 }
588 route_prepare_msgout(route, msgout_cloned);
589 msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
590 }
592 if (msgout_list_deliver) {
593 if (deliver_route_msgout_list(route, msgout_list_deliver)) {
594 ok = TRUE;
595 }
596 destroy_msg_out_list(msgout_list_deliver);
597 }
598 return ok;
599 }
601 /* copy pointers of delivered addresses to the msg's non_rcpt_list,
602 to make sure that they will not be delivered again.
603 */
604 void
605 update_non_rcpt_list(msg_out * msgout)
606 {
607 GList *rcpt_node;
608 message *msg = msgout->msg;
610 foreach(msgout->rcpt_list, rcpt_node) {
611 address *rcpt = (address *) (rcpt_node->data);
612 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt)) {
613 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
614 }
615 }
616 }
618 /* after delivery attempts, we check if there are any rcpt addresses left in
619 the message. If all addresses have been completed, the spool files will be
620 deleted, otherwise the header spool will be written back. We never changed
621 the data spool, so there is no need to write that back.
623 returns TRUE if all went well.
624 */
625 gboolean
626 deliver_finish(msg_out * msgout)
627 {
628 GList *rcpt_node;
629 message *msg = msgout->msg;
630 gboolean finished = TRUE;
632 update_non_rcpt_list(msgout);
634 /* we NEVER made copies of the addresses, flags affecting addresses
635 were always set on the original address structs */
636 foreach(msg->rcpt_list, rcpt_node) {
637 address *rcpt = (address *) (rcpt_node->data);
638 if (!addr_is_finished_children(rcpt)) {
639 finished = FALSE;
640 } else {
641 /* if ALL children have been delivered, mark parent as
642 delivered. if there is one or more not delivered,
643 it must have failed, we mark the parent as failed
644 as well.
645 */
646 if (addr_is_delivered_children(rcpt)) {
647 addr_mark_delivered(rcpt);
648 } else {
649 addr_mark_failed(rcpt);
650 }
651 }
652 }
654 if (finished) {
655 if (spool_delete_all(msg)) {
656 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
657 return TRUE;
658 }
659 return FALSE;
660 }
662 /* one not delivered address was found */
663 if (!spool_write(msg, FALSE)) {
664 logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
665 return FALSE;
666 }
668 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
669 return TRUE;
670 }
672 gboolean
673 deliver_finish_list(GList * msgout_list)
674 {
675 gboolean ok = TRUE;
676 GList *msgout_node;
677 foreach(msgout_list, msgout_node) {
678 msg_out *msgout = (msg_out *) (msgout_node->data);
679 if (!deliver_finish(msgout)) {
680 ok = FALSE;
681 }
682 }
683 return ok;
684 }
686 gboolean
687 deliver_msgout_list_online(GList * msgout_list)
688 {
689 GList *rf_list = NULL;
690 gchar *connect_name = NULL;
691 gboolean ok = FALSE;
693 connect_name = online_query();
694 if (!connect_name) {
695 return FALSE;
696 }
698 /* we are online! */
699 logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
701 rf_list = (GList *) table_find(conf.connect_routes, connect_name);
702 if (!rf_list) {
703 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
704 return FALSE;
705 }
707 GList *route_list = read_route_list(rf_list, FALSE);
708 if (!route_list) {
709 logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
710 return FALSE;
711 }
713 GList *route_node;
714 foreach(route_list, route_node) {
715 connect_route *route = (connect_route *) (route_node->data);
716 /* TODO: ok gets overwritten */
717 ok = deliver_route_msg_list(route, msgout_list);
718 }
719 destroy_route_list(route_list);
720 return ok;
721 }
723 gboolean
724 deliver_msg_list(GList * msg_list, guint flags)
725 {
726 GList *msgout_list = create_msg_out_list(msg_list);
727 GList *local_msgout_list = NULL;
728 GList *localnet_msgout_list = NULL;
729 GList *other_msgout_list = NULL;
730 GList *msgout_node;
731 GList *alias_table = NULL;
732 gboolean ok = TRUE;
734 if (conf.alias_file) {
735 alias_table = table_read(conf.alias_file, ':');
736 }
738 /* sort messages for different deliveries */
739 foreach(msgout_list, msgout_node) {
740 msg_out *msgout = (msg_out *) (msgout_node->data);
741 GList *rcpt_list;
742 GList *local_rcpt_list = NULL;
743 GList *localnet_rcpt_list = NULL;
744 GList *other_rcpt_list = NULL;
746 if (!spool_lock(msgout->msg->uid)) {
747 DEBUG(5) debugf("spool_lock(%s) failed.\n", msgout->msg->uid);
748 continue;
749 }
750 DEBUG(5) debugf("spool_lock(%s)\n", msgout->msg->uid);
752 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
753 if (conf.log_user) {
754 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
755 if (addr) {
756 rcpt_list = g_list_prepend(rcpt_list, addr);
757 } else {
758 logwrite(LOG_ALERT, "invalid log_user address `%s', ignoring\n", conf.log_user);
759 }
760 }
761 if (alias_table) {
762 GList *aliased_rcpt_list;
763 aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list);
764 g_list_free(rcpt_list);
765 rcpt_list = aliased_rcpt_list;
766 }
768 split_rcpts(rcpt_list, conf.local_nets, &local_rcpt_list, &localnet_rcpt_list, &other_rcpt_list);
769 g_list_free(rcpt_list);
771 /* local recipients */
772 if ((flags & DLVR_LOCAL) && local_rcpt_list) {
773 msg_out *local_msgout = clone_msg_out(msgout);
774 local_msgout->rcpt_list = local_rcpt_list;
775 local_msgout_list = g_list_append(local_msgout_list, local_msgout);
776 }
778 /* local net recipients */
779 if ((flags & DLVR_LAN) && localnet_rcpt_list) {
780 msg_out *localnet_msgout = clone_msg_out(msgout);
781 localnet_msgout->rcpt_list = localnet_rcpt_list;
782 localnet_msgout_list = g_list_append(localnet_msgout_list, localnet_msgout);
783 }
785 /* remote recipients (the rest), requires online delivery */
786 if ((flags & DLVR_ONLINE) && other_rcpt_list) {
787 msg_out *other_msgout = clone_msg_out(msgout);
788 other_msgout->rcpt_list = other_rcpt_list;
789 other_msgout_list = g_list_append(other_msgout_list, other_msgout);
790 }
791 }
793 if (alias_table) {
794 destroy_table(alias_table);
795 }
797 /* actual delivery */
799 if (local_msgout_list) {
800 DEBUG(5) debugf("local_msgout_list\n");
801 foreach(local_msgout_list, msgout_node) {
802 msg_out *msgout = (msg_out *) (msgout_node->data);
803 if (!deliver_local(msgout)) {
804 ok = FALSE;
805 }
806 }
807 destroy_msg_out_list(local_msgout_list);
808 }
810 if (localnet_msgout_list) {
811 GList *route_list = NULL;
812 GList *route_node;
814 DEBUG(5) debugf("localnet_msgout_list\n");
815 if (conf.local_net_routes) {
816 route_list = read_route_list(conf.local_net_routes, TRUE);
817 } else {
818 route_list = g_list_append(NULL, create_local_route());
819 }
821 foreach(route_list, route_node) {
822 connect_route *route = (connect_route *) (route_node->data);
823 if (!deliver_route_msg_list(route, localnet_msgout_list)) {
824 ok = FALSE;
825 }
826 }
827 destroy_msg_out_list(localnet_msgout_list);
828 destroy_route_list(route_list);
829 }
831 if (other_msgout_list) {
832 DEBUG(5) debugf("other_msgout_list\n");
833 if (!deliver_msgout_list_online(other_msgout_list)) {
834 ok = FALSE;
835 }
836 destroy_msg_out_list(other_msgout_list);
837 }
839 foreach(msgout_list, msgout_node) {
840 msg_out *msgout = (msg_out *) (msgout_node->data);
841 if (spool_unlock(msgout->msg->uid)) {
842 DEBUG(5) debugf("spool_unlock(%s)\n", msgout->msg->uid);
843 } else {
844 DEBUG(5) debugf("spool_unlock(%s) failed.\n", msgout->msg->uid);
845 }
847 }
849 destroy_msg_out_list(msgout_list);
851 return ok;
852 }
854 /* This function searches in the list of rcpt addresses
855 for local and 'local net' addresses. Remote addresses
856 which are reachable only when online are treated specially
857 in another function.
859 deliver() is called when a message has just been received and should
860 be delivered immediately.
861 */
862 gboolean
863 deliver(message * msg)
864 {
865 gboolean ok;
866 GList *msg_list = g_list_append(NULL, msg);
868 ok = deliver_msg_list(msg_list, DLVR_ALL);
869 g_list_free(msg_list);
871 return ok;
872 }