masqmail
view src/deliver.c @ 178:91f8ee6514f5
removed `remote_port' config option
it was already deprecated for some time
see NEWS at release 0.2.12 for details
author | meillo@marmaro.de |
---|---|
date | Wed, 14 Jul 2010 16:48:45 +0200 |
parents | a80ebfa16cd5 |
children | 3190e6864452 |
line source
1 /* MasqMail
2 Copyright (C) 1999-2002 Oliver Kurth
3 Copyright (C) 2008 markus schnalke <meillo@marmaro.de>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
20 #include <fnmatch.h>
21 #include <sysexits.h>
22 #include <netdb.h>
24 #include "masqmail.h"
25 #include "smtp_out.h"
27 /* collect failed/defered rcpts for failure/warning messages */
28 /* returns TRUE if either there are no failures or a failure message has been successfully sent */
29 gboolean
30 delivery_failures(message * msg, GList * rcpt_list, gchar * err_fmt, ...)
31 {
32 gboolean ok_fail = TRUE, ok_warn = TRUE;
33 time_t now = time(NULL);
35 GList *failed_list = NULL, *defered_list = NULL, *rcpt_node;
36 va_list args;
37 va_start(args, err_fmt);
39 foreach(rcpt_list, rcpt_node) {
40 address *rcpt = (address *) (rcpt_node->data);
42 if (addr_is_defered(rcpt)) {
43 if ((now - msg->received_time) >= conf.max_defer_time) {
44 addr_mark_failed(rcpt);
45 } else
46 defered_list = g_list_prepend(defered_list, rcpt);
47 }
48 if (addr_is_failed(rcpt))
49 failed_list = g_list_prepend(failed_list, rcpt);
50 }
51 if (failed_list != NULL) {
52 ok_fail = fail_msg(msg, conf.errmsg_file, failed_list, err_fmt, args);
53 g_list_free(failed_list);
54 }
55 if (defered_list != NULL) {
56 ok_warn = warn_msg(msg, conf.warnmsg_file, defered_list, err_fmt, args);
57 g_list_free(defered_list);
58 }
59 va_end(args);
60 return ok_fail && ok_warn;
61 }
63 static gint
64 _g_list_strcasecmp(gconstpointer a, gconstpointer b)
65 {
66 return (gint) strcasecmp(a, b);
67 }
69 gboolean
70 deliver_local(msg_out * msgout)
71 {
72 message *msg = msgout->msg;
73 GList *rcpt_list = msgout->rcpt_list;
74 GList *rcpt_node;
75 gboolean ok = TRUE, flag = FALSE, ok_fail = FALSE;
77 DEBUG(5) debugf("deliver_local entered\n");
79 flag = (msg->data_list == NULL);
80 if (flag) {
81 if (!(ok = spool_read_data(msg))) {
82 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
83 }
84 }
85 if (!ok)
86 return FALSE;
88 ok = FALSE;
89 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
90 GList *hdr_list;
91 address *rcpt = (address *) (rcpt_node->data);
92 address *env_addr = addr_find_ancestor(rcpt);
93 address *ret_path = msg->return_path;
94 header *retpath_hdr, *envto_hdr;
96 /* we need a private copy of the hdr list because we add headers here that belong to the rcpt only.
97 g_list_copy copies only the nodes, so it is safe to g_list_free it */
98 hdr_list = g_list_copy(msg->hdr_list);
99 retpath_hdr = create_header(HEAD_ENVELOPE_TO, "Envelope-to: %s\n", addr_string(env_addr));
100 envto_hdr = create_header(HEAD_RETURN_PATH, "Return-path: %s\n", addr_string(ret_path));
102 hdr_list = g_list_prepend(hdr_list, envto_hdr);
103 hdr_list = g_list_prepend(hdr_list, retpath_hdr);
105 if (rcpt->local_part[0] == '|') {
106 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
107 if (pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]),
108 (conf.pipe_fromline ? MSGSTR_FROMLINE : 0)
109 | (conf.pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
110 logwrite(LOG_NOTICE, "%s => %s <%s@%s> with pipe\n",
111 msg->uid, rcpt->local_part, env_addr->local_part, env_addr->domain);
112 addr_mark_delivered(rcpt);
113 ok = TRUE;
114 } else {
115 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
116 addr_mark_failed(rcpt);
117 } else {
118 addr_mark_defered(rcpt); /* has no effect yet, except that mail remains in spool */
119 }
120 }
121 } else {
122 /* figure out which mailbox type should be used for this user */
123 gchar *user = rcpt->local_part;
124 gchar *mbox_type = conf.mbox_default;
126 if (g_list_find_custom (conf.mbox_users, user, _g_list_strcasecmp) != NULL)
127 mbox_type = "mbox";
128 else if (g_list_find_custom (conf.mda_users, user, _g_list_strcasecmp) != NULL)
129 mbox_type = "mda";
130 else if (g_list_find_custom (conf.maildir_users, user, _g_list_strcasecmp) != NULL)
131 mbox_type = "maildir";
133 if (strcmp(mbox_type, "mbox") == 0) {
134 DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
135 if (append_file(msg, hdr_list, rcpt->local_part)) {
136 if (env_addr != rcpt) {
137 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with mbox\n",
138 msg->uid, rcpt->local_part, rcpt->domain,
139 env_addr->local_part, env_addr->domain);
140 } else {
141 logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n",
142 msg->uid, rcpt->local_part, rcpt->domain);
143 }
144 addr_mark_delivered(rcpt);
145 ok = TRUE;
146 } else {
147 if (errno != EAGAIN) { /* prevents 'Resource temporarily unavailable (11)' */
148 addr_mark_failed(rcpt);
149 } else {
150 addr_mark_defered(rcpt);
151 }
152 }
154 } else if (strcmp(mbox_type, "mda") == 0) {
155 if (conf.mda) {
156 gchar *cmd = g_malloc(256);
157 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
159 DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
161 if (expand(var_table, conf.mda, cmd, 256)) {
163 if (pipe_out(msg, hdr_list, rcpt, cmd, (conf.mda_fromline ? MSGSTR_FROMLINE : 0)
164 | (conf.mda_fromhack ? MSGSTR_FROMHACK : 0))) {
165 logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
166 msg->uid, rcpt->local_part, rcpt->domain, cmd);
167 addr_mark_delivered(rcpt);
168 ok = TRUE;
169 } else {
170 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
171 addr_mark_failed(rcpt);
172 } else {
173 addr_mark_defered(rcpt); /* has no effect yet, except that mail remains in spool */
174 }
175 }
176 } else
177 logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
179 destroy_table(var_table);
180 } else
181 logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n");
183 #ifdef ENABLE_MAILDIR
184 } else if (strcmp(mbox_type, "maildir") == 0) {
185 DEBUG(1) debugf("attempting to deliver %s with maildir\n", msg->uid);
186 if (maildir_out(msg, hdr_list, rcpt->local_part, 0)) {
187 if (env_addr != rcpt) {
188 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with local\n", msg->uid,
189 rcpt->local_part, rcpt->domain, env_addr->local_part, env_addr->domain);
190 } else {
191 logwrite(LOG_NOTICE, "%s => <%s@%s> with maildir\n", msg->uid,
192 rcpt->local_part, rcpt->domain);
193 }
194 addr_mark_delivered(rcpt);
195 ok = TRUE;
196 } else
197 addr_mark_failed(rcpt);
198 #endif
199 } else
200 logwrite(LOG_ALERT, "unknown mbox type '%s'\n", mbox_type);
201 }
203 destroy_header(retpath_hdr);
204 destroy_header(envto_hdr);
206 g_list_free(hdr_list);
207 }
208 ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)", ext_strerror(errno), errno);
210 if (flag)
211 msg_free_data(msg);
212 if (ok || ok_fail)
213 deliver_finish(msgout);
215 return ok;
216 }
218 /* make a list of rcpt's of a message that are local return a new copy of the list */
219 void
220 msg_rcptlist_local(GList * rcpt_list, GList ** p_local_list, GList ** p_nonlocal_list)
221 {
222 GList *rcpt_node;
224 foreach(rcpt_list, rcpt_node) {
225 address *rcpt = (address *) (rcpt_node->data);
226 GList *dom_node;
228 DEBUG(5) debugf("checking address %s\n", rcpt->address);
230 /* search for local host list: */
231 foreach(conf.local_hosts, dom_node) {
232 if (strcasecmp(dom_node->data, rcpt->domain) == 0) {
233 *p_local_list = g_list_append(*p_local_list, rcpt);
234 DEBUG(5) debugf("<%s@%s> is local\n", rcpt->local_part, rcpt->domain);
235 break;
236 } else {
237 *p_nonlocal_list = g_list_append(*p_nonlocal_list, rcpt);
238 }
239 }
240 }
241 }
243 gboolean
244 deliver_msglist_host_pipe(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
245 {
246 gboolean ok = TRUE;
247 GList *msgout_node;
249 DEBUG(5) debugf("deliver_msglist_host_pipe entered\n");
251 if (route->pipe == NULL) {
252 logwrite(LOG_ALERT, "no pipe command given for route (protocol is pipe!)\n");
253 return FALSE;
254 }
256 foreach(msgout_list, msgout_node) {
257 msg_out *msgout = (msg_out *) (msgout_node->data);
258 gboolean flag, ok_msg = TRUE, ok_fail = FALSE;
259 message *msg = msgout->msg;
260 GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
262 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
264 flag = (msg->data_list == NULL);
265 if (flag) {
266 if (!(ok_msg = spool_read_data(msg))) {
267 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
268 }
269 }
270 if (!ok_msg)
271 continue;
273 ok = FALSE;
274 foreach(rcpt_list, rcpt_node) {
275 address *rcpt = (address *) (rcpt_node->data);
276 gchar *cmd = g_malloc(256);
277 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
279 DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n", msg->uid, rcpt->local_part, rcpt->domain);
281 if (expand(var_table, route->pipe, cmd, 256)) {
283 if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0)
284 | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
285 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n",
286 msg->uid, rcpt->local_part, rcpt->domain, cmd);
287 addr_mark_delivered(rcpt);
288 ok = TRUE;
289 } else {
290 logwrite(LOG_ALERT, "pipe_out '%s' failed\n", route->pipe);
292 if (route->connect_error_fail) {
293 addr_mark_failed(rcpt);
294 } else {
295 addr_mark_defered(rcpt);
296 }
297 }
298 } else
299 logwrite(LOG_ALERT, "could not expand string %s\n", route->pipe);
301 destroy_table(var_table);
302 }
303 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
305 if (flag)
306 msg_free_data(msg);
308 if (ok || ok_fail)
309 deliver_finish(msgout);
310 }
312 return ok;
313 }
315 /* deliver list of messages to one host and finishes them if the message was delivered to at least one rcpt.
316 Returns TRUE if at least one msg was delivered to at least one rcpt.
317 */
318 gboolean
319 deliver_msglist_host_smtp(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
320 {
321 gboolean ok = FALSE;
322 GList *msgout_node;
323 smtp_base *psb;
324 gint port = 25;
326 /* paranoid check: */
327 if (msgout_list == NULL) {
328 logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n");
329 return FALSE;
330 }
332 if (host == NULL) {
333 host = route->mail_host->address;
334 port = route->mail_host->port;
335 }
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 alias_table = table_read(conf.alias_file, ':');
685 }
687 /* sort messages for different deliveries */
688 foreach(msgout_list, msgout_node) {
689 msg_out *msgout = (msg_out *) (msgout_node->data);
690 GList *rcpt_list;
691 GList *local_rcpt_list = NULL;
692 GList *localnet_rcpt_list = NULL;
693 GList *other_rcpt_list;
695 if (!spool_lock(msgout->msg->uid)) {
696 DEBUG(5) debugf("spool_lock(%s) failed.\n", msgout->msg->uid);
697 continue;
698 }
699 DEBUG(5) debugf("spool_lock(%s)\n", msgout->msg->uid);
701 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
702 if (conf.log_user) {
703 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
704 if (addr)
705 rcpt_list = g_list_prepend(rcpt_list, addr);
706 }
707 if (alias_table) {
708 GList *aliased_rcpt_list;
709 aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list);
710 g_list_free(rcpt_list);
711 rcpt_list = aliased_rcpt_list;
712 }
714 /* local recipients */
715 other_rcpt_list = NULL;
716 rcptlist_with_addr_is_local(rcpt_list, &local_rcpt_list, &other_rcpt_list);
718 if (flags & DLVR_LOCAL) {
719 if (local_rcpt_list != NULL) {
720 msg_out *local_msgout = clone_msg_out(msgout);
721 local_msgout->rcpt_list = local_rcpt_list;
722 local_msgout_list = g_list_append(local_msgout_list, local_msgout);
723 }
724 }
726 g_list_free(rcpt_list);
728 /* local net recipients */
729 rcpt_list = other_rcpt_list;
730 other_rcpt_list = NULL;
731 rcptlist_with_one_of_hostlist(rcpt_list, conf.local_nets, &localnet_rcpt_list, &other_rcpt_list);
733 if (flags & DLVR_LAN) {
734 if (localnet_rcpt_list != NULL) {
735 msg_out *localnet_msgout = clone_msg_out(msgout);
736 localnet_msgout->rcpt_list = localnet_rcpt_list;
737 localnet_msgout_list = g_list_append(localnet_msgout_list, localnet_msgout);
738 }
739 }
741 if (flags & DLVR_ONLINE) {
742 /* the rest, this is online delivery */
743 if (other_rcpt_list != NULL) {
744 msg_out *other_msgout = clone_msg_out(msgout);
745 other_msgout->rcpt_list = other_rcpt_list;
746 other_msgout_list = g_list_append(other_msgout_list, other_msgout);
747 }
748 }
749 }
751 if (alias_table)
752 destroy_table(alias_table);
754 /* actual delivery */
755 if (local_msgout_list != NULL) {
756 DEBUG(5) debugf("local_msgout_list\n");
757 foreach(local_msgout_list, msgout_node) {
758 msg_out *msgout = (msg_out *) (msgout_node->data);
759 if (!deliver_local(msgout))
760 ok = FALSE;
761 }
762 destroy_msg_out_list(local_msgout_list);
763 }
765 if (localnet_msgout_list != NULL) {
766 GList *route_list = NULL;
767 GList *route_node;
769 DEBUG(5) debugf("localnet_msgout_list\n");
770 if (conf.local_net_routes)
771 route_list = read_route_list(conf.local_net_routes, TRUE);
772 else
773 route_list = g_list_append(NULL, create_local_route());
775 foreach(route_list, route_node) {
776 connect_route *route = (connect_route *) (route_node->data);
777 if (!deliver_route_msg_list(route, localnet_msgout_list))
778 ok = FALSE;
779 }
780 destroy_msg_out_list(localnet_msgout_list);
781 destroy_route_list(route_list);
782 }
784 if (other_msgout_list != NULL) {
785 DEBUG(5) debugf("other_msgout_list\n");
786 if (!deliver_msgout_list_online(other_msgout_list))
787 ok = FALSE;
788 destroy_msg_out_list(other_msgout_list);
789 }
791 foreach(msgout_list, msgout_node) {
792 msg_out *msgout = (msg_out *) (msgout_node->data);
793 if (spool_unlock(msgout->msg->uid)) {
794 DEBUG(5) debugf("spool_unlock(%s)\n", msgout->msg->uid);
795 } else {
796 DEBUG(5) debugf("spool_unlock(%s) failed.\n", msgout->msg->uid);
797 }
799 }
801 destroy_msg_out_list(msgout_list);
803 return ok;
804 }
806 /* This function searches in the list of rcpt addresses
807 for local and 'local net' addresses. Remote addresses
808 which are reachable only when online are treated specially
809 in another function.
811 deliver() is called when a message has just been received and should
812 be delivered immediately.
813 */
814 gboolean
815 deliver(message * msg)
816 {
817 gboolean ok;
818 GList *msg_list = g_list_append(NULL, msg);
820 ok = deliver_msg_list(msg_list, DLVR_ALL);
821 g_list_free(msg_list);
823 return ok;
824 }