masqmail-0.2

view src/deliver.c @ 15:f671821d8222

code beautifying; 0 -> \0 if appropriate
author meillo@marmaro.de
date Thu, 06 Nov 2008 09:18:38 +0100
parents 9fb7ddbaf129
children 6c59dedd06be
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 <fnmatch.h>
20 #include <sysexits.h>
21 #include <netdb.h>
23 #include "masqmail.h"
24 #include "smtp_out.h"
26 /* collect failed/defered rcpts for failure/warning messages */
27 /* returns TRUE if either there are no failures or a 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 that belong to the rcpt only.
96 g_list_copy copies only the nodes, so it is safe to g_list_free it */
97 hdr_list = g_list_copy(msg->hdr_list);
98 retpath_hdr = create_header(HEAD_ENVELOPE_TO, "Envelope-to: %s\n", addr_string(env_addr));
99 envto_hdr = create_header(HEAD_RETURN_PATH, "Return-path: %s\n", addr_string(ret_path));
101 hdr_list = g_list_prepend(hdr_list, envto_hdr);
102 hdr_list = g_list_prepend(hdr_list, retpath_hdr);
104 if (rcpt->local_part[0] == '|') {
105 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
106 if (pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]),
107 (conf.pipe_fromline ? MSGSTR_FROMLINE : 0)
108 | (conf.pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
109 logwrite(LOG_NOTICE, "%s => %s <%s@%s> with pipe\n",
110 msg->uid, rcpt->local_part, env_addr->local_part, env_addr->domain);
111 addr_mark_delivered(rcpt);
112 ok = TRUE;
113 } else {
114 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
115 addr_mark_failed(rcpt);
116 } else {
117 addr_mark_defered(rcpt); /* has no effect yet, except that mail remains in spool */
118 }
119 }
120 } else {
121 /* figure out which mailbox type should be used for this user */
122 gchar *user = rcpt->local_part;
123 gchar *mbox_type = conf.mbox_default;
125 if (g_list_find_custom (conf.mbox_users, user, _g_list_strcasecmp) != NULL)
126 mbox_type = "mbox";
127 else if (g_list_find_custom (conf.mda_users, user, _g_list_strcasecmp) != NULL)
128 mbox_type = "mda";
129 else if (g_list_find_custom (conf.maildir_users, user, _g_list_strcasecmp) != NULL)
130 mbox_type = "maildir";
132 if (strcmp(mbox_type, "mbox") == 0) {
133 DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
134 if (append_file(msg, hdr_list, rcpt->local_part)) {
135 if (env_addr != rcpt) {
136 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with mbox\n",
137 msg->uid, rcpt->local_part, rcpt->domain,
138 env_addr->local_part, env_addr->domain);
139 } else {
140 logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n",
141 msg->uid, rcpt->local_part, rcpt->domain);
142 }
143 addr_mark_delivered(rcpt);
144 ok = TRUE;
145 } else {
146 if (errno != EAGAIN) { /* prevents 'Resource temporarily unavailable (11)' */
147 addr_mark_failed(rcpt);
148 } else {
149 addr_mark_defered(rcpt);
150 }
151 }
153 } else if (strcmp(mbox_type, "mda") == 0) {
154 if (conf.mda) {
155 gchar *cmd = g_malloc(256);
156 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
158 DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
160 if (expand(var_table, conf.mda, cmd, 256)) {
162 if (pipe_out(msg, hdr_list, rcpt, cmd, (conf.mda_fromline ? MSGSTR_FROMLINE : 0)
163 | (conf.mda_fromhack ? MSGSTR_FROMHACK : 0))) {
164 logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
165 msg->uid, rcpt->local_part, rcpt->domain, cmd);
166 addr_mark_delivered(rcpt);
167 ok = TRUE;
168 } else {
169 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
170 addr_mark_failed(rcpt);
171 } else {
172 addr_mark_defered(rcpt); /* has no effect yet, except that mail remains in spool */
173 }
174 }
175 } else
176 logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
178 destroy_table(var_table);
179 } else
180 logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n");
182 #ifdef ENABLE_MAILDIR
183 } else if (strcmp(mbox_type, "maildir") == 0) {
184 DEBUG(1) debugf("attempting to deliver %s with maildir\n", msg->uid);
185 if (maildir_out(msg, hdr_list, rcpt->local_part, 0)) {
186 if (env_addr != rcpt) {
187 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with local\n", msg->uid,
188 rcpt->local_part, rcpt->domain, env_addr->local_part, env_addr->domain);
189 } else {
190 logwrite(LOG_NOTICE, "%s => <%s@%s> with maildir\n", msg->uid,
191 rcpt->local_part, rcpt->domain);
192 }
193 addr_mark_delivered(rcpt);
194 ok = TRUE;
195 } else
196 addr_mark_failed(rcpt);
197 #endif
198 } else
199 logwrite(LOG_ALERT, "unknown mbox type '%s'\n", mbox_type);
200 }
202 destroy_header(retpath_hdr);
203 destroy_header(envto_hdr);
205 g_list_free(hdr_list);
206 }
207 ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)", ext_strerror(errno), errno);
209 if (flag)
210 msg_free_data(msg);
211 if (ok || ok_fail)
212 deliver_finish(msgout);
214 return ok;
215 }
217 /* make a list of rcpt's of a message that are local return a new copy of the list */
218 void
219 msg_rcptlist_local(GList * rcpt_list, GList ** p_local_list, GList ** p_nonlocal_list)
220 {
221 GList *rcpt_node;
223 foreach(rcpt_list, rcpt_node) {
224 address *rcpt = (address *) (rcpt_node->data);
225 GList *dom_node;
227 DEBUG(5) debugf("checking address %s\n", rcpt->address);
229 /* search for local host list: */
230 foreach(conf.local_hosts, dom_node) {
231 if (strcasecmp(dom_node->data, rcpt->domain) == 0) {
232 *p_local_list = g_list_append(*p_local_list, rcpt);
233 DEBUG(5) debugf("<%s@%s> is local\n", rcpt->local_part, rcpt->domain);
234 break;
235 } else {
236 *p_nonlocal_list = g_list_append(*p_nonlocal_list, rcpt);
237 }
238 }
239 }
240 }
242 gboolean
243 deliver_msglist_host_pipe(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
244 {
245 gboolean ok = TRUE;
246 GList *msgout_node;
248 DEBUG(5) debugf("deliver_msglist_host_pipe entered\n");
250 if (route->pipe == NULL) {
251 logwrite(LOG_ALERT, "no pipe command given for route (protocol is pipe!)\n");
252 return FALSE;
253 }
255 foreach(msgout_list, msgout_node) {
256 msg_out *msgout = (msg_out *) (msgout_node->data);
257 gboolean flag, ok_msg = TRUE, ok_fail = FALSE;
258 message *msg = msgout->msg;
259 GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
261 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
263 flag = (msg->data_list == NULL);
264 if (flag) {
265 if (!(ok_msg = spool_read_data(msg))) {
266 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
267 }
268 }
269 if (!ok_msg)
270 continue;
272 ok = FALSE;
273 foreach(rcpt_list, rcpt_node) {
274 address *rcpt = (address *) (rcpt_node->data);
275 gchar *cmd = g_malloc(256);
276 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
278 DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n", msg->uid, rcpt->local_part, rcpt->domain);
280 if (expand(var_table, route->pipe, cmd, 256)) {
282 if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0)
283 | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
284 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n",
285 msg->uid, rcpt->local_part, rcpt->domain, cmd);
286 addr_mark_delivered(rcpt);
287 ok = TRUE;
288 } else {
289 logwrite(LOG_ALERT, "pipe_out '%s' failed\n", route->pipe);
291 if (route->connect_error_fail) {
292 addr_mark_failed(rcpt);
293 } else {
294 addr_mark_defered(rcpt);
295 }
296 }
297 } else
298 logwrite(LOG_ALERT, "could not expand string %s\n", route->pipe);
300 destroy_table(var_table);
301 }
302 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
304 if (flag)
305 msg_free_data(msg);
307 if (ok || ok_fail)
308 deliver_finish(msgout);
309 }
311 return ok;
312 }
314 /* deliver list of messages to one host and finishes them if the message was delivered to at least one rcpt.
315 Returns TRUE if at least one msg was delivered to at least one rcpt.
316 */
317 gboolean
318 deliver_msglist_host_smtp(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
319 {
320 gboolean ok = FALSE;
321 GList *msgout_node;
322 smtp_base *psb;
323 gint port;
325 /* paranoid check: */
326 if (msgout_list == NULL) {
327 logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n");
328 return FALSE;
329 }
331 if (host == NULL) {
332 host = route->mail_host->address;
333 port = route->mail_host->port;
334 } else
335 port = conf.remote_port;
337 #ifdef ENABLE_POP3
338 if (route->pop3_login) {
339 if (!(pop_before_smtp(route->pop3_login)))
340 return FALSE;
341 }
342 #endif
344 if ((psb = (route->wrapper ? smtp_out_open_child(route->wrapper) : smtp_out_open(host, port, res_list)))) {
346 if (route->wrapper)
347 psb->remote_host = host;
349 set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
351 #ifdef ENABLE_AUTH
352 if ((route->auth_name) && (route->auth_login) && (route->auth_secret))
353 set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
354 #endif
355 if (smtp_out_init(psb)) {
357 if (!route->do_pipelining)
358 psb->use_pipelining = FALSE;
360 foreach(msgout_list, msgout_node) {
361 msg_out *msgout = (msg_out *) (msgout_node->data);
362 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
363 message *msg = msgout->msg;
365 /* we may have to read the data at this point and remember if we did */
366 flag = (msg->data_list == NULL);
367 if (flag) {
368 if (!spool_read_data(msg)) {
369 logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
370 break;
371 }
372 }
374 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
376 ok_fail = delivery_failures(msg, msgout->rcpt_list,
377 "while connected with %s, the server replied\n\t%s", host, psb->buffer);
379 if ((psb->error == smtp_eof)
380 || (psb->error == smtp_timeout)) {
381 /* connection lost */
382 break;
383 } else if (psb->error != smtp_ok) {
384 if (g_list_next(msgout_node) != NULL)
385 if (!smtp_out_rset(psb))
386 break;
387 }
388 ok_msg = (psb->error == smtp_ok);
390 if (flag)
391 msg_free_data(msg);
392 if (ok_msg)
393 ok = TRUE;
394 if (ok_msg || ok_fail) {
395 deliver_finish(msgout);
396 }
397 }
398 if (psb->error == smtp_ok || (psb->error == smtp_fail)
399 || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
400 smtp_out_quit(psb);
401 }
402 } else {
403 /* smtp_out_init() failed */
404 if ((psb->error == smtp_fail) || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
405 smtp_out_quit(psb);
407 foreach(msgout_list, msgout_node) {
408 msg_out *msgout = (msg_out *) (msgout_node->data);
409 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
411 if (delivery_failures(msgout->msg, msgout->rcpt_list,
412 "while connected with %s, the server replied\n\t%s", host, psb->buffer))
413 deliver_finish(msgout);
414 }
415 }
416 }
417 destroy_smtpbase(psb);
418 } else {
419 /* smtp_out_open() failed */
420 foreach(msgout_list, msgout_node) {
421 msg_out *msgout = (msg_out *) (msgout_node->data);
422 GList *rcpt_node;
424 for (rcpt_node = g_list_first(msgout->rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
425 address *rcpt = (address *) (rcpt_node->data);
427 addr_unmark_delivered(rcpt);
428 if (route->connect_error_fail) {
429 addr_mark_failed(rcpt);
430 } else {
431 addr_mark_defered(rcpt);
432 }
433 if (route->wrapper
434 ? delivery_failures(msgout->msg, msgout->rcpt_list, "could not open wrapper:\n\t%s",
435 strerror(errno))
436 : delivery_failures(msgout->msg, msgout->rcpt_list, "could not open connection to %s:%d :\n\t%s",
437 host, port, h_errno != 0 ? hstrerror(h_errno) : strerror(errno)))
438 deliver_finish(msgout);
439 }
440 }
441 }
442 return ok;
443 }
445 gboolean
446 deliver_msglist_host(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
447 {
448 DEBUG(5) debugf("protocol = %s\n", route->protocol);
450 if (strcmp(route->protocol, "pipe") == 0) {
451 return deliver_msglist_host_pipe(route, msgout_list, host, res_list);
452 } else {
453 return deliver_msglist_host_smtp(route, msgout_list, host, res_list);
454 }
455 }
457 /*
458 delivers messages in msgout_list using route
459 */
460 gboolean
461 deliver_route_msgout_list(connect_route * route, GList * msgout_list)
462 {
463 gboolean ok = FALSE;
465 DEBUG(5) debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name);
467 if (route->mail_host != NULL) {
468 /* this is easy... */
469 if (deliver_msglist_host(route, msgout_list, NULL, route->resolve_list))
470 ok = TRUE;
472 } else {
473 /* this is not easy... */
474 GList *mo_ph_list;
476 mo_ph_list = route_msgout_list(route, msgout_list);
477 /* okay, now we have ordered our messages by the hosts. */
478 if (mo_ph_list != NULL) {
479 GList *mo_ph_node;
480 /* TODO: It would be nice to be able to fork for each host.
481 We cannot do that yet because of complications with finishing the
482 messages. Threads could be a solution because they use the same
483 memory. But we are not thread safe yet...
484 */
485 foreach(mo_ph_list, mo_ph_node) {
486 msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
487 if (deliver_msglist_host (route, mo_ph->msgout_list, mo_ph->host, route->resolve_list))
488 ok = TRUE;
490 destroy_msgout_perhost(mo_ph);
491 }
492 g_list_free(mo_ph_list);
493 }
494 }
495 return ok;
496 }
498 /*
499 calls route_prepare_msg()
500 delivers messages in msg_list using route by calling deliver_route_msgout_list()
501 */
502 gboolean
503 deliver_route_msg_list(connect_route * route, GList * msgout_list)
504 {
505 GList *msgout_list_deliver = NULL;
506 GList *msgout_node;
507 gboolean ok = TRUE;
509 DEBUG(6) debugf("deliver_route_msg_list()\n");
511 foreach(msgout_list, msgout_node) {
512 msg_out *msgout = (msg_out *) (msgout_node->data);
513 msg_out *msgout_cloned = clone_msg_out(msgout);
514 GList *rcpt_list_non_delivered = NULL;
515 GList *rcpt_node;
517 /* we have to delete already delivered rcpt's because a previous route may have delivered to it */
518 foreach(msgout_cloned->rcpt_list, rcpt_node) {
519 address *rcpt = (address *) (rcpt_node->data);
520 /* failed addresses already have been bounced - there should be a better way to handle those. */
521 if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt)
522 && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE))
523 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
524 }
525 g_list_free(msgout_cloned->rcpt_list);
526 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
528 if (msgout_cloned->rcpt_list) {
529 if (route_is_allowed_mail_local(route, msgout->msg->return_path)
530 && route_is_allowed_return_path(route, msgout->msg-> return_path)) {
531 GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
532 msg_rcptlist_route(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
534 if (rcpt_list_allowed != NULL) {
535 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
537 g_list_free(msgout_cloned->rcpt_list);
538 msgout_cloned->rcpt_list = rcpt_list_allowed;
540 if (route->last_route) {
541 GList *rcpt_node;
542 foreach(msgout_cloned->rcpt_list, rcpt_node) {
543 address *rcpt = (address *) (rcpt_node->data);
544 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
545 }
546 }
548 route_prepare_msgout(route, msgout_cloned);
549 msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
550 } else
551 destroy_msg_out(msgout_cloned);
552 } else
553 destroy_msg_out(msgout_cloned);
554 } else
555 destroy_msg_out(msgout_cloned);
556 }
558 if (msgout_list_deliver != NULL) {
559 if (deliver_route_msgout_list(route, msgout_list_deliver))
560 ok = TRUE;
561 destroy_msg_out_list(msgout_list_deliver);
562 }
563 return ok;
564 }
566 /* copy pointers of delivered addresses to the msg's non_rcpt_list,
567 to make sure that they will not be delivered again.
568 */
569 void
570 update_non_rcpt_list(msg_out * msgout)
571 {
572 GList *rcpt_node;
573 message *msg = msgout->msg;
575 foreach(msgout->rcpt_list, rcpt_node) {
576 address *rcpt = (address *) (rcpt_node->data);
577 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt))
578 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
579 }
580 }
582 /* after delivery attempts, we check if there are any rcpt addresses left in the message.
583 If all addresses have been completed, the spool files will be deleted,
584 otherwise the header spool will be written back.
585 We never changed the data spool, so there is no need to write that back.
587 returns TRUE if all went well.
588 */
589 gboolean
590 deliver_finish(msg_out * msgout)
591 {
592 GList *rcpt_node;
593 gboolean ok = FALSE;
594 message *msg = msgout->msg;
595 gboolean finished = TRUE;
597 update_non_rcpt_list(msgout);
599 /* we NEVER made copies of the addresses, flags affecting addresses
600 were always set on the original address structs */
601 foreach(msg->rcpt_list, rcpt_node) {
602 address *rcpt = (address *) (rcpt_node->data);
603 if (!addr_is_finished_children(rcpt))
604 finished = FALSE;
605 else {
606 /* if ALL children have been delivered, mark parent as delivered.
607 if there is one or more not delivered, it must have failed, we mark the parent as failed as well.
608 */
609 if (addr_is_delivered_children(rcpt)) {
610 addr_mark_delivered(rcpt);
611 } else {
612 addr_mark_failed(rcpt);
613 }
614 }
615 }
617 if (!finished) {
618 /* one not delivered address was found */
619 if (spool_write(msg, FALSE)) {
620 ok = TRUE;
621 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
622 } else
623 logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
624 } else {
625 ok = spool_delete_all(msg);
626 if (ok)
627 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
628 }
629 return ok;
630 }
632 gboolean
633 deliver_finish_list(GList * msgout_list)
634 {
635 gboolean ok = TRUE;
636 GList *msgout_node;
637 foreach(msgout_list, msgout_node) {
638 msg_out *msgout = (msg_out *) (msgout_node->data);
639 if (!deliver_finish(msgout))
640 ok = FALSE;
641 }
642 return ok;
643 }
645 gboolean
646 deliver_msgout_list_online(GList * msgout_list)
647 {
648 GList *rf_list = NULL;
649 gchar *connect_name = detect_online();
650 gboolean ok = FALSE;
652 if (connect_name != NULL) {
653 logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
654 /* we are online! */
655 rf_list = (GList *) table_find(conf.connect_routes, connect_name);
656 if (rf_list != NULL) {
657 GList *route_list = read_route_list(rf_list, FALSE);
658 if (route_list) {
659 GList *route_node;
660 foreach(route_list, route_node) {
661 connect_route *route = (connect_route *) (route_node->data);
662 ok = deliver_route_msg_list(route, msgout_list);
663 }
664 destroy_route_list(route_list);
665 } else
666 logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
667 } else {
668 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
669 }
670 }
671 return ok;
672 }
674 gboolean
675 deliver_msg_list(GList * msg_list, guint flags)
676 {
677 GList *msgout_list = create_msg_out_list(msg_list);
678 GList *local_msgout_list = NULL, *localnet_msgout_list = NULL, *other_msgout_list = NULL;
679 GList *msgout_node;
680 GList *alias_table = NULL;
681 gboolean ok = TRUE;
683 if (conf.alias_file) {
684 if (!(alias_table = table_read(conf.alias_file, ':')))
685 return FALSE;
686 }
688 /* sort messages for different deliveries */
689 foreach(msgout_list, msgout_node) {
690 msg_out *msgout = (msg_out *) (msgout_node->data);
691 GList *rcpt_list;
692 GList *local_rcpt_list = NULL;
693 GList *localnet_rcpt_list = NULL;
694 GList *other_rcpt_list;
696 if (!spool_lock(msgout->msg->uid))
697 continue;
699 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
700 if (conf.log_user) {
701 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
702 if (addr)
703 rcpt_list = g_list_prepend(rcpt_list, addr);
704 }
705 if (alias_table) {
706 GList *aliased_rcpt_list;
707 aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list);
708 g_list_free(rcpt_list);
709 rcpt_list = aliased_rcpt_list;
710 }
712 /* local recipients */
713 other_rcpt_list = NULL;
714 rcptlist_with_addr_is_local(rcpt_list, &local_rcpt_list, &other_rcpt_list);
716 if (flags & DLVR_LOCAL) {
717 if (local_rcpt_list != NULL) {
718 msg_out *local_msgout = clone_msg_out(msgout);
719 local_msgout->rcpt_list = local_rcpt_list;
720 local_msgout_list = g_list_append(local_msgout_list, local_msgout);
721 }
722 }
724 g_list_free(rcpt_list);
726 /* local net recipients */
727 rcpt_list = other_rcpt_list;
728 other_rcpt_list = NULL;
729 rcptlist_with_one_of_hostlist(rcpt_list, conf.local_nets, &localnet_rcpt_list, &other_rcpt_list);
731 if (flags & DLVR_LAN) {
732 if (localnet_rcpt_list != NULL) {
733 msg_out *localnet_msgout = clone_msg_out(msgout);
734 localnet_msgout->rcpt_list = localnet_rcpt_list;
735 localnet_msgout_list = g_list_append(localnet_msgout_list, localnet_msgout);
736 }
737 }
739 if (flags & DLVR_ONLINE) {
740 /* the rest, this is online delivery */
741 if (other_rcpt_list != NULL) {
742 msg_out *other_msgout = clone_msg_out(msgout);
743 other_msgout->rcpt_list = other_rcpt_list;
744 other_msgout_list = g_list_append(other_msgout_list, other_msgout);
745 }
746 }
747 }
749 if (alias_table)
750 destroy_table(alias_table);
752 /* actual delivery */
753 if (local_msgout_list != NULL) {
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 if (conf.local_net_routes)
767 route_list = read_route_list(conf.local_net_routes, TRUE);
768 else
769 route_list = g_list_append(NULL, create_local_route());
771 foreach(route_list, route_node) {
772 connect_route *route = (connect_route *) (route_node->data);
773 if (!deliver_route_msg_list(route, localnet_msgout_list))
774 ok = FALSE;
775 }
776 destroy_msg_out_list(localnet_msgout_list);
777 destroy_route_list(route_list);
778 }
780 if (other_msgout_list != NULL) {
781 if (!deliver_msgout_list_online(other_msgout_list))
782 ok = FALSE;
783 destroy_msg_out_list(other_msgout_list);
784 }
786 foreach(msgout_list, msgout_node) {
787 msg_out *msgout = (msg_out *) (msgout_node->data);
788 spool_unlock(msgout->msg->uid);
789 }
791 destroy_msg_out_list(msgout_list);
793 return ok;
794 }
796 /* This function searches in the list of rcpt addresses
797 for local and 'local net' addresses. Remote addresses
798 which are reachable only when online are treated specially
799 in another function.
801 deliver() is called when a message has just been received and should
802 be delivered immediately.
803 */
804 gboolean
805 deliver(message * msg)
806 {
807 gboolean ok;
808 GList *msg_list = g_list_append(NULL, msg);
810 ok = deliver_msg_list(msg_list, DLVR_ALL);
811 g_list_free(msg_list);
813 return ok;
814 }