masqmail

changeset 280:72e377210d5e

heavy refactoring of deliver.c I need to have closer looks in there; seems as if there are possibilies to clean up
author markus schnalke <meillo@marmaro.de>
date Mon, 06 Dec 2010 18:07:01 -0300
parents 1aa107c6b1e5
children ea5f86e0a81c
files src/deliver.c
diffstat 1 files changed, 361 insertions(+), 276 deletions(-) [+]
line diff
     1.1 --- a/src/deliver.c	Mon Dec 06 17:46:24 2010 -0300
     1.2 +++ b/src/deliver.c	Mon Dec 06 18:07:01 2010 -0300
     1.3 @@ -42,17 +42,19 @@
     1.4  		if (addr_is_defered(rcpt)) {
     1.5  			if ((now - msg->received_time) >= conf.max_defer_time) {
     1.6  				addr_mark_failed(rcpt);
     1.7 -			} else
     1.8 +			} else {
     1.9  				defered_list = g_list_prepend(defered_list, rcpt);
    1.10 +			}
    1.11  		}
    1.12 -		if (addr_is_failed(rcpt))
    1.13 +		if (addr_is_failed(rcpt)) {
    1.14  			failed_list = g_list_prepend(failed_list, rcpt);
    1.15 +		}
    1.16  	}
    1.17 -	if (failed_list != NULL) {
    1.18 +	if (failed_list) {
    1.19  		ok_fail = fail_msg(msg, conf.errmsg_file, failed_list, err_fmt, args);
    1.20  		g_list_free(failed_list);
    1.21  	}
    1.22 -	if (defered_list != NULL) {
    1.23 +	if (defered_list) {
    1.24  		ok_warn = warn_msg(msg, conf.warnmsg_file, defered_list, err_fmt, args);
    1.25  		g_list_free(defered_list);
    1.26  	}
    1.27 @@ -67,25 +69,103 @@
    1.28  }
    1.29  
    1.30  gboolean
    1.31 +deliver_local_mbox(message* msg, GList* hdr_list, address* rcpt, address* env_addr)
    1.32 +{
    1.33 +	DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
    1.34 +	if (append_file(msg, hdr_list, rcpt->local_part)) {
    1.35 +		if (env_addr != rcpt) {
    1.36 +			logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with mbox\n", msg->uid, rcpt->local_part, rcpt->domain, env_addr->local_part, env_addr->domain);
    1.37 +		} else {
    1.38 +			logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n", msg->uid, rcpt->local_part, rcpt->domain);
    1.39 +		}
    1.40 +		addr_mark_delivered(rcpt);
    1.41 +		return TRUE;
    1.42 +	}
    1.43 +
    1.44 +	/* prevents 'Resource temporarily unavailable (11)' */
    1.45 +	if (errno != EAGAIN) {
    1.46 +		addr_mark_failed(rcpt);
    1.47 +	} else {
    1.48 +		addr_mark_defered(rcpt);
    1.49 +	}
    1.50 +	return FALSE;
    1.51 +}
    1.52 +
    1.53 +gboolean
    1.54 +deliver_local_pipe(message* msg, GList* hdr_list, address* rcpt, address* env_addr)
    1.55 +{
    1.56 +	guint flags;
    1.57 +
    1.58 +	DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
    1.59 +
    1.60 +	flags = (conf.pipe_fromline) ? MSGSTR_FROMLINE : 0;
    1.61 +	flags |= (conf.pipe_fromhack) ? MSGSTR_FROMHACK : 0;
    1.62 +	if (pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]), flags)) {
    1.63 +		logwrite(LOG_NOTICE, "%s => %s <%s@%s> with pipe\n",
    1.64 +		         msg->uid, rcpt->local_part, env_addr->local_part, env_addr->domain);
    1.65 +		addr_mark_delivered(rcpt);
    1.66 +		return TRUE;
    1.67 +	}
    1.68 +
    1.69 +	if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
    1.70 +		addr_mark_failed(rcpt);
    1.71 +	} else {
    1.72 +		addr_mark_defered(rcpt);
    1.73 +		/* has no effect yet, except that mail remains in spool */
    1.74 +	}
    1.75 +	return FALSE;
    1.76 +}
    1.77 +
    1.78 +gboolean
    1.79 +deliver_local_mda(message* msg, GList* hdr_list, address* rcpt, address* env_addr)
    1.80 +{
    1.81 +	gboolean ok = FALSE;
    1.82 +	gchar *cmd = g_malloc(256);
    1.83 +	GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
    1.84 +	guint flags;
    1.85 +
    1.86 +	DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
    1.87 +
    1.88 +	if (!expand(var_table, conf.mda, cmd, 256)) {
    1.89 +		logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
    1.90 +		destroy_table(var_table);
    1.91 +		return FALSE;
    1.92 +	}
    1.93 +
    1.94 +	flags = (conf.mda_fromline) ? MSGSTR_FROMLINE : 0;
    1.95 +	flags |= (conf.mda_fromhack) ? MSGSTR_FROMHACK : 0;
    1.96 +	if (pipe_out(msg, hdr_list, rcpt, cmd, flags)) {
    1.97 +		logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
    1.98 +		         msg->uid, rcpt->local_part, rcpt->domain, cmd);
    1.99 +		addr_mark_delivered(rcpt);
   1.100 +		ok = TRUE;
   1.101 +	} else if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
   1.102 +		addr_mark_failed(rcpt);
   1.103 +	} else {
   1.104 +		addr_mark_defered(rcpt);
   1.105 +		/* has no effect yet, except that mail remains in spool */
   1.106 +	}
   1.107 +
   1.108 +	destroy_table(var_table);
   1.109 +	return ok;
   1.110 +}
   1.111 +
   1.112 +gboolean
   1.113  deliver_local(msg_out * msgout)
   1.114  {
   1.115  	message *msg = msgout->msg;
   1.116  	GList *rcpt_list = msgout->rcpt_list;
   1.117  	GList *rcpt_node;
   1.118 -	gboolean ok = TRUE, flag = FALSE, ok_fail = FALSE;
   1.119 +	gboolean ok = FALSE, flag = FALSE, ok_fail = FALSE;
   1.120  
   1.121  	DEBUG(5) debugf("deliver_local entered\n");
   1.122  
   1.123  	flag = (msg->data_list == NULL);
   1.124 -	if (flag) {
   1.125 -		if (!(ok = spool_read_data(msg))) {
   1.126 -			logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
   1.127 -		}
   1.128 +	if (flag && !spool_read_data(msg)) {
   1.129 +		logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
   1.130 +		return FALSE;
   1.131  	}
   1.132 -	if (!ok)
   1.133 -		return FALSE;
   1.134  
   1.135 -	ok = FALSE;
   1.136  	for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
   1.137  		GList *hdr_list;
   1.138  		address *rcpt = (address *) (rcpt_node->data);
   1.139 @@ -93,8 +173,9 @@
   1.140  		address *ret_path = msg->return_path;
   1.141  		header *retpath_hdr, *envto_hdr;
   1.142  
   1.143 -		/* we need a private copy of the hdr list because we add headers here that belong to the rcpt only.
   1.144 -		   g_list_copy copies only the nodes, so it is safe to g_list_free it */
   1.145 +		/* we need a private copy of the hdr list because we add headers
   1.146 +		   here that belong to the rcpt only. g_list_copy copies only
   1.147 +		   the nodes, so it is safe to g_list_free it */
   1.148  		hdr_list = g_list_copy(msg->hdr_list);
   1.149  		retpath_hdr = create_header(HEAD_ENVELOPE_TO, "Envelope-to: %s\n", addr_string(env_addr));
   1.150  		envto_hdr = create_header(HEAD_RETURN_PATH, "Return-path: %s\n", addr_string(ret_path));
   1.151 @@ -103,82 +184,38 @@
   1.152  		hdr_list = g_list_prepend(hdr_list, retpath_hdr);
   1.153  
   1.154  		if (rcpt->local_part[0] == '|') {
   1.155 -			DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
   1.156 -			if (pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]),
   1.157 -			    (conf.pipe_fromline ? MSGSTR_FROMLINE : 0)
   1.158 -			    | (conf.pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
   1.159 -				logwrite(LOG_NOTICE, "%s => %s <%s@%s> with pipe\n",
   1.160 -				         msg->uid, rcpt->local_part, env_addr->local_part, env_addr->domain);
   1.161 -				addr_mark_delivered(rcpt);
   1.162 +			/* probably for expanded aliases, but why not done
   1.163 +			   like with the mda? //meillo 2010-12-06 */
   1.164 +			if (deliver_local_pipe(msg, hdr_list, rcpt, env_addr)) {
   1.165  				ok = TRUE;
   1.166 -			} else {
   1.167 -				if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
   1.168 -					addr_mark_failed(rcpt);
   1.169 -				} else {
   1.170 -					addr_mark_defered(rcpt);  /* has no effect yet, except that mail remains in spool */
   1.171 -				}
   1.172  			}
   1.173  		} else {
   1.174  			/* figure out which mailbox type should be used for this user */
   1.175  			gchar *user = rcpt->local_part;
   1.176  			gchar *mbox_type = conf.mbox_default;
   1.177  
   1.178 -			if (g_list_find_custom (conf.mbox_users, user, _g_list_strcasecmp) != NULL)
   1.179 +			if (g_list_find_custom (conf.mbox_users, user, _g_list_strcasecmp)) {
   1.180  				mbox_type = "mbox";
   1.181 -			else if (g_list_find_custom (conf.mda_users, user, _g_list_strcasecmp) != NULL)
   1.182 +			} else if (g_list_find_custom (conf.mda_users, user, _g_list_strcasecmp)) {
   1.183  				mbox_type = "mda";
   1.184 +			}
   1.185  
   1.186  			if (strcmp(mbox_type, "mbox") == 0) {
   1.187 -				DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
   1.188 -				if (append_file(msg, hdr_list, rcpt->local_part)) {
   1.189 -					if (env_addr != rcpt) {
   1.190 -						logwrite(LOG_NOTICE, "%s => %s@%s <%s@%s> with mbox\n",
   1.191 -						         msg->uid, rcpt->local_part, rcpt->domain,
   1.192 -						         env_addr->local_part, env_addr->domain);
   1.193 -					} else {
   1.194 -						logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n",
   1.195 -						         msg->uid, rcpt->local_part, rcpt->domain);
   1.196 +				if (deliver_local_mbox(msg, hdr_list, rcpt, env_addr)) {
   1.197 +					ok = TRUE;
   1.198 +				}
   1.199 +			} else if (strcmp(mbox_type, "mda") == 0) {
   1.200 +				if (conf.mda) {
   1.201 +					if (deliver_local_mda(msg, hdr_list, rcpt, env_addr)) {
   1.202 +						ok = TRUE;
   1.203  					}
   1.204 -					addr_mark_delivered(rcpt);
   1.205 -					ok = TRUE;
   1.206  				} else {
   1.207 -					if (errno != EAGAIN) {  /* prevents 'Resource temporarily unavailable (11)' */
   1.208 -						addr_mark_failed(rcpt);
   1.209 -					} else {
   1.210 -						addr_mark_defered(rcpt);
   1.211 -					}
   1.212 +					logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n");
   1.213  				}
   1.214  
   1.215 -			} else if (strcmp(mbox_type, "mda") == 0) {
   1.216 -				if (conf.mda) {
   1.217 -					gchar *cmd = g_malloc(256);
   1.218 -					GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
   1.219 -
   1.220 -					DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
   1.221 -
   1.222 -					if (expand(var_table, conf.mda, cmd, 256)) {
   1.223 -
   1.224 -						if (pipe_out(msg, hdr_list, rcpt, cmd, (conf.mda_fromline ? MSGSTR_FROMLINE : 0)
   1.225 -						    | (conf.mda_fromhack ? MSGSTR_FROMHACK : 0))) {
   1.226 -							logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
   1.227 -							         msg->uid, rcpt->local_part, rcpt->domain, cmd);
   1.228 -							addr_mark_delivered(rcpt);
   1.229 -							ok = TRUE;
   1.230 -						} else {
   1.231 -							if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
   1.232 -								addr_mark_failed(rcpt);
   1.233 -							} else {
   1.234 -								addr_mark_defered(rcpt);  /* has no effect yet, except that mail remains in spool */
   1.235 -							}
   1.236 -						}
   1.237 -					} else
   1.238 -						logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
   1.239 -
   1.240 -					destroy_table(var_table);
   1.241 -				} else
   1.242 -					logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n");
   1.243 -			} else
   1.244 +			} else {
   1.245  				logwrite(LOG_ALERT, "unknown mbox type '%s'\n", mbox_type);
   1.246 +			}
   1.247  		}
   1.248  
   1.249  		destroy_header(retpath_hdr);
   1.250 @@ -188,10 +225,12 @@
   1.251  	}
   1.252  	ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)", ext_strerror(errno), errno);
   1.253  
   1.254 -	if (flag)
   1.255 +	if (flag) {
   1.256  		msg_free_data(msg);
   1.257 -	if (ok || ok_fail)
   1.258 +	}
   1.259 +	if (ok || ok_fail) {
   1.260  		deliver_finish(msgout);
   1.261 +	}
   1.262  
   1.263  	return ok;
   1.264  }
   1.265 @@ -236,20 +275,17 @@
   1.266  
   1.267  	foreach(msgout_list, msgout_node) {
   1.268  		msg_out *msgout = (msg_out *) (msgout_node->data);
   1.269 -		gboolean flag, ok_msg = TRUE, ok_fail = FALSE;
   1.270 +		gboolean flag, ok_fail = FALSE;
   1.271  		message *msg = msgout->msg;
   1.272  		GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
   1.273  
   1.274  		DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
   1.275  
   1.276  		flag = (msg->data_list == NULL);
   1.277 -		if (flag) {
   1.278 -			if (!(ok_msg = spool_read_data(msg))) {
   1.279 -				logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
   1.280 -			}
   1.281 +		if (flag && !spool_read_data(msg)) {
   1.282 +			logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
   1.283 +			continue;
   1.284  		}
   1.285 -		if (!ok_msg)
   1.286 -			continue;
   1.287  
   1.288  		ok = FALSE;
   1.289  		foreach(rcpt_list, rcpt_node) {
   1.290 @@ -259,7 +295,9 @@
   1.291  
   1.292  			DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n", msg->uid, rcpt->local_part, rcpt->domain);
   1.293  
   1.294 -			if (expand(var_table, route->pipe, cmd, 256)) {
   1.295 +			if (!expand(var_table, route->pipe, cmd, 256)) {
   1.296 +				logwrite(LOG_ALERT, "could not expand string %s\n", route->pipe);
   1.297 +			} else {
   1.298  
   1.299  				if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0)
   1.300  				    | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
   1.301 @@ -276,24 +314,25 @@
   1.302  						addr_mark_defered(rcpt);
   1.303  					}
   1.304  				}
   1.305 -			} else
   1.306 -				logwrite(LOG_ALERT, "could not expand string %s\n", route->pipe);
   1.307 +			}
   1.308  
   1.309  			destroy_table(var_table);
   1.310  		}
   1.311  		ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
   1.312  
   1.313 -		if (flag)
   1.314 +		if (flag) {
   1.315  			msg_free_data(msg);
   1.316 -
   1.317 -		if (ok || ok_fail)
   1.318 +		}
   1.319 +		if (ok || ok_fail) {
   1.320  			deliver_finish(msgout);
   1.321 +		}
   1.322  	}
   1.323  
   1.324  	return ok;
   1.325  }
   1.326  
   1.327 -/* deliver list of messages to one host and finishes them if the message was delivered to at least one rcpt.
   1.328 +/* deliver list of messages to one host and finishes them if the message was
   1.329 +   delivered to at least one rcpt.
   1.330     Returns TRUE if at least one msg was delivered to at least one rcpt.
   1.331  */
   1.332  gboolean
   1.333 @@ -305,102 +344,34 @@
   1.334  	gint port = 25;
   1.335  
   1.336  	/* paranoid check: */
   1.337 -	if (msgout_list == NULL) {
   1.338 +	if (!msgout_list) {
   1.339  		logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n");
   1.340  		return FALSE;
   1.341  	}
   1.342  
   1.343 -	if (host == NULL) {
   1.344 +	if (!host) {
   1.345  		/* XXX: what if mail_host isn't set? Is this possible? */
   1.346  		host = route->mail_host->address;
   1.347  		port = route->mail_host->port;
   1.348  	}
   1.349  
   1.350 -	if ((psb = (route->wrapper ? smtp_out_open_child(route->wrapper) : smtp_out_open(host, port, res_list)))) {
   1.351 +	if (route->wrapper) {
   1.352 +		psb = smtp_out_open_child(route->wrapper);
   1.353 +	} else {
   1.354 +		psb = smtp_out_open(host, port, res_list);
   1.355 +	}
   1.356  
   1.357 -		if (route->wrapper) {
   1.358 -			/* it seems as if the remote_host is only set for logging
   1.359 -			/* XXX: this could probably be moved into smtp_out_open_child() */
   1.360 -			psb->remote_host = host;
   1.361 -		}
   1.362 -
   1.363 -		set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
   1.364 -
   1.365 -#ifdef ENABLE_AUTH
   1.366 -		if ((route->auth_name) && (route->auth_login) && (route->auth_secret))
   1.367 -			set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
   1.368 -#endif
   1.369 -		if (smtp_out_init(psb, route->instant_helo)) {
   1.370 -
   1.371 -			if (!route->do_pipelining)
   1.372 -				psb->use_pipelining = FALSE;
   1.373 -
   1.374 -			foreach(msgout_list, msgout_node) {
   1.375 -				msg_out *msgout = (msg_out *) (msgout_node->data);
   1.376 -				gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
   1.377 -				message *msg = msgout->msg;
   1.378 -
   1.379 -				/* we may have to read the data at this point and remember if we did */
   1.380 -				flag = (msg->data_list == NULL);
   1.381 -				if (flag) {
   1.382 -					if (!spool_read_data(msg)) {
   1.383 -						logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
   1.384 -						break;
   1.385 -					}
   1.386 -				}
   1.387 -
   1.388 -				smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
   1.389 -
   1.390 -				ok_fail = delivery_failures(msg, msgout->rcpt_list,
   1.391 -				                            "while connected with %s, the server replied\n\t%s", host, psb->buffer);
   1.392 -
   1.393 -				if ((psb->error == smtp_eof)
   1.394 -				    || (psb->error == smtp_timeout)) {
   1.395 -					/* connection lost */
   1.396 -					break;
   1.397 -				} else if (psb->error != smtp_ok) {
   1.398 -					if (g_list_next(msgout_node) != NULL)
   1.399 -						if (!smtp_out_rset(psb))
   1.400 -							break;
   1.401 -				}
   1.402 -				ok_msg = (psb->error == smtp_ok);
   1.403 -
   1.404 -				if (flag)
   1.405 -					msg_free_data(msg);
   1.406 -				if (ok_msg)
   1.407 -					ok = TRUE;
   1.408 -				if (ok_msg || ok_fail) {
   1.409 -					deliver_finish(msgout);
   1.410 -				}
   1.411 -			}
   1.412 -			if (psb->error == smtp_ok || (psb->error == smtp_fail)
   1.413 -			    || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
   1.414 -				smtp_out_quit(psb);
   1.415 -			}
   1.416 -		} else {
   1.417 -			/* smtp_out_init() failed */
   1.418 -			if ((psb->error == smtp_fail) || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
   1.419 -				smtp_out_quit(psb);
   1.420 -
   1.421 -				foreach(msgout_list, msgout_node) {
   1.422 -					msg_out *msgout = (msg_out *) (msgout_node->data);
   1.423 -					smtp_out_mark_rcpts(psb, msgout->rcpt_list);
   1.424 -
   1.425 -					if (delivery_failures(msgout->msg, msgout->rcpt_list,
   1.426 -					    "while connected with %s, the server replied\n\t%s", host, psb->buffer))
   1.427 -						deliver_finish(msgout);
   1.428 -				}
   1.429 -			}
   1.430 -		}
   1.431 -		destroy_smtpbase(psb);
   1.432 -	} else {
   1.433 +	if (!psb) {
   1.434  		/* smtp_out_open() failed */
   1.435  		foreach(msgout_list, msgout_node) {
   1.436  			msg_out *msgout = (msg_out *) (msgout_node->data);
   1.437  			GList *rcpt_node;
   1.438  
   1.439 -			for (rcpt_node = g_list_first(msgout->rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
   1.440 +			for (rcpt_node = g_list_first(msgout->rcpt_list);
   1.441 +			     rcpt_node;
   1.442 +			     rcpt_node = g_list_next(rcpt_node)) {
   1.443  				address *rcpt = (address *) (rcpt_node->data);
   1.444 +				gboolean ret = FALSE;
   1.445  
   1.446  				addr_unmark_delivered(rcpt);
   1.447  				if (route->connect_error_fail) {
   1.448 @@ -408,15 +379,96 @@
   1.449  				} else {
   1.450  					addr_mark_defered(rcpt);
   1.451  				}
   1.452 -				if (route->wrapper
   1.453 -				    ? delivery_failures(msgout->msg, msgout->rcpt_list, "could not open wrapper:\n\t%s",
   1.454 -				                        strerror(errno))
   1.455 -				    : delivery_failures(msgout->msg, msgout->rcpt_list, "could not open connection to %s:%d :\n\t%s",
   1.456 -				                        host, port, h_errno != 0 ? hstrerror(h_errno) : strerror(errno)))
   1.457 +				if (route->wrapper) {
   1.458 +					ret = delivery_failures(msgout->msg, msgout->rcpt_list, "could not open wrapper:\n\t%s", strerror(errno));
   1.459 +				} else {
   1.460 +					ret = delivery_failures(msgout->msg, msgout->rcpt_list, "could not open connection to %s:%d :\n\t%s", host, port, h_errno != 0 ? hstrerror(h_errno) : strerror(errno));
   1.461 +				}
   1.462 +				if (ret) {
   1.463  					deliver_finish(msgout);
   1.464 +				}
   1.465  			}
   1.466  		}
   1.467 +		return ok;
   1.468  	}
   1.469 +
   1.470 +
   1.471 +	if (route->wrapper) {
   1.472 +		/* it seems as if the remote_host is only set for logging
   1.473 +		/* XXX: this could probably be moved into smtp_out_open_child() */
   1.474 +		psb->remote_host = host;
   1.475 +	}
   1.476 +
   1.477 +	set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
   1.478 +
   1.479 +#ifdef ENABLE_AUTH
   1.480 +	if ((route->auth_name) && (route->auth_login) && (route->auth_secret)) {
   1.481 +		set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
   1.482 +	}
   1.483 +#endif
   1.484 +	if (!smtp_out_init(psb, route->instant_helo)) {
   1.485 +		/* smtp_out_init() failed */
   1.486 +		if ((psb->error==smtp_fail) || (psb->error==smtp_trylater) || (psb->error==smtp_syntax)) {
   1.487 +			smtp_out_quit(psb);
   1.488 +
   1.489 +			foreach(msgout_list, msgout_node) {
   1.490 +				msg_out *msgout = (msg_out *) (msgout_node->data);
   1.491 +				smtp_out_mark_rcpts(psb, msgout->rcpt_list);
   1.492 +
   1.493 +				if (delivery_failures(msgout->msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", host, psb->buffer)) {
   1.494 +					deliver_finish(msgout);
   1.495 +				}
   1.496 +			}
   1.497 +		}
   1.498 +		destroy_smtpbase(psb);
   1.499 +		return ok;
   1.500 +	}
   1.501 +
   1.502 +	if (!route->do_pipelining) {
   1.503 +		psb->use_pipelining = FALSE;
   1.504 +	}
   1.505 +
   1.506 +	foreach(msgout_list, msgout_node) {
   1.507 +		msg_out *msgout = (msg_out *) (msgout_node->data);
   1.508 +		gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
   1.509 +		message *msg = msgout->msg;
   1.510 +
   1.511 +		/* we may have to read the data at this point and remember if we did */
   1.512 +		flag = (msg->data_list == NULL);
   1.513 +		if (flag && !spool_read_data(msg)) {
   1.514 +			logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
   1.515 +			break;
   1.516 +		}
   1.517 +
   1.518 +		smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
   1.519 +
   1.520 +		ok_fail = delivery_failures(msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", host, psb->buffer);
   1.521 +
   1.522 +		if ((psb->error == smtp_eof) || (psb->error == smtp_timeout)) {
   1.523 +			/* connection lost */
   1.524 +			break;
   1.525 +		} else if (psb->error != smtp_ok) {
   1.526 +			if (g_list_next(msgout_node) && !smtp_out_rset(psb)) {
   1.527 +				break;
   1.528 +			}
   1.529 +		}
   1.530 +		ok_msg = (psb->error == smtp_ok);
   1.531 +
   1.532 +		if (flag) {
   1.533 +			msg_free_data(msg);
   1.534 +		}
   1.535 +		if (ok_msg) {
   1.536 +			ok = TRUE;
   1.537 +		}
   1.538 +		if (ok_msg || ok_fail) {
   1.539 +			deliver_finish(msgout);
   1.540 +		}
   1.541 +	}
   1.542 +	if (psb->error == smtp_ok || (psb->error == smtp_fail)
   1.543 +	    || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
   1.544 +		smtp_out_quit(psb);
   1.545 +	}
   1.546 +	destroy_smtpbase(psb);
   1.547  	return ok;
   1.548  }
   1.549  
   1.550 @@ -439,37 +491,37 @@
   1.551  deliver_route_msgout_list(connect_route * route, GList * msgout_list)
   1.552  {
   1.553  	gboolean ok = FALSE;
   1.554 +	GList *mo_ph_list;
   1.555 +	GList *mo_ph_node;
   1.556  
   1.557  	DEBUG(5) debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name);
   1.558  
   1.559  	if (route->mail_host) {
   1.560  		/* this is easy... deliver everything to a smart host for relay */
   1.561 -		if (deliver_msglist_host(route, msgout_list, NULL, route->resolve_list))
   1.562 +		return deliver_msglist_host(route, msgout_list, NULL, route->resolve_list);
   1.563 +	}
   1.564 +
   1.565 +	/* this is not easy... */
   1.566 +
   1.567 +	mo_ph_list = route_msgout_list(route, msgout_list);
   1.568 +	/* okay, now we have ordered our messages by the hosts. */
   1.569 +	if (!mo_ph_list) {
   1.570 +		return FALSE;
   1.571 +	}
   1.572 +
   1.573 +	/* TODO: It would be nice to be able to fork for each host.
   1.574 +	   We cannot do that yet because of complications with finishing the
   1.575 +	   messages. Threads could be a solution because they use the same
   1.576 +	   memory. But we are not thread safe yet...
   1.577 +	 */
   1.578 +	foreach(mo_ph_list, mo_ph_node) {
   1.579 +		msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
   1.580 +		if (deliver_msglist_host(route, mo_ph->msgout_list, mo_ph->host, route->resolve_list)) {
   1.581  			ok = TRUE;
   1.582 -
   1.583 -	} else {
   1.584 -		/* this is not easy... */
   1.585 -		GList *mo_ph_list;
   1.586 -
   1.587 -		mo_ph_list = route_msgout_list(route, msgout_list);
   1.588 -		/* okay, now we have ordered our messages by the hosts. */
   1.589 -		if (mo_ph_list != NULL) {
   1.590 -			GList *mo_ph_node;
   1.591 -			/* TODO: It would be nice to be able to fork for each host.
   1.592 -			   We cannot do that yet because of complications with finishing the
   1.593 -			   messages. Threads could be a solution because they use the same
   1.594 -			   memory. But we are not thread safe yet...
   1.595 -			 */
   1.596 -			foreach(mo_ph_list, mo_ph_node) {
   1.597 -				msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
   1.598 -				if (deliver_msglist_host (route, mo_ph->msgout_list, mo_ph->host, route->resolve_list))
   1.599 -					ok = TRUE;
   1.600 -
   1.601 -				destroy_msgout_perhost(mo_ph);
   1.602 -			}
   1.603 -			g_list_free(mo_ph_list);
   1.604  		}
   1.605 +		destroy_msgout_perhost(mo_ph);
   1.606  	}
   1.607 +	g_list_free(mo_ph_list);
   1.608  	return ok;
   1.609  }
   1.610  
   1.611 @@ -492,50 +544,59 @@
   1.612  		GList *rcpt_list_non_delivered = NULL;
   1.613  		GList *rcpt_node;
   1.614  
   1.615 -		/* we have to delete already delivered rcpt's because a previous route may have delivered to it */
   1.616 +		/* we have to delete already delivered rcpt's because a
   1.617 +		   previous route may have delivered to it */
   1.618  		foreach(msgout_cloned->rcpt_list, rcpt_node) {
   1.619  			address *rcpt = (address *) (rcpt_node->data);
   1.620 -			/* failed addresses already have been bounced - there should be a better way to handle those. */
   1.621 +			/* failed addresses already have been bounced;
   1.622 +			   there should be a better way to handle those. */
   1.623  			if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt)
   1.624 -			    && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE))
   1.625 +			    && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE)) {
   1.626  				rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
   1.627 +			}
   1.628  		}
   1.629  		g_list_free(msgout_cloned->rcpt_list);
   1.630  		msgout_cloned->rcpt_list = rcpt_list_non_delivered;
   1.631  
   1.632 -		if (msgout_cloned->rcpt_list) {
   1.633 -			if (route_is_allowed_mail_local(route, msgout->msg->return_path)
   1.634 -			   && route_is_allowed_return_path(route, msgout->msg-> return_path)) {
   1.635 -				GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
   1.636 -				msg_rcptlist_route(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
   1.637 +		if (!msgout_cloned->rcpt_list) {
   1.638 +			destroy_msg_out(msgout_cloned);
   1.639 +			continue;
   1.640 +		}
   1.641  
   1.642 -				if (rcpt_list_allowed != NULL) {
   1.643 -					logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
   1.644 +		if (!route_is_allowed_mail_local(route, msgout->msg->return_path)
   1.645 +		   || !route_is_allowed_return_path(route, msgout->msg-> return_path)) {
   1.646 +			destroy_msg_out(msgout_cloned);
   1.647 +			continue;
   1.648 +		}
   1.649  
   1.650 -					g_list_free(msgout_cloned->rcpt_list);
   1.651 -					msgout_cloned->rcpt_list = rcpt_list_allowed;
   1.652 +		GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
   1.653 +		msg_rcptlist_route(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
   1.654  
   1.655 -					if (route->last_route) {
   1.656 -						GList *rcpt_node;
   1.657 -						foreach(msgout_cloned->rcpt_list, rcpt_node) {
   1.658 -							address *rcpt = (address *) (rcpt_node->data);
   1.659 -							rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
   1.660 -						}
   1.661 -					}
   1.662 +		if (!rcpt_list_allowed) {
   1.663 +			destroy_msg_out(msgout_cloned);
   1.664 +			continue;
   1.665 +		}
   1.666 +		logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
   1.667  
   1.668 -					route_prepare_msgout(route, msgout_cloned);
   1.669 -					msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
   1.670 -				} else
   1.671 -					destroy_msg_out(msgout_cloned);
   1.672 -			} else
   1.673 -				destroy_msg_out(msgout_cloned);
   1.674 -		} else
   1.675 -			destroy_msg_out(msgout_cloned);
   1.676 +		g_list_free(msgout_cloned->rcpt_list);
   1.677 +		msgout_cloned->rcpt_list = rcpt_list_allowed;
   1.678 +
   1.679 +		if (route->last_route) {
   1.680 +			GList *rcpt_node;
   1.681 +			foreach(msgout_cloned->rcpt_list, rcpt_node) {
   1.682 +				address *rcpt = (address *) (rcpt_node->data);
   1.683 +				rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
   1.684 +			}
   1.685 +		}
   1.686 +
   1.687 +		route_prepare_msgout(route, msgout_cloned);
   1.688 +		msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
   1.689  	}
   1.690  
   1.691 -	if (msgout_list_deliver != NULL) {
   1.692 -		if (deliver_route_msgout_list(route, msgout_list_deliver))
   1.693 +	if (msgout_list_deliver) {
   1.694 +		if (deliver_route_msgout_list(route, msgout_list_deliver)) {
   1.695  			ok = TRUE;
   1.696 +		}
   1.697  		destroy_msg_out_list(msgout_list_deliver);
   1.698  	}
   1.699  	return ok;
   1.700 @@ -552,15 +613,16 @@
   1.701  
   1.702  	foreach(msgout->rcpt_list, rcpt_node) {
   1.703  		address *rcpt = (address *) (rcpt_node->data);
   1.704 -		if (addr_is_delivered(rcpt) || addr_is_failed(rcpt))
   1.705 +		if (addr_is_delivered(rcpt) || addr_is_failed(rcpt)) {
   1.706  			msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
   1.707 +		}
   1.708  	}
   1.709  }
   1.710  
   1.711 -/* after delivery attempts, we check if there are any rcpt addresses left in the message.
   1.712 -   If all addresses have been completed, the spool files will be deleted,
   1.713 -   otherwise the header spool will be written back.
   1.714 -   We never changed the data spool, so there is no need to write that back.
   1.715 +/* after delivery attempts, we check if there are any rcpt addresses left in
   1.716 +   the message. If all addresses have been completed, the spool files will be
   1.717 +   deleted, otherwise the header spool will be written back. We never changed
   1.718 +   the data spool, so there is no need to write that back.
   1.719  
   1.720     returns TRUE if all went well.
   1.721  */
   1.722 @@ -568,7 +630,6 @@
   1.723  deliver_finish(msg_out * msgout)
   1.724  {
   1.725  	GList *rcpt_node;
   1.726 -	gboolean ok = FALSE;
   1.727  	message *msg = msgout->msg;
   1.728  	gboolean finished = TRUE;
   1.729  
   1.730 @@ -578,11 +639,13 @@
   1.731  	   were always set on the original address structs */
   1.732  	foreach(msg->rcpt_list, rcpt_node) {
   1.733  		address *rcpt = (address *) (rcpt_node->data);
   1.734 -		if (!addr_is_finished_children(rcpt))
   1.735 +		if (!addr_is_finished_children(rcpt)) {
   1.736  			finished = FALSE;
   1.737 -		else {
   1.738 -			/* if ALL children have been delivered, mark parent as delivered.
   1.739 -			   if there is one or more not delivered, it must have failed, we mark the parent as failed as well.
   1.740 +		} else {
   1.741 +			/* if ALL children have been delivered, mark parent as
   1.742 +			   delivered. if there is one or more not delivered,
   1.743 +			   it must have failed, we mark the parent as failed
   1.744 +			   as well.
   1.745  			 */
   1.746  			if (addr_is_delivered_children(rcpt)) {
   1.747  				addr_mark_delivered(rcpt);
   1.748 @@ -592,19 +655,22 @@
   1.749  		}
   1.750  	}
   1.751  
   1.752 -	if (!finished) {
   1.753 -		/* one not delivered address was found */
   1.754 -		if (spool_write(msg, FALSE)) {
   1.755 -			ok = TRUE;
   1.756 -			DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
   1.757 -		} else
   1.758 -			logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
   1.759 -	} else {
   1.760 -		ok = spool_delete_all(msg);
   1.761 -		if (ok)
   1.762 +	if (finished) {
   1.763 +		if (spool_delete_all(msg)) {
   1.764  			logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
   1.765 +			return TRUE;
   1.766 +		}
   1.767 +		return FALSE;
   1.768  	}
   1.769 -	return ok;
   1.770 +
   1.771 +	/* one not delivered address was found */
   1.772 +	if (!spool_write(msg, FALSE)) {
   1.773 +		logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
   1.774 +		return FALSE;
   1.775 +	}
   1.776 +
   1.777 +	DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
   1.778 +	return TRUE;
   1.779  }
   1.780  
   1.781  gboolean
   1.782 @@ -614,8 +680,9 @@
   1.783  	GList *msgout_node;
   1.784  	foreach(msgout_list, msgout_node) {
   1.785  		msg_out *msgout = (msg_out *) (msgout_node->data);
   1.786 -		if (!deliver_finish(msgout))
   1.787 +		if (!deliver_finish(msgout)) {
   1.788  			ok = FALSE;
   1.789 +		}
   1.790  	}
   1.791  	return ok;
   1.792  }
   1.793 @@ -624,28 +691,36 @@
   1.794  deliver_msgout_list_online(GList * msgout_list)
   1.795  {
   1.796  	GList *rf_list = NULL;
   1.797 -	gchar *connect_name = detect_online();
   1.798 +	gchar *connect_name = NULL;
   1.799  	gboolean ok = FALSE;
   1.800  
   1.801 -	if (connect_name != NULL) {
   1.802 -		logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
   1.803 -		/* we are online! */
   1.804 -		rf_list = (GList *) table_find(conf.connect_routes, connect_name);
   1.805 -		if (rf_list != NULL) {
   1.806 -			GList *route_list = read_route_list(rf_list, FALSE);
   1.807 -			if (route_list) {
   1.808 -				GList *route_node;
   1.809 -				foreach(route_list, route_node) {
   1.810 -					connect_route *route = (connect_route *) (route_node->data);
   1.811 -					ok = deliver_route_msg_list(route, msgout_list);
   1.812 -				}
   1.813 -				destroy_route_list(route_list);
   1.814 -			} else
   1.815 -				logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
   1.816 -		} else {
   1.817 -			logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
   1.818 -		}
   1.819 +	connect_name = detect_online();
   1.820 +	if (!connect_name) {
   1.821 +		return FALSE;
   1.822  	}
   1.823 +
   1.824 +	/* we are online! */
   1.825 +	logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
   1.826 +
   1.827 +	rf_list = (GList *) table_find(conf.connect_routes, connect_name);
   1.828 +	if (!rf_list) {
   1.829 +		logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
   1.830 +		return FALSE;
   1.831 +	}
   1.832 +
   1.833 +	GList *route_list = read_route_list(rf_list, FALSE);
   1.834 +	if (!route_list) {
   1.835 +		logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
   1.836 +		return FALSE;
   1.837 +	}
   1.838 +
   1.839 +	GList *route_node;
   1.840 +	foreach(route_list, route_node) {
   1.841 +		connect_route *route = (connect_route *) (route_node->data);
   1.842 +		/* TODO: ok gets overwritten */
   1.843 +		ok = deliver_route_msg_list(route, msgout_list);
   1.844 +	}
   1.845 +	destroy_route_list(route_list);
   1.846  	return ok;
   1.847  }
   1.848  
   1.849 @@ -653,7 +728,9 @@
   1.850  deliver_msg_list(GList * msg_list, guint flags)
   1.851  {
   1.852  	GList *msgout_list = create_msg_out_list(msg_list);
   1.853 -	GList *local_msgout_list = NULL, *localnet_msgout_list = NULL, *other_msgout_list = NULL;
   1.854 +	GList *local_msgout_list = NULL;
   1.855 +	GList *localnet_msgout_list = NULL;
   1.856 +	GList *other_msgout_list = NULL;
   1.857  	GList *msgout_node;
   1.858  	GList *alias_table = NULL;
   1.859  	gboolean ok = TRUE;
   1.860 @@ -679,8 +756,11 @@
   1.861  		rcpt_list = g_list_copy(msgout->msg->rcpt_list);
   1.862  		if (conf.log_user) {
   1.863  			address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
   1.864 -			if (addr)
   1.865 +			if (addr) {
   1.866  				rcpt_list = g_list_prepend(rcpt_list, addr);
   1.867 +			} else {
   1.868 +				logwrite(LOG_ALERT, "invalid log_user address `%s', ignoring\n", conf.log_user);
   1.869 +			}
   1.870  		}
   1.871  		if (alias_table) {
   1.872  			GList *aliased_rcpt_list;
   1.873 @@ -714,8 +794,9 @@
   1.874  		}
   1.875  	}
   1.876  
   1.877 -	if (alias_table)
   1.878 +	if (alias_table) {
   1.879  		destroy_table(alias_table);
   1.880 +	}
   1.881  
   1.882  	/* actual delivery */
   1.883  
   1.884 @@ -723,8 +804,9 @@
   1.885  		DEBUG(5) debugf("local_msgout_list\n");
   1.886  		foreach(local_msgout_list, msgout_node) {
   1.887  			msg_out *msgout = (msg_out *) (msgout_node->data);
   1.888 -			if (!deliver_local(msgout))
   1.889 +			if (!deliver_local(msgout)) {
   1.890  				ok = FALSE;
   1.891 +			}
   1.892  		}
   1.893  		destroy_msg_out_list(local_msgout_list);
   1.894  	}
   1.895 @@ -734,15 +816,17 @@
   1.896  		GList *route_node;
   1.897  
   1.898  		DEBUG(5) debugf("localnet_msgout_list\n");
   1.899 -		if (conf.local_net_routes)
   1.900 +		if (conf.local_net_routes) {
   1.901  			route_list = read_route_list(conf.local_net_routes, TRUE);
   1.902 -		else
   1.903 +		} else {
   1.904  			route_list = g_list_append(NULL, create_local_route());
   1.905 +		}
   1.906  
   1.907  		foreach(route_list, route_node) {
   1.908  			connect_route *route = (connect_route *) (route_node->data);
   1.909 -			if (!deliver_route_msg_list(route, localnet_msgout_list))
   1.910 +			if (!deliver_route_msg_list(route, localnet_msgout_list)) {
   1.911  				ok = FALSE;
   1.912 +			}
   1.913  		}
   1.914  		destroy_msg_out_list(localnet_msgout_list);
   1.915  		destroy_route_list(route_list);
   1.916 @@ -750,8 +834,9 @@
   1.917  
   1.918  	if (other_msgout_list) {
   1.919  		DEBUG(5) debugf("other_msgout_list\n");
   1.920 -		if (!deliver_msgout_list_online(other_msgout_list))
   1.921 +		if (!deliver_msgout_list_online(other_msgout_list)) {
   1.922  			ok = FALSE;
   1.923 +		}
   1.924  		destroy_msg_out_list(other_msgout_list);
   1.925  	}
   1.926