masqmail

view src/deliver.c @ 209:10da50168dab

replaced the MD5 implementation with the one of Solar Designer Until now, the sample code of RFC 1321 was used. It had an ugly license. Now we use the implementation of Solar Designer, which is in the Public Domain. http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
author meillo@marmaro.de
date Sun, 18 Jul 2010 21:58:15 +0200
parents dc89737b27aa
children 8cddc65765bd
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";
131 if (strcmp(mbox_type, "mbox") == 0) {
132 DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
133 if (append_file(msg, hdr_list, rcpt->local_part)) {
134 if (env_addr != rcpt) {
135 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with mbox\n",
136 msg->uid, rcpt->local_part, rcpt->domain,
137 env_addr->local_part, env_addr->domain);
138 } else {
139 logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n",
140 msg->uid, rcpt->local_part, rcpt->domain);
141 }
142 addr_mark_delivered(rcpt);
143 ok = TRUE;
144 } else {
145 if (errno != EAGAIN) { /* prevents 'Resource temporarily unavailable (11)' */
146 addr_mark_failed(rcpt);
147 } else {
148 addr_mark_defered(rcpt);
149 }
150 }
152 } else if (strcmp(mbox_type, "mda") == 0) {
153 if (conf.mda) {
154 gchar *cmd = g_malloc(256);
155 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
157 DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
159 if (expand(var_table, conf.mda, cmd, 256)) {
161 if (pipe_out(msg, hdr_list, rcpt, cmd, (conf.mda_fromline ? MSGSTR_FROMLINE : 0)
162 | (conf.mda_fromhack ? MSGSTR_FROMHACK : 0))) {
163 logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
164 msg->uid, rcpt->local_part, rcpt->domain, cmd);
165 addr_mark_delivered(rcpt);
166 ok = TRUE;
167 } else {
168 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
169 addr_mark_failed(rcpt);
170 } else {
171 addr_mark_defered(rcpt); /* has no effect yet, except that mail remains in spool */
172 }
173 }
174 } else
175 logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
177 destroy_table(var_table);
178 } else
179 logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n");
180 } else
181 logwrite(LOG_ALERT, "unknown mbox type '%s'\n", mbox_type);
182 }
184 destroy_header(retpath_hdr);
185 destroy_header(envto_hdr);
187 g_list_free(hdr_list);
188 }
189 ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)", ext_strerror(errno), errno);
191 if (flag)
192 msg_free_data(msg);
193 if (ok || ok_fail)
194 deliver_finish(msgout);
196 return ok;
197 }
199 /* make a list of rcpt's of a message that are local return a new copy of the list */
200 void
201 msg_rcptlist_local(GList * rcpt_list, GList ** p_local_list, GList ** p_nonlocal_list)
202 {
203 GList *rcpt_node;
205 foreach(rcpt_list, rcpt_node) {
206 address *rcpt = (address *) (rcpt_node->data);
207 GList *dom_node;
209 DEBUG(5) debugf("checking address %s\n", rcpt->address);
211 /* search for local host list: */
212 foreach(conf.local_hosts, dom_node) {
213 if (strcasecmp(dom_node->data, rcpt->domain) == 0) {
214 *p_local_list = g_list_append(*p_local_list, rcpt);
215 DEBUG(5) debugf("<%s@%s> is local\n", rcpt->local_part, rcpt->domain);
216 break;
217 } else {
218 *p_nonlocal_list = g_list_append(*p_nonlocal_list, rcpt);
219 }
220 }
221 }
222 }
224 gboolean
225 deliver_msglist_host_pipe(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
226 {
227 gboolean ok = TRUE;
228 GList *msgout_node;
230 DEBUG(5) debugf("deliver_msglist_host_pipe entered\n");
232 if (route->pipe == NULL) {
233 logwrite(LOG_ALERT, "no pipe command given for route (protocol is pipe!)\n");
234 return FALSE;
235 }
237 foreach(msgout_list, msgout_node) {
238 msg_out *msgout = (msg_out *) (msgout_node->data);
239 gboolean flag, ok_msg = TRUE, ok_fail = FALSE;
240 message *msg = msgout->msg;
241 GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
243 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
245 flag = (msg->data_list == NULL);
246 if (flag) {
247 if (!(ok_msg = spool_read_data(msg))) {
248 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
249 }
250 }
251 if (!ok_msg)
252 continue;
254 ok = FALSE;
255 foreach(rcpt_list, rcpt_node) {
256 address *rcpt = (address *) (rcpt_node->data);
257 gchar *cmd = g_malloc(256);
258 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
260 DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n", msg->uid, rcpt->local_part, rcpt->domain);
262 if (expand(var_table, route->pipe, cmd, 256)) {
264 if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0)
265 | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
266 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n",
267 msg->uid, rcpt->local_part, rcpt->domain, cmd);
268 addr_mark_delivered(rcpt);
269 ok = TRUE;
270 } else {
271 logwrite(LOG_ALERT, "pipe_out '%s' failed\n", route->pipe);
273 if (route->connect_error_fail) {
274 addr_mark_failed(rcpt);
275 } else {
276 addr_mark_defered(rcpt);
277 }
278 }
279 } else
280 logwrite(LOG_ALERT, "could not expand string %s\n", route->pipe);
282 destroy_table(var_table);
283 }
284 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
286 if (flag)
287 msg_free_data(msg);
289 if (ok || ok_fail)
290 deliver_finish(msgout);
291 }
293 return ok;
294 }
296 /* deliver list of messages to one host and finishes them if the message was delivered to at least one rcpt.
297 Returns TRUE if at least one msg was delivered to at least one rcpt.
298 */
299 gboolean
300 deliver_msglist_host_smtp(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
301 {
302 gboolean ok = FALSE;
303 GList *msgout_node;
304 smtp_base *psb;
305 gint port = 25;
307 /* paranoid check: */
308 if (msgout_list == NULL) {
309 logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n");
310 return FALSE;
311 }
313 if (host == NULL) {
314 /* XXX: what if mail_host isn't set? Is this possible? */
315 host = route->mail_host->address;
316 port = route->mail_host->port;
317 }
319 if ((psb = (route->wrapper ? smtp_out_open_child(route->wrapper) : smtp_out_open(host, port, res_list)))) {
321 if (route->wrapper) {
322 /* it seems as if the remote_host is only set for logging
323 /* XXX: this could probably be moved into smtp_out_open_child() */
324 psb->remote_host = host;
325 }
327 set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
329 #ifdef ENABLE_AUTH
330 if ((route->auth_name) && (route->auth_login) && (route->auth_secret))
331 set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
332 #endif
333 if (smtp_out_init(psb)) {
335 if (!route->do_pipelining)
336 psb->use_pipelining = FALSE;
338 foreach(msgout_list, msgout_node) {
339 msg_out *msgout = (msg_out *) (msgout_node->data);
340 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
341 message *msg = msgout->msg;
343 /* we may have to read the data at this point and remember if we did */
344 flag = (msg->data_list == NULL);
345 if (flag) {
346 if (!spool_read_data(msg)) {
347 logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
348 break;
349 }
350 }
352 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
354 ok_fail = delivery_failures(msg, msgout->rcpt_list,
355 "while connected with %s, the server replied\n\t%s", host, psb->buffer);
357 if ((psb->error == smtp_eof)
358 || (psb->error == smtp_timeout)) {
359 /* connection lost */
360 break;
361 } else if (psb->error != smtp_ok) {
362 if (g_list_next(msgout_node) != NULL)
363 if (!smtp_out_rset(psb))
364 break;
365 }
366 ok_msg = (psb->error == smtp_ok);
368 if (flag)
369 msg_free_data(msg);
370 if (ok_msg)
371 ok = TRUE;
372 if (ok_msg || ok_fail) {
373 deliver_finish(msgout);
374 }
375 }
376 if (psb->error == smtp_ok || (psb->error == smtp_fail)
377 || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
378 smtp_out_quit(psb);
379 }
380 } else {
381 /* smtp_out_init() failed */
382 if ((psb->error == smtp_fail) || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
383 smtp_out_quit(psb);
385 foreach(msgout_list, msgout_node) {
386 msg_out *msgout = (msg_out *) (msgout_node->data);
387 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
389 if (delivery_failures(msgout->msg, msgout->rcpt_list,
390 "while connected with %s, the server replied\n\t%s", host, psb->buffer))
391 deliver_finish(msgout);
392 }
393 }
394 }
395 destroy_smtpbase(psb);
396 } else {
397 /* smtp_out_open() failed */
398 foreach(msgout_list, msgout_node) {
399 msg_out *msgout = (msg_out *) (msgout_node->data);
400 GList *rcpt_node;
402 for (rcpt_node = g_list_first(msgout->rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
403 address *rcpt = (address *) (rcpt_node->data);
405 addr_unmark_delivered(rcpt);
406 if (route->connect_error_fail) {
407 addr_mark_failed(rcpt);
408 } else {
409 addr_mark_defered(rcpt);
410 }
411 if (route->wrapper
412 ? delivery_failures(msgout->msg, msgout->rcpt_list, "could not open wrapper:\n\t%s",
413 strerror(errno))
414 : delivery_failures(msgout->msg, msgout->rcpt_list, "could not open connection to %s:%d :\n\t%s",
415 host, port, h_errno != 0 ? hstrerror(h_errno) : strerror(errno)))
416 deliver_finish(msgout);
417 }
418 }
419 }
420 return ok;
421 }
423 gboolean
424 deliver_msglist_host(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
425 {
426 DEBUG(5) debugf("protocol = %s\n", route->protocol);
428 if (strcmp(route->protocol, "pipe") == 0) {
429 return deliver_msglist_host_pipe(route, msgout_list, host, res_list);
430 } else {
431 return deliver_msglist_host_smtp(route, msgout_list, host, res_list);
432 }
433 }
435 /*
436 delivers messages in msgout_list using route
437 */
438 gboolean
439 deliver_route_msgout_list(connect_route * route, GList * msgout_list)
440 {
441 gboolean ok = FALSE;
443 DEBUG(5) debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name);
445 if (route->mail_host) {
446 /* this is easy... deliver everything to a smart host for relay */
447 if (deliver_msglist_host(route, msgout_list, NULL, route->resolve_list))
448 ok = TRUE;
450 } else {
451 /* this is not easy... */
452 GList *mo_ph_list;
454 mo_ph_list = route_msgout_list(route, msgout_list);
455 /* okay, now we have ordered our messages by the hosts. */
456 if (mo_ph_list != NULL) {
457 GList *mo_ph_node;
458 /* TODO: It would be nice to be able to fork for each host.
459 We cannot do that yet because of complications with finishing the
460 messages. Threads could be a solution because they use the same
461 memory. But we are not thread safe yet...
462 */
463 foreach(mo_ph_list, mo_ph_node) {
464 msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
465 if (deliver_msglist_host (route, mo_ph->msgout_list, mo_ph->host, route->resolve_list))
466 ok = TRUE;
468 destroy_msgout_perhost(mo_ph);
469 }
470 g_list_free(mo_ph_list);
471 }
472 }
473 return ok;
474 }
476 /*
477 calls route_prepare_msg()
478 delivers messages in msg_list using route by calling deliver_route_msgout_list()
479 */
480 gboolean
481 deliver_route_msg_list(connect_route * route, GList * msgout_list)
482 {
483 GList *msgout_list_deliver = NULL;
484 GList *msgout_node;
485 gboolean ok = TRUE;
487 DEBUG(6) debugf("deliver_route_msg_list()\n");
489 foreach(msgout_list, msgout_node) {
490 msg_out *msgout = (msg_out *) (msgout_node->data);
491 msg_out *msgout_cloned = clone_msg_out(msgout);
492 GList *rcpt_list_non_delivered = NULL;
493 GList *rcpt_node;
495 /* we have to delete already delivered rcpt's because a previous route may have delivered to it */
496 foreach(msgout_cloned->rcpt_list, rcpt_node) {
497 address *rcpt = (address *) (rcpt_node->data);
498 /* failed addresses already have been bounced - there should be a better way to handle those. */
499 if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt)
500 && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE))
501 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
502 }
503 g_list_free(msgout_cloned->rcpt_list);
504 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
506 if (msgout_cloned->rcpt_list) {
507 if (route_is_allowed_mail_local(route, msgout->msg->return_path)
508 && route_is_allowed_return_path(route, msgout->msg-> return_path)) {
509 GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
510 msg_rcptlist_route(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
512 if (rcpt_list_allowed != NULL) {
513 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
515 g_list_free(msgout_cloned->rcpt_list);
516 msgout_cloned->rcpt_list = rcpt_list_allowed;
518 if (route->last_route) {
519 GList *rcpt_node;
520 foreach(msgout_cloned->rcpt_list, rcpt_node) {
521 address *rcpt = (address *) (rcpt_node->data);
522 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
523 }
524 }
526 route_prepare_msgout(route, msgout_cloned);
527 msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
528 } else
529 destroy_msg_out(msgout_cloned);
530 } else
531 destroy_msg_out(msgout_cloned);
532 } else
533 destroy_msg_out(msgout_cloned);
534 }
536 if (msgout_list_deliver != NULL) {
537 if (deliver_route_msgout_list(route, msgout_list_deliver))
538 ok = TRUE;
539 destroy_msg_out_list(msgout_list_deliver);
540 }
541 return ok;
542 }
544 /* copy pointers of delivered addresses to the msg's non_rcpt_list,
545 to make sure that they will not be delivered again.
546 */
547 void
548 update_non_rcpt_list(msg_out * msgout)
549 {
550 GList *rcpt_node;
551 message *msg = msgout->msg;
553 foreach(msgout->rcpt_list, rcpt_node) {
554 address *rcpt = (address *) (rcpt_node->data);
555 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt))
556 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
557 }
558 }
560 /* after delivery attempts, we check if there are any rcpt addresses left in the message.
561 If all addresses have been completed, the spool files will be deleted,
562 otherwise the header spool will be written back.
563 We never changed the data spool, so there is no need to write that back.
565 returns TRUE if all went well.
566 */
567 gboolean
568 deliver_finish(msg_out * msgout)
569 {
570 GList *rcpt_node;
571 gboolean ok = FALSE;
572 message *msg = msgout->msg;
573 gboolean finished = TRUE;
575 update_non_rcpt_list(msgout);
577 /* we NEVER made copies of the addresses, flags affecting addresses
578 were always set on the original address structs */
579 foreach(msg->rcpt_list, rcpt_node) {
580 address *rcpt = (address *) (rcpt_node->data);
581 if (!addr_is_finished_children(rcpt))
582 finished = FALSE;
583 else {
584 /* if ALL children have been delivered, mark parent as delivered.
585 if there is one or more not delivered, it must have failed, we mark the parent as failed as well.
586 */
587 if (addr_is_delivered_children(rcpt)) {
588 addr_mark_delivered(rcpt);
589 } else {
590 addr_mark_failed(rcpt);
591 }
592 }
593 }
595 if (!finished) {
596 /* one not delivered address was found */
597 if (spool_write(msg, FALSE)) {
598 ok = TRUE;
599 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
600 } else
601 logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
602 } else {
603 ok = spool_delete_all(msg);
604 if (ok)
605 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
606 }
607 return ok;
608 }
610 gboolean
611 deliver_finish_list(GList * msgout_list)
612 {
613 gboolean ok = TRUE;
614 GList *msgout_node;
615 foreach(msgout_list, msgout_node) {
616 msg_out *msgout = (msg_out *) (msgout_node->data);
617 if (!deliver_finish(msgout))
618 ok = FALSE;
619 }
620 return ok;
621 }
623 gboolean
624 deliver_msgout_list_online(GList * msgout_list)
625 {
626 GList *rf_list = NULL;
627 gchar *connect_name = detect_online();
628 gboolean ok = FALSE;
630 if (connect_name != NULL) {
631 logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
632 /* we are online! */
633 rf_list = (GList *) table_find(conf.connect_routes, connect_name);
634 if (rf_list != NULL) {
635 GList *route_list = read_route_list(rf_list, FALSE);
636 if (route_list) {
637 GList *route_node;
638 foreach(route_list, route_node) {
639 connect_route *route = (connect_route *) (route_node->data);
640 ok = deliver_route_msg_list(route, msgout_list);
641 }
642 destroy_route_list(route_list);
643 } else
644 logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
645 } else {
646 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
647 }
648 }
649 return ok;
650 }
652 gboolean
653 deliver_msg_list(GList * msg_list, guint flags)
654 {
655 GList *msgout_list = create_msg_out_list(msg_list);
656 GList *local_msgout_list = NULL, *localnet_msgout_list = NULL, *other_msgout_list = NULL;
657 GList *msgout_node;
658 GList *alias_table = NULL;
659 gboolean ok = TRUE;
661 if (conf.alias_file) {
662 alias_table = table_read(conf.alias_file, ':');
663 }
665 /* sort messages for different deliveries */
666 foreach(msgout_list, msgout_node) {
667 msg_out *msgout = (msg_out *) (msgout_node->data);
668 GList *rcpt_list;
669 GList *local_rcpt_list = NULL;
670 GList *localnet_rcpt_list = NULL;
671 GList *other_rcpt_list;
673 if (!spool_lock(msgout->msg->uid)) {
674 DEBUG(5) debugf("spool_lock(%s) failed.\n", msgout->msg->uid);
675 continue;
676 }
677 DEBUG(5) debugf("spool_lock(%s)\n", msgout->msg->uid);
679 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
680 if (conf.log_user) {
681 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
682 if (addr)
683 rcpt_list = g_list_prepend(rcpt_list, addr);
684 }
685 if (alias_table) {
686 GList *aliased_rcpt_list;
687 aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list);
688 g_list_free(rcpt_list);
689 rcpt_list = aliased_rcpt_list;
690 }
692 /* local recipients */
693 other_rcpt_list = NULL;
694 rcptlist_with_addr_is_local(rcpt_list, &local_rcpt_list, &other_rcpt_list);
696 if (flags & DLVR_LOCAL) {
697 if (local_rcpt_list != NULL) {
698 msg_out *local_msgout = clone_msg_out(msgout);
699 local_msgout->rcpt_list = local_rcpt_list;
700 local_msgout_list = g_list_append(local_msgout_list, local_msgout);
701 }
702 }
704 g_list_free(rcpt_list);
706 /* local net recipients */
707 rcpt_list = other_rcpt_list;
708 other_rcpt_list = NULL;
709 rcptlist_with_one_of_hostlist(rcpt_list, conf.local_nets, &localnet_rcpt_list, &other_rcpt_list);
711 if (flags & DLVR_LAN) {
712 if (localnet_rcpt_list != NULL) {
713 msg_out *localnet_msgout = clone_msg_out(msgout);
714 localnet_msgout->rcpt_list = localnet_rcpt_list;
715 localnet_msgout_list = g_list_append(localnet_msgout_list, localnet_msgout);
716 }
717 }
719 if (flags & DLVR_ONLINE) {
720 /* the rest, this is online delivery */
721 if (other_rcpt_list != NULL) {
722 msg_out *other_msgout = clone_msg_out(msgout);
723 other_msgout->rcpt_list = other_rcpt_list;
724 other_msgout_list = g_list_append(other_msgout_list, other_msgout);
725 }
726 }
727 }
729 if (alias_table)
730 destroy_table(alias_table);
732 /* actual delivery */
733 if (local_msgout_list != NULL) {
734 DEBUG(5) debugf("local_msgout_list\n");
735 foreach(local_msgout_list, msgout_node) {
736 msg_out *msgout = (msg_out *) (msgout_node->data);
737 if (!deliver_local(msgout))
738 ok = FALSE;
739 }
740 destroy_msg_out_list(local_msgout_list);
741 }
743 if (localnet_msgout_list != NULL) {
744 GList *route_list = NULL;
745 GList *route_node;
747 DEBUG(5) debugf("localnet_msgout_list\n");
748 if (conf.local_net_routes)
749 route_list = read_route_list(conf.local_net_routes, TRUE);
750 else
751 route_list = g_list_append(NULL, create_local_route());
753 foreach(route_list, route_node) {
754 connect_route *route = (connect_route *) (route_node->data);
755 if (!deliver_route_msg_list(route, localnet_msgout_list))
756 ok = FALSE;
757 }
758 destroy_msg_out_list(localnet_msgout_list);
759 destroy_route_list(route_list);
760 }
762 if (other_msgout_list != NULL) {
763 DEBUG(5) debugf("other_msgout_list\n");
764 if (!deliver_msgout_list_online(other_msgout_list))
765 ok = FALSE;
766 destroy_msg_out_list(other_msgout_list);
767 }
769 foreach(msgout_list, msgout_node) {
770 msg_out *msgout = (msg_out *) (msgout_node->data);
771 if (spool_unlock(msgout->msg->uid)) {
772 DEBUG(5) debugf("spool_unlock(%s)\n", msgout->msg->uid);
773 } else {
774 DEBUG(5) debugf("spool_unlock(%s) failed.\n", msgout->msg->uid);
775 }
777 }
779 destroy_msg_out_list(msgout_list);
781 return ok;
782 }
784 /* This function searches in the list of rcpt addresses
785 for local and 'local net' addresses. Remote addresses
786 which are reachable only when online are treated specially
787 in another function.
789 deliver() is called when a message has just been received and should
790 be delivered immediately.
791 */
792 gboolean
793 deliver(message * msg)
794 {
795 gboolean ok;
796 GList *msg_list = g_list_append(NULL, msg);
798 ok = deliver_msg_list(msg_list, DLVR_ALL);
799 g_list_free(msg_list);
801 return ok;
802 }