masqmail-0.2

view src/deliver.c @ 13:49dab67fe461

code beautifying
author meillo@marmaro.de
date Wed, 29 Oct 2008 21:10:18 +0100
parents 26e34ae9a3e3
children f671821d8222
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) && (route->auth_secret))
359 set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
360 #endif
361 if (smtp_out_init(psb)) {
363 if (!route->do_pipelining)
364 psb->use_pipelining = FALSE;
366 foreach(msgout_list, msgout_node) {
367 msg_out *msgout = (msg_out *) (msgout_node->data);
368 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
369 message *msg = msgout->msg;
371 /* we may have to read the data at this point
372 and remember if we did */
373 flag = (msg->data_list == NULL);
374 if (flag) {
375 if (!spool_read_data(msg)) {
376 logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
377 break;
378 }
379 }
381 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
383 ok_fail = delivery_failures(msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", host, psb->buffer);
385 if ((psb->error == smtp_eof)
386 || (psb->error == smtp_timeout)) {
387 /* connection lost */
388 break;
389 } else if (psb->error != smtp_ok) {
390 if (g_list_next(msgout_node) != NULL)
391 if (!smtp_out_rset(psb))
392 break;
393 }
394 ok_msg = (psb->error == smtp_ok);
396 if (flag)
397 msg_free_data(msg);
398 if (ok_msg)
399 ok = TRUE;
400 if (ok_msg || ok_fail) {
401 deliver_finish(msgout);
402 }
403 }
404 if (psb->error == smtp_ok || (psb->error == smtp_fail)
405 || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
406 smtp_out_quit(psb);
407 }
408 } else {
409 /* smtp_out_init() failed */
410 if ((psb->error == smtp_fail) || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
411 smtp_out_quit(psb);
413 foreach(msgout_list, msgout_node) {
414 msg_out *msgout = (msg_out *) (msgout_node->data);
415 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
417 if (delivery_failures(msgout->msg, msgout->rcpt_list,
418 "while connected with %s, the server replied\n\t%s", host, psb->buffer))
419 deliver_finish(msgout);
420 }
421 }
422 }
423 destroy_smtpbase(psb);
424 } else {
425 /* smtp_out_open() failed */
426 foreach(msgout_list, msgout_node) {
427 msg_out *msgout = (msg_out *) (msgout_node->data);
428 GList *rcpt_node;
430 for (rcpt_node = g_list_first(msgout->rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
431 address *rcpt = (address *) (rcpt_node->data);
433 addr_unmark_delivered(rcpt);
434 if (route->connect_error_fail) {
435 addr_mark_failed(rcpt);
436 } else {
437 addr_mark_defered(rcpt);
438 }
439 if (route->wrapper
440 ? delivery_failures(msgout->msg, msgout->rcpt_list,
441 "could not open wrapper:\n\t%s",
442 strerror(errno))
443 : delivery_failures(msgout->msg, msgout->rcpt_list,
444 "could not open connection to %s:%d :\n\t%s",
445 host, port, h_errno != 0 ? hstrerror(h_errno) : strerror(errno)))
446 deliver_finish(msgout);
447 }
448 }
449 }
450 return ok;
451 }
453 gboolean
454 deliver_msglist_host(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
455 {
456 DEBUG(5) debugf("protocol = %s\n", route->protocol);
458 if (strcmp(route->protocol, "pipe") == 0) {
459 return deliver_msglist_host_pipe(route, msgout_list, host, res_list);
460 } else {
461 return deliver_msglist_host_smtp(route, msgout_list, host, res_list);
462 }
463 }
465 /*
466 delivers messages in msgout_list using route
467 */
468 gboolean
469 deliver_route_msgout_list(connect_route * route, GList * msgout_list)
470 {
471 gboolean ok = FALSE;
473 DEBUG(5)
474 debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name);
476 if (route->mail_host != NULL) {
477 /* this is easy... */
478 if (deliver_msglist_host(route, msgout_list, NULL, route->resolve_list))
479 ok = TRUE;
481 } else {
482 /* this is not easy... */
483 GList *mo_ph_list;
485 mo_ph_list = route_msgout_list(route, msgout_list);
486 /* okay, now we have ordered our messages by the hosts. */
487 if (mo_ph_list != NULL) {
488 GList *mo_ph_node;
489 /* TODO: It would be nice to be able to fork for each host.
490 We cannot do that yet because of complications with finishing the
491 messages. Threads could be a solution because they use the same
492 memory. But we are not thread safe yet...
493 */
494 foreach(mo_ph_list, mo_ph_node) {
495 msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
496 if (deliver_msglist_host (route, mo_ph->msgout_list, mo_ph->host, route->resolve_list))
497 ok = TRUE;
499 destroy_msgout_perhost(mo_ph);
500 }
501 g_list_free(mo_ph_list);
502 }
503 }
504 return ok;
505 }
507 /*
508 calls route_prepare_msg()
509 delivers messages in msg_list using route
510 by calling deliver_route_msgout_list()
511 */
512 gboolean
513 deliver_route_msg_list(connect_route * route, GList * msgout_list)
514 {
515 GList *msgout_list_deliver = NULL;
516 GList *msgout_node;
517 gboolean ok = TRUE;
519 DEBUG(6) debugf("deliver_route_msg_list()\n");
521 foreach(msgout_list, msgout_node) {
522 msg_out *msgout = (msg_out *) (msgout_node->data);
523 msg_out *msgout_cloned = clone_msg_out(msgout);
524 GList *rcpt_list_non_delivered = NULL;
525 GList *rcpt_node;
527 /* we have to delete already delivered rcpt's
528 because a previous route may have delivered to it */
529 foreach(msgout_cloned->rcpt_list, rcpt_node) {
530 address *rcpt = (address *) (rcpt_node->data);
531 /* failed addresses already have been bounced
532 - there should be a better way to handle those. */
533 if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt)
534 && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE))
535 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
536 }
537 g_list_free(msgout_cloned->rcpt_list);
538 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
540 if (msgout_cloned->rcpt_list) {
541 if (route_is_allowed_mail_local(route, msgout->msg->return_path)
542 && route_is_allowed_return_path(route, msgout->msg-> return_path)) {
543 GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
544 msg_rcptlist_route(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
546 if (rcpt_list_allowed != NULL) {
547 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
549 g_list_free(msgout_cloned->rcpt_list);
550 msgout_cloned->rcpt_list = rcpt_list_allowed;
552 if (route->last_route) {
553 GList *rcpt_node;
554 foreach(msgout_cloned->rcpt_list, rcpt_node) {
555 address *rcpt = (address *) (rcpt_node->data);
556 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
557 }
558 }
560 route_prepare_msgout(route, msgout_cloned);
561 msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
562 } else
563 destroy_msg_out(msgout_cloned);
564 } else
565 destroy_msg_out(msgout_cloned);
566 } else
567 destroy_msg_out(msgout_cloned);
568 }
570 if (msgout_list_deliver != NULL) {
571 if (deliver_route_msgout_list(route, msgout_list_deliver))
572 ok = TRUE;
573 destroy_msg_out_list(msgout_list_deliver);
574 }
575 return ok;
576 }
578 /* copy pointers of delivered addresses to the msg's non_rcpt_list,
579 to make sure that they will not be delivered again.
580 */
581 void
582 update_non_rcpt_list(msg_out * msgout)
583 {
584 GList *rcpt_node;
585 message *msg = msgout->msg;
587 foreach(msgout->rcpt_list, rcpt_node) {
588 address *rcpt = (address *) (rcpt_node->data);
589 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt))
590 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
591 }
592 }
594 /* after delivery attempts, we check if there are any
595 rcpt addresses left in the message.
596 If all addresses have been completed, the spool files will
597 be deleted, otherwise the header spool will be written back.
598 We never changed the data spool, so there is no need to write that back.
600 returns TRUE if all went well.
601 */
602 gboolean
603 deliver_finish(msg_out * msgout)
604 {
605 GList *rcpt_node;
606 gboolean ok = FALSE;
607 message *msg = msgout->msg;
608 gboolean finished = TRUE;
610 update_non_rcpt_list(msgout);
612 /* we NEVER made copies of the addresses, flags affecting addresses
613 were always set on the original address structs */
614 foreach(msg->rcpt_list, rcpt_node) {
615 address *rcpt = (address *) (rcpt_node->data);
616 if (!addr_is_finished_children(rcpt))
617 finished = FALSE;
618 else {
619 /* if ALL children have been delivered,
620 mark parent as delivered.
621 if there is one or more not delivered,
622 it must have failed, we mark the parent as failed as well.
623 */
624 if (addr_is_delivered_children(rcpt)) {
625 addr_mark_delivered(rcpt);
626 } else {
627 addr_mark_failed(rcpt);
628 }
629 }
630 }
632 if (!finished) {
633 /* one not delivered address was found */
634 if (spool_write(msg, FALSE)) {
635 ok = TRUE;
636 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
637 } else
638 logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
639 } else {
640 ok = spool_delete_all(msg);
641 if (ok)
642 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
643 }
644 return ok;
645 }
647 gboolean
648 deliver_finish_list(GList * msgout_list)
649 {
650 gboolean ok = TRUE;
651 GList *msgout_node;
652 foreach(msgout_list, msgout_node) {
653 msg_out *msgout = (msg_out *) (msgout_node->data);
654 if (!deliver_finish(msgout))
655 ok = FALSE;
656 }
657 return ok;
658 }
660 gboolean
661 deliver_msgout_list_online(GList * msgout_list)
662 {
663 GList *rf_list = NULL;
664 gchar *connect_name = detect_online();
665 gboolean ok = FALSE;
667 if (connect_name != NULL) {
668 logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
669 /* we are online! */
670 rf_list = (GList *) table_find(conf.connect_routes, connect_name);
671 if (rf_list != NULL) {
672 GList *route_list = read_route_list(rf_list, FALSE);
673 if (route_list) {
674 GList *route_node;
675 foreach(route_list, route_node) {
676 connect_route *route = (connect_route *) (route_node->data);
677 ok = deliver_route_msg_list(route, msgout_list);
678 }
679 destroy_route_list(route_list);
680 } else
681 logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
682 } else {
683 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
684 }
685 }
686 return ok;
687 }
689 gboolean
690 deliver_msg_list(GList * msg_list, guint flags)
691 {
692 GList *msgout_list = create_msg_out_list(msg_list);
693 GList *local_msgout_list = NULL, *localnet_msgout_list = NULL, *other_msgout_list = NULL;
694 GList *msgout_node;
695 GList *alias_table = NULL;
696 gboolean ok = TRUE;
698 if (conf.alias_file) {
699 if (!(alias_table = table_read(conf.alias_file, ':')))
700 return FALSE;
701 }
703 /* sort messages for different deliveries */
704 foreach(msgout_list, msgout_node) {
705 msg_out *msgout = (msg_out *) (msgout_node->data);
706 GList *rcpt_list;
707 GList *local_rcpt_list = NULL;
708 GList *localnet_rcpt_list = NULL;
709 GList *other_rcpt_list;
711 if (!spool_lock(msgout->msg->uid))
712 continue;
714 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
715 if (conf.log_user) {
716 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
717 if (addr)
718 rcpt_list = g_list_prepend(rcpt_list, addr);
719 }
720 if (alias_table) {
721 GList *aliased_rcpt_list;
722 aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list);
723 g_list_free(rcpt_list);
724 rcpt_list = aliased_rcpt_list;
725 }
727 /* local recipients */
728 other_rcpt_list = NULL;
729 rcptlist_with_addr_is_local(rcpt_list, &local_rcpt_list, &other_rcpt_list);
731 if (flags & DLVR_LOCAL) {
732 if (local_rcpt_list != NULL) {
733 msg_out *local_msgout = clone_msg_out(msgout);
734 local_msgout->rcpt_list = local_rcpt_list;
735 local_msgout_list = g_list_append(local_msgout_list, local_msgout);
736 }
737 }
739 g_list_free(rcpt_list);
741 /* local net recipients */
742 rcpt_list = other_rcpt_list;
743 other_rcpt_list = NULL;
744 rcptlist_with_one_of_hostlist(rcpt_list, conf.local_nets, &localnet_rcpt_list, &other_rcpt_list);
746 if (flags & DLVR_LAN) {
747 if (localnet_rcpt_list != NULL) {
748 msg_out *localnet_msgout = clone_msg_out(msgout);
749 localnet_msgout->rcpt_list = localnet_rcpt_list;
750 localnet_msgout_list = g_list_append(localnet_msgout_list, localnet_msgout);
751 }
752 }
754 if (flags & DLVR_ONLINE) {
755 /* the rest, this is online delivery */
756 if (other_rcpt_list != NULL) {
757 msg_out *other_msgout = clone_msg_out(msgout);
758 other_msgout->rcpt_list = other_rcpt_list;
759 other_msgout_list = g_list_append(other_msgout_list, other_msgout);
760 }
761 }
762 }
764 if (alias_table)
765 destroy_table(alias_table);
767 /* actual delivery */
768 if (local_msgout_list != NULL) {
769 foreach(local_msgout_list, msgout_node) {
770 msg_out *msgout = (msg_out *) (msgout_node->data);
771 if (!deliver_local(msgout))
772 ok = FALSE;
773 }
774 destroy_msg_out_list(local_msgout_list);
775 }
777 if (localnet_msgout_list != NULL) {
778 GList *route_list = NULL;
779 GList *route_node;
781 if (conf.local_net_routes)
782 route_list = read_route_list(conf.local_net_routes, TRUE);
783 else
784 route_list = g_list_append(NULL, create_local_route());
786 foreach(route_list, route_node) {
787 connect_route *route = (connect_route *) (route_node->data);
788 if (!deliver_route_msg_list(route, localnet_msgout_list))
789 ok = FALSE;
790 }
791 destroy_msg_out_list(localnet_msgout_list);
792 destroy_route_list(route_list);
793 }
795 if (other_msgout_list != NULL) {
796 if (!deliver_msgout_list_online(other_msgout_list))
797 ok = FALSE;
798 destroy_msg_out_list(other_msgout_list);
799 }
801 foreach(msgout_list, msgout_node) {
802 msg_out *msgout = (msg_out *) (msgout_node->data);
803 spool_unlock(msgout->msg->uid);
804 }
806 destroy_msg_out_list(msgout_list);
808 return ok;
809 }
811 /* This function searches in the list of rcpt addresses
812 for local and 'local net' addresses. Remote addresses
813 which are reachable only when online are treated specially
814 in another function.
816 deliver() is called when a message has just been received and should
817 be delivered immediately.
818 */
819 gboolean
820 deliver(message * msg)
821 {
822 gboolean ok;
823 GList *msg_list = g_list_append(NULL, msg);
825 ok = deliver_msg_list(msg_list, DLVR_ALL);
826 g_list_free(msg_list);
828 return ok;
829 }