masqmail-0.2

view src/deliver.c @ 0:08114f7dcc23

this is masqmail-0.2.21 from oliver kurth
author meillo@marmaro.de
date Fri, 26 Sep 2008 17:05:23 +0200
parents
children 26e34ae9a3e3
line source
1 /* MasqMail
2 Copyright (C) 1999-2002 Oliver Kurth
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
19 #include "masqmail.h"
20 #include "smtp_out.h"
21 #include <fnmatch.h>
22 #include <sysexits.h>
23 #include <netdb.h>
25 /* collect failed/defered rcpts for failure/warning messages */
26 /* returns TRUE if either there are no failures or a
27 failure message has been successfully sent */
28 gboolean delivery_failures(message *msg, GList *rcpt_list, gchar *err_fmt, ...)
29 {
30 gboolean ok_fail = TRUE, ok_warn = TRUE;
31 time_t now = time(NULL);
33 GList *failed_list = NULL, *defered_list = NULL, *rcpt_node;
34 va_list args;
35 va_start(args, err_fmt);
37 foreach(rcpt_list, rcpt_node){
38 address *rcpt = (address *)(rcpt_node->data);
40 if(addr_is_defered(rcpt)){
41 if((now - msg->received_time) >= conf.max_defer_time){
42 addr_mark_failed(rcpt);
43 }else
44 defered_list = g_list_prepend(defered_list, rcpt);
45 }
46 if(addr_is_failed(rcpt))
47 failed_list = g_list_prepend(failed_list, rcpt);
48 }
49 if(failed_list != NULL){
50 ok_fail = fail_msg(msg, conf.errmsg_file, failed_list, err_fmt, args);
51 g_list_free(failed_list);
52 }
53 if(defered_list != NULL){
54 ok_warn = warn_msg(msg, conf.warnmsg_file, defered_list, err_fmt, args);
55 g_list_free(defered_list);
56 }
57 va_end(args);
58 return ok_fail && ok_warn;
59 }
61 static gint _g_list_strcasecmp(gconstpointer a, gconstpointer b)
62 {
63 return (gint)strcasecmp(a, b);
64 }
66 gboolean deliver_local(msg_out *msgout)
67 {
68 message *msg = msgout->msg;
69 GList *rcpt_list = msgout->rcpt_list;
70 GList *rcpt_node;
71 gboolean ok = TRUE, flag = FALSE, ok_fail = FALSE;
73 DEBUG(5) debugf("deliver_local entered\n");
75 flag = (msg->data_list == NULL);
76 if(flag){
77 if(!(ok = spool_read_data(msg))){
78 logwrite(LOG_ALERT, "could not open data spool file for %s\n",
79 msg->uid);
80 }
81 }
82 if(!ok) return FALSE;
84 ok = FALSE;
85 for(rcpt_node = g_list_first(rcpt_list);
86 rcpt_node;
87 rcpt_node = g_list_next(rcpt_node)){
88 GList *hdr_list;
89 address *rcpt = (address *)(rcpt_node->data);
90 address *env_addr = addr_find_ancestor(rcpt);
91 address *ret_path = msg->return_path;
92 header *retpath_hdr, *envto_hdr;
94 /* we need a private copy of the hdr list because we add headers here
95 that belong to the rcpt only.
96 g_list_copy copies only the nodes, so it is safe to
97 g_list_free it
98 */
99 hdr_list = g_list_copy(msg->hdr_list);
100 retpath_hdr = create_header(HEAD_ENVELOPE_TO,
101 "Envelope-to: %s\n", addr_string(env_addr));
102 envto_hdr = create_header(HEAD_RETURN_PATH,
103 "Return-path: %s\n", addr_string(ret_path));
105 hdr_list = g_list_prepend(hdr_list, envto_hdr);
106 hdr_list = g_list_prepend(hdr_list, retpath_hdr);
108 if(rcpt->local_part[0] == '|'){
109 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
110 if(pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]),
111 (conf.pipe_fromline ? MSGSTR_FROMLINE : 0) |
112 (conf.pipe_fromhack ? MSGSTR_FROMHACK : 0))){
113 logwrite(LOG_NOTICE, "%s => %s <%s@%s> with pipe\n",
114 msg->uid, rcpt->local_part,
115 env_addr->local_part, env_addr->domain
116 );
117 addr_mark_delivered(rcpt);
118 ok = TRUE;
119 }else{
120 if((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)){
121 addr_mark_failed(rcpt);
122 }else{
123 addr_mark_defered(rcpt); /* has no effect yet,
124 except that mail remains in spool */
125 }
126 }
127 }else{
128 /* figure out which mailbox type should be used for this user */
129 gchar *user = rcpt->local_part;
130 gchar *mbox_type = conf.mbox_default;
132 if(g_list_find_custom(conf.mbox_users, user, _g_list_strcasecmp) != NULL)
133 mbox_type = "mbox";
134 else if(g_list_find_custom(conf.mda_users, user, _g_list_strcasecmp) != NULL)
135 mbox_type = "mda";
136 else if(g_list_find_custom(conf.maildir_users, user, _g_list_strcasecmp) != NULL)
137 mbox_type = "maildir";
139 if(strcmp(mbox_type, "mbox") == 0){
140 DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
141 if(append_file(msg, hdr_list, rcpt->local_part)){
142 if(env_addr != rcpt){
143 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with mbox\n",
144 msg->uid, rcpt->local_part, rcpt->domain,
145 env_addr->local_part, env_addr->domain
146 );
147 }else{
148 logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n",
149 msg->uid, rcpt->local_part, rcpt->domain);
150 }
151 addr_mark_delivered(rcpt);
152 ok = TRUE;
153 }else{
154 if(errno != EAGAIN){ /* prevents 'Resource temporarily unavailable (11)' */
155 addr_mark_failed(rcpt);
156 }else{
157 addr_mark_defered(rcpt);
158 }
159 }
161 }else if(strcmp(mbox_type, "mda") == 0){
162 if(conf.mda){
163 gchar *cmd = g_malloc(256);
164 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
166 DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
168 if(expand(var_table, conf.mda, cmd, 256)){
170 if(pipe_out(msg, hdr_list, rcpt, cmd,
171 (conf.mda_fromline ? MSGSTR_FROMLINE : 0) |
172 (conf.mda_fromhack ? MSGSTR_FROMHACK : 0))){
173 logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
174 msg->uid, rcpt->local_part, rcpt->domain, cmd
175 );
176 addr_mark_delivered(rcpt);
177 ok = TRUE;
178 }else{
179 if((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)){
180 addr_mark_failed(rcpt);
181 }else{
182 addr_mark_defered(rcpt); /* has no effect yet,
183 except that mail remains in spool */
184 }
185 }
186 }else
187 logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
189 destroy_table(var_table);
190 }else
191 logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n");
193 #ifdef ENABLE_MAILDIR
194 }else if(strcmp(mbox_type, "maildir") == 0){
195 DEBUG(1) debugf("attempting to deliver %s with maildir\n", msg->uid);
196 if(maildir_out(msg, hdr_list, rcpt->local_part, 0)){
197 if(env_addr != rcpt){
198 logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with local\n",
199 msg->uid, rcpt->local_part, rcpt->domain,
200 env_addr->local_part, env_addr->domain
201 );
202 }else{
203 logwrite(LOG_NOTICE, "%s => <%s@%s> with maildir\n",
204 msg->uid, rcpt->local_part, rcpt->domain);
205 }
206 addr_mark_delivered(rcpt);
207 ok = TRUE;
208 }else
209 addr_mark_failed(rcpt);
210 #endif
211 }else
212 logwrite(LOG_ALERT, "unknown mbox type '%s'\n", mbox_type);
213 }
215 destroy_header(retpath_hdr);
216 destroy_header(envto_hdr);
218 g_list_free(hdr_list);
219 }
220 ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)", ext_strerror(errno), errno);
222 if(flag) msg_free_data(msg);
223 if(ok || ok_fail) deliver_finish(msgout);
225 return ok;
226 }
228 /* make a list of rcpt's of a message that are local
229 return a new copy of the list
230 */
231 void msg_rcptlist_local(GList *rcpt_list, GList **p_local_list, GList **p_nonlocal_list)
232 {
233 GList *rcpt_node;
235 foreach(rcpt_list, rcpt_node){
236 address *rcpt = (address *)(rcpt_node->data);
237 GList *dom_node;
239 DEBUG(5) debugf("checking address %s\n", rcpt->address);
241 /* search for local host list: */
242 foreach(conf.local_hosts, dom_node){
243 if(strcasecmp(dom_node->data, rcpt->domain) == 0){
244 *p_local_list = g_list_append(*p_local_list, rcpt);
245 DEBUG(5) debugf("<%s@%s> is local\n", rcpt->local_part, rcpt->domain);
246 break;
247 }else{
248 *p_nonlocal_list = g_list_append(*p_nonlocal_list, rcpt);
249 }
250 }
251 }
252 }
254 gboolean deliver_msglist_host_pipe(connect_route *route, GList *msgout_list, gchar *host, GList *res_list)
255 {
256 gboolean ok = TRUE;
257 GList *msgout_node;
259 DEBUG(5) debugf("deliver_msglist_host_pipe entered\n");
261 if(route->pipe == NULL){
262 logwrite(LOG_ALERT, "no pipe command given for route (protocol is pipe!)\n");
263 return FALSE;
264 }
266 foreach(msgout_list, msgout_node){
267 msg_out *msgout = (msg_out *)(msgout_node->data);
268 gboolean flag, ok_msg = TRUE, ok_fail = FALSE;
269 message *msg = msgout->msg;
270 GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
272 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
274 flag = (msg->data_list == NULL);
275 if(flag){
276 if(!(ok_msg = spool_read_data(msg))){
277 logwrite(LOG_ALERT, "could not open data spool file for %s\n",
278 msg->uid);
279 }
280 }
281 if(!ok_msg) continue;
283 ok = FALSE;
284 foreach(rcpt_list, rcpt_node){
285 address *rcpt = (address *)(rcpt_node->data);
286 gchar *cmd = g_malloc(256);
287 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
289 DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n",
290 msg->uid, rcpt->local_part, rcpt->domain);
292 if(expand(var_table, route->pipe, cmd, 256)){
294 if(pipe_out(msg, msg->hdr_list, rcpt, cmd,
295 (route->pipe_fromline ? MSGSTR_FROMLINE : 0) |
296 (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))){
297 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n",
298 msg->uid, rcpt->local_part, rcpt->domain, cmd
299 );
300 addr_mark_delivered(rcpt);
301 ok = TRUE;
302 }else{
303 logwrite(LOG_ALERT, "pipe_out '%s' failed\n", route->pipe);
305 if(route->connect_error_fail){
306 addr_mark_failed(rcpt);
307 }else{
308 addr_mark_defered(rcpt);
309 }
310 }
311 }else
312 logwrite(LOG_ALERT, "could not expand string %s\n", route->pipe);
314 destroy_table(var_table);
315 }
316 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
318 if(flag) msg_free_data(msg);
320 if(ok || ok_fail) deliver_finish(msgout);
321 }
323 return ok;
324 }
326 /* deliver list of messages to one host
327 and finishes them if the message was delivered to at least one
328 rcpt.
329 Returns TRUE if at least one msg was delivered to at least one
330 rcpt.
331 */
333 gboolean deliver_msglist_host_smtp(connect_route *route, GList *msgout_list, gchar *host, GList *res_list)
334 {
335 gboolean ok = FALSE;
336 GList *msgout_node;
337 smtp_base *psb;
338 gint port;
340 /* paranoid check: */
341 if(msgout_list == NULL){
342 logwrite(LOG_ALERT,
343 "Ooops: empty list of messages in deliver_msglist_host()\n");
344 return FALSE;
345 }
347 if(host == NULL){
348 host = route->mail_host->address;
349 port = route->mail_host->port;
350 }else
351 port = conf.remote_port;
353 #ifdef ENABLE_POP3
354 if(route->pop3_login){
355 if(!(pop_before_smtp(route->pop3_login)))
356 return FALSE;
357 }
358 #endif
360 if((psb = (route->wrapper ?
361 smtp_out_open_child(route->wrapper) :
362 smtp_out_open(host, port, res_list)))){
364 if(route->wrapper) psb->remote_host = host;
366 set_heloname(psb,
367 route->helo_name ? route->helo_name : conf.host_name,
368 route->do_correct_helo);
370 #ifdef ENABLE_AUTH
371 if((route->auth_name) && (route->auth_login) && (route->auth_secret))
372 set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
373 #endif
374 if(smtp_out_init(psb)){
376 if(!route->do_pipelining) psb->use_pipelining = FALSE;
378 foreach(msgout_list, msgout_node){
379 msg_out *msgout = (msg_out *)(msgout_node->data);
380 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
381 message *msg = msgout->msg;
383 /* we may have to read the data at this point
384 and remember if we did */
385 flag = (msg->data_list == NULL);
386 if(flag){
387 if(!spool_read_data(msg)){
388 logwrite(LOG_ALERT, "could not open data spool file %s\n",
389 msg->uid);
390 break;
391 }
392 }
394 smtp_out_msg(psb, msg,
395 msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
397 ok_fail = delivery_failures(msg, msgout->rcpt_list,
398 "while connected with %s, the server replied\n\t%s",
399 host, psb->buffer);
401 if((psb->error == smtp_eof) ||
402 (psb->error == smtp_timeout)){
403 /* connection lost */
404 break;
405 }
406 else if(psb->error != smtp_ok){
407 if(g_list_next(msgout_node) != NULL)
408 if(!smtp_out_rset(psb))
409 break;
410 }
411 ok_msg = (psb->error == smtp_ok);
413 if(flag) msg_free_data(msg);
414 if(ok_msg) ok = TRUE;
415 if(ok_msg || ok_fail){
416 deliver_finish(msgout);
417 }
418 }
419 if(psb->error == smtp_ok ||
420 (psb->error == smtp_fail) ||
421 (psb->error == smtp_trylater) ||
422 (psb->error == smtp_syntax)){
424 smtp_out_quit(psb);
425 }
426 }else{
427 /* smtp_out_init() failed */
428 if((psb->error == smtp_fail) ||
429 (psb->error == smtp_trylater) ||
430 (psb->error == smtp_syntax)){
431 smtp_out_quit(psb);
433 foreach(msgout_list, msgout_node){
434 msg_out *msgout = (msg_out *)(msgout_node->data);
435 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
437 if(delivery_failures(msgout->msg, msgout->rcpt_list,
438 "while connected with %s, the server replied\n\t%s",
439 host, psb->buffer))
440 deliver_finish(msgout);
441 }
442 }
443 }
444 destroy_smtpbase(psb);
445 }else{
446 /* smtp_out_open() failed */
447 foreach(msgout_list, msgout_node){
448 msg_out *msgout = (msg_out *)(msgout_node->data);
449 GList *rcpt_node;
451 for(rcpt_node = g_list_first(msgout->rcpt_list);
452 rcpt_node;
453 rcpt_node = g_list_next(rcpt_node)){
454 address *rcpt = (address *)(rcpt_node->data);
456 addr_unmark_delivered(rcpt);
457 if(route->connect_error_fail){
458 addr_mark_failed(rcpt);
459 }else{
460 addr_mark_defered(rcpt);
461 }
462 if(route->wrapper ?
463 delivery_failures(msgout->msg, msgout->rcpt_list,
464 "could not open wrapper:\n\t%s",
465 strerror(errno)) :
466 delivery_failures(msgout->msg, msgout->rcpt_list,
467 "could not open connection to %s:%d :\n\t%s",
468 host, port, h_errno != 0 ? hstrerror(h_errno) : strerror(errno)))
469 deliver_finish(msgout);
470 }
471 }
472 }
473 return ok;
474 }
476 gboolean deliver_msglist_host(connect_route *route, GList *msgout_list, gchar *host, GList *res_list)
477 {
478 DEBUG(5) debugf("protocol = %s\n", route->protocol);
480 if(strcmp(route->protocol, "pipe") == 0){
481 return deliver_msglist_host_pipe(route, msgout_list, host, res_list);
482 }else{
483 return deliver_msglist_host_smtp(route, msgout_list, host, res_list);
484 }
485 }
487 /*
488 delivers messages in msgout_list using route
489 */
490 gboolean deliver_route_msgout_list(connect_route *route, GList *msgout_list)
491 {
492 gboolean ok = FALSE;
494 DEBUG(5) debugf("deliver_route_msgout_list entered, route->name = %s\n",
495 route->name);
497 if(route->mail_host != NULL){
498 /* this is easy... */
499 if(deliver_msglist_host(route, msgout_list,
500 NULL, route->resolve_list))
501 ok = TRUE;
503 }else{
504 /* this is not easy... */
505 GList *mo_ph_list;
507 mo_ph_list = route_msgout_list(route, msgout_list);
508 /* okay, now we have ordered our messages by the hosts. */
509 if(mo_ph_list != NULL){
510 GList *mo_ph_node;
511 /* TODO: It would be nice to be able to fork for each host.
512 We cannot do that yet because of complications with finishing the
513 messages. Threads could be a solution because they use the same
514 memory. But we are not thread safe yet...
515 */
516 foreach(mo_ph_list, mo_ph_node){
517 msgout_perhost *mo_ph = (msgout_perhost *)(mo_ph_node->data);
518 if(deliver_msglist_host(route, mo_ph->msgout_list,
519 mo_ph->host, route->resolve_list))
520 ok = TRUE;
522 destroy_msgout_perhost(mo_ph);
523 }
524 g_list_free(mo_ph_list);
525 }
526 }
527 return ok;
528 }
530 /*
531 calls route_prepare_msg()
532 delivers messages in msg_list using route
533 by calling deliver_route_msgout_list()
534 */
535 gboolean deliver_route_msg_list(connect_route *route, GList *msgout_list)
536 {
537 GList *msgout_list_deliver = NULL;
538 GList *msgout_node;
539 gboolean ok = TRUE;
541 DEBUG(6) debugf("deliver_route_msg_list()\n");
543 foreach(msgout_list, msgout_node){
544 msg_out *msgout = (msg_out *)(msgout_node->data);
545 msg_out *msgout_cloned = clone_msg_out(msgout);
546 GList *rcpt_list_non_delivered = NULL;
547 GList *rcpt_node;
549 /* we have to delete already delivered rcpt's
550 because a previous route may have delivered to it */
551 foreach(msgout_cloned->rcpt_list, rcpt_node){
552 address *rcpt = (address *)(rcpt_node->data);
553 /* failed addresses already have been bounced
554 - there should be a better way to handle those.*/
555 if(!addr_is_delivered(rcpt) && !addr_is_failed(rcpt) && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE))
556 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
557 }
558 g_list_free(msgout_cloned->rcpt_list);
559 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
561 if(msgout_cloned->rcpt_list){
562 if(route_is_allowed_mail_local(route, msgout->msg->return_path) &&
563 route_is_allowed_return_path(route, msgout->msg->return_path)){
564 GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
565 msg_rcptlist_route(route, msgout_cloned->rcpt_list,
566 &rcpt_list_allowed, &rcpt_list_notallowed);
568 if(rcpt_list_allowed != NULL){
569 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
571 g_list_free(msgout_cloned->rcpt_list);
572 msgout_cloned->rcpt_list = rcpt_list_allowed;
574 if(route->last_route){
575 GList *rcpt_node;
576 foreach(msgout_cloned->rcpt_list, rcpt_node){
577 address *rcpt = (address *)(rcpt_node->data);
578 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
579 }
580 }
582 route_prepare_msgout(route, msgout_cloned);
583 msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
584 }else
585 destroy_msg_out(msgout_cloned);
586 }
587 else
588 destroy_msg_out(msgout_cloned);
589 }else
590 destroy_msg_out(msgout_cloned);
591 }
593 if(msgout_list_deliver != NULL){
594 if(deliver_route_msgout_list(route, msgout_list_deliver))
595 ok = TRUE;
596 destroy_msg_out_list(msgout_list_deliver);
597 }
598 return ok;
599 }
601 /* copy pointers of delivered addresses to the msg's non_rcpt_list,
602 to make sure that they will not be delivered again.
603 */
604 void update_non_rcpt_list(msg_out *msgout)
605 {
606 GList *rcpt_node;
607 message *msg = msgout->msg;
609 foreach(msgout->rcpt_list, rcpt_node){
610 address *rcpt = (address *)(rcpt_node->data);
611 if(addr_is_delivered(rcpt) || addr_is_failed(rcpt))
612 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
613 }
614 }
616 /* after delivery attempts, we check if there are any
617 rcpt addresses left in the message.
618 If all addresses have been completed, the spool files will
619 be deleted, otherwise the header spool will be written back.
620 We never changed the data spool, so there is no need to write that back.
622 returns TRUE if all went well.
623 */
624 gboolean deliver_finish(msg_out *msgout)
625 {
626 GList *rcpt_node;
627 gboolean ok = FALSE;
628 message *msg = msgout->msg;
629 gboolean finished = TRUE;
631 update_non_rcpt_list(msgout);
633 /* we NEVER made copies of the addresses, flags affecting addresses
634 were always set on the original address structs */
635 foreach(msg->rcpt_list, rcpt_node){
636 address *rcpt = (address *)(rcpt_node->data);
637 if(!addr_is_finished_children(rcpt))
638 finished = FALSE;
639 else{
640 /* if ALL children have been delivered,
641 mark parent as delivered.
642 if there is one or more not delivered,
643 it must have failed, we mark the parent as failed as well.
644 */
645 if(addr_is_delivered_children(rcpt)){
646 addr_mark_delivered(rcpt);
647 }else{
648 addr_mark_failed(rcpt);
649 }
650 }
651 }
653 if(!finished){
654 /* one not delivered address was found */
655 if(spool_write(msg, FALSE)){
656 ok = TRUE;
657 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
658 }else
659 logwrite(LOG_ALERT, "could not write back spool header for %s\n",
660 msg->uid);
661 }else{
662 ok = spool_delete_all(msg);
663 if(ok)
664 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
665 }
666 return ok;
667 }
669 gboolean deliver_finish_list(GList *msgout_list)
670 {
671 gboolean ok = TRUE;
672 GList *msgout_node;
673 foreach(msgout_list, msgout_node){
674 msg_out *msgout = (msg_out *)(msgout_node->data);
675 if(!deliver_finish(msgout))
676 ok = FALSE;
677 }
678 return ok;
679 }
681 gboolean deliver_msgout_list_online(GList *msgout_list)
682 {
683 GList *rf_list = NULL;
684 gchar *connect_name = detect_online();
685 gboolean ok = FALSE;
687 if(connect_name != NULL){
688 logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
689 /* we are online! */
690 rf_list = (GList *)table_find(conf.connect_routes, connect_name);
691 if(rf_list != NULL){
692 GList *route_list = read_route_list(rf_list, FALSE);
693 if(route_list){
694 GList *route_node;
695 foreach(route_list, route_node){
696 connect_route *route = (connect_route *)(route_node->data);
697 ok = deliver_route_msg_list(route, msgout_list);
698 }
699 destroy_route_list(route_list);
700 }
701 else
702 logwrite(LOG_ALERT,
703 "could not read route list '%s'\n", connect_name);
704 }else{
705 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
706 }
707 }
708 return ok;
709 }
711 gboolean deliver_msg_list(GList *msg_list, guint flags){
712 GList *msgout_list = create_msg_out_list(msg_list);
713 GList *local_msgout_list = NULL, *localnet_msgout_list = NULL, *other_msgout_list = NULL;
714 GList *msgout_node;
715 GList *alias_table = NULL;
716 gboolean ok = TRUE;
718 if(conf.alias_file){
719 if(!(alias_table = table_read(conf.alias_file, ':')))
720 return FALSE;
721 }
723 /* sort messages for different deliveries */
724 foreach(msgout_list, msgout_node){
725 msg_out *msgout = (msg_out *)(msgout_node->data);
726 GList *rcpt_list;
727 GList *local_rcpt_list = NULL;
728 GList *localnet_rcpt_list = NULL;
729 GList *other_rcpt_list;
731 if(!spool_lock(msgout->msg->uid)) continue;
733 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
734 if(conf.log_user){
735 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
736 if(addr)
737 rcpt_list = g_list_prepend(rcpt_list, addr);
738 }
739 if(alias_table){
740 GList *aliased_rcpt_list;
741 aliased_rcpt_list = alias_expand(alias_table, rcpt_list,
742 msgout->msg->non_rcpt_list);
743 g_list_free(rcpt_list);
744 rcpt_list = aliased_rcpt_list;
745 }
747 /* local recipients */
748 other_rcpt_list = NULL;
749 rcptlist_with_addr_is_local(rcpt_list, &local_rcpt_list, &other_rcpt_list);
751 if(flags & DLVR_LOCAL){
752 if(local_rcpt_list != NULL){
753 msg_out *local_msgout = clone_msg_out(msgout);
754 local_msgout->rcpt_list = local_rcpt_list;
755 local_msgout_list = g_list_append(local_msgout_list, local_msgout);
756 }
757 }
759 g_list_free(rcpt_list);
761 /* local net recipients */
762 rcpt_list = other_rcpt_list;
763 other_rcpt_list = NULL;
764 rcptlist_with_one_of_hostlist(rcpt_list, conf.local_nets,
765 &localnet_rcpt_list, &other_rcpt_list);
767 if(flags & DLVR_LAN){
768 if(localnet_rcpt_list != NULL){
769 msg_out *localnet_msgout = clone_msg_out(msgout);
770 localnet_msgout->rcpt_list = localnet_rcpt_list;
771 localnet_msgout_list = g_list_append(localnet_msgout_list, localnet_msgout);
772 }
773 }
775 if(flags & DLVR_ONLINE){
776 /* the rest, this is online delivery */
777 if(other_rcpt_list != NULL){
778 msg_out *other_msgout = clone_msg_out(msgout);
779 other_msgout->rcpt_list = other_rcpt_list;
780 other_msgout_list = g_list_append(other_msgout_list, other_msgout);
781 }
782 }
783 }
785 if(alias_table)
786 destroy_table(alias_table);
788 /* actual delivery */
789 if(local_msgout_list != NULL){
790 foreach(local_msgout_list, msgout_node){
791 msg_out *msgout = (msg_out *)(msgout_node->data);
792 if(!deliver_local(msgout)) ok = FALSE;
793 }
794 destroy_msg_out_list(local_msgout_list);
795 }
797 if(localnet_msgout_list != NULL){
798 GList *route_list = NULL;
799 GList *route_node;
801 if(conf.local_net_routes)
802 route_list = read_route_list(conf.local_net_routes, TRUE);
803 else
804 route_list = g_list_append(NULL, create_local_route());
806 foreach(route_list, route_node){
807 connect_route *route = (connect_route *)(route_node->data);
808 if(!deliver_route_msg_list(route, localnet_msgout_list)) ok = FALSE;
809 }
810 destroy_msg_out_list(localnet_msgout_list);
811 destroy_route_list(route_list);
812 }
814 if(other_msgout_list != NULL){
815 if(!deliver_msgout_list_online(other_msgout_list)) ok = FALSE;
816 destroy_msg_out_list(other_msgout_list);
817 }
819 foreach(msgout_list, msgout_node){
820 msg_out *msgout = (msg_out *)(msgout_node->data);
821 spool_unlock(msgout->msg->uid);
822 }
824 destroy_msg_out_list(msgout_list);
826 return ok;
827 }
829 /* This function searches in the list of rcpt addresses
830 for local and 'local net' addresses. Remote addresses
831 which are reachable only when online are treated specially
832 in another function.
834 deliver() is called when a message has just been received and should
835 be delivered immediately.
836 */
837 gboolean deliver(message *msg)
838 {
839 gboolean ok;
841 GList *msg_list = g_list_append(NULL, msg);
843 ok = deliver_msg_list(msg_list, DLVR_ALL);
845 g_list_free(msg_list);
847 return ok;
848 }