1 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "llist.h"
5 #include "ioloop.h"
6 #include "net.h"
7 #include "istream.h"
8 #include "istream-crlf.h"
9 #include "ostream.h"
10 #include "str.h"
11 #include "str-sanitize.h"
12 #include "dns-lookup.h"
13 
14 #include "smtp-common.h"
15 #include "smtp-address.h"
16 #include "smtp-params.h"
17 #include "smtp-client-private.h"
18 #include "smtp-client-command.h"
19 #include "smtp-client-transaction.h"
20 
21 #include <ctype.h>
22 
23 const char *const smtp_client_transaction_state_names[] = {
24 	"new",
25 	"mail_from",
26 	"rcpt_to",
27 	"data",
28 	"reset",
29 	"finished",
30 	"aborted"
31 };
32 
33 static void
34 smtp_client_transaction_submit_more(struct smtp_client_transaction *trans);
35 static void
36 smtp_client_transaction_submit(struct smtp_client_transaction *trans,
37 			       bool start);
38 
39 static void
40 smtp_client_transaction_try_complete(struct smtp_client_transaction *trans);
41 
42 static void
43 smtp_client_transaction_send_data(struct smtp_client_transaction *trans);
44 static void
45 smtp_client_transaction_send_reset(struct smtp_client_transaction *trans);
46 
47 /*
48  * Sender
49  */
50 
51 static struct smtp_client_transaction_mail *
smtp_client_transaction_mail_new(struct smtp_client_transaction * trans,const struct smtp_address * mail_from,const struct smtp_params_mail * mail_params)52 smtp_client_transaction_mail_new(struct smtp_client_transaction *trans,
53 				 const struct smtp_address *mail_from,
54 				 const struct smtp_params_mail *mail_params)
55 {
56 	struct smtp_client_transaction_mail *mail;
57 	pool_t pool;
58 
59 	pool = pool_alloconly_create("smtp transaction mail", 512);
60 	mail = p_new(pool, struct smtp_client_transaction_mail, 1);
61 	mail->pool = pool;
62 	mail->trans = trans;
63 	mail->mail_from = smtp_address_clone(pool, mail_from);
64 	smtp_params_mail_copy(pool, &mail->mail_params, mail_params);
65 
66 	DLLIST2_APPEND(&trans->mail_head, &trans->mail_tail, mail);
67 	if (trans->mail_send == NULL)
68 		trans->mail_send = mail;
69 
70 	return mail;
71 }
72 
73 static void
smtp_client_transaction_mail_free(struct smtp_client_transaction_mail ** _mail)74 smtp_client_transaction_mail_free(struct smtp_client_transaction_mail **_mail)
75 {
76 	struct smtp_client_transaction_mail *mail = *_mail;
77 	struct smtp_client_transaction *trans = mail->trans;
78 
79 	*_mail = NULL;
80 
81 	if (mail->cmd_mail_from != NULL)
82 		smtp_client_command_abort(&mail->cmd_mail_from);
83 	DLLIST2_REMOVE(&trans->mail_head, &trans->mail_tail, mail);
84 	pool_unref(&mail->pool);
85 }
86 
87 static void
smtp_client_transaction_mail_replied(struct smtp_client_transaction_mail ** _mail,const struct smtp_reply * reply)88 smtp_client_transaction_mail_replied(
89 	struct smtp_client_transaction_mail **_mail,
90 	const struct smtp_reply *reply)
91 {
92 	struct smtp_client_transaction_mail *mail = *_mail;
93 	smtp_client_command_callback_t *mail_callback = mail->mail_callback;
94 	void *context = mail->context;
95 
96 	mail->mail_callback = NULL;
97 
98 	/* call the callback */
99 	if (mail_callback != NULL)
100 		mail_callback(reply, context);
101 
102 	smtp_client_transaction_mail_free(_mail);
103 }
104 
smtp_client_transaction_mail_abort(struct smtp_client_transaction_mail ** _mail)105 void smtp_client_transaction_mail_abort(
106 	struct smtp_client_transaction_mail **_mail)
107 {
108 	struct smtp_client_transaction_mail *mail = *_mail;
109 	struct smtp_client_transaction *trans = mail->trans;
110 
111 	i_assert(trans->state <= SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM ||
112 		 trans->state == SMTP_CLIENT_TRANSACTION_STATE_ABORTED);
113 
114 	smtp_client_transaction_mail_free(_mail);
115 }
116 
117 static void
smtp_client_transaction_mail_fail_reply(struct smtp_client_transaction_mail ** _mail,const struct smtp_reply * reply)118 smtp_client_transaction_mail_fail_reply(
119 	struct smtp_client_transaction_mail **_mail,
120 	const struct smtp_reply *reply)
121 {
122 	struct smtp_client_transaction_mail *mail = *_mail;
123 	smtp_client_command_callback_t *callback = mail->mail_callback;
124 	void *context = mail->context;
125 
126 	mail->mail_callback = NULL;
127 
128 	if (callback != NULL)
129 		callback(reply, context);
130 
131 	smtp_client_transaction_mail_free(_mail);
132 }
133 
134 /*
135  * Recipient
136  */
137 
138 static void
smtp_client_transaction_rcpt_update_event(struct smtp_client_transaction_rcpt * rcpt)139 smtp_client_transaction_rcpt_update_event(
140 	struct smtp_client_transaction_rcpt *rcpt)
141 {
142 	const char *to = smtp_address_encode(rcpt->rcpt_to);
143 
144 	event_set_append_log_prefix(rcpt->event,
145 		t_strdup_printf("rcpt <%s>: ", str_sanitize(to, 128)));
146 	event_add_str(rcpt->event, "rcpt_to", to);
147 	smtp_params_rcpt_add_to_event(&rcpt->rcpt_params, rcpt->event);
148 }
149 
150 static struct smtp_client_transaction_rcpt *
smtp_client_transaction_rcpt_new(struct smtp_client_transaction * trans,pool_t pool,const struct smtp_address * rcpt_to,const struct smtp_params_rcpt * rcpt_params)151 smtp_client_transaction_rcpt_new(
152 	struct smtp_client_transaction *trans, pool_t pool,
153 	const struct smtp_address *rcpt_to,
154 	const struct smtp_params_rcpt *rcpt_params)
155 {
156 	struct smtp_client_transaction_rcpt *rcpt;
157 
158 	pool_ref(pool);
159 
160 	rcpt = p_new(pool, struct smtp_client_transaction_rcpt, 1);
161 	rcpt->pool = pool;
162 	rcpt->trans = trans;
163 	rcpt->rcpt_to = smtp_address_clone(pool, rcpt_to);
164 	smtp_params_rcpt_copy(pool, &rcpt->rcpt_params, rcpt_params);
165 
166 	DLLIST2_APPEND(&trans->rcpts_queue_head, &trans->rcpts_queue_tail,
167 		       rcpt);
168 	trans->rcpts_queue_count++;
169 	rcpt->queued = TRUE;
170 	if (trans->rcpts_send == NULL)
171 		trans->rcpts_send = rcpt;
172 
173 	rcpt->event = event_create(trans->event);
174 	smtp_client_transaction_rcpt_update_event(rcpt);
175 
176 	trans->rcpts_total++;
177 
178 	return rcpt;
179 }
180 
181 static void
smtp_client_transaction_rcpt_free(struct smtp_client_transaction_rcpt ** _rcpt)182 smtp_client_transaction_rcpt_free(
183 	struct smtp_client_transaction_rcpt **_rcpt)
184 {
185 	struct smtp_client_transaction_rcpt *rcpt = *_rcpt;
186 	struct smtp_client_transaction *trans = rcpt->trans;
187 
188 	*_rcpt = NULL;
189 
190 	if (trans->rcpts_send == rcpt)
191 		trans->rcpts_send = rcpt->next;
192 	if (trans->rcpts_data == rcpt)
193 		trans->rcpts_data = rcpt->next;
194 	if (rcpt->queued) {
195 		DLLIST2_REMOVE(&trans->rcpts_queue_head,
196 			       &trans->rcpts_queue_tail, rcpt);
197 		trans->rcpts_queue_count--;
198 	} else {
199 		DLLIST2_REMOVE(&trans->rcpts_head,
200 			       &trans->rcpts_tail, rcpt);
201 		trans->rcpts_count--;
202 	}
203 
204 	if (!rcpt->finished) {
205 		struct smtp_reply failure;
206 
207 		trans->rcpts_aborted++;
208 
209 		smtp_reply_init(&failure,
210 				SMTP_CLIENT_COMMAND_ERROR_ABORTED,
211 				"Aborted");
212 		failure.enhanced_code = SMTP_REPLY_ENH_CODE(9, 0, 0);
213 
214 		struct event_passthrough *e =
215 			event_create_passthrough(rcpt->event)->
216 			set_name("smtp_client_transaction_rcpt_finished");
217 		smtp_reply_add_to_event(&failure, e);
218 		e_debug(e->event(), "Aborted");
219 	}
220 
221 	event_unref(&rcpt->event);
222 
223 	if (rcpt->queued || rcpt->external_pool) {
224 		i_assert(rcpt->pool != NULL);
225 		pool_unref(&rcpt->pool);
226 	}
227 }
228 
229 static void
smtp_client_transaction_rcpt_approved(struct smtp_client_transaction_rcpt ** _rcpt)230 smtp_client_transaction_rcpt_approved(
231 	struct smtp_client_transaction_rcpt **_rcpt)
232 {
233 	struct smtp_client_transaction_rcpt *prcpt = *_rcpt;
234 	struct smtp_client_transaction *trans = prcpt->trans;
235 	struct smtp_client_transaction_rcpt *rcpt;
236 	pool_t pool;
237 
238 	i_assert(prcpt->queued);
239 
240 	if (prcpt->external_pool) {
241 		/* allocated externally; just remove it from the queue */
242 		prcpt->queued = FALSE;
243 		if (trans->rcpts_send == prcpt)
244 			trans->rcpts_send = prcpt->next;
245 		DLLIST2_REMOVE(&trans->rcpts_queue_head,
246 			       &trans->rcpts_queue_tail, prcpt);
247 		trans->rcpts_queue_count--;
248 
249 		rcpt = prcpt;
250 	} else {
251 		/* move to transaction pool */
252 		pool = trans->pool;
253 		rcpt = p_new(pool, struct smtp_client_transaction_rcpt, 1);
254 		rcpt->trans = trans;
255 		rcpt->rcpt_to = smtp_address_clone(pool, prcpt->rcpt_to);
256 		smtp_params_rcpt_copy(pool, &rcpt->rcpt_params,
257 				      &prcpt->rcpt_params);
258 		rcpt->data_callback = prcpt->data_callback;
259 		rcpt->data_context = prcpt->data_context;
260 
261 		rcpt->event = prcpt->event;
262 		event_ref(rcpt->event);
263 
264 		/* free the old object, thereby removing it from the queue */
265 		smtp_client_transaction_rcpt_free(&prcpt);
266 	}
267 
268 	/* recipient is approved */
269 	DLLIST2_APPEND(&trans->rcpts_head, &trans->rcpts_tail, rcpt);
270 	trans->rcpts_count++;
271 	if (trans->rcpts_data == NULL)
272 		trans->rcpts_data = trans->rcpts_head;
273 
274 	*_rcpt = rcpt;
275 }
276 
277 static void
smtp_client_transaction_rcpt_denied(struct smtp_client_transaction_rcpt ** _rcpt,const struct smtp_reply * reply)278 smtp_client_transaction_rcpt_denied(
279 	struct smtp_client_transaction_rcpt **_rcpt,
280 	const struct smtp_reply *reply)
281 {
282 	struct smtp_client_transaction_rcpt *prcpt = *_rcpt;
283 	struct smtp_client_transaction *trans = prcpt->trans;
284 
285 	*_rcpt = NULL;
286 
287 	trans->rcpts_denied++;
288 	trans->rcpts_failed++;
289 
290 	struct event_passthrough *e =
291 		event_create_passthrough(prcpt->event)->
292 		set_name("smtp_client_transaction_rcpt_finished");
293 	smtp_reply_add_to_event(reply, e);
294 	e_debug(e->event(), "Denied");
295 
296 	/* not pending anymore */
297 	smtp_client_transaction_rcpt_free(&prcpt);
298 }
299 
300 static void
smtp_client_transaction_rcpt_replied(struct smtp_client_transaction_rcpt ** _rcpt,const struct smtp_reply * reply)301 smtp_client_transaction_rcpt_replied(
302 	struct smtp_client_transaction_rcpt **_rcpt,
303 	const struct smtp_reply *reply)
304 {
305 	struct smtp_client_transaction_rcpt *rcpt = *_rcpt;
306 	bool success = smtp_reply_is_success(reply);
307 	smtp_client_command_callback_t *rcpt_callback = rcpt->rcpt_callback;
308 	void *context = rcpt->context;
309 
310 	rcpt->rcpt_callback = NULL;
311 
312 	if (rcpt->finished)
313 		return;
314 	rcpt->finished = !success;
315 
316 	if (success)
317 		smtp_client_transaction_rcpt_approved(_rcpt);
318 	else
319 		smtp_client_transaction_rcpt_denied(_rcpt, reply);
320 
321 	/* call the callback */
322 	if (rcpt_callback != NULL)
323 		rcpt_callback(reply, context);
324 }
325 
smtp_client_transaction_rcpt_abort(struct smtp_client_transaction_rcpt ** _rcpt)326 void smtp_client_transaction_rcpt_abort(
327 	struct smtp_client_transaction_rcpt **_rcpt)
328 {
329 	struct smtp_client_transaction_rcpt *rcpt = *_rcpt;
330 	struct smtp_client_transaction *trans = rcpt->trans;
331 
332 	i_assert(rcpt->queued || rcpt->external_pool);
333 
334 	i_assert(trans->state <= SMTP_CLIENT_TRANSACTION_STATE_RCPT_TO ||
335 		 trans->state == SMTP_CLIENT_TRANSACTION_STATE_ABORTED);
336 
337 	smtp_client_transaction_rcpt_free(_rcpt);
338 }
339 
340 static void
smtp_client_transaction_rcpt_fail_reply(struct smtp_client_transaction_rcpt ** _rcpt,const struct smtp_reply * reply)341 smtp_client_transaction_rcpt_fail_reply(
342 	struct smtp_client_transaction_rcpt **_rcpt,
343 	const struct smtp_reply *reply)
344 {
345 	struct smtp_client_transaction_rcpt *rcpt = *_rcpt;
346 	struct smtp_client_transaction *trans = rcpt->trans;
347 	smtp_client_command_callback_t *callback;
348 	void *context;
349 
350 	if (rcpt->finished)
351 		return;
352 	rcpt->finished = TRUE;
353 
354 	trans->rcpts_failed++;
355 
356 	if (rcpt->queued) {
357 		callback = rcpt->rcpt_callback;
358 		context = rcpt->context;
359 	} else {
360 		callback = rcpt->data_callback;
361 		context = rcpt->data_context;
362 	}
363 	rcpt->rcpt_callback = NULL;
364 	rcpt->data_callback = NULL;
365 
366 	struct event_passthrough *e =
367 		event_create_passthrough(rcpt->event)->
368 		set_name("smtp_client_transaction_rcpt_finished");
369 	smtp_reply_add_to_event(reply, e);
370 	e_debug(e->event(), "Failed");
371 
372 	if (callback != NULL)
373 		callback(reply, context);
374 
375 	smtp_client_transaction_rcpt_free(_rcpt);
376 }
377 
378 static void
smtp_client_transaction_rcpt_finished(struct smtp_client_transaction_rcpt * rcpt,const struct smtp_reply * reply)379 smtp_client_transaction_rcpt_finished(struct smtp_client_transaction_rcpt *rcpt,
380 				      const struct smtp_reply *reply)
381 {
382 	struct smtp_client_transaction *trans = rcpt->trans;
383 
384 	i_assert(!rcpt->finished);
385 	rcpt->finished = TRUE;
386 
387 	if (smtp_reply_is_success(reply))
388 		trans->rcpts_succeeded++;
389 	else
390 		trans->rcpts_failed++;
391 
392 	struct event_passthrough *e =
393 		event_create_passthrough(rcpt->event)->
394 		set_name("smtp_client_transaction_rcpt_finished");
395 	smtp_reply_add_to_event(reply, e);
396 	e_debug(e->event(), "Finished");
397 
398 	if (rcpt->data_callback != NULL)
399 		rcpt->data_callback(reply, rcpt->data_context);
400 	rcpt->data_callback = NULL;
401 }
402 
403 #undef smtp_client_transaction_rcpt_set_data_callback
smtp_client_transaction_rcpt_set_data_callback(struct smtp_client_transaction_rcpt * rcpt,smtp_client_command_callback_t * callback,void * context)404 void smtp_client_transaction_rcpt_set_data_callback(
405 	struct smtp_client_transaction_rcpt *rcpt,
406 	smtp_client_command_callback_t *callback, void *context)
407 {
408 	i_assert(!rcpt->finished);
409 
410 	rcpt->data_callback = callback;
411 	rcpt->data_context = context;
412 }
413 
414 /*
415  * Transaction
416  */
417 
418 static void
smtp_client_transaction_update_event(struct smtp_client_transaction * trans)419 smtp_client_transaction_update_event(struct smtp_client_transaction *trans)
420 {
421 	event_set_append_log_prefix(trans->event, "transaction: ");
422 }
423 
424 static struct event_passthrough *
smtp_client_transaction_result_event(struct smtp_client_transaction * trans,const struct smtp_reply * reply)425 smtp_client_transaction_result_event(struct smtp_client_transaction *trans,
426 				     const struct smtp_reply *reply)
427 {
428 	struct event_passthrough *e;
429 	unsigned int rcpts_aborted = trans->rcpts_aborted +
430 				     trans->rcpts_queue_count;
431 
432 	e = event_create_passthrough(trans->event)->
433 		set_name("smtp_client_transaction_finished")->
434 		add_int("recipients", trans->rcpts_total)->
435 		add_int("recipients_aborted", rcpts_aborted)->
436 		add_int("recipients_denied", trans->rcpts_denied)->
437 		add_int("recipients_failed", trans->rcpts_failed)->
438 		add_int("recipients_succeeded", trans->rcpts_succeeded);
439 
440 	smtp_reply_add_to_event(reply, e);
441 	if (trans->reset)
442 		e->add_str("is_reset", "yes");
443 	return e;
444 }
445 
446 #undef smtp_client_transaction_create_empty
447 struct smtp_client_transaction *
smtp_client_transaction_create_empty(struct smtp_client_connection * conn,enum smtp_client_transaction_flags flags,smtp_client_transaction_callback_t * callback,void * context)448 smtp_client_transaction_create_empty(
449 	struct smtp_client_connection *conn,
450 	enum smtp_client_transaction_flags flags,
451 	smtp_client_transaction_callback_t *callback, void *context)
452 {
453 	struct smtp_client_transaction *trans;
454 	pool_t pool;
455 
456 	if (conn->protocol == SMTP_PROTOCOL_LMTP)
457 		flags |= SMTP_CLIENT_TRANSACTION_FLAG_REPLY_PER_RCPT;
458 
459 	pool = pool_alloconly_create("smtp transaction", 4096);
460 	trans = p_new(pool, struct smtp_client_transaction, 1);
461 	trans->refcount = 1;
462 	trans->pool = pool;
463 	trans->flags = flags;
464 	trans->callback = callback;
465 	trans->context = context;
466 
467 	trans->event = event_create(conn->event);
468 	smtp_client_transaction_update_event(trans);
469 
470 	trans->conn = conn;
471 	smtp_client_connection_ref(conn);
472 
473 	e_debug(trans->event, "Created");
474 
475 	return trans;
476 }
477 
478 #undef smtp_client_transaction_create
479 struct smtp_client_transaction *
smtp_client_transaction_create(struct smtp_client_connection * conn,const struct smtp_address * mail_from,const struct smtp_params_mail * mail_params,enum smtp_client_transaction_flags flags,smtp_client_transaction_callback_t * callback,void * context)480 smtp_client_transaction_create(struct smtp_client_connection *conn,
481 	const struct smtp_address *mail_from,
482 	const struct smtp_params_mail *mail_params,
483 	enum smtp_client_transaction_flags flags,
484 	smtp_client_transaction_callback_t *callback, void *context)
485 {
486 	struct smtp_client_transaction *trans;
487 
488 	trans = smtp_client_transaction_create_empty(conn, flags,
489 						     callback, context);
490 	(void)smtp_client_transaction_mail_new(trans, mail_from, mail_params);
491 	return trans;
492 }
493 
494 static void
smtp_client_transaction_finish(struct smtp_client_transaction * trans,const struct smtp_reply * final_reply)495 smtp_client_transaction_finish(struct smtp_client_transaction *trans,
496 			       const struct smtp_reply *final_reply)
497 {
498 	struct smtp_client_connection *conn = trans->conn;
499 
500 	if (trans->state >= SMTP_CLIENT_TRANSACTION_STATE_FINISHED)
501 		return;
502 
503 	timeout_remove(&trans->to_finish);
504 
505 	struct event_passthrough *e =
506 		smtp_client_transaction_result_event(trans, final_reply);
507 	e_debug(e->event(), "Finished");
508 
509 	io_loop_time_refresh();
510 	trans->times.finished = ioloop_timeval;
511 
512 	i_assert(trans->to_send == NULL);
513 
514 	trans->state = SMTP_CLIENT_TRANSACTION_STATE_FINISHED;
515 	i_assert(trans->callback != NULL);
516 	trans->callback(trans->context);
517 
518 	if (!trans->submitted_data)
519 		smtp_client_connection_abort_transaction(conn, trans);
520 
521 	smtp_client_transaction_unref(&trans);
522 }
523 
smtp_client_transaction_abort(struct smtp_client_transaction * trans)524 void smtp_client_transaction_abort(struct smtp_client_transaction *trans)
525 {
526 	struct smtp_client_connection *conn = trans->conn;
527 
528 	if (trans->failing) {
529 		e_debug(trans->event, "Abort (already failing)");
530 		return;
531 	}
532 
533 	e_debug(trans->event, "Abort");
534 
535 	/* clean up */
536 	i_stream_unref(&trans->data_input);
537 	timeout_remove(&trans->to_send);
538 	timeout_remove(&trans->to_finish);
539 
540 	trans->cmd_last = NULL;
541 
542 	/* abort any pending commands */
543 	while (trans->mail_head != NULL) {
544 		struct smtp_client_transaction_mail *mail = trans->mail_head;
545 
546 		if (mail->cmd_mail_from != NULL)
547 			smtp_client_command_abort(&mail->cmd_mail_from);
548 		smtp_client_transaction_mail_free(&mail);
549 	}
550 	while (trans->rcpts_queue_count > 0) {
551 		struct smtp_client_transaction_rcpt *rcpt =
552 			trans->rcpts_queue_head;
553 
554 		if (rcpt->cmd_rcpt_to != NULL)
555 			smtp_client_command_abort(&rcpt->cmd_rcpt_to);
556 		smtp_client_transaction_rcpt_free(&rcpt);
557 	}
558 	if (trans->cmd_data != NULL)
559 		smtp_client_command_abort(&trans->cmd_data);
560 	if (trans->cmd_rset != NULL)
561 		smtp_client_command_abort(&trans->cmd_rset);
562 	if (trans->cmd_plug != NULL)
563 		smtp_client_command_abort(&trans->cmd_plug);
564 	trans->cmd_data = NULL;
565 	trans->cmd_rset = NULL;
566 	trans->cmd_plug = NULL;
567 
568 	smtp_client_connection_abort_transaction(conn, trans);
569 
570 	/* abort if not finished */
571 	if (trans->state < SMTP_CLIENT_TRANSACTION_STATE_FINISHED) {
572 		struct event_passthrough *e;
573 
574 		if (trans->failure != NULL) {
575 			e = smtp_client_transaction_result_event(
576 				trans, trans->failure);
577 			e_debug(e->event(), "Failed");
578 		} else {
579 			struct smtp_reply failure;
580 
581 			smtp_reply_init(&failure,
582 					SMTP_CLIENT_COMMAND_ERROR_ABORTED,
583 					"Aborted");
584 			failure.enhanced_code = SMTP_REPLY_ENH_CODE(9, 0, 0);
585 
586 			e = smtp_client_transaction_result_event(
587 				trans, &failure);
588 			e_debug(e->event(), "Aborted");
589 		}
590 
591 		trans->state = SMTP_CLIENT_TRANSACTION_STATE_ABORTED;
592 		i_assert(trans->callback != NULL);
593 		trans->callback(trans->context);
594 
595 		smtp_client_transaction_unref(&trans);
596 	}
597 }
598 
smtp_client_transaction_ref(struct smtp_client_transaction * trans)599 void smtp_client_transaction_ref(struct smtp_client_transaction *trans)
600 {
601 	trans->refcount++;
602 }
603 
smtp_client_transaction_unref(struct smtp_client_transaction ** _trans)604 void smtp_client_transaction_unref(struct smtp_client_transaction **_trans)
605 {
606 	struct smtp_client_transaction *trans = *_trans;
607 	struct smtp_client_connection *conn;
608 
609 	*_trans = NULL;
610 
611 	if (trans == NULL)
612 		return;
613 	conn = trans->conn;
614 
615 	i_assert(trans->refcount > 0);
616 	if (--trans->refcount > 0)
617 		return;
618 
619 	e_debug(trans->event, "Destroy");
620 
621 	i_stream_unref(&trans->data_input);
622 	smtp_client_transaction_abort(trans);
623 
624 	while (trans->rcpts_count > 0) {
625 		struct smtp_client_transaction_rcpt *rcpt =
626 			trans->rcpts_head;
627 		smtp_client_transaction_rcpt_free(&rcpt);
628 	}
629 
630 	i_assert(trans->state >= SMTP_CLIENT_TRANSACTION_STATE_FINISHED);
631 	event_unref(&trans->event);
632 	pool_unref(&trans->pool);
633 
634 	smtp_client_connection_unref(&conn);
635 }
636 
smtp_client_transaction_destroy(struct smtp_client_transaction ** _trans)637 void smtp_client_transaction_destroy(struct smtp_client_transaction **_trans)
638 {
639 	struct smtp_client_transaction *trans = *_trans;
640 	struct smtp_client_transaction_mail *mail;
641 	struct smtp_client_transaction_rcpt *rcpt;
642 
643 	*_trans = NULL;
644 
645 	if (trans == NULL)
646 		return;
647 
648 	smtp_client_transaction_ref(trans);
649 	smtp_client_transaction_abort(trans);
650 
651 	/* Make sure this transaction doesn't produce any more callbacks.
652 	   We cannot fully abort (destroy) these commands, as this may be
653 	   called from a callback. */
654 	for (mail = trans->mail_head; mail != NULL; mail = mail->next) {
655 		if (mail->cmd_mail_from != NULL)
656 			smtp_client_command_drop_callback(mail->cmd_mail_from);
657 	}
658 	for (rcpt = trans->rcpts_queue_head; rcpt != NULL; rcpt = rcpt->next) {
659 		if (rcpt->cmd_rcpt_to != NULL)
660 			smtp_client_command_drop_callback(rcpt->cmd_rcpt_to);
661 	}
662 	if (trans->cmd_data != NULL)
663 		smtp_client_command_drop_callback(trans->cmd_data);
664 	if (trans->cmd_rset != NULL)
665 		smtp_client_command_drop_callback(trans->cmd_rset);
666 	if (trans->cmd_plug != NULL)
667 		smtp_client_command_abort(&trans->cmd_plug);
668 
669 	/* Free any approved recipients early */
670 	while (trans->rcpts_count > 0) {
671 		struct smtp_client_transaction_rcpt *rcpt =
672 			trans->rcpts_head;
673 		smtp_client_transaction_rcpt_free(&rcpt);
674 	}
675 
676 	if (trans->state < SMTP_CLIENT_TRANSACTION_STATE_FINISHED) {
677 		struct smtp_client_transaction *trans_tmp = trans;
678 
679 		trans->state = SMTP_CLIENT_TRANSACTION_STATE_ABORTED;
680 		smtp_client_transaction_unref(&trans_tmp);
681 	}
682 
683 	smtp_client_transaction_unref(&trans);
684 }
685 
smtp_client_transaction_fail_reply(struct smtp_client_transaction * trans,const struct smtp_reply * reply)686 void smtp_client_transaction_fail_reply(struct smtp_client_transaction *trans,
687 	const struct smtp_reply *reply)
688 {
689 	struct smtp_client_transaction_rcpt *rcpt, *rcpt_next;
690 
691 	if (reply == NULL)
692 		reply = trans->failure;
693 	i_assert(reply != NULL);
694 
695 	trans->failing = TRUE;
696 
697 	e_debug(trans->event, "Returning failure: %s", smtp_reply_log(reply));
698 
699 	/* hold a reference to prevent early destruction in a callback */
700 	smtp_client_transaction_ref(trans);
701 
702 	trans->cmd_last = NULL;
703 
704 	timeout_remove(&trans->to_send);
705 
706 	/* MAIL */
707 	while (trans->mail_head != NULL) {
708 		struct smtp_client_transaction_mail *mail = trans->mail_head;
709 
710 		if (mail->cmd_mail_from != NULL)
711 			smtp_client_command_abort(&mail->cmd_mail_from);
712 		smtp_client_transaction_mail_fail_reply(&mail, reply);
713 	}
714 
715 	/* RCPT */
716 	rcpt = trans->rcpts_queue_head;
717 	while (rcpt != NULL) {
718 		struct smtp_client_command *cmd = rcpt->cmd_rcpt_to;
719 
720 		rcpt_next = rcpt->next;
721 
722 		rcpt->cmd_rcpt_to = NULL;
723 		if (cmd != NULL)
724 			smtp_client_command_fail_reply(&cmd, reply);
725 		else
726 			smtp_client_transaction_rcpt_fail_reply(&rcpt, reply);
727 
728 		rcpt = rcpt_next;
729 	}
730 
731 	/* DATA / RSET */
732 	if (!trans->data_provided && !trans->reset) {
733 		/* none of smtp_client_transaction_send() and
734 		   smtp_client_transaction_reset() was called so far
735 		 */
736 	} else if (trans->cmd_data != NULL) {
737 		/* the DATA command is still pending; handle the failure by
738 		   failing the DATA command. */
739 		smtp_client_command_fail_reply(&trans->cmd_data, reply);
740 	} else if (trans->cmd_rset != NULL) {
741 		/* the RSET command is still pending; handle the failure by
742 		   failing the RSET command. */
743 		smtp_client_command_fail_reply(&trans->cmd_rset, reply);
744 	} else {
745 		i_assert(!trans->reset);
746 
747 		/* the DATA command was not sent yet; call all DATA callbacks
748 		   for the recipients that were previously accepted. */
749 		rcpt = trans->rcpts_data;
750 		while (rcpt != NULL) {
751 			rcpt_next = rcpt->next;
752 			smtp_client_transaction_rcpt_fail_reply(&rcpt, reply);
753 			rcpt = rcpt_next;
754 		}
755 		if (trans->data_callback != NULL)
756 			trans->data_callback(reply, trans->data_context);
757 		trans->data_callback = NULL;
758 	}
759 
760 	/* plug */
761 	if (trans->failure == NULL)
762 		trans->failure = smtp_reply_clone(trans->pool, reply);
763 	if (trans->cmd_plug != NULL)
764 		smtp_client_command_abort(&trans->cmd_plug);
765 	trans->cmd_plug = NULL;
766 
767 	trans->failing = FALSE;
768 
769 	if (trans->data_provided || trans->reset) {
770 		/* abort the transaction only if smtp_client_transaction_send()
771 		   or  smtp_client_transaction_reset() was called (and if it is
772 		   not aborted already) */
773 		smtp_client_transaction_abort(trans);
774 	}
775 
776 	/* drop reference held earlier in this function */
777 	smtp_client_transaction_unref(&trans);
778 }
779 
smtp_client_transaction_fail(struct smtp_client_transaction * trans,unsigned int status,const char * error)780 void smtp_client_transaction_fail(struct smtp_client_transaction *trans,
781 	unsigned int status, const char *error)
782 {
783 	struct smtp_reply reply;
784 
785 	smtp_reply_init(&reply, status, error);
786 	smtp_client_transaction_fail_reply(trans, &reply);
787 }
788 
smtp_client_transaction_set_event(struct smtp_client_transaction * trans,struct event * event)789 void smtp_client_transaction_set_event(struct smtp_client_transaction *trans,
790 				       struct event *event)
791 {
792 	i_assert(trans->conn != NULL);
793 	event_unref(&trans->event);
794 	trans->event = event_create(event);
795 	event_set_forced_debug(trans->event, trans->conn->set.debug);
796 	smtp_client_transaction_update_event(trans);
797 }
798 
799 static void
smtp_client_transaction_timeout(struct smtp_client_transaction * trans)800 smtp_client_transaction_timeout(struct smtp_client_transaction *trans)
801 {
802 	struct smtp_reply reply;
803 
804 	smtp_reply_printf(&reply, 451,
805 		"Remote server not answering "
806 		"(transaction timed out while %s)",
807 		smtp_client_transaction_get_state_destription(trans));
808 	reply.enhanced_code = SMTP_REPLY_ENH_CODE(4, 4, 0);
809 
810 	smtp_client_transaction_fail_reply(trans, &reply);
811 }
812 
smtp_client_transaction_set_timeout(struct smtp_client_transaction * trans,unsigned int timeout_msecs)813 void smtp_client_transaction_set_timeout(struct smtp_client_transaction *trans,
814 	unsigned int timeout_msecs)
815 {
816 	i_assert(trans->state < SMTP_CLIENT_TRANSACTION_STATE_FINISHED);
817 
818 	trans->finish_timeout_msecs = timeout_msecs;
819 
820 	if (trans->data_input != NULL && timeout_msecs > 0) {
821 		/* adjust timeout if it is already started */
822 		timeout_remove(&trans->to_finish);
823 		trans->to_finish = timeout_add(trans->finish_timeout_msecs,
824 			smtp_client_transaction_timeout, trans);
825 	}
826 }
827 
828 static void
smtp_client_transaction_mail_cb(const struct smtp_reply * reply,struct smtp_client_transaction * trans)829 smtp_client_transaction_mail_cb(const struct smtp_reply *reply,
830 				struct smtp_client_transaction *trans)
831 {
832 	struct smtp_client_transaction_mail *mail = trans->mail_head;
833 	bool success = smtp_reply_is_success(reply);
834 
835 	e_debug(trans->event, "Got MAIL reply: %s", smtp_reply_log(reply));
836 
837 	i_assert(mail != NULL);
838 	i_assert(trans->conn != NULL);
839 
840 	if (success) {
841 		if (trans->sender_accepted) {
842 			smtp_client_transaction_fail(
843 				trans, SMTP_CLIENT_COMMAND_ERROR_BAD_REPLY,
844 				"Server accepted more than a single MAIL command.");
845 			return;
846 		}
847 		trans->mail_failure = NULL;
848 		trans->sender_accepted = TRUE;
849 	}
850 
851 	/* plug command line pipeline if no RCPT commands are yet issued */
852 	if (!trans->immediate && mail->next == NULL &&
853 	    mail->cmd_mail_from == trans->cmd_last) {
854 		trans->cmd_plug = trans->cmd_last =
855 			smtp_client_command_plug(trans->conn, trans->cmd_last);
856 	}
857 	mail->cmd_mail_from = NULL;
858 
859 	if (trans->rcpts_queue_count > 0)
860 		trans->state = SMTP_CLIENT_TRANSACTION_STATE_RCPT_TO;
861 	else if (trans->reset)
862 		trans->state = SMTP_CLIENT_TRANSACTION_STATE_RESET;
863 
864 	{
865 		enum smtp_client_transaction_state state;
866 		struct smtp_client_transaction *tmp_trans = trans;
867 
868 		smtp_client_transaction_ref(tmp_trans);
869 
870 		smtp_client_transaction_mail_replied(&mail, reply);
871 
872 		state = trans->state;
873 		smtp_client_transaction_unref(&tmp_trans);
874 		if (state >= SMTP_CLIENT_TRANSACTION_STATE_FINISHED)
875 			return;
876 	}
877 
878 	if (!trans->sender_accepted && trans->mail_head != NULL) {
879 		/* Update transaction with next MAIL command candidate */
880 		mail = trans->mail_head;
881 		event_add_str(trans->event, "mail_from",
882 			      smtp_address_encode(mail->mail_from));
883 		smtp_params_mail_add_to_event(&mail->mail_params,
884 					      trans->event);
885 	}
886 
887 	if (!success && !trans->sender_accepted) {
888 		if (trans->state > SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM)
889 			smtp_client_transaction_fail_reply(trans, reply);
890 		else if (trans->mail_failure == NULL)
891 			trans->mail_failure = smtp_reply_clone(trans->pool, reply);
892 	}
893 }
894 
895 #undef smtp_client_transaction_add_mail
896 struct smtp_client_transaction_mail *
smtp_client_transaction_add_mail(struct smtp_client_transaction * trans,const struct smtp_address * mail_from,const struct smtp_params_mail * mail_params,smtp_client_command_callback_t * mail_callback,void * context)897 smtp_client_transaction_add_mail(struct smtp_client_transaction *trans,
898 				 const struct smtp_address *mail_from,
899 				 const struct smtp_params_mail *mail_params,
900 				 smtp_client_command_callback_t *mail_callback,
901 				 void *context)
902 {
903 	struct smtp_client_transaction_mail *mail;
904 
905 	e_debug(trans->event, "Add MAIL command");
906 
907 	i_assert(!trans->data_provided);
908 	i_assert(!trans->reset);
909 
910 	i_assert(trans->state < SMTP_CLIENT_TRANSACTION_STATE_RCPT_TO);
911 
912 	mail = smtp_client_transaction_mail_new(trans, mail_from, mail_params);
913 	mail->mail_callback = mail_callback;
914 	mail->context = context;
915 
916 	smtp_client_transaction_submit(trans, FALSE);
917 
918 	return mail;
919 }
920 
smtp_client_transaction_connection_ready(struct smtp_client_transaction * trans)921 static void smtp_client_transaction_connection_ready(
922 	struct smtp_client_transaction *trans)
923 {
924 	if (trans->state != SMTP_CLIENT_TRANSACTION_STATE_PENDING)
925 		return;
926 
927 	e_debug(trans->event, "Connecton is ready for transaction");
928 
929 	trans->state = SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM;
930 
931 	smtp_client_transaction_submit_more(trans);
932 }
933 
934 #undef smtp_client_transaction_start
smtp_client_transaction_start(struct smtp_client_transaction * trans,smtp_client_command_callback_t * mail_callback,void * context)935 void smtp_client_transaction_start(
936 	struct smtp_client_transaction *trans,
937 	smtp_client_command_callback_t *mail_callback, void *context)
938 {
939 	struct smtp_client_connection *conn = trans->conn;
940 	struct smtp_client_transaction_mail *mail = trans->mail_head;
941 
942 	i_assert(trans->state == SMTP_CLIENT_TRANSACTION_STATE_NEW);
943 	i_assert(trans->conn != NULL);
944 
945 	i_assert(mail != NULL);
946 	event_add_str(trans->event, "mail_from",
947 		      smtp_address_encode(mail->mail_from));
948 	event_add_str(trans->event, "mail_from_raw",
949 		      smtp_address_encode_raw(mail->mail_from));
950 	smtp_params_mail_add_to_event(&mail->mail_params,
951 				      trans->event);
952 
953 	struct event_passthrough *e =
954 		event_create_passthrough(trans->event)->
955 		set_name("smtp_client_transaction_started");
956 	e_debug(e->event(), "Start");
957 
958 	io_loop_time_refresh();
959 	trans->times.started = ioloop_timeval;
960 
961 	i_assert(mail->mail_callback == NULL);
962 
963 	mail->mail_callback = mail_callback;
964 	mail->context = context;
965 
966 	trans->state = SMTP_CLIENT_TRANSACTION_STATE_PENDING;
967 
968 	smtp_client_connection_add_transaction(conn, trans);
969 
970 	if (trans->immediate &&
971 	    conn->state == SMTP_CLIENT_CONNECTION_STATE_READY) {
972 		trans->state = SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM;
973 
974 		if (!trans->submitting)
975 			smtp_client_transaction_submit_more(trans);
976 	}
977 }
978 
979 #undef smtp_client_transaction_start_empty
smtp_client_transaction_start_empty(struct smtp_client_transaction * trans,const struct smtp_address * mail_from,const struct smtp_params_mail * mail_params,smtp_client_command_callback_t * mail_callback,void * context)980 void smtp_client_transaction_start_empty(
981 	struct smtp_client_transaction *trans,
982 	const struct smtp_address *mail_from,
983 	const struct smtp_params_mail *mail_params,
984 	smtp_client_command_callback_t *mail_callback, void *context)
985 {
986 	i_assert(trans->mail_head == NULL);
987 
988 	(void)smtp_client_transaction_mail_new(trans, mail_from, mail_params);
989 
990 	smtp_client_transaction_start(trans, mail_callback, context);
991 }
992 
993 static void
smtp_client_transaction_rcpt_cb(const struct smtp_reply * reply,struct smtp_client_transaction_rcpt * rcpt)994 smtp_client_transaction_rcpt_cb(const struct smtp_reply *reply,
995 				struct smtp_client_transaction_rcpt *rcpt)
996 {
997 	struct smtp_client_transaction *trans = rcpt->trans;
998 
999 	i_assert(trans->conn != NULL);
1000 
1001 	e_debug(trans->event, "Got RCPT reply: %s", smtp_reply_log(reply));
1002 
1003 	/* plug command line pipeline if DATA command is not yet issued */
1004 	if (!trans->immediate && !trans->reset &&
1005 	    rcpt->cmd_rcpt_to == trans->cmd_last && trans->cmd_data == NULL) {
1006 		trans->cmd_plug = trans->cmd_last =
1007 			smtp_client_command_plug(trans->conn, trans->cmd_last);
1008 	}
1009 	rcpt->cmd_rcpt_to = NULL;
1010 
1011 	{
1012 		enum smtp_client_transaction_state state;
1013 		struct smtp_client_transaction *tmp_trans = trans;
1014 
1015 		smtp_client_transaction_ref(tmp_trans);
1016 
1017 		smtp_client_transaction_rcpt_replied(&rcpt, reply);
1018 
1019 		state = trans->state;
1020 		smtp_client_transaction_unref(&tmp_trans);
1021 		if (state >= SMTP_CLIENT_TRANSACTION_STATE_FINISHED)
1022 			return;
1023 	}
1024 
1025 	smtp_client_transaction_try_complete(trans);
1026 }
1027 
1028 #undef smtp_client_transaction_add_rcpt
1029 struct smtp_client_transaction_rcpt *
smtp_client_transaction_add_rcpt(struct smtp_client_transaction * trans,const struct smtp_address * rcpt_to,const struct smtp_params_rcpt * rcpt_params,smtp_client_command_callback_t * rcpt_callback,smtp_client_command_callback_t * data_callback,void * context)1030 smtp_client_transaction_add_rcpt(struct smtp_client_transaction *trans,
1031 				 const struct smtp_address *rcpt_to,
1032 				 const struct smtp_params_rcpt *rcpt_params,
1033 				 smtp_client_command_callback_t *rcpt_callback,
1034 				 smtp_client_command_callback_t *data_callback,
1035 				 void *context)
1036 {
1037 	struct smtp_client_transaction_rcpt *rcpt;
1038 	pool_t pool;
1039 
1040 	e_debug(trans->event, "Add recipient");
1041 
1042 	i_assert(!trans->data_provided);
1043 	i_assert(!trans->reset);
1044 
1045 	i_assert(trans->state < SMTP_CLIENT_TRANSACTION_STATE_FINISHED);
1046 
1047 	if (trans->mail_head == NULL &&
1048 		trans->state == SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM)
1049 		trans->state = SMTP_CLIENT_TRANSACTION_STATE_RCPT_TO;
1050 
1051 	pool = pool_alloconly_create("smtp transaction rcpt", 512);
1052 	rcpt = smtp_client_transaction_rcpt_new(trans, pool,
1053 						rcpt_to, rcpt_params);
1054 	pool_unref(&pool);
1055 
1056 	rcpt->rcpt_callback = rcpt_callback;
1057 	rcpt->context = context;
1058 
1059 	rcpt->data_callback = data_callback;
1060 	rcpt->data_context = context;
1061 
1062 	smtp_client_transaction_submit(trans, FALSE);
1063 
1064 	return rcpt;
1065 }
1066 
1067 #undef smtp_client_transaction_add_pool_rcpt
1068 struct smtp_client_transaction_rcpt *
smtp_client_transaction_add_pool_rcpt(struct smtp_client_transaction * trans,pool_t pool,const struct smtp_address * rcpt_to,const struct smtp_params_rcpt * rcpt_params,smtp_client_command_callback_t * rcpt_callback,void * context)1069 smtp_client_transaction_add_pool_rcpt(
1070 	struct smtp_client_transaction *trans, pool_t pool,
1071 	const struct smtp_address *rcpt_to,
1072 	const struct smtp_params_rcpt *rcpt_params,
1073 	smtp_client_command_callback_t *rcpt_callback, void *context)
1074 {
1075 	struct smtp_client_transaction_rcpt *rcpt;
1076 
1077 	e_debug(trans->event, "Add recipient (external pool)");
1078 
1079 	i_assert(!trans->data_provided);
1080 	i_assert(!trans->reset);
1081 
1082 	i_assert(trans->state < SMTP_CLIENT_TRANSACTION_STATE_FINISHED);
1083 
1084 	if (trans->mail_head == NULL &&
1085 		trans->state == SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM)
1086 		trans->state = SMTP_CLIENT_TRANSACTION_STATE_RCPT_TO;
1087 
1088 	rcpt = smtp_client_transaction_rcpt_new(trans, pool,
1089 						rcpt_to, rcpt_params);
1090 	rcpt->rcpt_callback = rcpt_callback;
1091 	rcpt->context = context;
1092 	rcpt->external_pool = TRUE;
1093 
1094 	smtp_client_transaction_submit(trans, FALSE);
1095 
1096 	return rcpt;
1097 }
1098 
1099 static void
smtp_client_transaction_data_cb(const struct smtp_reply * reply,struct smtp_client_transaction * trans)1100 smtp_client_transaction_data_cb(const struct smtp_reply *reply,
1101 				struct smtp_client_transaction *trans)
1102 {
1103 	bool reply_per_rcpt = HAS_ALL_BITS(
1104 		trans->flags, SMTP_CLIENT_TRANSACTION_FLAG_REPLY_PER_RCPT);
1105 
1106 	i_assert(!trans->reset);
1107 
1108 	smtp_client_transaction_ref(trans);
1109 
1110 	if (trans->data_input != NULL) {
1111 		event_add_int(trans->event, "data_sent",
1112 			      trans->data_input->v_offset);
1113 		i_stream_unref(&trans->data_input);
1114 	}
1115 
1116 	if (reply_per_rcpt &&
1117 	    trans->cmd_data != NULL && /* NULL when failed early */
1118 	    trans->rcpts_data == NULL && trans->rcpts_count > 0) {
1119 		smtp_client_command_set_replies(trans->cmd_data,
1120 						trans->rcpts_count);
1121 	}
1122 	while (trans->rcpts_data != NULL) {
1123 		struct smtp_client_transaction_rcpt *rcpt = trans->rcpts_data;
1124 
1125 		trans->rcpts_data = trans->rcpts_data->next;
1126 		smtp_client_transaction_rcpt_finished(rcpt, reply);
1127 		if (HAS_ALL_BITS(trans->flags,
1128 				 SMTP_CLIENT_TRANSACTION_FLAG_REPLY_PER_RCPT))
1129 			break;
1130 	}
1131 
1132 	if (reply_per_rcpt && trans->rcpts_count > 1 &&
1133 	    !smtp_reply_is_success(reply) && trans->data_failure == NULL)
1134 		trans->data_failure = smtp_reply_clone(trans->pool, reply);
1135 	if (trans->rcpts_data != NULL) {
1136 		smtp_client_transaction_unref(&trans);
1137 		return;
1138 	}
1139 
1140 	trans->cmd_data = NULL;
1141 
1142 	if (trans->data_callback != NULL)
1143 		trans->data_callback(reply, trans->data_context);
1144 	trans->data_callback = NULL;
1145 
1146 	/* finished */
1147 	smtp_client_transaction_finish(
1148 		trans, (trans->data_failure == NULL ? reply :
1149 			trans->data_failure));
1150 
1151 	smtp_client_transaction_unref(&trans);
1152 }
1153 
1154 static void
smtp_client_transaction_send_data(struct smtp_client_transaction * trans)1155 smtp_client_transaction_send_data(struct smtp_client_transaction *trans)
1156 {
1157 	struct smtp_reply failure;
1158 
1159 	i_assert(!trans->reset);
1160 	i_assert(trans->data_input != NULL);
1161 
1162 	e_debug(trans->event, "Sending data");
1163 
1164 	timeout_remove(&trans->to_send);
1165 
1166 	i_zero(&failure);
1167 	if (trans->failure != NULL) {
1168 		smtp_client_transaction_fail_reply(trans, trans->failure);
1169 		failure = *trans->failure;
1170 		i_assert(failure.status != 0);
1171 	} else if ((trans->rcpts_count + trans->rcpts_queue_count) == 0) {
1172 		e_debug(trans->event, "No valid recipients");
1173 		if (trans->failure != NULL)
1174 			failure = *trans->failure;
1175 		else {
1176 			smtp_reply_init(&failure, 554, "No valid recipients");
1177 			failure.enhanced_code = SMTP_REPLY_ENH_CODE(5, 5, 0);
1178 		}
1179 		i_assert(failure.status != 0);
1180 	} else {
1181 		i_assert(trans->conn != NULL);
1182 
1183 		trans->cmd_data = smtp_client_command_data_submit_after(
1184 			trans->conn, 0, trans->cmd_last, trans->data_input,
1185 			smtp_client_transaction_data_cb, trans);
1186 		trans->submitted_data = TRUE;
1187 
1188 		if (trans->cmd_last != NULL)
1189 			smtp_client_command_unlock(trans->cmd_last);
1190 
1191 		smtp_client_transaction_try_complete(trans);
1192 	}
1193 
1194 	if (trans->cmd_plug != NULL)
1195 		smtp_client_command_abort(&trans->cmd_plug);
1196 	trans->cmd_last = NULL;
1197 
1198 	if (failure.status != 0)
1199 		smtp_client_transaction_finish(trans, &failure);
1200 }
1201 
1202 #undef smtp_client_transaction_send
smtp_client_transaction_send(struct smtp_client_transaction * trans,struct istream * data_input,smtp_client_command_callback_t * data_callback,void * data_context)1203 void smtp_client_transaction_send(
1204 	struct smtp_client_transaction *trans, struct istream *data_input,
1205 	smtp_client_command_callback_t *data_callback, void *data_context)
1206 {
1207 	i_assert(trans->state < SMTP_CLIENT_TRANSACTION_STATE_FINISHED);
1208 	i_assert(!trans->data_provided);
1209 	i_assert(!trans->reset);
1210 
1211 	if (trans->rcpts_queue_count == 0)
1212 		e_debug(trans->event, "Got all RCPT replies");
1213 
1214 	e_debug(trans->event, "Send");
1215 
1216 	trans->data_provided = TRUE;
1217 
1218 	i_assert(trans->data_input == NULL);
1219 	trans->data_input = i_stream_create_crlf(data_input);
1220 
1221 	trans->data_callback = data_callback;
1222 	trans->data_context = data_context;
1223 
1224 	if (trans->finish_timeout_msecs > 0) {
1225 		i_assert(trans->to_finish == NULL);
1226 		trans->to_finish = timeout_add(trans->finish_timeout_msecs,
1227 			smtp_client_transaction_timeout, trans);
1228 	}
1229 
1230 	smtp_client_transaction_submit(trans, TRUE);
1231 }
1232 
1233 static void
smtp_client_transaction_rset_cb(const struct smtp_reply * reply,struct smtp_client_transaction * trans)1234 smtp_client_transaction_rset_cb(const struct smtp_reply *reply,
1235 				struct smtp_client_transaction *trans)
1236 {
1237 	smtp_client_transaction_ref(trans);
1238 
1239 	trans->cmd_rset = NULL;
1240 
1241 	if (trans->reset_callback != NULL)
1242 		trans->reset_callback(reply, trans->reset_context);
1243 	trans->reset_callback = NULL;
1244 
1245 	/* finished */
1246 	smtp_client_transaction_finish(trans, reply);
1247 
1248 	smtp_client_transaction_unref(&trans);
1249 }
1250 
1251 static void
smtp_client_transaction_send_reset(struct smtp_client_transaction * trans)1252 smtp_client_transaction_send_reset(struct smtp_client_transaction *trans)
1253 {
1254 	struct smtp_reply failure;
1255 
1256 	i_assert(trans->reset);
1257 
1258 	e_debug(trans->event, "Sending reset");
1259 
1260 	timeout_remove(&trans->to_send);
1261 
1262 	i_zero(&failure);
1263 	if (trans->failure != NULL) {
1264 		smtp_client_transaction_fail_reply(trans, trans->failure);
1265 		failure = *trans->failure;
1266 		i_assert(failure.status != 0);
1267 	} else {
1268 		i_assert(trans->conn != NULL);
1269 
1270 		trans->cmd_rset = smtp_client_command_rset_submit_after(
1271 			trans->conn, 0, trans->cmd_last,
1272 			smtp_client_transaction_rset_cb, trans);
1273 
1274 		if (trans->cmd_last != NULL)
1275 			smtp_client_command_unlock(trans->cmd_last);
1276 
1277 		smtp_client_transaction_try_complete(trans);
1278 	}
1279 
1280 	if (trans->cmd_plug != NULL)
1281 		smtp_client_command_abort(&trans->cmd_plug);
1282 	trans->cmd_last = NULL;
1283 
1284 	if (failure.status != 0)
1285 		smtp_client_transaction_finish(trans, &failure);
1286 }
1287 
1288 #undef smtp_client_transaction_reset
smtp_client_transaction_reset(struct smtp_client_transaction * trans,smtp_client_command_callback_t * reset_callback,void * reset_context)1289 void smtp_client_transaction_reset(
1290 	struct smtp_client_transaction *trans,
1291 	smtp_client_command_callback_t *reset_callback, void *reset_context)
1292 {
1293 	i_assert(trans->state < SMTP_CLIENT_TRANSACTION_STATE_FINISHED);
1294 	i_assert(!trans->data_provided);
1295 	i_assert(!trans->reset);
1296 
1297 	e_debug(trans->event, "Reset");
1298 
1299 	trans->reset = TRUE;
1300 
1301 	trans->reset_callback = reset_callback;
1302 	trans->reset_context = reset_context;
1303 
1304 	if (trans->finish_timeout_msecs > 0) {
1305 		i_assert(trans->to_finish == NULL);
1306 		trans->to_finish = timeout_add(trans->finish_timeout_msecs,
1307 			smtp_client_transaction_timeout, trans);
1308 	}
1309 
1310 	smtp_client_transaction_submit(trans, TRUE);
1311 }
1312 
1313 static void
smtp_client_transaction_do_submit_more(struct smtp_client_transaction * trans)1314 smtp_client_transaction_do_submit_more(struct smtp_client_transaction *trans)
1315 {
1316 	timeout_remove(&trans->to_send);
1317 
1318 	if (trans->immediate)
1319 		trans->cmd_last = NULL;
1320 
1321 	/* Check whether we already failed */
1322 	if (trans->failure == NULL &&
1323 	    trans->state > SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM)
1324 		trans->failure = trans->mail_failure;
1325 	if (trans->failure != NULL) {
1326 		smtp_client_transaction_fail_reply(trans, trans->failure);
1327 		return;
1328 	}
1329 
1330 	i_assert(trans->conn != NULL);
1331 
1332 	/* Make sure transaction is started */
1333 	if (trans->state == SMTP_CLIENT_TRANSACTION_STATE_NEW) {
1334 		enum smtp_client_transaction_state state;
1335 		struct smtp_client_transaction *tmp_trans = trans;
1336 
1337 		smtp_client_transaction_ref(tmp_trans);
1338 		smtp_client_transaction_start(tmp_trans, NULL, NULL);
1339 		state = trans->state;
1340 		smtp_client_transaction_unref(&tmp_trans);
1341 		if (state >= SMTP_CLIENT_TRANSACTION_STATE_FINISHED)
1342 			return;
1343 	}
1344 
1345 	if (trans->state <= SMTP_CLIENT_TRANSACTION_STATE_PENDING)
1346 		return;
1347 
1348 	/* MAIL */
1349 	if (trans->mail_send != NULL) {
1350 		e_debug(trans->event, "Sending MAIL command");
1351 
1352 		i_assert(trans->state == SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM);
1353 
1354 		if (trans->cmd_last != NULL)
1355 			smtp_client_command_unlock(trans->cmd_last);
1356 
1357 		while (trans->mail_send != NULL) {
1358 			struct smtp_client_transaction_mail *mail =
1359 				trans->mail_send;
1360 
1361 			trans->mail_send = trans->mail_send->next;
1362 			mail->cmd_mail_from = trans->cmd_last =
1363 				smtp_client_command_mail_submit(trans->conn, 0,
1364 					mail->mail_from, &mail->mail_params,
1365 					smtp_client_transaction_mail_cb, trans);
1366 		}
1367 
1368 		if (!trans->immediate)
1369 			smtp_client_command_lock(trans->cmd_last);
1370 	}
1371 
1372 	/* RCPT */
1373 	if (trans->rcpts_send != NULL) {
1374 		e_debug(trans->event, "Sending recipients");
1375 
1376 		if (trans->cmd_last != NULL)
1377 			smtp_client_command_unlock(trans->cmd_last);
1378 
1379 		while (trans->rcpts_send != NULL) {
1380 			struct smtp_client_transaction_rcpt *rcpt =
1381 				trans->rcpts_send;
1382 
1383 			trans->rcpts_send = trans->rcpts_send->next;
1384 			rcpt->cmd_rcpt_to = trans->cmd_last =
1385 				smtp_client_command_rcpt_submit_after(
1386 					trans->conn, 0,	trans->cmd_last,
1387 					rcpt->rcpt_to, &rcpt->rcpt_params,
1388 					smtp_client_transaction_rcpt_cb, rcpt);
1389 		}
1390 		if (!trans->immediate)
1391 			smtp_client_command_lock(trans->cmd_last);
1392 	}
1393 
1394 	if (trans->cmd_plug != NULL &&
1395 	    (trans->immediate || trans->cmd_last != trans->cmd_plug))
1396 		smtp_client_command_abort(&trans->cmd_plug);
1397 
1398 	/* DATA / RSET */
1399 	if (trans->reset) {
1400 		smtp_client_transaction_send_reset(trans);
1401 	} else if (trans->data_input != NULL) {
1402 		smtp_client_transaction_send_data(trans);
1403 	}
1404 }
1405 
1406 static void
smtp_client_transaction_submit_more(struct smtp_client_transaction * trans)1407 smtp_client_transaction_submit_more(struct smtp_client_transaction *trans)
1408 {
1409 	smtp_client_transaction_ref(trans);
1410 	trans->submitting = TRUE;
1411 	smtp_client_transaction_do_submit_more(trans);
1412 	trans->submitting = FALSE;
1413 	smtp_client_transaction_unref(&trans);
1414 }
1415 
1416 static void
smtp_client_transaction_submit(struct smtp_client_transaction * trans,bool start)1417 smtp_client_transaction_submit(struct smtp_client_transaction *trans,
1418 			       bool start)
1419 {
1420 	if (trans->failure == NULL && !start &&
1421 	    trans->state <= SMTP_CLIENT_TRANSACTION_STATE_PENDING) {
1422 		/* Cannot submit commands at this time */
1423 		return;
1424 	}
1425 
1426 	if (trans->immediate) {
1427 		/* Submit immediately if not failed already: avoid calling
1428 		   failure callbacks directly (which is the first thing
1429 		   smtp_client_transaction_submit_more() would do). */
1430 		if (trans->failure == NULL &&
1431 		    trans->state > SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM)
1432 			trans->failure = trans->mail_failure;
1433 		if (trans->failure == NULL) {
1434 			smtp_client_transaction_submit_more(trans);
1435 			return;
1436 		}
1437 	}
1438 
1439 	if (trans->to_send != NULL) {
1440 		/* Already scheduled command submission */
1441 		return;
1442 	}
1443 
1444 	trans->to_send = timeout_add_short(0,
1445 		smtp_client_transaction_submit_more, trans);
1446 }
1447 
1448 static void
smtp_client_transaction_try_complete(struct smtp_client_transaction * trans)1449 smtp_client_transaction_try_complete(struct smtp_client_transaction *trans)
1450 {
1451 	i_assert(trans->conn != NULL);
1452 
1453 	if (trans->rcpts_queue_count > 0) {
1454 		/* Not all RCPT replies have come in yet */
1455 		e_debug(trans->event,  "RCPT replies are still pending (%u/%u)",
1456 			trans->rcpts_queue_count,
1457 			(trans->rcpts_queue_count + trans->rcpts_count));
1458 		return;
1459 	}
1460 	if (!trans->data_provided && !trans->reset) {
1461 		/* Still waiting for application to issue either
1462 		   smtp_client_transaction_send() or
1463 		   smtp_client_transaction_reset() */
1464 		e_debug(trans->event, "Transaction is not yet complete");
1465 		return;
1466 	}
1467 
1468 	if (trans->state == SMTP_CLIENT_TRANSACTION_STATE_RCPT_TO) {
1469 		/* Completed at this instance */
1470 		e_debug(trans->event,
1471 			"Got all RCPT replies and transaction is complete");
1472 	}
1473 
1474 	if (trans->reset) {
1475 		/* Entering reset state */
1476 		trans->state = SMTP_CLIENT_TRANSACTION_STATE_RESET;
1477 
1478 		if (trans->cmd_rset == NULL)
1479 			return;
1480 	} else {
1481 		/* Entering data state */
1482 		trans->state = SMTP_CLIENT_TRANSACTION_STATE_DATA;
1483 
1484 		if (trans->rcpts_count == 0) {
1485 			/* abort transaction if all recipients failed */
1486 			smtp_client_transaction_abort(trans);
1487 			return;
1488 		}
1489 
1490 		if (trans->cmd_data == NULL)
1491 			return;
1492 
1493 		if (HAS_ALL_BITS(trans->flags,
1494 				 SMTP_CLIENT_TRANSACTION_FLAG_REPLY_PER_RCPT)) {
1495 			smtp_client_command_set_replies(trans->cmd_data,
1496 							trans->rcpts_count);
1497 		}
1498 	}
1499 
1500 	/* Got replies for all recipients and submitted our last command;
1501 	   the next transaction can submit its commands now. */
1502 	smtp_client_connection_next_transaction(trans->conn, trans);
1503 }
1504 
smtp_client_transaction_set_immediate(struct smtp_client_transaction * trans,bool immediate)1505 void smtp_client_transaction_set_immediate(
1506 	struct smtp_client_transaction *trans, bool immediate)
1507 {
1508 	trans->immediate = immediate;
1509 }
1510 
smtp_client_transaction_connection_result(struct smtp_client_transaction * trans,const struct smtp_reply * reply)1511 void smtp_client_transaction_connection_result(
1512 	struct smtp_client_transaction *trans,
1513 	const struct smtp_reply *reply)
1514 {
1515 	if (!smtp_reply_is_success(reply)) {
1516 		if (trans->state <= SMTP_CLIENT_TRANSACTION_STATE_PENDING) {
1517 			e_debug(trans->event, "Failed to connect: %s",
1518 				smtp_reply_log(reply));
1519 		} else {
1520 			e_debug(trans->event, "Connection lost: %s",
1521 				smtp_reply_log(reply));
1522 		}
1523 		smtp_client_transaction_fail_reply(trans, reply);
1524 		return;
1525 	}
1526 
1527 	smtp_client_transaction_connection_ready(trans);
1528 }
1529 
smtp_client_transaction_connection_destroyed(struct smtp_client_transaction * trans)1530 void smtp_client_transaction_connection_destroyed(
1531 	struct smtp_client_transaction *trans)
1532 {
1533 	i_assert(trans->failure != NULL);
1534 	smtp_client_connection_unref(&trans->conn);
1535 }
1536 
1537 const struct smtp_client_transaction_times *
smtp_client_transaction_get_times(struct smtp_client_transaction * trans)1538 smtp_client_transaction_get_times(struct smtp_client_transaction *trans)
1539 {
1540 	return &trans->times;
1541 }
1542 
1543 enum smtp_client_transaction_state
smtp_client_transaction_get_state(struct smtp_client_transaction * trans)1544 smtp_client_transaction_get_state(struct smtp_client_transaction *trans)
1545 {
1546 	return trans->state;
1547 }
1548 
1549 const char *
smtp_client_transaction_get_state_name(struct smtp_client_transaction * trans)1550 smtp_client_transaction_get_state_name(struct smtp_client_transaction *trans)
1551 {
1552 	i_assert(trans->state >= SMTP_CLIENT_TRANSACTION_STATE_NEW &&
1553 		trans->state <= SMTP_CLIENT_TRANSACTION_STATE_ABORTED);
1554 	return smtp_client_transaction_state_names[trans->state];
1555 }
1556 
1557 const char *
smtp_client_transaction_get_state_destription(struct smtp_client_transaction * trans)1558 smtp_client_transaction_get_state_destription(
1559 	struct smtp_client_transaction *trans)
1560 {
1561 	enum smtp_client_connection_state conn_state;
1562 
1563 	switch (trans->state) {
1564 	case SMTP_CLIENT_TRANSACTION_STATE_NEW:
1565 		break;
1566 	case SMTP_CLIENT_TRANSACTION_STATE_PENDING:
1567 		i_assert(trans->conn != NULL);
1568 		conn_state = smtp_client_connection_get_state(trans->conn);
1569 		switch (conn_state) {
1570 		case SMTP_CLIENT_CONNECTION_STATE_CONNECTING:
1571 		case SMTP_CLIENT_CONNECTION_STATE_HANDSHAKING:
1572 		case SMTP_CLIENT_CONNECTION_STATE_AUTHENTICATING:
1573 			return smtp_client_connection_state_names[conn_state];
1574 		case SMTP_CLIENT_CONNECTION_STATE_TRANSACTION:
1575 			return "waiting for connection";
1576 		case SMTP_CLIENT_CONNECTION_STATE_DISCONNECTED:
1577 		case SMTP_CLIENT_CONNECTION_STATE_READY:
1578 		default:
1579 			break;
1580 		}
1581 		break;
1582 	case SMTP_CLIENT_TRANSACTION_STATE_MAIL_FROM:
1583 		return "waiting for reply to MAIL FROM";
1584 	case SMTP_CLIENT_TRANSACTION_STATE_RCPT_TO:
1585 		return "waiting for reply to RCPT TO";
1586 	case SMTP_CLIENT_TRANSACTION_STATE_DATA:
1587 		return "waiting for reply to DATA";
1588 	case SMTP_CLIENT_TRANSACTION_STATE_RESET:
1589 		return "waiting for reply to RESET";
1590 	case SMTP_CLIENT_TRANSACTION_STATE_FINISHED:
1591 		return "finished";
1592 	case SMTP_CLIENT_TRANSACTION_STATE_ABORTED:
1593 		return "aborted";
1594 	}
1595 	i_unreached();
1596 }
1597 
smtp_client_transaction_switch_ioloop(struct smtp_client_transaction * trans)1598 void smtp_client_transaction_switch_ioloop(
1599 	struct smtp_client_transaction *trans)
1600 {
1601 	if (trans->to_send != NULL)
1602 		trans->to_send = io_loop_move_timeout(&trans->to_send);
1603 	if (trans->to_finish != NULL)
1604 		trans->to_finish = io_loop_move_timeout(&trans->to_finish);
1605 }
1606