masqmail

view src/deliver.c @ 200:116b0269c934

reworked resolvtest; let it build; refactored in lookup.c the resolvtest helper and code test tool was available in the code but did not get built I moved it to resolvtest.c and included it into the build process the define RESOLV_TEST was removed
author meillo@marmaro.de
date Fri, 16 Jul 2010 12:53:07 +0200
parents 3190e6864452
children 4fd237550525
line source
1 /* MasqMail
2 Copyright (C) 1999-2002 Oliver Kurth
3 Copyright (C) 2008 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 if (addr_is_failed(rcpt))
49 failed_list = g_list_prepend(failed_list, rcpt);
50 }
51 if (failed_list != NULL) {
52 ok_fail = fail_msg(msg, conf.errmsg_file, failed_list, err_fmt, args);
53 g_list_free(failed_list);
54 }
55 if (defered_list != NULL) {
56 ok_warn = warn_msg(msg, conf.warnmsg_file, defered_list, err_fmt, args);
57 g_list_free(defered_list);
58 }
59 va_end(args);
60 return ok_fail && ok_warn;
61 }
63 static gint
64 _g_list_strcasecmp(gconstpointer a, gconstpointer b)
65 {
66 return (gint) strcasecmp(a, b);
67 }
69 gboolean
70 deliver_local(msg_out * msgout)
71 {
72 message *msg = msgout->msg;
73 GList *rcpt_list = msgout->rcpt_list;
74 GList *rcpt_node;
75 gboolean ok = TRUE, flag = FALSE, ok_fail = FALSE;
77 DEBUG(5) debugf("deliver_local entered\n");
79 flag = (msg->data_list == NULL);
80 if (flag) {
81 if (!(ok = spool_read_data(msg))) {
82 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
83 }
84 }
85 if (!ok)
86 return FALSE;
88 ok = FALSE;
89 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
90 GList *hdr_list;
91 address *rcpt = (address *) (rcpt_node->data);
92 address *env_addr = addr_find_ancestor(rcpt);
93 address *ret_path = msg->return_path;
94 header *retpath_hdr, *envto_hdr;
96 /* we need a private copy of the hdr list because we add headers here that belong to the rcpt only.
97 g_list_copy copies only the nodes, so it is safe to g_list_free it */
98 hdr_list = g_list_copy(msg->hdr_list);
99 retpath_hdr = create_header(HEAD_ENVELOPE_TO, "Envelope-to: %s\n", addr_string(env_addr));
100 envto_hdr = create_header(HEAD_RETURN_PATH, "Return-path: %s\n", addr_string(ret_path));
102 hdr_list = g_list_prepend(hdr_list, envto_hdr);
103 hdr_list = g_list_prepend(hdr_list, retpath_hdr);
105 if (rcpt->local_part[0] == '|') {
106 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
107 if (pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]),
108 (conf.pipe_fromline ? MSGSTR_FROMLINE : 0)
109 | (conf.pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
110 logwrite(LOG_NOTICE, "%s => %s <%s@%s> with pipe\n",
111 msg->uid, rcpt->local_part, env_addr->local_part, env_addr->domain);
112 addr_mark_delivered(rcpt);
113 ok = TRUE;
114 } else {
115 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
116 addr_mark_failed(rcpt);
117 } else {
118 addr_mark_defered(rcpt); /* has no effect yet, except that mail remains in spool */
119 }
120 }
121 } else {
122 /* figure out which mailbox type should be used for this user */
123 gchar *user = rcpt->local_part;
124 gchar *mbox_type = conf.mbox_default;
126 if (g_list_find_custom (conf.mbox_users, user, _g_list_strcasecmp) != NULL)
127 mbox_type = "mbox";
128 else if (g_list_find_custom (conf.mda_users, user, _g_list_strcasecmp) != NULL)
129 mbox_type = "mda";
130 else if (g_list_find_custom (conf.maildir_users, user, _g_list_strcasecmp) != NULL)
131 mbox_type = "maildir";
133 if (strcmp(mbox_type, "mbox") == 0) {
134 DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
135 if (append_file(msg, hdr_list, rcpt->local_part)) {
136 if (env_addr != rcpt) {
137 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with mbox\n",
138 msg->uid, rcpt->local_part, rcpt->domain,
139 env_addr->local_part, env_addr->domain);
140 } else {
141 logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n",
142 msg->uid, rcpt->local_part, rcpt->domain);
143 }
144 addr_mark_delivered(rcpt);
145 ok = TRUE;
146 } else {
147 if (errno != EAGAIN) { /* prevents 'Resource temporarily unavailable (11)' */
148 addr_mark_failed(rcpt);
149 } else {
150 addr_mark_defered(rcpt);
151 }
152 }
154 } else if (strcmp(mbox_type, "mda") == 0) {
155 if (conf.mda) {
156 gchar *cmd = g_malloc(256);
157 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
159 DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
161 if (expand(var_table, conf.mda, cmd, 256)) {
163 if (pipe_out(msg, hdr_list, rcpt, cmd, (conf.mda_fromline ? MSGSTR_FROMLINE : 0)
164 | (conf.mda_fromhack ? MSGSTR_FROMHACK : 0))) {
165 logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
166 msg->uid, rcpt->local_part, rcpt->domain, cmd);
167 addr_mark_delivered(rcpt);
168 ok = TRUE;
169 } else {
170 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
171 addr_mark_failed(rcpt);
172 } else {
173 addr_mark_defered(rcpt); /* has no effect yet, except that mail remains in spool */
174 }
175 }
176 } else
177 logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
179 destroy_table(var_table);
180 } else
181 logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n");
183 #ifdef ENABLE_MAILDIR
184 } else if (strcmp(mbox_type, "maildir") == 0) {
185 DEBUG(1) debugf("attempting to deliver %s with maildir\n", msg->uid);
186 if (maildir_out(msg, hdr_list, rcpt->local_part, 0)) {
187 if (env_addr != rcpt) {
188 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with local\n", msg->uid,
189 rcpt->local_part, rcpt->domain, env_addr->local_part, env_addr->domain);
190 } else {
191 logwrite(LOG_NOTICE, "%s => <%s@%s> with maildir\n", msg->uid,
192 rcpt->local_part, rcpt->domain);
193 }
194 addr_mark_delivered(rcpt);
195 ok = TRUE;
196 } else
197 addr_mark_failed(rcpt);
198 #endif
199 } else
200 logwrite(LOG_ALERT, "unknown mbox type '%s'\n", mbox_type);
201 }
203 destroy_header(retpath_hdr);
204 destroy_header(envto_hdr);
206 g_list_free(hdr_list);
207 }
208 ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)", ext_strerror(errno), errno);
210 if (flag)
211 msg_free_data(msg);
212 if (ok || ok_fail)
213 deliver_finish(msgout);
215 return ok;
216 }
218 /* make a list of rcpt's of a message that are local return a new copy of the list */
219 void
220 msg_rcptlist_local(GList * rcpt_list, GList ** p_local_list, GList ** p_nonlocal_list)
221 {
222 GList *rcpt_node;
224 foreach(rcpt_list, rcpt_node) {
225 address *rcpt = (address *) (rcpt_node->data);
226 GList *dom_node;
228 DEBUG(5) debugf("checking address %s\n", rcpt->address);
230 /* search for local host list: */
231 foreach(conf.local_hosts, dom_node) {
232 if (strcasecmp(dom_node->data, rcpt->domain) == 0) {
233 *p_local_list = g_list_append(*p_local_list, rcpt);
234 DEBUG(5) debugf("<%s@%s> is local\n", rcpt->local_part, rcpt->domain);
235 break;
236 } else {
237 *p_nonlocal_list = g_list_append(*p_nonlocal_list, rcpt);
238 }
239 }
240 }
241 }
243 gboolean
244 deliver_msglist_host_pipe(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
245 {
246 gboolean ok = TRUE;
247 GList *msgout_node;
249 DEBUG(5) debugf("deliver_msglist_host_pipe entered\n");
251 if (route->pipe == NULL) {
252 logwrite(LOG_ALERT, "no pipe command given for route (protocol is pipe!)\n");
253 return FALSE;
254 }
256 foreach(msgout_list, msgout_node) {
257 msg_out *msgout = (msg_out *) (msgout_node->data);
258 gboolean flag, ok_msg = TRUE, ok_fail = FALSE;
259 message *msg = msgout->msg;
260 GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
262 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
264 flag = (msg->data_list == NULL);
265 if (flag) {
266 if (!(ok_msg = spool_read_data(msg))) {
267 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
268 }
269 }
270 if (!ok_msg)
271 continue;
273 ok = FALSE;
274 foreach(rcpt_list, rcpt_node) {
275 address *rcpt = (address *) (rcpt_node->data);
276 gchar *cmd = g_malloc(256);
277 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
279 DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n", msg->uid, rcpt->local_part, rcpt->domain);
281 if (expand(var_table, route->pipe, cmd, 256)) {
283 if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0)
284 | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
285 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n",
286 msg->uid, rcpt->local_part, rcpt->domain, cmd);
287 addr_mark_delivered(rcpt);
288 ok = TRUE;
289 } else {
290 logwrite(LOG_ALERT, "pipe_out '%s' failed\n", route->pipe);
292 if (route->connect_error_fail) {
293 addr_mark_failed(rcpt);
294 } else {
295 addr_mark_defered(rcpt);
296 }
297 }
298 } else
299 logwrite(LOG_ALERT, "could not expand string %s\n", route->pipe);
301 destroy_table(var_table);
302 }
303 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
305 if (flag)
306 msg_free_data(msg);
308 if (ok || ok_fail)
309 deliver_finish(msgout);
310 }
312 return ok;
313 }
315 /* deliver list of messages to one host and finishes them if the message was delivered to at least one rcpt.
316 Returns TRUE if at least one msg was delivered to at least one rcpt.
317 */
318 gboolean
319 deliver_msglist_host_smtp(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
320 {
321 gboolean ok = FALSE;
322 GList *msgout_node;
323 smtp_base *psb;
324 gint port = 25;
326 /* paranoid check: */
327 if (msgout_list == NULL) {
328 logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n");
329 return FALSE;
330 }
332 if (host == NULL) {
333 /* XXX: what if mail_host isn't set? Is this possible? */
334 host = route->mail_host->address;
335 port = route->mail_host->port;
336 }
338 if ((psb = (route->wrapper ? smtp_out_open_child(route->wrapper) : smtp_out_open(host, port, res_list)))) {
340 if (route->wrapper) {
341 /* it seems as if the remote_host is only set for logging
342 /* XXX: this could probably be moved into smtp_out_open_child() */
343 psb->remote_host = host;
344 }
346 set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
348 #ifdef ENABLE_AUTH
349 if ((route->auth_name) && (route->auth_login) && (route->auth_secret))
350 set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
351 #endif
352 if (smtp_out_init(psb)) {
354 if (!route->do_pipelining)
355 psb->use_pipelining = FALSE;
357 foreach(msgout_list, msgout_node) {
358 msg_out *msgout = (msg_out *) (msgout_node->data);
359 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
360 message *msg = msgout->msg;
362 /* we may have to read the data at this point and remember if we did */
363 flag = (msg->data_list == NULL);
364 if (flag) {
365 if (!spool_read_data(msg)) {
366 logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
367 break;
368 }
369 }
371 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
373 ok_fail = delivery_failures(msg, msgout->rcpt_list,
374 "while connected with %s, the server replied\n\t%s", host, psb->buffer);
376 if ((psb->error == smtp_eof)
377 || (psb->error == smtp_timeout)) {
378 /* connection lost */
379 break;
380 } else if (psb->error != smtp_ok) {
381 if (g_list_next(msgout_node) != NULL)
382 if (!smtp_out_rset(psb))
383 break;
384 }
385 ok_msg = (psb->error == smtp_ok);
387 if (flag)
388 msg_free_data(msg);
389 if (ok_msg)
390 ok = TRUE;
391 if (ok_msg || ok_fail) {
392 deliver_finish(msgout);
393 }
394 }
395 if (psb->error == smtp_ok || (psb->error == smtp_fail)
396 || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
397 smtp_out_quit(psb);
398 }
399 } else {
400 /* smtp_out_init() failed */
401 if ((psb->error == smtp_fail) || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
402 smtp_out_quit(psb);
404 foreach(msgout_list, msgout_node) {
405 msg_out *msgout = (msg_out *) (msgout_node->data);
406 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
408 if (delivery_failures(msgout->msg, msgout->rcpt_list,
409 "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 } else {
416 /* smtp_out_open() failed */
417 foreach(msgout_list, msgout_node) {
418 msg_out *msgout = (msg_out *) (msgout_node->data);
419 GList *rcpt_node;
421 for (rcpt_node = g_list_first(msgout->rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
422 address *rcpt = (address *) (rcpt_node->data);
424 addr_unmark_delivered(rcpt);
425 if (route->connect_error_fail) {
426 addr_mark_failed(rcpt);
427 } else {
428 addr_mark_defered(rcpt);
429 }
430 if (route->wrapper
431 ? delivery_failures(msgout->msg, msgout->rcpt_list, "could not open wrapper:\n\t%s",
432 strerror(errno))
433 : delivery_failures(msgout->msg, msgout->rcpt_list, "could not open connection to %s:%d :\n\t%s",
434 host, port, h_errno != 0 ? hstrerror(h_errno) : strerror(errno)))
435 deliver_finish(msgout);
436 }
437 }
438 }
439 return ok;
440 }
442 gboolean
443 deliver_msglist_host(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
444 {
445 DEBUG(5) debugf("protocol = %s\n", route->protocol);
447 if (strcmp(route->protocol, "pipe") == 0) {
448 return deliver_msglist_host_pipe(route, msgout_list, host, res_list);
449 } else {
450 return deliver_msglist_host_smtp(route, msgout_list, host, res_list);
451 }
452 }
454 /*
455 delivers messages in msgout_list using route
456 */
457 gboolean
458 deliver_route_msgout_list(connect_route * route, GList * msgout_list)
459 {
460 gboolean ok = FALSE;
462 DEBUG(5) debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name);
464 if (route->mail_host) {
465 /* this is easy... deliver everything to a smart host for relay */
466 if (deliver_msglist_host(route, msgout_list, NULL, route->resolve_list))
467 ok = TRUE;
469 } else {
470 /* this is not easy... */
471 GList *mo_ph_list;
473 mo_ph_list = route_msgout_list(route, msgout_list);
474 /* okay, now we have ordered our messages by the hosts. */
475 if (mo_ph_list != NULL) {
476 GList *mo_ph_node;
477 /* TODO: It would be nice to be able to fork for each host.
478 We cannot do that yet because of complications with finishing the
479 messages. Threads could be a solution because they use the same
480 memory. But we are not thread safe yet...
481 */
482 foreach(mo_ph_list, mo_ph_node) {
483 msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
484 if (deliver_msglist_host (route, mo_ph->msgout_list, mo_ph->host, route->resolve_list))
485 ok = TRUE;
487 destroy_msgout_perhost(mo_ph);
488 }
489 g_list_free(mo_ph_list);
490 }
491 }
492 return ok;
493 }
495 /*
496 calls route_prepare_msg()
497 delivers messages in msg_list using route by calling deliver_route_msgout_list()
498 */
499 gboolean
500 deliver_route_msg_list(connect_route * route, GList * msgout_list)
501 {
502 GList *msgout_list_deliver = NULL;
503 GList *msgout_node;
504 gboolean ok = TRUE;
506 DEBUG(6) debugf("deliver_route_msg_list()\n");
508 foreach(msgout_list, msgout_node) {
509 msg_out *msgout = (msg_out *) (msgout_node->data);
510 msg_out *msgout_cloned = clone_msg_out(msgout);
511 GList *rcpt_list_non_delivered = NULL;
512 GList *rcpt_node;
514 /* we have to delete already delivered rcpt's because a previous route may have delivered to it */
515 foreach(msgout_cloned->rcpt_list, rcpt_node) {
516 address *rcpt = (address *) (rcpt_node->data);
517 /* failed addresses already have been bounced - there should be a better way to handle those. */
518 if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt)
519 && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE))
520 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
521 }
522 g_list_free(msgout_cloned->rcpt_list);
523 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
525 if (msgout_cloned->rcpt_list) {
526 if (route_is_allowed_mail_local(route, msgout->msg->return_path)
527 && route_is_allowed_return_path(route, msgout->msg-> return_path)) {
528 GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
529 msg_rcptlist_route(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
531 if (rcpt_list_allowed != NULL) {
532 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
534 g_list_free(msgout_cloned->rcpt_list);
535 msgout_cloned->rcpt_list = rcpt_list_allowed;
537 if (route->last_route) {
538 GList *rcpt_node;
539 foreach(msgout_cloned->rcpt_list, rcpt_node) {
540 address *rcpt = (address *) (rcpt_node->data);
541 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
542 }
543 }
545 route_prepare_msgout(route, msgout_cloned);
546 msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
547 } else
548 destroy_msg_out(msgout_cloned);
549 } else
550 destroy_msg_out(msgout_cloned);
551 } else
552 destroy_msg_out(msgout_cloned);
553 }
555 if (msgout_list_deliver != NULL) {
556 if (deliver_route_msgout_list(route, msgout_list_deliver))
557 ok = TRUE;
558 destroy_msg_out_list(msgout_list_deliver);
559 }
560 return ok;
561 }
563 /* copy pointers of delivered addresses to the msg's non_rcpt_list,
564 to make sure that they will not be delivered again.
565 */
566 void
567 update_non_rcpt_list(msg_out * msgout)
568 {
569 GList *rcpt_node;
570 message *msg = msgout->msg;
572 foreach(msgout->rcpt_list, rcpt_node) {
573 address *rcpt = (address *) (rcpt_node->data);
574 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt))
575 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
576 }
577 }
579 /* after delivery attempts, we check if there are any rcpt addresses left in the message.
580 If all addresses have been completed, the spool files will be deleted,
581 otherwise the header spool will be written back.
582 We never changed the data spool, so there is no need to write that back.
584 returns TRUE if all went well.
585 */
586 gboolean
587 deliver_finish(msg_out * msgout)
588 {
589 GList *rcpt_node;
590 gboolean ok = FALSE;
591 message *msg = msgout->msg;
592 gboolean finished = TRUE;
594 update_non_rcpt_list(msgout);
596 /* we NEVER made copies of the addresses, flags affecting addresses
597 were always set on the original address structs */
598 foreach(msg->rcpt_list, rcpt_node) {
599 address *rcpt = (address *) (rcpt_node->data);
600 if (!addr_is_finished_children(rcpt))
601 finished = FALSE;
602 else {
603 /* if ALL children have been delivered, mark parent as delivered.
604 if there is one or more not delivered, it must have failed, we mark the parent as failed as well.
605 */
606 if (addr_is_delivered_children(rcpt)) {
607 addr_mark_delivered(rcpt);
608 } else {
609 addr_mark_failed(rcpt);
610 }
611 }
612 }
614 if (!finished) {
615 /* one not delivered address was found */
616 if (spool_write(msg, FALSE)) {
617 ok = TRUE;
618 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
619 } else
620 logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
621 } else {
622 ok = spool_delete_all(msg);
623 if (ok)
624 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
625 }
626 return ok;
627 }
629 gboolean
630 deliver_finish_list(GList * msgout_list)
631 {
632 gboolean ok = TRUE;
633 GList *msgout_node;
634 foreach(msgout_list, msgout_node) {
635 msg_out *msgout = (msg_out *) (msgout_node->data);
636 if (!deliver_finish(msgout))
637 ok = FALSE;
638 }
639 return ok;
640 }
642 gboolean
643 deliver_msgout_list_online(GList * msgout_list)
644 {
645 GList *rf_list = NULL;
646 gchar *connect_name = detect_online();
647 gboolean ok = FALSE;
649 if (connect_name != NULL) {
650 logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
651 /* we are online! */
652 rf_list = (GList *) table_find(conf.connect_routes, connect_name);
653 if (rf_list != NULL) {
654 GList *route_list = read_route_list(rf_list, FALSE);
655 if (route_list) {
656 GList *route_node;
657 foreach(route_list, route_node) {
658 connect_route *route = (connect_route *) (route_node->data);
659 ok = deliver_route_msg_list(route, msgout_list);
660 }
661 destroy_route_list(route_list);
662 } else
663 logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
664 } else {
665 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
666 }
667 }
668 return ok;
669 }
671 gboolean
672 deliver_msg_list(GList * msg_list, guint flags)
673 {
674 GList *msgout_list = create_msg_out_list(msg_list);
675 GList *local_msgout_list = NULL, *localnet_msgout_list = NULL, *other_msgout_list = NULL;
676 GList *msgout_node;
677 GList *alias_table = NULL;
678 gboolean ok = TRUE;
680 if (conf.alias_file) {
681 alias_table = table_read(conf.alias_file, ':');
682 }
684 /* sort messages for different deliveries */
685 foreach(msgout_list, msgout_node) {
686 msg_out *msgout = (msg_out *) (msgout_node->data);
687 GList *rcpt_list;
688 GList *local_rcpt_list = NULL;
689 GList *localnet_rcpt_list = NULL;
690 GList *other_rcpt_list;
692 if (!spool_lock(msgout->msg->uid)) {
693 DEBUG(5) debugf("spool_lock(%s) failed.\n", msgout->msg->uid);
694 continue;
695 }
696 DEBUG(5) debugf("spool_lock(%s)\n", msgout->msg->uid);
698 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
699 if (conf.log_user) {
700 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
701 if (addr)
702 rcpt_list = g_list_prepend(rcpt_list, addr);
703 }
704 if (alias_table) {
705 GList *aliased_rcpt_list;
706 aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list);
707 g_list_free(rcpt_list);
708 rcpt_list = aliased_rcpt_list;
709 }
711 /* local recipients */
712 other_rcpt_list = NULL;
713 rcptlist_with_addr_is_local(rcpt_list, &local_rcpt_list, &other_rcpt_list);
715 if (flags & DLVR_LOCAL) {
716 if (local_rcpt_list != NULL) {
717 msg_out *local_msgout = clone_msg_out(msgout);
718 local_msgout->rcpt_list = local_rcpt_list;
719 local_msgout_list = g_list_append(local_msgout_list, local_msgout);
720 }
721 }
723 g_list_free(rcpt_list);
725 /* local net recipients */
726 rcpt_list = other_rcpt_list;
727 other_rcpt_list = NULL;
728 rcptlist_with_one_of_hostlist(rcpt_list, conf.local_nets, &localnet_rcpt_list, &other_rcpt_list);
730 if (flags & DLVR_LAN) {
731 if (localnet_rcpt_list != NULL) {
732 msg_out *localnet_msgout = clone_msg_out(msgout);
733 localnet_msgout->rcpt_list = localnet_rcpt_list;
734 localnet_msgout_list = g_list_append(localnet_msgout_list, localnet_msgout);
735 }
736 }
738 if (flags & DLVR_ONLINE) {
739 /* the rest, this is online delivery */
740 if (other_rcpt_list != NULL) {
741 msg_out *other_msgout = clone_msg_out(msgout);
742 other_msgout->rcpt_list = other_rcpt_list;
743 other_msgout_list = g_list_append(other_msgout_list, other_msgout);
744 }
745 }
746 }
748 if (alias_table)
749 destroy_table(alias_table);
751 /* actual delivery */
752 if (local_msgout_list != NULL) {
753 DEBUG(5) debugf("local_msgout_list\n");
754 foreach(local_msgout_list, msgout_node) {
755 msg_out *msgout = (msg_out *) (msgout_node->data);
756 if (!deliver_local(msgout))
757 ok = FALSE;
758 }
759 destroy_msg_out_list(local_msgout_list);
760 }
762 if (localnet_msgout_list != NULL) {
763 GList *route_list = NULL;
764 GList *route_node;
766 DEBUG(5) debugf("localnet_msgout_list\n");
767 if (conf.local_net_routes)
768 route_list = read_route_list(conf.local_net_routes, TRUE);
769 else
770 route_list = g_list_append(NULL, create_local_route());
772 foreach(route_list, route_node) {
773 connect_route *route = (connect_route *) (route_node->data);
774 if (!deliver_route_msg_list(route, localnet_msgout_list))
775 ok = FALSE;
776 }
777 destroy_msg_out_list(localnet_msgout_list);
778 destroy_route_list(route_list);
779 }
781 if (other_msgout_list != NULL) {
782 DEBUG(5) debugf("other_msgout_list\n");
783 if (!deliver_msgout_list_online(other_msgout_list))
784 ok = FALSE;
785 destroy_msg_out_list(other_msgout_list);
786 }
788 foreach(msgout_list, msgout_node) {
789 msg_out *msgout = (msg_out *) (msgout_node->data);
790 if (spool_unlock(msgout->msg->uid)) {
791 DEBUG(5) debugf("spool_unlock(%s)\n", msgout->msg->uid);
792 } else {
793 DEBUG(5) debugf("spool_unlock(%s) failed.\n", msgout->msg->uid);
794 }
796 }
798 destroy_msg_out_list(msgout_list);
800 return ok;
801 }
803 /* This function searches in the list of rcpt addresses
804 for local and 'local net' addresses. Remote addresses
805 which are reachable only when online are treated specially
806 in another function.
808 deliver() is called when a message has just been received and should
809 be delivered immediately.
810 */
811 gboolean
812 deliver(message * msg)
813 {
814 gboolean ok;
815 GList *msg_list = g_list_append(NULL, msg);
817 ok = deliver_msg_list(msg_list, DLVR_ALL);
818 g_list_free(msg_list);
820 return ok;
821 }