masqmail

view src/deliver.c @ 421:f37384470855

Changed lockdir to /var/lock/masqmail; Create lockdir and piddir on startup. Moved the lockdir out of the spool dir. (When /var/lock is a ramdisk we do well to have the lock files there.) Added the new configure option --with-lockdir to change that location. Nontheless, if we run_as_user, then lock files are always stored in the spool dir directly. Instead of installing the lockdir and piddir at installation time, we create them on startup time now if they are missing. This is necessary if lockdir or piddir are a tmpfs.
author markus schnalke <meillo@marmaro.de>
date Wed, 30 May 2012 09:38:38 +0200
parents 899c97e877a5
children 5593964ec779
line source
1 /*
2 ** MasqMail
3 ** Copyright (C) 1999-2002 Oliver Kurth
4 ** Copyright (C) 2008, 2010 markus schnalke <meillo@marmaro.de>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
21 #include <fnmatch.h>
22 #include <sysexits.h>
23 #include <netdb.h>
25 #include "masqmail.h"
26 #include "smtp_out.h"
28 /*
29 ** collect failed/defered rcpts for failure/warning messages
30 ** returns TRUE if either there are no failures or a failure message has
31 ** been successfully sent
32 */
33 gboolean
34 delivery_failures(message *msg, GList *rcpt_list, gchar *err_fmt, ...)
35 {
36 gboolean ok_fail = TRUE, ok_warn = TRUE;
37 time_t now = time(NULL);
39 GList *failed_list = NULL, *defered_list = NULL, *rcpt_node;
40 va_list args;
41 va_start(args, err_fmt);
43 foreach(rcpt_list, rcpt_node) {
44 address *rcpt = (address *) (rcpt_node->data);
46 if (addr_is_defered(rcpt)) {
47 if ((now - msg->received_time) >= conf.max_defer_time){
48 addr_mark_failed(rcpt);
49 } else {
50 defered_list = g_list_prepend(defered_list,
51 rcpt);
52 }
53 }
54 if (addr_is_failed(rcpt)) {
55 failed_list = g_list_prepend(failed_list, rcpt);
56 }
57 }
58 if (failed_list) {
59 ok_fail = fail_msg(msg, conf.errmsg_file, failed_list,
60 err_fmt, args);
61 g_list_free(failed_list);
62 }
63 if (defered_list) {
64 ok_warn = warn_msg(msg, conf.warnmsg_file, defered_list,
65 err_fmt, args);
66 g_list_free(defered_list);
67 }
68 va_end(args);
69 return ok_fail && ok_warn;
70 }
72 static gint
73 _g_list_strcasecmp(gconstpointer a, gconstpointer b)
74 {
75 return (gint) strcasecmp(a, b);
76 }
78 gboolean
79 deliver_local_mbox(message *msg, GList *hdr_list, address *rcpt,
80 address *env_addr)
81 {
82 DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
83 if (append_file(msg, hdr_list, rcpt->local_part)) {
84 if (env_addr != rcpt) {
85 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with mbox\n",
86 msg->uid, rcpt->local_part,
87 rcpt->domain, env_addr->local_part,
88 env_addr->domain);
89 } else {
90 logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n",
91 msg->uid, rcpt->local_part,
92 rcpt->domain);
93 }
94 addr_mark_delivered(rcpt);
95 return TRUE;
96 }
98 /* prevents 'Resource temporarily unavailable (11)' */
99 if (errno != EAGAIN) {
100 addr_mark_failed(rcpt);
101 } else {
102 addr_mark_defered(rcpt);
103 }
104 return FALSE;
105 }
107 gboolean
108 deliver_local_pipe(message *msg, GList *hdr_list, address *rcpt,
109 address *env_addr)
110 {
111 guint flags = 0;
113 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
115 flags |= (conf.pipe_fromline) ? MSGSTR_FROMLINE : 0;
116 flags |= (conf.pipe_fromhack) ? MSGSTR_FROMHACK : 0;
117 if (pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]), flags)) {
118 logwrite(LOG_NOTICE, "%s => %s <%s@%s> with pipe\n",
119 msg->uid, rcpt->local_part,
120 env_addr->local_part, env_addr->domain);
121 addr_mark_delivered(rcpt);
122 return TRUE;
123 }
125 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
126 addr_mark_failed(rcpt);
127 } else {
128 addr_mark_defered(rcpt);
129 /* has no effect yet, except that mail remains in spool */
130 }
131 return FALSE;
132 }
134 gboolean
135 deliver_local_mda(message *msg, GList *hdr_list, address *rcpt,
136 address *env_addr)
137 {
138 gboolean ok = FALSE;
139 gchar *cmd = g_malloc(256);
140 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
141 guint flags = 0;
143 DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
145 if (!expand(var_table, conf.mda, cmd, 256)) {
146 logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
147 destroy_table(var_table);
148 return FALSE;
149 }
151 flags |= (conf.mda_fromline) ? MSGSTR_FROMLINE : 0;
152 flags |= (conf.mda_fromhack) ? MSGSTR_FROMHACK : 0;
153 if (pipe_out(msg, hdr_list, rcpt, cmd, flags)) {
154 logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
155 msg->uid, rcpt->local_part, rcpt->domain, cmd);
156 addr_mark_delivered(rcpt);
157 ok = TRUE;
158 } else if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
159 addr_mark_failed(rcpt);
160 } else {
161 addr_mark_defered(rcpt);
162 /* has no effect yet, except that mail remains in spool */
163 }
165 destroy_table(var_table);
166 return ok;
167 }
169 gboolean
170 deliver_local(msg_out *msgout)
171 {
172 message *msg = msgout->msg;
173 GList *rcpt_list = msgout->rcpt_list;
174 GList *rcpt_node;
175 gboolean ok = FALSE, flag = FALSE, ok_fail = FALSE;
177 DEBUG(5) debugf("deliver_local entered\n");
179 flag = (msg->data_list == NULL);
180 if (flag && !spool_read_data(msg)) {
181 logwrite(LOG_ALERT, "could not open data spool file for %s\n",
182 msg->uid);
183 return FALSE;
184 }
186 for (rcpt_node = g_list_first(rcpt_list); rcpt_node;
187 rcpt_node = g_list_next(rcpt_node)) {
188 GList *hdr_list;
189 address *rcpt = (address *) (rcpt_node->data);
190 address *env_addr = addr_find_ancestor(rcpt);
191 address *ret_path = msg->return_path;
192 header *retpath_hdr, *envto_hdr;
194 /*
195 ** we need a private copy of the hdr list because we add
196 ** headers here that belong to the rcpt only. g_list_copy
197 ** copies only the nodes, so it is safe to g_list_free it
198 */
199 hdr_list = g_list_copy(msg->hdr_list);
200 retpath_hdr = create_header(HEAD_ENVELOPE_TO,
201 "Envelope-to: %s\n", addr_string(env_addr));
202 envto_hdr = create_header(HEAD_RETURN_PATH,
203 "Return-path: %s\n", addr_string(ret_path));
205 hdr_list = g_list_prepend(hdr_list, envto_hdr);
206 hdr_list = g_list_prepend(hdr_list, retpath_hdr);
208 if (*rcpt->local_part == '|') {
209 /*
210 ** probably for expanded aliases, but why not done
211 ** like with the mda? //meillo 2010-12-06
212 */
213 if (deliver_local_pipe(msg, hdr_list, rcpt,
214 env_addr)) {
215 ok = TRUE;
216 }
217 } else {
218 /* figure out which mailbox type should be used
219 ** for this user */
220 gchar *user = rcpt->local_part;
221 gchar *mbox_type = conf.mbox_default;
223 if (g_list_find_custom(conf.mbox_users, user,
224 _g_list_strcasecmp)) {
225 mbox_type = "mbox";
226 } else if (g_list_find_custom (conf.mda_users, user,
227 _g_list_strcasecmp)) {
228 mbox_type = "mda";
229 }
231 if (strcmp(mbox_type, "mbox")==0) {
232 if (deliver_local_mbox(msg, hdr_list, rcpt,
233 env_addr)) {
234 ok = TRUE;
235 }
236 } else if (strcmp(mbox_type, "mda") == 0) {
237 if (conf.mda) {
238 if (deliver_local_mda(msg, hdr_list,
239 rcpt, env_addr)) {
240 ok = TRUE;
241 }
242 } else {
243 logwrite(LOG_ALERT, "mbox type is "
244 "mda, but no mda "
245 "command given in "
246 "configuration\n");
247 }
249 } else {
250 logwrite(LOG_ALERT, "unknown mbox type '%s'\n",
251 mbox_type);
252 }
253 }
255 destroy_header(retpath_hdr);
256 destroy_header(envto_hdr);
258 g_list_free(hdr_list);
259 }
260 ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)",
261 ext_strerror(errno), errno);
263 if (flag) {
264 msg_free_data(msg);
265 }
266 if (ok || ok_fail) {
267 deliver_finish(msgout);
268 }
270 return ok;
271 }
273 /*
274 ** make a list of rcpt's of a message that are local
275 ** return a new copy of the list
276 */
277 void
278 msg_rcptlist_local(GList *rcpt_list, GList **p_local_list,
279 GList **p_nonlocal_list)
280 {
281 GList *rcpt_node;
283 foreach(rcpt_list, rcpt_node) {
284 address *rcpt = (address *) (rcpt_node->data);
285 GList *dom_node;
287 DEBUG(5) debugf("checking address %s\n", rcpt->address);
289 /* search for local host list: */
290 foreach(conf.local_hosts, dom_node) {
291 if (fnmatch(dom_node->data, rcpt->domain,
292 FNM_CASEFOLD)==0) {
293 *p_local_list = g_list_append(*p_local_list,
294 rcpt);
295 DEBUG(5) debugf("<%s@%s> is local\n",
296 rcpt->local_part,
297 rcpt->domain);
298 break;
299 } else {
300 *p_nonlocal_list = g_list_append(
301 *p_nonlocal_list, rcpt);
302 }
303 }
304 }
305 }
307 gboolean
308 deliver_msglist_host_pipe(connect_route *route, GList *msgout_list,
309 gchar *host, GList *res_list)
310 {
311 gboolean ok = TRUE;
312 GList *msgout_node;
314 DEBUG(5) debugf("deliver_msglist_host_pipe entered\n");
316 foreach(msgout_list, msgout_node) {
317 msg_out *msgout = (msg_out *) (msgout_node->data);
318 gboolean flag, ok_fail = FALSE;
319 message *msg = msgout->msg;
320 GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
322 DEBUG(1) debugf("attempting to deliver %s with pipe\n",
323 msg->uid);
325 flag = (msg->data_list == NULL);
326 if (flag && !spool_read_data(msg)) {
327 logwrite(LOG_ALERT, "could not open data spool file "
328 "for %s\n", msg->uid);
329 continue;
330 }
332 ok = FALSE;
333 foreach(rcpt_list, rcpt_node) {
334 address *rcpt = (address *) (rcpt_node->data);
335 gchar *cmd = g_malloc(256);
336 GList *var_table = var_table_rcpt(var_table_msg(NULL,
337 msg), rcpt);
339 DEBUG(1) debugf("attempting to deliver %s to %s@%s "
340 "with pipe\n", msg->uid,
341 rcpt->local_part, rcpt->domain);
343 if (!expand(var_table, route->pipe, cmd, 256)) {
344 logwrite(LOG_ALERT, "could not expand string `%s'\n", route->pipe);
345 destroy_table(var_table);
346 continue;
347 }
349 if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0)
350 | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
351 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n",
352 msg->uid, rcpt->local_part, rcpt->domain, cmd);
353 addr_mark_delivered(rcpt);
354 ok = TRUE;
355 } else {
356 logwrite(LOG_ALERT, "pipe_out '%s' failed\n", route->pipe);
358 if (route->connect_error_fail) {
359 addr_mark_failed(rcpt);
360 } else {
361 addr_mark_defered(rcpt);
362 }
363 }
365 destroy_table(var_table);
366 }
367 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
369 if (flag) {
370 msg_free_data(msg);
371 }
372 if (ok || ok_fail) {
373 deliver_finish(msgout);
374 }
375 }
377 return ok;
378 }
380 /*
381 ** deliver list of messages to one host and finishes them if the message was
382 ** delivered to at least one rcpt.
383 ** Returns TRUE if at least one msg was delivered to at least one rcpt.
384 */
385 gboolean
386 deliver_msglist_host_smtp(connect_route *route, GList *msgout_list,
387 gchar *host, GList *res_list)
388 {
389 gboolean ok = FALSE;
390 GList *msgout_node;
391 smtp_base *psb;
392 gint port = 25;
394 /* paranoid check: */
395 if (!msgout_list) {
396 logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n");
397 return FALSE;
398 }
400 if (!host) {
401 /* XXX: what if mail_host isn't set? Is this possible? */
402 host = route->mail_host->address;
403 port = route->mail_host->port;
404 }
406 if (route->wrapper) {
407 psb = smtp_out_open_child(route->wrapper);
408 if (psb) {
409 psb->remote_host = host;
410 }
411 } else {
412 psb = smtp_out_open(host, port, res_list);
413 }
415 if (!psb) {
416 /* smtp_out_open() failed */
417 foreach(msgout_list, msgout_node) {
418 msg_out *msgout = (msg_out *) (msgout_node->data);
419 GList *rcpt_node;
421 for (rcpt_node = g_list_first(msgout->rcpt_list);
422 rcpt_node;
423 rcpt_node = g_list_next(rcpt_node)) {
424 address *rcpt = (address *) (rcpt_node->data);
425 gboolean ret = FALSE;
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 ret = delivery_failures(msgout->msg,
435 msgout->rcpt_list,
436 "could not open "
437 "wrapper:\n\t%s",
438 strerror(errno));
439 } else {
440 ret = delivery_failures(msgout->msg,
441 msgout->rcpt_list,
442 "could not open "
443 "connection to %s:%d "
444 ":\n\t%s", host, port,
445 h_errno != 0 ?
446 hstrerror(h_errno) :
447 strerror(errno));
448 }
449 if (ret) {
450 deliver_finish(msgout);
451 }
452 }
453 }
454 return ok;
455 }
457 set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name,
458 route->do_correct_helo);
460 #ifdef ENABLE_AUTH
461 if (route->auth_name && route->auth_login && route->auth_secret) {
462 set_auth(psb, route->auth_name, route->auth_login,
463 route->auth_secret);
464 }
465 #endif
466 if (!smtp_out_init(psb, route->instant_helo)) {
467 /* smtp_out_init() failed */
468 if ((psb->error==smtp_fail) || (psb->error==smtp_trylater) ||
469 (psb->error==smtp_syntax)) {
470 smtp_out_quit(psb);
472 foreach(msgout_list, msgout_node) {
473 msg_out *msgout =
474 (msg_out *)(msgout_node->data);
475 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
477 if (delivery_failures(msgout->msg,
478 msgout->rcpt_list,
479 "while connected with %s, "
480 "the server replied\n\t%s",
481 (route->wrapper) ?
482 "<wrapper>" : host,
483 psb->buffer)) {
484 deliver_finish(msgout);
485 }
486 }
487 }
488 destroy_smtpbase(psb);
489 return ok;
490 }
492 if (!route->do_pipelining) {
493 psb->use_pipelining = FALSE;
494 }
496 foreach(msgout_list, msgout_node) {
497 msg_out *msgout = (msg_out *) (msgout_node->data);
498 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
499 message *msg = msgout->msg;
501 /* we may have to read the data at this point
502 ** and remember if we did */
503 flag = (msg->data_list == NULL);
504 if (flag && !spool_read_data(msg)) {
505 logwrite(LOG_ALERT, "could not open data spool "
506 "file %s\n", msg->uid);
507 break;
508 }
510 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list,
511 msgout->hdr_list);
513 ok_fail = delivery_failures(msg, msgout->rcpt_list,
514 "while connected with %s, the server "
515 "replied\n\t%s", (route->wrapper) ?
516 "<wrapper>" : host, psb->buffer);
518 if ((psb->error == smtp_eof) || (psb->error == smtp_timeout)) {
519 /* connection lost */
520 break;
521 } else if (psb->error != smtp_ok) {
522 if (g_list_next(msgout_node) && !smtp_out_rset(psb)) {
523 break;
524 }
525 }
526 ok_msg = (psb->error == smtp_ok);
528 if (flag) {
529 msg_free_data(msg);
530 }
531 if (ok_msg) {
532 ok = TRUE;
533 }
534 if (ok_msg || ok_fail) {
535 deliver_finish(msgout);
536 }
537 }
538 if (psb->error == smtp_ok || (psb->error == smtp_fail) ||
539 (psb->error == smtp_trylater) ||
540 (psb->error == smtp_syntax)) {
541 smtp_out_quit(psb);
542 }
543 destroy_smtpbase(psb);
544 return ok;
545 }
547 gboolean
548 deliver_msglist_host(connect_route *route, GList *msgout_list, gchar *host,
549 GList *res_list)
550 {
552 if (route->pipe) {
553 DEBUG(5) debugf("with pipe\n");
554 return deliver_msglist_host_pipe(route, msgout_list,
555 host, res_list);
556 } else {
557 DEBUG(5) debugf("with smtp\n");
558 return deliver_msglist_host_smtp(route, msgout_list,
559 host, res_list);
560 }
561 }
563 /*
564 ** delivers messages in msgout_list using route
565 */
566 gboolean
567 deliver_route_msgout_list(connect_route *route, GList *msgout_list)
568 {
569 gboolean ok = FALSE;
570 GList *mo_ph_list;
571 GList *mo_ph_node;
573 DEBUG(5) debugf("deliver_route_msgout_list entered, route->name=%s\n",
574 route->name);
576 if (route->mail_host) {
577 /* easy: deliver everything to a smart host for relay */
578 return deliver_msglist_host(route, msgout_list, NULL,
579 route->resolve_list);
580 }
582 /* this is not easy... */
584 mo_ph_list = route_msgout_list(route, msgout_list);
585 /* okay, now we have ordered our messages by the hosts. */
586 if (!mo_ph_list) {
587 return FALSE;
588 }
590 /*
591 ** TODO: It would be nice to be able to fork for each host.
592 ** We cannot do that yet because of complications with finishing the
593 ** messages. Threads could be a solution because they use the same
594 ** memory. But we are not thread safe yet...
595 */
596 foreach(mo_ph_list, mo_ph_node) {
597 msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
598 if (deliver_msglist_host(route, mo_ph->msgout_list,
599 mo_ph->host, route->resolve_list)) {
600 ok = TRUE;
601 }
602 destroy_msgout_perhost(mo_ph);
603 }
604 g_list_free(mo_ph_list);
605 return ok;
606 }
608 /*
609 ** calls route_prepare_msg()
610 ** delivers messages in msg_list using route by calling
611 ** deliver_route_msgout_list()
612 */
613 gboolean
614 deliver_route_msg_list(connect_route *route, GList *msgout_list)
615 {
616 GList *msgout_list_deliver = NULL;
617 GList *msgout_node;
618 gboolean ok = TRUE;
620 DEBUG(6) debugf("deliver_route_msg_list()\n");
622 foreach(msgout_list, msgout_node) {
623 msg_out *msgout = (msg_out *) (msgout_node->data);
624 msg_out *msgout_cloned = clone_msg_out(msgout);
625 GList *rcpt_list_non_delivered = NULL;
626 GList *rcpt_node;
628 /*
629 ** we have to delete already delivered rcpt's because a
630 ** previous route may have delivered to it
631 */
632 foreach(msgout_cloned->rcpt_list, rcpt_node) {
633 address *rcpt = (address *) (rcpt_node->data);
634 /*
635 ** failed addresses already have been bounced;
636 ** there should be a better way to handle those.
637 */
638 if (!addr_is_delivered(rcpt) &&
639 !addr_is_failed(rcpt) &&
640 !(rcpt->flags & ADDR_FLAG_LAST_ROUTE)){
641 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
642 }
643 }
644 g_list_free(msgout_cloned->rcpt_list);
645 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
647 if (!msgout_cloned->rcpt_list) {
648 destroy_msg_out(msgout_cloned);
649 continue;
650 }
652 /* filter by allowed envelope sender */
653 if (!route_sender_is_allowed(route, msgout->msg->return_path)){
654 DEBUG(6) debugf("sender `%s' is not allowed for this "
655 "route\n", msgout->msg->return_path);
656 destroy_msg_out(msgout_cloned);
657 continue;
658 }
660 /* filter by allowed envelope rcpts */
661 GList *rcpt_list_allowed = NULL;
662 GList *rcpt_list_notallowed = NULL;
663 route_split_rcpts(route, msgout_cloned->rcpt_list,
664 &rcpt_list_allowed, &rcpt_list_notallowed);
665 if (!rcpt_list_allowed) {
666 destroy_msg_out(msgout_cloned);
667 continue;
668 }
670 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid,
671 route->name);
673 g_list_free(msgout_cloned->rcpt_list);
674 msgout_cloned->rcpt_list = rcpt_list_allowed;
676 if (route->last_route) {
677 GList *rcpt_node;
678 foreach(msgout_cloned->rcpt_list, rcpt_node) {
679 address *rcpt = (address *) (rcpt_node->data);
680 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
681 }
682 }
684 route_prepare_msgout(route, msgout_cloned);
685 msgout_list_deliver = g_list_append(msgout_list_deliver,
686 msgout_cloned);
687 }
689 if (msgout_list_deliver) {
690 if (deliver_route_msgout_list(route, msgout_list_deliver)) {
691 ok = TRUE;
692 }
693 destroy_msg_out_list(msgout_list_deliver);
694 }
695 return ok;
696 }
698 /*
699 ** copy pointers of delivered addresses to the msg's non_rcpt_list,
700 ** to make sure that they will not be delivered again.
701 */
702 void
703 update_non_rcpt_list(msg_out *msgout)
704 {
705 GList *rcpt_node;
706 message *msg = msgout->msg;
708 foreach(msgout->rcpt_list, rcpt_node) {
709 address *rcpt = (address *) (rcpt_node->data);
710 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt)) {
711 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list,
712 rcpt);
713 }
714 }
715 }
717 /*
718 ** after delivery attempts, we check if there are any rcpt addresses left in
719 ** the message. If all addresses have been completed, the spool files will be
720 ** deleted, otherwise the header spool will be written back. We never changed
721 ** the data spool, so there is no need to write that back.
722 **
723 ** returns TRUE if all went well.
724 */
725 gboolean
726 deliver_finish(msg_out *msgout)
727 {
728 GList *rcpt_node;
729 message *msg = msgout->msg;
730 gboolean finished = TRUE;
732 update_non_rcpt_list(msgout);
734 /*
735 ** we NEVER made copies of the addresses, flags affecting addresses
736 ** were always set on the original address structs
737 */
738 foreach(msg->rcpt_list, rcpt_node) {
739 address *rcpt = (address *) (rcpt_node->data);
740 if (!addr_is_finished_children(rcpt)) {
741 finished = FALSE;
742 } else {
743 /*
744 ** if ALL children have been delivered, mark parent as
745 ** delivered. if there is one or more not delivered,
746 ** it must have failed, we mark the parent as failed
747 ** as well.
748 */
749 if (addr_is_delivered_children(rcpt)) {
750 addr_mark_delivered(rcpt);
751 } else {
752 addr_mark_failed(rcpt);
753 }
754 }
755 }
757 if (finished) {
758 if (spool_delete_all(msg)) {
759 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
760 return TRUE;
761 }
762 return FALSE;
763 }
765 /* one not delivered address was found */
766 if (!spool_write(msg, FALSE)) {
767 logwrite(LOG_ALERT, "could not write back spool header "
768 "for %s\n", msg->uid);
769 return FALSE;
770 }
772 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
773 return TRUE;
774 }
776 int
777 deliver_remote(GList *remote_msgout_list)
778 {
779 int ok = TRUE;
780 GList *route_list = NULL;
781 GList *route_node;
782 GList *rf_list = NULL;
783 gchar *connect_name = NULL;
785 if (!remote_msgout_list) {
786 return FALSE;
787 }
789 /* perma routes */
790 if (conf.perma_routes) {
791 DEBUG(5) debugf("processing perma_routes\n");
793 route_list = read_route_list(conf.perma_routes, TRUE);
794 foreach(route_list, route_node) {
795 connect_route *route =
796 (connect_route *) (route_node->data);
797 if (!deliver_route_msg_list(route,
798 remote_msgout_list)) {
799 ok = FALSE;
800 }
801 }
802 destroy_route_list(route_list);
803 }
805 /* query routes */
806 connect_name = online_query();
807 if (!connect_name) {
808 DEBUG(5) debugf("online query returned false\n");
809 return FALSE;
810 }
812 /* we are online! */
813 DEBUG(5) debugf("processing query_routes\n");
814 logwrite(LOG_NOTICE, "detected online configuration `%s'\n",
815 connect_name);
817 rf_list = (GList *) table_find(conf.query_routes, connect_name);
818 if (!rf_list) {
819 logwrite(LOG_ALERT, "route list with name '%s' not found.\n",
820 connect_name);
821 return FALSE;
822 }
824 route_list = read_route_list(rf_list, FALSE);
825 if (!route_list) {
826 logwrite(LOG_ALERT, "could not read route list '%s'\n",
827 connect_name);
828 return FALSE;
829 }
831 foreach(route_list, route_node) {
832 connect_route *route = (connect_route *) (route_node->data);
833 /* TODO: ok gets overwritten */
834 ok = deliver_route_msg_list(route, remote_msgout_list);
835 }
836 destroy_route_list(route_list);
838 return ok;
839 }
841 /*
842 ** This function splits the list of rcpt addresses
843 ** into local and remote addresses and processes them accordingly.
844 */
845 gboolean
846 deliver_msg_list(GList *msg_list, guint flags)
847 {
848 GList *msgout_list = NULL;
849 GList *msg_node;
850 GList *local_msgout_list = NULL;
851 GList *remote_msgout_list = NULL;
852 GList *msgout_node;
853 GList *alias_table = NULL;
854 GList *globalias_table = NULL;
855 gboolean ok = TRUE;
857 /* create msgout_list */
858 foreach(msg_list, msg_node) {
859 message *msg = (message *) msg_node->data;
860 msgout_list = g_list_append(msgout_list, create_msg_out(msg));
861 }
863 if (conf.globalias_file) {
864 globalias_table = table_read(conf.globalias_file, ':');
865 }
866 if (conf.alias_file) {
867 alias_table = table_read(conf.alias_file, ':');
868 }
870 /* sort messages for different deliveries */
871 foreach(msgout_list, msgout_node) {
872 msg_out *msgout = (msg_out *) (msgout_node->data);
873 GList *rcpt_list;
874 GList *local_rcpt_list = NULL;
875 GList *other_rcpt_list = NULL;
877 if (!spool_lock(msgout->msg->uid)) {
878 DEBUG(5) debugf("spool_lock(%s) failed.\n",
879 msgout->msg->uid);
880 continue;
881 }
882 DEBUG(5) debugf("spool_lock(%s)\n", msgout->msg->uid);
884 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
885 if (conf.log_user) {
886 address *addr = create_address_qualified(conf.log_user,
887 TRUE, conf.host_name);
888 if (addr) {
889 rcpt_list = g_list_prepend(rcpt_list, addr);
890 } else {
891 logwrite(LOG_ALERT, "invalid log_user "
892 "address `%s', ignoring\n",
893 conf.log_user);
894 }
895 }
896 if (globalias_table) {
897 GList *globaliased_rcpt_list;
899 DEBUG(5) debugf("Doing globalias expansion\n");
900 globaliased_rcpt_list = alias_expand(globalias_table,
901 rcpt_list,
902 msgout->msg->non_rcpt_list, 1);
903 g_list_free(rcpt_list);
904 rcpt_list = globaliased_rcpt_list;
905 }
906 if (alias_table) {
907 GList *aliased_rcpt_list;
909 DEBUG(5) debugf("Doing alias expansion\n");
910 aliased_rcpt_list = alias_expand(alias_table,
911 rcpt_list,
912 msgout->msg->non_rcpt_list, 0);
913 g_list_free(rcpt_list);
914 rcpt_list = aliased_rcpt_list;
915 }
917 /* split_rcpts(rcpt_list, NULL, &local_rcpt_list, NULL,
918 ** &other_rcpt_list); */
919 local_rcpt_list = local_rcpts(rcpt_list);
920 other_rcpt_list = remote_rcpts(rcpt_list);
921 g_list_free(rcpt_list);
923 /* local recipients */
924 if ((flags & DLVR_LOCAL) && local_rcpt_list) {
925 msg_out *local_msgout = clone_msg_out(msgout);
926 local_msgout->rcpt_list = local_rcpt_list;
927 local_msgout_list = g_list_append(local_msgout_list,
928 local_msgout);
929 }
931 /* remote recipients, requires online delivery */
932 if ((flags & DLVR_ONLINE) && other_rcpt_list) {
933 msg_out *remote_msgout = clone_msg_out(msgout);
934 remote_msgout->rcpt_list = other_rcpt_list;
935 remote_msgout_list = g_list_append(remote_msgout_list,
936 remote_msgout);
937 }
938 }
940 if (alias_table) {
941 destroy_table(alias_table);
942 }
943 if (globalias_table) {
944 destroy_table(globalias_table);
945 }
947 /* process local/remote msgout lists -> delivery */
949 if (local_msgout_list) {
950 DEBUG(5) debugf("local_msgout_list\n");
951 foreach(local_msgout_list, msgout_node) {
952 msg_out *msgout = (msg_out *) (msgout_node->data);
953 if (!deliver_local(msgout)) {
954 ok = FALSE;
955 }
956 }
957 destroy_msg_out_list(local_msgout_list);
958 }
960 if (remote_msgout_list) {
961 DEBUG(5) debugf("remote_msgout_list\n");
962 deliver_remote(remote_msgout_list);
963 destroy_msg_out_list(remote_msgout_list);
964 }
966 /* unlock spool files */
967 foreach(msgout_list, msgout_node) {
968 msg_out *msgout = (msg_out *) (msgout_node->data);
969 if (spool_unlock(msgout->msg->uid)) {
970 DEBUG(5) debugf("spool_unlock(%s)\n",
971 msgout->msg->uid);
972 } else {
973 DEBUG(5) debugf("spool_unlock(%s) failed.\n",
974 msgout->msg->uid);
975 }
976 }
977 destroy_msg_out_list(msgout_list);
979 return ok;
980 }
982 /*
983 ** deliver() is called when a message has just been received
984 ** (mode_accept and smtp_in) and should be delivered immediately
985 ** (neither -odq nor do_queue). Only this one message will be tried to
986 ** deliver then.
987 */
988 gboolean
989 deliver(message *msg)
990 {
991 gboolean ok;
992 GList *msg_list = g_list_append(NULL, msg);
994 ok = deliver_msg_list(msg_list, DLVR_ALL);
995 g_list_free(msg_list);
997 return ok;
998 }