comparison src/deliver.c @ 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 5f9f3a65032e
children f10a56dc7481
comparison
equal deleted inserted replaced
279:1aa107c6b1e5 280:72e377210d5e
40 address *rcpt = (address *) (rcpt_node->data); 40 address *rcpt = (address *) (rcpt_node->data);
41 41
42 if (addr_is_defered(rcpt)) { 42 if (addr_is_defered(rcpt)) {
43 if ((now - msg->received_time) >= conf.max_defer_time) { 43 if ((now - msg->received_time) >= conf.max_defer_time) {
44 addr_mark_failed(rcpt); 44 addr_mark_failed(rcpt);
45 } else 45 } else {
46 defered_list = g_list_prepend(defered_list, rcpt); 46 defered_list = g_list_prepend(defered_list, rcpt);
47 } 47 }
48 if (addr_is_failed(rcpt)) 48 }
49 if (addr_is_failed(rcpt)) {
49 failed_list = g_list_prepend(failed_list, rcpt); 50 failed_list = g_list_prepend(failed_list, rcpt);
50 } 51 }
51 if (failed_list != NULL) { 52 }
53 if (failed_list) {
52 ok_fail = fail_msg(msg, conf.errmsg_file, failed_list, err_fmt, args); 54 ok_fail = fail_msg(msg, conf.errmsg_file, failed_list, err_fmt, args);
53 g_list_free(failed_list); 55 g_list_free(failed_list);
54 } 56 }
55 if (defered_list != NULL) { 57 if (defered_list) {
56 ok_warn = warn_msg(msg, conf.warnmsg_file, defered_list, err_fmt, args); 58 ok_warn = warn_msg(msg, conf.warnmsg_file, defered_list, err_fmt, args);
57 g_list_free(defered_list); 59 g_list_free(defered_list);
58 } 60 }
59 va_end(args); 61 va_end(args);
60 return ok_fail && ok_warn; 62 return ok_fail && ok_warn;
62 64
63 static gint 65 static gint
64 _g_list_strcasecmp(gconstpointer a, gconstpointer b) 66 _g_list_strcasecmp(gconstpointer a, gconstpointer b)
65 { 67 {
66 return (gint) strcasecmp(a, b); 68 return (gint) strcasecmp(a, b);
69 }
70
71 gboolean
72 deliver_local_mbox(message* msg, GList* hdr_list, address* rcpt, address* env_addr)
73 {
74 DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid);
75 if (append_file(msg, hdr_list, rcpt->local_part)) {
76 if (env_addr != rcpt) {
77 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);
78 } else {
79 logwrite(LOG_NOTICE, "%s => <%s@%s> with mbox\n", msg->uid, rcpt->local_part, rcpt->domain);
80 }
81 addr_mark_delivered(rcpt);
82 return TRUE;
83 }
84
85 /* prevents 'Resource temporarily unavailable (11)' */
86 if (errno != EAGAIN) {
87 addr_mark_failed(rcpt);
88 } else {
89 addr_mark_defered(rcpt);
90 }
91 return FALSE;
92 }
93
94 gboolean
95 deliver_local_pipe(message* msg, GList* hdr_list, address* rcpt, address* env_addr)
96 {
97 guint flags;
98
99 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
100
101 flags = (conf.pipe_fromline) ? MSGSTR_FROMLINE : 0;
102 flags |= (conf.pipe_fromhack) ? MSGSTR_FROMHACK : 0;
103 if (pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]), flags)) {
104 logwrite(LOG_NOTICE, "%s => %s <%s@%s> with pipe\n",
105 msg->uid, rcpt->local_part, env_addr->local_part, env_addr->domain);
106 addr_mark_delivered(rcpt);
107 return TRUE;
108 }
109
110 if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
111 addr_mark_failed(rcpt);
112 } else {
113 addr_mark_defered(rcpt);
114 /* has no effect yet, except that mail remains in spool */
115 }
116 return FALSE;
117 }
118
119 gboolean
120 deliver_local_mda(message* msg, GList* hdr_list, address* rcpt, address* env_addr)
121 {
122 gboolean ok = FALSE;
123 gchar *cmd = g_malloc(256);
124 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
125 guint flags;
126
127 DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid);
128
129 if (!expand(var_table, conf.mda, cmd, 256)) {
130 logwrite(LOG_ALERT, "could not expand string %s\n", conf.mda);
131 destroy_table(var_table);
132 return FALSE;
133 }
134
135 flags = (conf.mda_fromline) ? MSGSTR_FROMLINE : 0;
136 flags |= (conf.mda_fromhack) ? MSGSTR_FROMHACK : 0;
137 if (pipe_out(msg, hdr_list, rcpt, cmd, flags)) {
138 logwrite(LOG_NOTICE, "%s => %s@%s with mda (cmd = '%s')\n",
139 msg->uid, rcpt->local_part, rcpt->domain, cmd);
140 addr_mark_delivered(rcpt);
141 ok = TRUE;
142 } else if ((errno != (1024 + EX_TEMPFAIL)) && (errno != EAGAIN)) {
143 addr_mark_failed(rcpt);
144 } else {
145 addr_mark_defered(rcpt);
146 /* has no effect yet, except that mail remains in spool */
147 }
148
149 destroy_table(var_table);
150 return ok;
67 } 151 }
68 152
69 gboolean 153 gboolean
70 deliver_local(msg_out * msgout) 154 deliver_local(msg_out * msgout)
71 { 155 {
72 message *msg = msgout->msg; 156 message *msg = msgout->msg;
73 GList *rcpt_list = msgout->rcpt_list; 157 GList *rcpt_list = msgout->rcpt_list;
74 GList *rcpt_node; 158 GList *rcpt_node;
75 gboolean ok = TRUE, flag = FALSE, ok_fail = FALSE; 159 gboolean ok = FALSE, flag = FALSE, ok_fail = FALSE;
76 160
77 DEBUG(5) debugf("deliver_local entered\n"); 161 DEBUG(5) debugf("deliver_local entered\n");
78 162
79 flag = (msg->data_list == NULL); 163 flag = (msg->data_list == NULL);
80 if (flag) { 164 if (flag && !spool_read_data(msg)) {
81 if (!(ok = spool_read_data(msg))) { 165 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
82 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid); 166 return FALSE;
83 } 167 }
84 } 168
85 if (!ok)
86 return FALSE;
87
88 ok = FALSE;
89 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) { 169 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
90 GList *hdr_list; 170 GList *hdr_list;
91 address *rcpt = (address *) (rcpt_node->data); 171 address *rcpt = (address *) (rcpt_node->data);
92 address *env_addr = addr_find_ancestor(rcpt); 172 address *env_addr = addr_find_ancestor(rcpt);
93 address *ret_path = msg->return_path; 173 address *ret_path = msg->return_path;
94 header *retpath_hdr, *envto_hdr; 174 header *retpath_hdr, *envto_hdr;
95 175
96 /* we need a private copy of the hdr list because we add headers here that belong to the rcpt only. 176 /* we need a private copy of the hdr list because we add headers
97 g_list_copy copies only the nodes, so it is safe to g_list_free it */ 177 here that belong to the rcpt only. g_list_copy copies only
178 the nodes, so it is safe to g_list_free it */
98 hdr_list = g_list_copy(msg->hdr_list); 179 hdr_list = g_list_copy(msg->hdr_list);
99 retpath_hdr = create_header(HEAD_ENVELOPE_TO, "Envelope-to: %s\n", addr_string(env_addr)); 180 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)); 181 envto_hdr = create_header(HEAD_RETURN_PATH, "Return-path: %s\n", addr_string(ret_path));
101 182
102 hdr_list = g_list_prepend(hdr_list, envto_hdr); 183 hdr_list = g_list_prepend(hdr_list, envto_hdr);
103 hdr_list = g_list_prepend(hdr_list, retpath_hdr); 184 hdr_list = g_list_prepend(hdr_list, retpath_hdr);
104 185
105 if (rcpt->local_part[0] == '|') { 186 if (rcpt->local_part[0] == '|') {
106 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid); 187 /* probably for expanded aliases, but why not done
107 if (pipe_out(msg, hdr_list, rcpt, &(rcpt->local_part[1]), 188 like with the mda? //meillo 2010-12-06 */
108 (conf.pipe_fromline ? MSGSTR_FROMLINE : 0) 189 if (deliver_local_pipe(msg, hdr_list, rcpt, env_addr)) {
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; 190 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 } 191 }
121 } else { 192 } else {
122 /* figure out which mailbox type should be used for this user */ 193 /* figure out which mailbox type should be used for this user */
123 gchar *user = rcpt->local_part; 194 gchar *user = rcpt->local_part;
124 gchar *mbox_type = conf.mbox_default; 195 gchar *mbox_type = conf.mbox_default;
125 196
126 if (g_list_find_custom (conf.mbox_users, user, _g_list_strcasecmp) != NULL) 197 if (g_list_find_custom (conf.mbox_users, user, _g_list_strcasecmp)) {
127 mbox_type = "mbox"; 198 mbox_type = "mbox";
128 else if (g_list_find_custom (conf.mda_users, user, _g_list_strcasecmp) != NULL) 199 } else if (g_list_find_custom (conf.mda_users, user, _g_list_strcasecmp)) {
129 mbox_type = "mda"; 200 mbox_type = "mda";
201 }
130 202
131 if (strcmp(mbox_type, "mbox") == 0) { 203 if (strcmp(mbox_type, "mbox") == 0) {
132 DEBUG(1) debugf("attempting to deliver %s with mbox\n", msg->uid); 204 if (deliver_local_mbox(msg, hdr_list, rcpt, env_addr)) {
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; 205 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 } 206 }
151
152 } else if (strcmp(mbox_type, "mda") == 0) { 207 } else if (strcmp(mbox_type, "mda") == 0) {
153 if (conf.mda) { 208 if (conf.mda) {
154 gchar *cmd = g_malloc(256); 209 if (deliver_local_mda(msg, hdr_list, rcpt, env_addr)) {
155 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt); 210 ok = TRUE;
156 211 }
157 DEBUG(1) debugf("attempting to deliver %s with mda\n", msg->uid); 212 } else {
158
159 if (expand(var_table, conf.mda, cmd, 256)) {
160
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);
176
177 destroy_table(var_table);
178 } else
179 logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n"); 213 logwrite(LOG_ALERT, "mbox type is mda, but no mda command given in configuration\n");
180 } else 214 }
215
216 } else {
181 logwrite(LOG_ALERT, "unknown mbox type '%s'\n", mbox_type); 217 logwrite(LOG_ALERT, "unknown mbox type '%s'\n", mbox_type);
218 }
182 } 219 }
183 220
184 destroy_header(retpath_hdr); 221 destroy_header(retpath_hdr);
185 destroy_header(envto_hdr); 222 destroy_header(envto_hdr);
186 223
187 g_list_free(hdr_list); 224 g_list_free(hdr_list);
188 } 225 }
189 ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)", ext_strerror(errno), errno); 226 ok_fail = delivery_failures(msg, rcpt_list, "%s (%d)", ext_strerror(errno), errno);
190 227
191 if (flag) 228 if (flag) {
192 msg_free_data(msg); 229 msg_free_data(msg);
193 if (ok || ok_fail) 230 }
231 if (ok || ok_fail) {
194 deliver_finish(msgout); 232 deliver_finish(msgout);
233 }
195 234
196 return ok; 235 return ok;
197 } 236 }
198 237
199 /* make a list of rcpt's of a message that are local return a new copy of the list */ 238 /* make a list of rcpt's of a message that are local return a new copy of the list */
234 return FALSE; 273 return FALSE;
235 } 274 }
236 275
237 foreach(msgout_list, msgout_node) { 276 foreach(msgout_list, msgout_node) {
238 msg_out *msgout = (msg_out *) (msgout_node->data); 277 msg_out *msgout = (msg_out *) (msgout_node->data);
239 gboolean flag, ok_msg = TRUE, ok_fail = FALSE; 278 gboolean flag, ok_fail = FALSE;
240 message *msg = msgout->msg; 279 message *msg = msgout->msg;
241 GList *rcpt_node, *rcpt_list = msgout->rcpt_list; 280 GList *rcpt_node, *rcpt_list = msgout->rcpt_list;
242 281
243 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid); 282 DEBUG(1) debugf("attempting to deliver %s with pipe\n", msg->uid);
244 283
245 flag = (msg->data_list == NULL); 284 flag = (msg->data_list == NULL);
246 if (flag) { 285 if (flag && !spool_read_data(msg)) {
247 if (!(ok_msg = spool_read_data(msg))) { 286 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
248 logwrite(LOG_ALERT, "could not open data spool file for %s\n", msg->uid);
249 }
250 }
251 if (!ok_msg)
252 continue; 287 continue;
288 }
253 289
254 ok = FALSE; 290 ok = FALSE;
255 foreach(rcpt_list, rcpt_node) { 291 foreach(rcpt_list, rcpt_node) {
256 address *rcpt = (address *) (rcpt_node->data); 292 address *rcpt = (address *) (rcpt_node->data);
257 gchar *cmd = g_malloc(256); 293 gchar *cmd = g_malloc(256);
258 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt); 294 GList *var_table = var_table_rcpt(var_table_msg(NULL, msg), rcpt);
259 295
260 DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n", msg->uid, rcpt->local_part, rcpt->domain); 296 DEBUG(1) debugf("attempting to deliver %s to %s@%s with pipe\n", msg->uid, rcpt->local_part, rcpt->domain);
261 297
262 if (expand(var_table, route->pipe, cmd, 256)) { 298 if (!expand(var_table, route->pipe, cmd, 256)) {
299 logwrite(LOG_ALERT, "could not expand string %s\n", route->pipe);
300 } else {
263 301
264 if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0) 302 if (pipe_out(msg, msg->hdr_list, rcpt, cmd, (route->pipe_fromline ? MSGSTR_FROMLINE : 0)
265 | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) { 303 | (route->pipe_fromhack ? MSGSTR_FROMHACK : 0))) {
266 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n", 304 logwrite(LOG_NOTICE, "%s => %s@%s with pipe (cmd = '%s')\n",
267 msg->uid, rcpt->local_part, rcpt->domain, cmd); 305 msg->uid, rcpt->local_part, rcpt->domain, cmd);
274 addr_mark_failed(rcpt); 312 addr_mark_failed(rcpt);
275 } else { 313 } else {
276 addr_mark_defered(rcpt); 314 addr_mark_defered(rcpt);
277 } 315 }
278 } 316 }
279 } else 317 }
280 logwrite(LOG_ALERT, "could not expand string %s\n", route->pipe);
281 318
282 destroy_table(var_table); 319 destroy_table(var_table);
283 } 320 }
284 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno)); 321 ok_fail = delivery_failures(msg, rcpt_list, "%s", strerror(errno));
285 322
286 if (flag) 323 if (flag) {
287 msg_free_data(msg); 324 msg_free_data(msg);
288 325 }
289 if (ok || ok_fail) 326 if (ok || ok_fail) {
290 deliver_finish(msgout); 327 deliver_finish(msgout);
291 } 328 }
292 329 }
293 return ok; 330
294 } 331 return ok;
295 332 }
296 /* deliver list of messages to one host and finishes them if the message was delivered to at least one rcpt. 333
334 /* deliver list of messages to one host and finishes them if the message was
335 delivered to at least one rcpt.
297 Returns TRUE if at least one msg was delivered to at least one rcpt. 336 Returns TRUE if at least one msg was delivered to at least one rcpt.
298 */ 337 */
299 gboolean 338 gboolean
300 deliver_msglist_host_smtp(connect_route * route, GList * msgout_list, gchar * host, GList * res_list) 339 deliver_msglist_host_smtp(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
301 { 340 {
303 GList *msgout_node; 342 GList *msgout_node;
304 smtp_base *psb; 343 smtp_base *psb;
305 gint port = 25; 344 gint port = 25;
306 345
307 /* paranoid check: */ 346 /* paranoid check: */
308 if (msgout_list == NULL) { 347 if (!msgout_list) {
309 logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n"); 348 logwrite(LOG_ALERT, "Ooops: empty list of messages in deliver_msglist_host()\n");
310 return FALSE; 349 return FALSE;
311 } 350 }
312 351
313 if (host == NULL) { 352 if (!host) {
314 /* XXX: what if mail_host isn't set? Is this possible? */ 353 /* XXX: what if mail_host isn't set? Is this possible? */
315 host = route->mail_host->address; 354 host = route->mail_host->address;
316 port = route->mail_host->port; 355 port = route->mail_host->port;
317 } 356 }
318 357
319 if ((psb = (route->wrapper ? smtp_out_open_child(route->wrapper) : smtp_out_open(host, port, res_list)))) { 358 if (route->wrapper) {
320 359 psb = smtp_out_open_child(route->wrapper);
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 }
326
327 set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
328
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, route->instant_helo)) {
334
335 if (!route->do_pipelining)
336 psb->use_pipelining = FALSE;
337
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;
342
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 }
351
352 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
353
354 ok_fail = delivery_failures(msg, msgout->rcpt_list,
355 "while connected with %s, the server replied\n\t%s", host, psb->buffer);
356
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);
367
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);
384
385 foreach(msgout_list, msgout_node) {
386 msg_out *msgout = (msg_out *) (msgout_node->data);
387 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
388
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 { 360 } else {
361 psb = smtp_out_open(host, port, res_list);
362 }
363
364 if (!psb) {
397 /* smtp_out_open() failed */ 365 /* smtp_out_open() failed */
398 foreach(msgout_list, msgout_node) { 366 foreach(msgout_list, msgout_node) {
399 msg_out *msgout = (msg_out *) (msgout_node->data); 367 msg_out *msgout = (msg_out *) (msgout_node->data);
400 GList *rcpt_node; 368 GList *rcpt_node;
401 369
402 for (rcpt_node = g_list_first(msgout->rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) { 370 for (rcpt_node = g_list_first(msgout->rcpt_list);
371 rcpt_node;
372 rcpt_node = g_list_next(rcpt_node)) {
403 address *rcpt = (address *) (rcpt_node->data); 373 address *rcpt = (address *) (rcpt_node->data);
374 gboolean ret = FALSE;
404 375
405 addr_unmark_delivered(rcpt); 376 addr_unmark_delivered(rcpt);
406 if (route->connect_error_fail) { 377 if (route->connect_error_fail) {
407 addr_mark_failed(rcpt); 378 addr_mark_failed(rcpt);
408 } else { 379 } else {
409 addr_mark_defered(rcpt); 380 addr_mark_defered(rcpt);
410 } 381 }
411 if (route->wrapper 382 if (route->wrapper) {
412 ? delivery_failures(msgout->msg, msgout->rcpt_list, "could not open wrapper:\n\t%s", 383 ret = delivery_failures(msgout->msg, msgout->rcpt_list, "could not open wrapper:\n\t%s", strerror(errno));
413 strerror(errno)) 384 } else {
414 : delivery_failures(msgout->msg, msgout->rcpt_list, "could not open connection to %s:%d :\n\t%s", 385 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));
415 host, port, h_errno != 0 ? hstrerror(h_errno) : strerror(errno))) 386 }
387 if (ret) {
416 deliver_finish(msgout); 388 deliver_finish(msgout);
417 } 389 }
418 } 390 }
419 } 391 }
392 return ok;
393 }
394
395
396 if (route->wrapper) {
397 /* it seems as if the remote_host is only set for logging
398 /* XXX: this could probably be moved into smtp_out_open_child() */
399 psb->remote_host = host;
400 }
401
402 set_heloname(psb, route->helo_name ? route->helo_name : conf.host_name, route->do_correct_helo);
403
404 #ifdef ENABLE_AUTH
405 if ((route->auth_name) && (route->auth_login) && (route->auth_secret)) {
406 set_auth(psb, route->auth_name, route->auth_login, route->auth_secret);
407 }
408 #endif
409 if (!smtp_out_init(psb, route->instant_helo)) {
410 /* smtp_out_init() failed */
411 if ((psb->error==smtp_fail) || (psb->error==smtp_trylater) || (psb->error==smtp_syntax)) {
412 smtp_out_quit(psb);
413
414 foreach(msgout_list, msgout_node) {
415 msg_out *msgout = (msg_out *) (msgout_node->data);
416 smtp_out_mark_rcpts(psb, msgout->rcpt_list);
417
418 if (delivery_failures(msgout->msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", host, psb->buffer)) {
419 deliver_finish(msgout);
420 }
421 }
422 }
423 destroy_smtpbase(psb);
424 return ok;
425 }
426
427 if (!route->do_pipelining) {
428 psb->use_pipelining = FALSE;
429 }
430
431 foreach(msgout_list, msgout_node) {
432 msg_out *msgout = (msg_out *) (msgout_node->data);
433 gboolean flag, ok_msg = FALSE, ok_fail = FALSE;
434 message *msg = msgout->msg;
435
436 /* we may have to read the data at this point and remember if we did */
437 flag = (msg->data_list == NULL);
438 if (flag && !spool_read_data(msg)) {
439 logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
440 break;
441 }
442
443 smtp_out_msg(psb, msg, msgout->return_path, msgout->rcpt_list, msgout->hdr_list);
444
445 ok_fail = delivery_failures(msg, msgout->rcpt_list, "while connected with %s, the server replied\n\t%s", host, psb->buffer);
446
447 if ((psb->error == smtp_eof) || (psb->error == smtp_timeout)) {
448 /* connection lost */
449 break;
450 } else if (psb->error != smtp_ok) {
451 if (g_list_next(msgout_node) && !smtp_out_rset(psb)) {
452 break;
453 }
454 }
455 ok_msg = (psb->error == smtp_ok);
456
457 if (flag) {
458 msg_free_data(msg);
459 }
460 if (ok_msg) {
461 ok = TRUE;
462 }
463 if (ok_msg || ok_fail) {
464 deliver_finish(msgout);
465 }
466 }
467 if (psb->error == smtp_ok || (psb->error == smtp_fail)
468 || (psb->error == smtp_trylater) || (psb->error == smtp_syntax)) {
469 smtp_out_quit(psb);
470 }
471 destroy_smtpbase(psb);
420 return ok; 472 return ok;
421 } 473 }
422 474
423 gboolean 475 gboolean
424 deliver_msglist_host(connect_route * route, GList * msgout_list, gchar * host, GList * res_list) 476 deliver_msglist_host(connect_route * route, GList * msgout_list, gchar * host, GList * res_list)
437 */ 489 */
438 gboolean 490 gboolean
439 deliver_route_msgout_list(connect_route * route, GList * msgout_list) 491 deliver_route_msgout_list(connect_route * route, GList * msgout_list)
440 { 492 {
441 gboolean ok = FALSE; 493 gboolean ok = FALSE;
494 GList *mo_ph_list;
495 GList *mo_ph_node;
442 496
443 DEBUG(5) debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name); 497 DEBUG(5) debugf("deliver_route_msgout_list entered, route->name = %s\n", route->name);
444 498
445 if (route->mail_host) { 499 if (route->mail_host) {
446 /* this is easy... deliver everything to a smart host for relay */ 500 /* this is easy... deliver everything to a smart host for relay */
447 if (deliver_msglist_host(route, msgout_list, NULL, route->resolve_list)) 501 return deliver_msglist_host(route, msgout_list, NULL, route->resolve_list);
502 }
503
504 /* this is not easy... */
505
506 mo_ph_list = route_msgout_list(route, msgout_list);
507 /* okay, now we have ordered our messages by the hosts. */
508 if (!mo_ph_list) {
509 return FALSE;
510 }
511
512 /* TODO: It would be nice to be able to fork for each host.
513 We cannot do that yet because of complications with finishing the
514 messages. Threads could be a solution because they use the same
515 memory. But we are not thread safe yet...
516 */
517 foreach(mo_ph_list, mo_ph_node) {
518 msgout_perhost *mo_ph = (msgout_perhost *) (mo_ph_node->data);
519 if (deliver_msglist_host(route, mo_ph->msgout_list, mo_ph->host, route->resolve_list)) {
448 ok = TRUE; 520 ok = TRUE;
449 521 }
450 } else { 522 destroy_msgout_perhost(mo_ph);
451 /* this is not easy... */ 523 }
452 GList *mo_ph_list; 524 g_list_free(mo_ph_list);
453
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;
467
468 destroy_msgout_perhost(mo_ph);
469 }
470 g_list_free(mo_ph_list);
471 }
472 }
473 return ok; 525 return ok;
474 } 526 }
475 527
476 /* 528 /*
477 calls route_prepare_msg() 529 calls route_prepare_msg()
490 msg_out *msgout = (msg_out *) (msgout_node->data); 542 msg_out *msgout = (msg_out *) (msgout_node->data);
491 msg_out *msgout_cloned = clone_msg_out(msgout); 543 msg_out *msgout_cloned = clone_msg_out(msgout);
492 GList *rcpt_list_non_delivered = NULL; 544 GList *rcpt_list_non_delivered = NULL;
493 GList *rcpt_node; 545 GList *rcpt_node;
494 546
495 /* we have to delete already delivered rcpt's because a previous route may have delivered to it */ 547 /* we have to delete already delivered rcpt's because a
548 previous route may have delivered to it */
496 foreach(msgout_cloned->rcpt_list, rcpt_node) { 549 foreach(msgout_cloned->rcpt_list, rcpt_node) {
497 address *rcpt = (address *) (rcpt_node->data); 550 address *rcpt = (address *) (rcpt_node->data);
498 /* failed addresses already have been bounced - there should be a better way to handle those. */ 551 /* failed addresses already have been bounced;
552 there should be a better way to handle those. */
499 if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt) 553 if (!addr_is_delivered(rcpt) && !addr_is_failed(rcpt)
500 && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE)) 554 && !(rcpt->flags & ADDR_FLAG_LAST_ROUTE)) {
501 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt); 555 rcpt_list_non_delivered = g_list_append(rcpt_list_non_delivered, rcpt);
556 }
502 } 557 }
503 g_list_free(msgout_cloned->rcpt_list); 558 g_list_free(msgout_cloned->rcpt_list);
504 msgout_cloned->rcpt_list = rcpt_list_non_delivered; 559 msgout_cloned->rcpt_list = rcpt_list_non_delivered;
505 560
506 if (msgout_cloned->rcpt_list) { 561 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);
511
512 if (rcpt_list_allowed != NULL) {
513 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
514
515 g_list_free(msgout_cloned->rcpt_list);
516 msgout_cloned->rcpt_list = rcpt_list_allowed;
517
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 }
525
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); 562 destroy_msg_out(msgout_cloned);
534 } 563 continue;
535 564 }
536 if (msgout_list_deliver != NULL) { 565
537 if (deliver_route_msgout_list(route, msgout_list_deliver)) 566 if (!route_is_allowed_mail_local(route, msgout->msg->return_path)
567 || !route_is_allowed_return_path(route, msgout->msg-> return_path)) {
568 destroy_msg_out(msgout_cloned);
569 continue;
570 }
571
572 GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
573 msg_rcptlist_route(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
574
575 if (!rcpt_list_allowed) {
576 destroy_msg_out(msgout_cloned);
577 continue;
578 }
579 logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
580
581 g_list_free(msgout_cloned->rcpt_list);
582 msgout_cloned->rcpt_list = rcpt_list_allowed;
583
584 if (route->last_route) {
585 GList *rcpt_node;
586 foreach(msgout_cloned->rcpt_list, rcpt_node) {
587 address *rcpt = (address *) (rcpt_node->data);
588 rcpt->flags |= ADDR_FLAG_LAST_ROUTE;
589 }
590 }
591
592 route_prepare_msgout(route, msgout_cloned);
593 msgout_list_deliver = g_list_append(msgout_list_deliver, msgout_cloned);
594 }
595
596 if (msgout_list_deliver) {
597 if (deliver_route_msgout_list(route, msgout_list_deliver)) {
538 ok = TRUE; 598 ok = TRUE;
599 }
539 destroy_msg_out_list(msgout_list_deliver); 600 destroy_msg_out_list(msgout_list_deliver);
540 } 601 }
541 return ok; 602 return ok;
542 } 603 }
543 604
550 GList *rcpt_node; 611 GList *rcpt_node;
551 message *msg = msgout->msg; 612 message *msg = msgout->msg;
552 613
553 foreach(msgout->rcpt_list, rcpt_node) { 614 foreach(msgout->rcpt_list, rcpt_node) {
554 address *rcpt = (address *) (rcpt_node->data); 615 address *rcpt = (address *) (rcpt_node->data);
555 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt)) 616 if (addr_is_delivered(rcpt) || addr_is_failed(rcpt)) {
556 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt); 617 msg->non_rcpt_list = g_list_append(msg->non_rcpt_list, rcpt);
557 } 618 }
558 } 619 }
559 620 }
560 /* after delivery attempts, we check if there are any rcpt addresses left in the message. 621
561 If all addresses have been completed, the spool files will be deleted, 622 /* after delivery attempts, we check if there are any rcpt addresses left in
562 otherwise the header spool will be written back. 623 the message. If all addresses have been completed, the spool files will be
563 We never changed the data spool, so there is no need to write that back. 624 deleted, otherwise the header spool will be written back. We never changed
625 the data spool, so there is no need to write that back.
564 626
565 returns TRUE if all went well. 627 returns TRUE if all went well.
566 */ 628 */
567 gboolean 629 gboolean
568 deliver_finish(msg_out * msgout) 630 deliver_finish(msg_out * msgout)
569 { 631 {
570 GList *rcpt_node; 632 GList *rcpt_node;
571 gboolean ok = FALSE;
572 message *msg = msgout->msg; 633 message *msg = msgout->msg;
573 gboolean finished = TRUE; 634 gboolean finished = TRUE;
574 635
575 update_non_rcpt_list(msgout); 636 update_non_rcpt_list(msgout);
576 637
577 /* we NEVER made copies of the addresses, flags affecting addresses 638 /* we NEVER made copies of the addresses, flags affecting addresses
578 were always set on the original address structs */ 639 were always set on the original address structs */
579 foreach(msg->rcpt_list, rcpt_node) { 640 foreach(msg->rcpt_list, rcpt_node) {
580 address *rcpt = (address *) (rcpt_node->data); 641 address *rcpt = (address *) (rcpt_node->data);
581 if (!addr_is_finished_children(rcpt)) 642 if (!addr_is_finished_children(rcpt)) {
582 finished = FALSE; 643 finished = FALSE;
583 else { 644 } else {
584 /* if ALL children have been delivered, mark parent as delivered. 645 /* if ALL children have been delivered, mark parent as
585 if there is one or more not delivered, it must have failed, we mark the parent as failed as well. 646 delivered. if there is one or more not delivered,
647 it must have failed, we mark the parent as failed
648 as well.
586 */ 649 */
587 if (addr_is_delivered_children(rcpt)) { 650 if (addr_is_delivered_children(rcpt)) {
588 addr_mark_delivered(rcpt); 651 addr_mark_delivered(rcpt);
589 } else { 652 } else {
590 addr_mark_failed(rcpt); 653 addr_mark_failed(rcpt);
591 } 654 }
592 } 655 }
593 } 656 }
594 657
595 if (!finished) { 658 if (finished) {
596 /* one not delivered address was found */ 659 if (spool_delete_all(msg)) {
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); 660 logwrite(LOG_NOTICE, "%s completed.\n", msg->uid);
606 } 661 return TRUE;
607 return ok; 662 }
663 return FALSE;
664 }
665
666 /* one not delivered address was found */
667 if (!spool_write(msg, FALSE)) {
668 logwrite(LOG_ALERT, "could not write back spool header for %s\n", msg->uid);
669 return FALSE;
670 }
671
672 DEBUG(2) debugf("spool header for %s written back.\n", msg->uid);
673 return TRUE;
608 } 674 }
609 675
610 gboolean 676 gboolean
611 deliver_finish_list(GList * msgout_list) 677 deliver_finish_list(GList * msgout_list)
612 { 678 {
613 gboolean ok = TRUE; 679 gboolean ok = TRUE;
614 GList *msgout_node; 680 GList *msgout_node;
615 foreach(msgout_list, msgout_node) { 681 foreach(msgout_list, msgout_node) {
616 msg_out *msgout = (msg_out *) (msgout_node->data); 682 msg_out *msgout = (msg_out *) (msgout_node->data);
617 if (!deliver_finish(msgout)) 683 if (!deliver_finish(msgout)) {
618 ok = FALSE; 684 ok = FALSE;
685 }
619 } 686 }
620 return ok; 687 return ok;
621 } 688 }
622 689
623 gboolean 690 gboolean
624 deliver_msgout_list_online(GList * msgout_list) 691 deliver_msgout_list_online(GList * msgout_list)
625 { 692 {
626 GList *rf_list = NULL; 693 GList *rf_list = NULL;
627 gchar *connect_name = detect_online(); 694 gchar *connect_name = NULL;
628 gboolean ok = FALSE; 695 gboolean ok = FALSE;
629 696
630 if (connect_name != NULL) { 697 connect_name = detect_online();
631 logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name); 698 if (!connect_name) {
632 /* we are online! */ 699 return FALSE;
633 rf_list = (GList *) table_find(conf.connect_routes, connect_name); 700 }
634 if (rf_list != NULL) { 701
635 GList *route_list = read_route_list(rf_list, FALSE); 702 /* we are online! */
636 if (route_list) { 703 logwrite(LOG_NOTICE, "detected online configuration %s\n", connect_name);
637 GList *route_node; 704
638 foreach(route_list, route_node) { 705 rf_list = (GList *) table_find(conf.connect_routes, connect_name);
639 connect_route *route = (connect_route *) (route_node->data); 706 if (!rf_list) {
640 ok = deliver_route_msg_list(route, msgout_list); 707 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name);
641 } 708 return FALSE;
642 destroy_route_list(route_list); 709 }
643 } else 710
644 logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name); 711 GList *route_list = read_route_list(rf_list, FALSE);
645 } else { 712 if (!route_list) {
646 logwrite(LOG_ALERT, "route list with name '%s' not found.\n", connect_name); 713 logwrite(LOG_ALERT, "could not read route list '%s'\n", connect_name);
647 } 714 return FALSE;
648 } 715 }
716
717 GList *route_node;
718 foreach(route_list, route_node) {
719 connect_route *route = (connect_route *) (route_node->data);
720 /* TODO: ok gets overwritten */
721 ok = deliver_route_msg_list(route, msgout_list);
722 }
723 destroy_route_list(route_list);
649 return ok; 724 return ok;
650 } 725 }
651 726
652 gboolean 727 gboolean
653 deliver_msg_list(GList * msg_list, guint flags) 728 deliver_msg_list(GList * msg_list, guint flags)
654 { 729 {
655 GList *msgout_list = create_msg_out_list(msg_list); 730 GList *msgout_list = create_msg_out_list(msg_list);
656 GList *local_msgout_list = NULL, *localnet_msgout_list = NULL, *other_msgout_list = NULL; 731 GList *local_msgout_list = NULL;
732 GList *localnet_msgout_list = NULL;
733 GList *other_msgout_list = NULL;
657 GList *msgout_node; 734 GList *msgout_node;
658 GList *alias_table = NULL; 735 GList *alias_table = NULL;
659 gboolean ok = TRUE; 736 gboolean ok = TRUE;
660 737
661 if (conf.alias_file) { 738 if (conf.alias_file) {
677 DEBUG(5) debugf("spool_lock(%s)\n", msgout->msg->uid); 754 DEBUG(5) debugf("spool_lock(%s)\n", msgout->msg->uid);
678 755
679 rcpt_list = g_list_copy(msgout->msg->rcpt_list); 756 rcpt_list = g_list_copy(msgout->msg->rcpt_list);
680 if (conf.log_user) { 757 if (conf.log_user) {
681 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name); 758 address *addr = create_address_qualified(conf.log_user, TRUE, conf.host_name);
682 if (addr) 759 if (addr) {
683 rcpt_list = g_list_prepend(rcpt_list, addr); 760 rcpt_list = g_list_prepend(rcpt_list, addr);
761 } else {
762 logwrite(LOG_ALERT, "invalid log_user address `%s', ignoring\n", conf.log_user);
763 }
684 } 764 }
685 if (alias_table) { 765 if (alias_table) {
686 GList *aliased_rcpt_list; 766 GList *aliased_rcpt_list;
687 aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list); 767 aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list);
688 g_list_free(rcpt_list); 768 g_list_free(rcpt_list);
712 other_msgout->rcpt_list = other_rcpt_list; 792 other_msgout->rcpt_list = other_rcpt_list;
713 other_msgout_list = g_list_append(other_msgout_list, other_msgout); 793 other_msgout_list = g_list_append(other_msgout_list, other_msgout);
714 } 794 }
715 } 795 }
716 796
717 if (alias_table) 797 if (alias_table) {
718 destroy_table(alias_table); 798 destroy_table(alias_table);
799 }
719 800
720 /* actual delivery */ 801 /* actual delivery */
721 802
722 if (local_msgout_list) { 803 if (local_msgout_list) {
723 DEBUG(5) debugf("local_msgout_list\n"); 804 DEBUG(5) debugf("local_msgout_list\n");
724 foreach(local_msgout_list, msgout_node) { 805 foreach(local_msgout_list, msgout_node) {
725 msg_out *msgout = (msg_out *) (msgout_node->data); 806 msg_out *msgout = (msg_out *) (msgout_node->data);
726 if (!deliver_local(msgout)) 807 if (!deliver_local(msgout)) {
727 ok = FALSE; 808 ok = FALSE;
809 }
728 } 810 }
729 destroy_msg_out_list(local_msgout_list); 811 destroy_msg_out_list(local_msgout_list);
730 } 812 }
731 813
732 if (localnet_msgout_list) { 814 if (localnet_msgout_list) {
733 GList *route_list = NULL; 815 GList *route_list = NULL;
734 GList *route_node; 816 GList *route_node;
735 817
736 DEBUG(5) debugf("localnet_msgout_list\n"); 818 DEBUG(5) debugf("localnet_msgout_list\n");
737 if (conf.local_net_routes) 819 if (conf.local_net_routes) {
738 route_list = read_route_list(conf.local_net_routes, TRUE); 820 route_list = read_route_list(conf.local_net_routes, TRUE);
739 else 821 } else {
740 route_list = g_list_append(NULL, create_local_route()); 822 route_list = g_list_append(NULL, create_local_route());
823 }
741 824
742 foreach(route_list, route_node) { 825 foreach(route_list, route_node) {
743 connect_route *route = (connect_route *) (route_node->data); 826 connect_route *route = (connect_route *) (route_node->data);
744 if (!deliver_route_msg_list(route, localnet_msgout_list)) 827 if (!deliver_route_msg_list(route, localnet_msgout_list)) {
745 ok = FALSE; 828 ok = FALSE;
829 }
746 } 830 }
747 destroy_msg_out_list(localnet_msgout_list); 831 destroy_msg_out_list(localnet_msgout_list);
748 destroy_route_list(route_list); 832 destroy_route_list(route_list);
749 } 833 }
750 834
751 if (other_msgout_list) { 835 if (other_msgout_list) {
752 DEBUG(5) debugf("other_msgout_list\n"); 836 DEBUG(5) debugf("other_msgout_list\n");
753 if (!deliver_msgout_list_online(other_msgout_list)) 837 if (!deliver_msgout_list_online(other_msgout_list)) {
754 ok = FALSE; 838 ok = FALSE;
839 }
755 destroy_msg_out_list(other_msgout_list); 840 destroy_msg_out_list(other_msgout_list);
756 } 841 }
757 842
758 foreach(msgout_list, msgout_node) { 843 foreach(msgout_list, msgout_node) {
759 msg_out *msgout = (msg_out *) (msgout_node->data); 844 msg_out *msgout = (msg_out *) (msgout_node->data);