masqmail-0.2

view src/deliver.c @ 113:c93023f58cc7

Paolo's code and vanilla code differs what is the correct way? Someone should check. ;-)
author meillo@marmaro.de
date Wed, 30 Jun 2010 13:23:49 +0200
parents 7354c2e0eb31
children a80ebfa16cd5
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;
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 host = route->mail_host->address;
334 port = route->mail_host->port;
335 } else
336 port = conf.remote_port;
338 #ifdef ENABLE_POP3
339 if (route->pop3_login) {
340 if (!(pop_before_smtp(route->pop3_login)))
341 return FALSE;
342 }
343 #endif
345 if ((psb = (route->wrapper ? smtp_out_open_child(route->wrapper) : smtp_out_open(host, port, res_list)))) {
347 if (route->wrapper)
348 psb->remote_host = host;
350 set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
352 #ifdef ENABLE_AUTH
353 if ((route->auth_name) && (route->auth_login) && (route->auth_secret))
354 set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
355 #endif
356 if (smtp_out_init(psb)) {
358 if (!route->do_pipelining)
359 psb->use_pipelining = FALSE;
361 foreach(msgout_list, msgout_node) {
362 msg_out *msgout = (msg_out *) (msgout_node->data);
363 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
364 message *msg = msgout->msg;
366 /* we may have to read the data at this point and remember if we did */
367 flag = (msg->data_list == NULL);
368 if (flag) {
369 if (!spool_read_data(msg)) {
370 logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
371 break;
372 }
373 }
375 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
377 ok_fail = delivery_failures(msg, msgout->rcpt_list,
378 "while connected with %s, the server replied\n\t%s", host, psb->buffer);
380 if ((psb->error == smtp_eof)
381 || (psb->error == smtp_timeout)) {
382 /* connection lost */
383 break;
384 } else if (psb->error != smtp_ok) {
385 if (g_list_next(msgout_node) != NULL)
386 if (!smtp_out_rset(psb))
387 break;
388 }
389 ok_msg = (psb->error == smtp_ok);
391 if (flag)
392 msg_free_data(msg);
393 if (ok_msg)
394 ok = TRUE;
395 if (ok_msg || ok_fail) {
396 deliver_finish(msgout);
397 }
398 }
399 if (psb->error == smtp_ok || (psb->error == smtp_fail)
400 || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
401 smtp_out_quit(psb);
402 }
403 } else {
404 /* smtp_out_init() failed */
405 if ((psb->error == smtp_fail) || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
406 smtp_out_quit(psb);
408 foreach(msgout_list, msgout_node) {
409 msg_out *msgout = (msg_out *) (msgout_node->data);
410 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
412 if (delivery_failures(msgout->msg, msgout->rcpt_list,
413 "while connected with %s, the server replied\n\t%s", host, psb->buffer))
414 deliver_finish(msgout);
415 }
416 }
417 }
418 destroy_smtpbase(psb);
419 } else {
420 /* smtp_out_open() failed */
421 foreach(msgout_list, msgout_node) {
422 msg_out *msgout = (msg_out *) (msgout_node->data);
423 GList *rcpt_node;
425 for (rcpt_node = g_list_first(msgout->rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
426 address *rcpt = (address *) (rcpt_node->data);
428 addr_unmark_delivered(rcpt);
429 if (route->connect_error_fail) {
430 addr_mark_failed(rcpt);
431 } else {
432 addr_mark_defered(rcpt);
433 }
434 if (route->wrapper
435 ? delivery_failures(msgout->msg, msgout->rcpt_list, "could not open wrapper:\n\t%s",
436 strerror(errno))
437 : delivery_failures(msgout->msg, msgout->rcpt_list, "could not open connection to %s:%d :\n\t%s",
438 host, port, h_errno != 0 ? hstrerror(h_errno) : strerror(errno)))
439 deliver_finish(msgout);
440 }
441 }
442 }
443 return ok;
444 }
446 gboolean
447 deliver_msglist_host(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
448 {
449 DEBUG(5) debugf("protocol = %s\n", route->protocol);
451 if (strcmp(route->protocol, "pipe") == 0) {
452 return deliver_msglist_host_pipe(route, msgout_list, host, res_list);
453 } else {
454 return deliver_msglist_host_smtp(route, msgout_list, host, res_list);
455 }
456 }
458 /*
459 delivers messages in msgout_list using route
460 */
461 gboolean
462 deliver_route_msgout_list(connect_route * route, GList * msgout_list)
463 {
464 gboolean ok = FALSE;
466 DEBUG(5) debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name);
468 if (route->mail_host != NULL) {
469 /* this is easy... */
470 if (deliver_msglist_host(route, msgout_list, NULL, route->resolve_list))
471 ok = TRUE;
473 } else {
474 /* this is not easy... */
475 GList *mo_ph_list;
477 mo_ph_list = route_msgout_list(route, msgout_list);
478 /* okay, now we have ordered our messages by the hosts. */
479 if (mo_ph_list != NULL) {
480 GList *mo_ph_node;
481 /* TODO: It would be nice to be able to fork for each host.
482 We cannot do that yet because of complications with finishing the
483 messages. Threads could be a solution because they use the same
484 memory. But we are not thread safe yet...
485 */
486 foreach(mo_ph_list, mo_ph_node) {
487 msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
488 if (deliver_msglist_host (route, mo_ph->msgout_list, mo_ph->host, route->resolve_list))
489 ok = TRUE;
491 destroy_msgout_perhost(mo_ph);
492 }
493 g_list_free(mo_ph_list);
494 }
495 }
496 return ok;
497 }
499 /*
500 calls route_prepare_msg()
501 delivers messages in msg_list using route by calling deliver_route_msgout_list()
502 */
503 gboolean
504 deliver_route_msg_list(connect_route * route, GList * msgout_list)
505 {
506 GList *msgout_list_deliver = NULL;
507 GList *msgout_node;
508 gboolean ok = TRUE;
510 DEBUG(6) debugf("deliver_route_msg_list()\n");
512 foreach(msgout_list, msgout_node) {
513 msg_out *msgout = (msg_out *) (msgout_node->data);
514 msg_out *msgout_cloned = clone_msg_out(msgout);
515 GList *rcpt_list_non_delivered = NULL;
516 GList *rcpt_node;
518 /* we have to delete already delivered rcpt's because a previous route may have delivered to it */
519 foreach(msgout_cloned->rcpt_list, rcpt_node) {
520 address *rcpt = (address *) (rcpt_node->data);
521 /* failed addresses already have been bounced - there should be a better way to handle those. */
522 if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt)
523 && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE))
524 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
525 }
526 g_list_free(msgout_cloned->rcpt_list);
527 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
529 if (msgout_cloned->rcpt_list) {
530 if (route_is_allowed_mail_local(route, msgout->msg->return_path)
531 && route_is_allowed_return_path(route, msgout->msg-> return_path)) {
532 GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
533 msg_rcptlist_route(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
535 if (rcpt_list_allowed != NULL) {
536 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
538 g_list_free(msgout_cloned->rcpt_list);
539 msgout_cloned->rcpt_list = rcpt_list_allowed;
541 if (route->last_route) {
542 GList *rcpt_node;
543 foreach(msgout_cloned->rcpt_list, rcpt_node) {
544 address *rcpt = (address *) (rcpt_node->data);
545 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
546 }
547 }
549 route_prepare_msgout(route, msgout_cloned);
550 msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
551 } else
552 destroy_msg_out(msgout_cloned);
553 } else
554 destroy_msg_out(msgout_cloned);
555 } else
556 destroy_msg_out(msgout_cloned);
557 }
559 if (msgout_list_deliver != NULL) {
560 if (deliver_route_msgout_list(route, msgout_list_deliver))
561 ok = TRUE;
562 destroy_msg_out_list(msgout_list_deliver);
563 }
564 return ok;
565 }
567 /* copy pointers of delivered addresses to the msg's non_rcpt_list,
568 to make sure that they will not be delivered again.
569 */
570 void
571 update_non_rcpt_list(msg_out * msgout)
572 {
573 GList *rcpt_node;
574 message *msg = msgout->msg;
576 foreach(msgout->rcpt_list, rcpt_node) {
577 address *rcpt = (address *) (rcpt_node->data);
578 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt))
579 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
580 }
581 }
583 /* after delivery attempts, we check if there are any rcpt addresses left in the message.
584 If all addresses have been completed, the spool files will be deleted,
585 otherwise the header spool will be written back.
586 We never changed the data spool, so there is no need to write that back.
588 returns TRUE if all went well.
589 */
590 gboolean
591 deliver_finish(msg_out * msgout)
592 {
593 GList *rcpt_node;
594 gboolean ok = FALSE;
595 message *msg = msgout->msg;
596 gboolean finished = TRUE;
598 update_non_rcpt_list(msgout);
600 /* we NEVER made copies of the addresses, flags affecting addresses
601 were always set on the original address structs */
602 foreach(msg->rcpt_list, rcpt_node) {
603 address *rcpt = (address *) (rcpt_node->data);
604 if (!addr_is_finished_children(rcpt))
605 finished = FALSE;
606 else {
607 /* if ALL children have been delivered, mark parent as delivered.
608 if there is one or more not delivered, it must have failed, we mark the parent as failed as well.
609 */
610 if (addr_is_delivered_children(rcpt)) {
611 addr_mark_delivered(rcpt);
612 } else {
613 addr_mark_failed(rcpt);
614 }
615 }
616 }
618 if (!finished) {
619 /* one not delivered address was found */
620 if (spool_write(msg, FALSE)) {
621 ok = TRUE;
622 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
623 } else
624 logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
625 } else {
626 ok = spool_delete_all(msg);
627 if (ok)
628 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
629 }
630 return ok;
631 }
633 gboolean
634 deliver_finish_list(GList * msgout_list)
635 {
636 gboolean ok = TRUE;
637 GList *msgout_node;
638 foreach(msgout_list, msgout_node) {
639 msg_out *msgout = (msg_out *) (msgout_node->data);
640 if (!deliver_finish(msgout))
641 ok = FALSE;
642 }
643 return ok;
644 }
646 gboolean
647 deliver_msgout_list_online(GList * msgout_list)
648 {
649 GList *rf_list = NULL;
650 gchar *connect_name = detect_online();
651 gboolean ok = FALSE;
653 if (connect_name != NULL) {
654 logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
655 /* we are online! */
656 rf_list = (GList *) table_find(conf.connect_routes, connect_name);
657 if (rf_list != NULL) {
658 GList *route_list = read_route_list(rf_list, FALSE);
659 if (route_list) {
660 GList *route_node;
661 foreach(route_list, route_node) {
662 connect_route *route = (connect_route *) (route_node->data);
663 ok = deliver_route_msg_list(route, msgout_list);
664 }
665 destroy_route_list(route_list);
666 } else
667 logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
668 } else {
669 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
670 }
671 }
672 return ok;
673 }
675 gboolean
676 deliver_msg_list(GList * msg_list, guint flags)
677 {
678 GList *msgout_list = create_msg_out_list(msg_list);
679 GList *local_msgout_list = NULL, *localnet_msgout_list = NULL, *other_msgout_list = NULL;
680 GList *msgout_node;
681 GList *alias_table = NULL;
682 gboolean ok = TRUE;
684 if (conf.alias_file) {
685 alias_table = table_read(conf.alias_file, ':');
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 }