masqmail-0.2

view src/deliver.c @ 10:26e34ae9a3e3

changed indention and line wrapping to a more consistent style
author meillo@marmaro.de
date Mon, 27 Oct 2008 16:23:10 +0100
parents 08114f7dcc23
children 9fb7ddbaf129
line source
1 /* MasqMail
2 Copyright (C) 1999-2002 Oliver Kurth
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
19 #include "masqmail.h"
20 #include "smtp_out.h"
21 #include <fnmatch.h>
22 #include <sysexits.h>
23 #include <netdb.h>
25 /* collect failed/defered rcpts for failure/warning messages */
26 /* returns TRUE if either there are no failures or a
27 failure message has been successfully sent */
28 gboolean
29 delivery_failures(message * msg, GList * rcpt_list, gchar * err_fmt, ...)
30 {
31 gboolean ok_fail = TRUE, ok_warn = TRUE;
32 time_t now = time(NULL);
34 GList *failed_list = NULL, *defered_list = NULL, *rcpt_node;
35 va_list args;
36 va_start(args, err_fmt);
38 foreach(rcpt_list, rcpt_node) {
39 address *rcpt = (address *) (rcpt_node->data);
41 if (addr_is_defered(rcpt)) {
42 if ((now - msg->received_time) >= conf.max_defer_time) {
43 addr_mark_failed(rcpt);
44 } else
45 defered_list = g_list_prepend(defered_list, rcpt);
46 }
47 if (addr_is_failed(rcpt))
48 failed_list = g_list_prepend(failed_list, rcpt);
49 }
50 if (failed_list != NULL) {
51 ok_fail = fail_msg(msg, conf.errmsg_file, failed_list, err_fmt, args);
52 g_list_free(failed_list);
53 }
54 if (defered_list != NULL) {
55 ok_warn = warn_msg(msg, conf.warnmsg_file, defered_list, err_fmt, args);
56 g_list_free(defered_list);
57 }
58 va_end(args);
59 return ok_fail && ok_warn;
60 }
62 static gint
63 _g_list_strcasecmp(gconstpointer a, gconstpointer b)
64 {
65 return (gint) strcasecmp(a, b);
66 }
68 gboolean
69 deliver_local(msg_out * msgout)
70 {
71 message *msg = msgout->msg;
72 GList *rcpt_list = msgout->rcpt_list;
73 GList *rcpt_node;
74 gboolean ok = TRUE, flag = FALSE, ok_fail = FALSE;
76 DEBUG(5) debugf("deliver_local entered\n");
78 flag = (msg->data_list == NULL);
79 if (flag) {
80 if (!(ok = spool_read_data(msg))) {
81 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
82 }
83 }
84 if (!ok)
85 return FALSE;
87 ok = FALSE;
88 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
89 GList *hdr_list;
90 address *rcpt = (address *) (rcpt_node->data);
91 address *env_addr = addr_find_ancestor(rcpt);
92 address *ret_path = msg->return_path;
93 header *retpath_hdr, *envto_hdr;
95 /* we need a private copy of the hdr list because we add headers here
96 that belong to the rcpt only.
97 g_list_copy copies only the nodes, so it is safe to
98 g_list_free it
99 */
100 hdr_list = g_list_copy(msg->hdr_list);
101 retpath_hdr = create_header(HEAD_ENVELOPE_TO, "Envelope-to: %s\n", addr_string(env_addr));
102 envto_hdr = create_header(HEAD_RETURN_PATH, "Return-path: %s\n", addr_string(ret_path));
104 hdr_list = g_list_prepend(hdr_list, envto_hdr);
105 hdr_list = g_list_prepend(hdr_list, retpath_hdr);
107 if (rcpt->local_part[0] == '|') {
108 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
109 if (pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]),
110 (conf.pipe_fromline ? MSGSTR_FROMLINE : 0)
111 | (conf.pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
112 logwrite(LOG_NOTICE, "%s => %s <%s@%s> with pipe\n", msg->uid, rcpt->local_part, env_addr->local_part, env_addr->domain);
113 addr_mark_delivered(rcpt);
114 ok = TRUE;
115 } else {
116 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
117 addr_mark_failed(rcpt);
118 } else {
119 addr_mark_defered(rcpt); /* has no effect yet, except that mail remains in spool */
120 }
121 }
122 } else {
123 /* figure out which mailbox type should be used for this user */
124 gchar *user = rcpt->local_part;
125 gchar *mbox_type = conf.mbox_default;
127 if (g_list_find_custom (conf.mbox_users, user, _g_list_strcasecmp) != NULL)
128 mbox_type = "mbox";
129 else if (g_list_find_custom (conf.mda_users, user, _g_list_strcasecmp) != NULL)
130 mbox_type = "mda";
131 else if (g_list_find_custom (conf.maildir_users, user, _g_list_strcasecmp) != NULL)
132 mbox_type = "maildir";
134 if (strcmp(mbox_type, "mbox") == 0) {
135 DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
136 if (append_file(msg, hdr_list, rcpt->local_part)) {
137 if (env_addr != rcpt) {
138 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with mbox\n",
139 msg->uid, rcpt->local_part, rcpt->domain,
140 env_addr->local_part, env_addr->domain);
141 } else {
142 logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n",
143 msg->uid, rcpt->local_part, rcpt->domain);
144 }
145 addr_mark_delivered(rcpt);
146 ok = TRUE;
147 } else {
148 if (errno != EAGAIN) { /* prevents 'Resource temporarily unavailable (11)' */
149 addr_mark_failed(rcpt);
150 } else {
151 addr_mark_defered(rcpt);
152 }
153 }
155 } else if (strcmp(mbox_type, "mda") == 0) {
156 if (conf.mda) {
157 gchar *cmd = g_malloc(256);
158 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
160 DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
162 if (expand(var_table, conf.mda, cmd, 256)) {
164 if (pipe_out(msg, hdr_list, rcpt, cmd, (conf.mda_fromline ? MSGSTR_FROMLINE : 0)
165 | (conf.mda_fromhack ? MSGSTR_FROMHACK : 0))) {
166 logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
167 msg->uid, rcpt->local_part, rcpt->domain, cmd);
168 addr_mark_delivered(rcpt);
169 ok = TRUE;
170 } else {
171 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
172 addr_mark_failed(rcpt);
173 } else {
174 addr_mark_defered(rcpt); /* has no effect yet, except that mail remains in spool */
175 }
176 }
177 } else
178 logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
180 destroy_table(var_table);
181 } else
182 logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n");
184 #ifdef ENABLE_MAILDIR
185 } else if (strcmp(mbox_type, "maildir") == 0) {
186 DEBUG(1) debugf("attempting to deliver %s with maildir\n", msg->uid);
187 if (maildir_out(msg, hdr_list, rcpt->local_part, 0)) {
188 if (env_addr != rcpt) {
189 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with local\n", msg->uid,
190 rcpt->local_part, rcpt->domain, env_addr->local_part, env_addr->domain);
191 } else {
192 logwrite(LOG_NOTICE, "%s => <%s@%s> with maildir\n", msg->uid,
193 rcpt->local_part, rcpt->domain);
194 }
195 addr_mark_delivered(rcpt);
196 ok = TRUE;
197 } else
198 addr_mark_failed(rcpt);
199 #endif
200 } else
201 logwrite(LOG_ALERT, "unknown mbox type '%s'\n", mbox_type);
202 }
204 destroy_header(retpath_hdr);
205 destroy_header(envto_hdr);
207 g_list_free(hdr_list);
208 }
209 ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)", ext_strerror(errno), errno);
211 if (flag)
212 msg_free_data(msg);
213 if (ok || ok_fail)
214 deliver_finish(msgout);
216 return ok;
217 }
219 /* make a list of rcpt's of a message that are local
220 return a new copy of the list
221 */
222 void
223 msg_rcptlist_local(GList * rcpt_list, GList ** p_local_list, GList ** p_nonlocal_list)
224 {
225 GList *rcpt_node;
227 foreach(rcpt_list, rcpt_node) {
228 address *rcpt = (address *) (rcpt_node->data);
229 GList *dom_node;
231 DEBUG(5) debugf("checking address %s\n", rcpt->address);
233 /* search for local host list: */
234 foreach(conf.local_hosts, dom_node) {
235 if (strcasecmp(dom_node->data, rcpt->domain) == 0) {
236 *p_local_list = g_list_append(*p_local_list, rcpt);
237 DEBUG(5) debugf("<%s@%s> is local\n", rcpt->local_part, rcpt->domain);
238 break;
239 } else {
240 *p_nonlocal_list = g_list_append(*p_nonlocal_list, rcpt);
241 }
242 }
243 }
244 }
246 gboolean
247 deliver_msglist_host_pipe(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
248 {
249 gboolean ok = TRUE;
250 GList *msgout_node;
252 DEBUG(5) debugf("deliver_msglist_host_pipe entered\n");
254 if (route->pipe == NULL) {
255 logwrite(LOG_ALERT, "no pipe command given for route (protocol is pipe!)\n");
256 return FALSE;
257 }
259 foreach(msgout_list, msgout_node) {
260 msg_out *msgout = (msg_out *) (msgout_node->data);
261 gboolean flag, ok_msg = TRUE, ok_fail = FALSE;
262 message *msg = msgout->msg;
263 GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
265 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
267 flag = (msg->data_list == NULL);
268 if (flag) {
269 if (!(ok_msg = spool_read_data(msg))) {
270 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
271 }
272 }
273 if (!ok_msg)
274 continue;
276 ok = FALSE;
277 foreach(rcpt_list, rcpt_node) {
278 address *rcpt = (address *) (rcpt_node->data);
279 gchar *cmd = g_malloc(256);
280 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
282 DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n", msg->uid, rcpt->local_part, rcpt->domain);
284 if (expand(var_table, route->pipe, cmd, 256)) {
286 if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0)
287 | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
288 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n",
289 msg->uid, rcpt->local_part, rcpt->domain, cmd);
290 addr_mark_delivered(rcpt);
291 ok = TRUE;
292 } else {
293 logwrite(LOG_ALERT, "pipe_out '%s' failed\n", route->pipe);
295 if (route->connect_error_fail) {
296 addr_mark_failed(rcpt);
297 } else {
298 addr_mark_defered(rcpt);
299 }
300 }
301 } else
302 logwrite(LOG_ALERT, "could not expand string %s\n", route->pipe);
304 destroy_table(var_table);
305 }
306 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
308 if (flag)
309 msg_free_data(msg);
311 if (ok || ok_fail)
312 deliver_finish(msgout);
313 }
315 return ok;
316 }
318 /* deliver list of messages to one host
319 and finishes them if the message was delivered to at least one rcpt.
320 Returns TRUE if at least one msg was delivered to at least one rcpt.
321 */
323 gboolean
324 deliver_msglist_host_smtp(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
325 {
326 gboolean ok = FALSE;
327 GList *msgout_node;
328 smtp_base *psb;
329 gint port;
331 /* paranoid check: */
332 if (msgout_list == NULL) {
333 logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n");
334 return FALSE;
335 }
337 if (host == NULL) {
338 host = route->mail_host->address;
339 port = route->mail_host->port;
340 } else
341 port = conf.remote_port;
343 #ifdef ENABLE_POP3
344 if (route->pop3_login) {
345 if (!(pop_before_smtp(route->pop3_login)))
346 return FALSE;
347 }
348 #endif
350 if ((psb = (route->wrapper ? smtp_out_open_child(route->wrapper) : smtp_out_open(host, port, res_list)))) {
352 if (route->wrapper)
353 psb->remote_host = host;
355 set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
357 #ifdef ENABLE_AUTH
358 if ((route->auth_name) && (route->auth_login)
359 && (route->auth_secret))
360 set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
361 #endif
362 if (smtp_out_init(psb)) {
364 if (!route->do_pipelining)
365 psb->use_pipelining = FALSE;
367 foreach(msgout_list, msgout_node) {
368 msg_out *msgout = (msg_out *) (msgout_node->data);
369 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
370 message *msg = msgout->msg;
372 /* we may have to read the data at this point
373 and remember if we did */
374 flag = (msg->data_list == NULL);
375 if (flag) {
376 if (!spool_read_data(msg)) {
377 logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
378 break;
379 }
380 }
382 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
384 ok_fail = delivery_failures(msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", host, psb->buffer);
386 if ((psb->error == smtp_eof)
387 || (psb->error == smtp_timeout)) {
388 /* connection lost */
389 break;
390 } else if (psb->error != smtp_ok) {
391 if (g_list_next(msgout_node) != NULL)
392 if (!smtp_out_rset(psb))
393 break;
394 }
395 ok_msg = (psb->error == smtp_ok);
397 if (flag)
398 msg_free_data(msg);
399 if (ok_msg)
400 ok = TRUE;
401 if (ok_msg || ok_fail) {
402 deliver_finish(msgout);
403 }
404 }
405 if (psb->error == smtp_ok || (psb->error == smtp_fail)
406 || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
407 smtp_out_quit(psb);
408 }
409 } else {
410 /* smtp_out_init() failed */
411 if ((psb->error == smtp_fail) || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
412 smtp_out_quit(psb);
414 foreach(msgout_list, msgout_node) {
415 msg_out *msgout = (msg_out *) (msgout_node->data);
416 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
418 if (delivery_failures(msgout->msg, msgout->rcpt_list,
419 "while connected with %s, the server replied\n\t%s", host, psb->buffer))
420 deliver_finish(msgout);
421 }
422 }
423 }
424 destroy_smtpbase(psb);
425 } else {
426 /* smtp_out_open() failed */
427 foreach(msgout_list, msgout_node) {
428 msg_out *msgout = (msg_out *) (msgout_node->data);
429 GList *rcpt_node;
431 for (rcpt_node = g_list_first(msgout->rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
432 address *rcpt = (address *) (rcpt_node->data);
434 addr_unmark_delivered(rcpt);
435 if (route->connect_error_fail) {
436 addr_mark_failed(rcpt);
437 } else {
438 addr_mark_defered(rcpt);
439 }
440 if (route->wrapper
441 ? delivery_failures(msgout->msg, msgout->rcpt_list,
442 "could not open wrapper:\n\t%s",
443 strerror(errno))
444 : delivery_failures(msgout->msg, msgout->rcpt_list,
445 "could not open connection to %s:%d :\n\t%s",
446 host, port, h_errno != 0 ? hstrerror(h_errno) : strerror(errno)))
447 deliver_finish(msgout);
448 }
449 }
450 }
451 return ok;
452 }
454 gboolean
455 deliver_msglist_host(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
456 {
457 DEBUG(5) debugf("protocol = %s\n", route->protocol);
459 if (strcmp(route->protocol, "pipe") == 0) {
460 return deliver_msglist_host_pipe(route, msgout_list, host, res_list);
461 } else {
462 return deliver_msglist_host_smtp(route, msgout_list, host, res_list);
463 }
464 }
466 /*
467 delivers messages in msgout_list using route
468 */
469 gboolean
470 deliver_route_msgout_list(connect_route * route, GList * msgout_list)
471 {
472 gboolean ok = FALSE;
474 DEBUG(5)
475 debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name);
477 if (route->mail_host != NULL) {
478 /* this is easy... */
479 if (deliver_msglist_host(route, msgout_list, NULL, route->resolve_list))
480 ok = TRUE;
482 } else {
483 /* this is not easy... */
484 GList *mo_ph_list;
486 mo_ph_list = route_msgout_list(route, msgout_list);
487 /* okay, now we have ordered our messages by the hosts. */
488 if (mo_ph_list != NULL) {
489 GList *mo_ph_node;
490 /* TODO: It would be nice to be able to fork for each host.
491 We cannot do that yet because of complications with finishing the
492 messages. Threads could be a solution because they use the same
493 memory. But we are not thread safe yet...
494 */
495 foreach(mo_ph_list, mo_ph_node) {
496 msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
497 if (deliver_msglist_host (route, mo_ph->msgout_list, mo_ph->host, route->resolve_list))
498 ok = TRUE;
500 destroy_msgout_perhost(mo_ph);
501 }
502 g_list_free(mo_ph_list);
503 }
504 }
505 return ok;
506 }
508 /*
509 calls route_prepare_msg()
510 delivers messages in msg_list using route
511 by calling deliver_route_msgout_list()
512 */
513 gboolean
514 deliver_route_msg_list(connect_route * route, GList * msgout_list)
515 {
516 GList *msgout_list_deliver = NULL;
517 GList *msgout_node;
518 gboolean ok = TRUE;
520 DEBUG(6) debugf("deliver_route_msg_list()\n");
522 foreach(msgout_list, msgout_node) {
523 msg_out *msgout = (msg_out *) (msgout_node->data);
524 msg_out *msgout_cloned = clone_msg_out(msgout);
525 GList *rcpt_list_non_delivered = NULL;
526 GList *rcpt_node;
528 /* we have to delete already delivered rcpt's
529 because a previous route may have delivered to it */
530 foreach(msgout_cloned->rcpt_list, rcpt_node) {
531 address *rcpt = (address *) (rcpt_node->data);
532 /* failed addresses already have been bounced
533 - there should be a better way to handle those. */
534 if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt)
535 && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE))
536 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
537 }
538 g_list_free(msgout_cloned->rcpt_list);
539 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
541 if (msgout_cloned->rcpt_list) {
542 if (route_is_allowed_mail_local(route, msgout->msg->return_path)
543 && route_is_allowed_return_path(route, msgout->msg-> return_path)) {
544 GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
545 msg_rcptlist_route(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
547 if (rcpt_list_allowed != NULL) {
548 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
550 g_list_free(msgout_cloned->rcpt_list);
551 msgout_cloned->rcpt_list = rcpt_list_allowed;
553 if (route->last_route) {
554 GList *rcpt_node;
555 foreach(msgout_cloned->rcpt_list, rcpt_node) {
556 address *rcpt = (address *) (rcpt_node->data);
557 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
558 }
559 }
561 route_prepare_msgout(route, msgout_cloned);
562 msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
563 } else
564 destroy_msg_out(msgout_cloned);
565 } else
566 destroy_msg_out(msgout_cloned);
567 } else
568 destroy_msg_out(msgout_cloned);
569 }
571 if (msgout_list_deliver != NULL) {
572 if (deliver_route_msgout_list(route, msgout_list_deliver))
573 ok = TRUE;
574 destroy_msg_out_list(msgout_list_deliver);
575 }
576 return ok;
577 }
579 /* copy pointers of delivered addresses to the msg's non_rcpt_list,
580 to make sure that they will not be delivered again.
581 */
582 void
583 update_non_rcpt_list(msg_out * msgout)
584 {
585 GList *rcpt_node;
586 message *msg = msgout->msg;
588 foreach(msgout->rcpt_list, rcpt_node) {
589 address *rcpt = (address *) (rcpt_node->data);
590 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt))
591 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
592 }
593 }
595 /* after delivery attempts, we check if there are any
596 rcpt addresses left in the message.
597 If all addresses have been completed, the spool files will
598 be deleted, otherwise the header spool will be written back.
599 We never changed the data spool, so there is no need to write that back.
601 returns TRUE if all went well.
602 */
603 gboolean
604 deliver_finish(msg_out * msgout)
605 {
606 GList *rcpt_node;
607 gboolean ok = FALSE;
608 message *msg = msgout->msg;
609 gboolean finished = TRUE;
611 update_non_rcpt_list(msgout);
613 /* we NEVER made copies of the addresses, flags affecting addresses
614 were always set on the original address structs */
615 foreach(msg->rcpt_list, rcpt_node) {
616 address *rcpt = (address *) (rcpt_node->data);
617 if (!addr_is_finished_children(rcpt))
618 finished = FALSE;
619 else {
620 /* if ALL children have been delivered,
621 mark parent as delivered.
622 if there is one or more not delivered,
623 it must have failed, we mark the parent as failed as well.
624 */
625 if (addr_is_delivered_children(rcpt)) {
626 addr_mark_delivered(rcpt);
627 } else {
628 addr_mark_failed(rcpt);
629 }
630 }
631 }
633 if (!finished) {
634 /* one not delivered address was found */
635 if (spool_write(msg, FALSE)) {
636 ok = TRUE;
637 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
638 } else
639 logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
640 } else {
641 ok = spool_delete_all(msg);
642 if (ok)
643 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
644 }
645 return ok;
646 }
648 gboolean
649 deliver_finish_list(GList * msgout_list)
650 {
651 gboolean ok = TRUE;
652 GList *msgout_node;
653 foreach(msgout_list, msgout_node) {
654 msg_out *msgout = (msg_out *) (msgout_node->data);
655 if (!deliver_finish(msgout))
656 ok = FALSE;
657 }
658 return ok;
659 }
661 gboolean
662 deliver_msgout_list_online(GList * msgout_list)
663 {
664 GList *rf_list = NULL;
665 gchar *connect_name = detect_online();
666 gboolean ok = FALSE;
668 if (connect_name != NULL) {
669 logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
670 /* we are online! */
671 rf_list = (GList *) table_find(conf.connect_routes, connect_name);
672 if (rf_list != NULL) {
673 GList *route_list = read_route_list(rf_list, FALSE);
674 if (route_list) {
675 GList *route_node;
676 foreach(route_list, route_node) {
677 connect_route *route = (connect_route *) (route_node->data);
678 ok = deliver_route_msg_list(route, msgout_list);
679 }
680 destroy_route_list(route_list);
681 } else
682 logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
683 } else {
684 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
685 }
686 }
687 return ok;
688 }
690 gboolean
691 deliver_msg_list(GList * msg_list, guint flags)
692 {
693 GList *msgout_list = create_msg_out_list(msg_list);
694 GList *local_msgout_list = NULL, *localnet_msgout_list = NULL, *other_msgout_list = NULL;
695 GList *msgout_node;
696 GList *alias_table = NULL;
697 gboolean ok = TRUE;
699 if (conf.alias_file) {
700 if (!(alias_table = table_read(conf.alias_file, ':')))
701 return FALSE;
702 }
704 /* sort messages for different deliveries */
705 foreach(msgout_list, msgout_node) {
706 msg_out *msgout = (msg_out *) (msgout_node->data);
707 GList *rcpt_list;
708 GList *local_rcpt_list = NULL;
709 GList *localnet_rcpt_list = NULL;
710 GList *other_rcpt_list;
712 if (!spool_lock(msgout->msg->uid))
713 continue;
715 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
716 if (conf.log_user) {
717 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
718 if (addr)
719 rcpt_list = g_list_prepend(rcpt_list, addr);
720 }
721 if (alias_table) {
722 GList *aliased_rcpt_list;
723 aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list);
724 g_list_free(rcpt_list);
725 rcpt_list = aliased_rcpt_list;
726 }
728 /* local recipients */
729 other_rcpt_list = NULL;
730 rcptlist_with_addr_is_local(rcpt_list, &local_rcpt_list, &other_rcpt_list);
732 if (flags & DLVR_LOCAL) {
733 if (local_rcpt_list != NULL) {
734 msg_out *local_msgout = clone_msg_out(msgout);
735 local_msgout->rcpt_list = local_rcpt_list;
736 local_msgout_list = g_list_append(local_msgout_list, local_msgout);
737 }
738 }
740 g_list_free(rcpt_list);
742 /* local net recipients */
743 rcpt_list = other_rcpt_list;
744 other_rcpt_list = NULL;
745 rcptlist_with_one_of_hostlist(rcpt_list, conf.local_nets, &localnet_rcpt_list, &other_rcpt_list);
747 if (flags & DLVR_LAN) {
748 if (localnet_rcpt_list != NULL) {
749 msg_out *localnet_msgout = clone_msg_out(msgout);
750 localnet_msgout->rcpt_list = localnet_rcpt_list;
751 localnet_msgout_list = g_list_append(localnet_msgout_list, localnet_msgout);
752 }
753 }
755 if (flags & DLVR_ONLINE) {
756 /* the rest, this is online delivery */
757 if (other_rcpt_list != NULL) {
758 msg_out *other_msgout = clone_msg_out(msgout);
759 other_msgout->rcpt_list = other_rcpt_list;
760 other_msgout_list = g_list_append(other_msgout_list, other_msgout);
761 }
762 }
763 }
765 if (alias_table)
766 destroy_table(alias_table);
768 /* actual delivery */
769 if (local_msgout_list != NULL) {
770 foreach(local_msgout_list, msgout_node) {
771 msg_out *msgout = (msg_out *) (msgout_node->data);
772 if (!deliver_local(msgout))
773 ok = FALSE;
774 }
775 destroy_msg_out_list(local_msgout_list);
776 }
778 if (localnet_msgout_list != NULL) {
779 GList *route_list = NULL;
780 GList *route_node;
782 if (conf.local_net_routes)
783 route_list = read_route_list(conf.local_net_routes, TRUE);
784 else
785 route_list = g_list_append(NULL, create_local_route());
787 foreach(route_list, route_node) {
788 connect_route *route = (connect_route *) (route_node->data);
789 if (!deliver_route_msg_list(route, localnet_msgout_list))
790 ok = FALSE;
791 }
792 destroy_msg_out_list(localnet_msgout_list);
793 destroy_route_list(route_list);
794 }
796 if (other_msgout_list != NULL) {
797 if (!deliver_msgout_list_online(other_msgout_list))
798 ok = FALSE;
799 destroy_msg_out_list(other_msgout_list);
800 }
802 foreach(msgout_list, msgout_node) {
803 msg_out *msgout = (msg_out *) (msgout_node->data);
804 spool_unlock(msgout->msg->uid);
805 }
807 destroy_msg_out_list(msgout_list);
809 return ok;
810 }
812 /* This function searches in the list of rcpt addresses
813 for local and 'local net' addresses. Remote addresses
814 which are reachable only when online are treated specially
815 in another function.
817 deliver() is called when a message has just been received and should
818 be delivered immediately.
819 */
820 gboolean
821 deliver(message * msg)
822 {
823 gboolean ok;
824 GList *msg_list = g_list_append(NULL, msg);
826 ok = deliver_msg_list(msg_list, DLVR_ALL);
827 g_list_free(msg_list);
829 return ok;
830 }