Improve SMTP client.
* include/mailutils/smtp.h (mu_smtp_dot): New proto. * libproto/mailer/smtp_dot.c: New file. * libproto/mailer/Makefile.am (libmu_mailer_la_SOURCES): Add smtp_dot.c. * libproto/mailer/smtp.c (smtp_send_message): Send RSET after an unexpected SMTP reply. Call mu_smtp_dot after successful sending. * libproto/mailer/smtp_data.c (_mu_smtp_data_end): Set state to MU_SMTP_DOT. * libproto/mailer/smtp_rset.c (mu_smtp_rset): Improve state selection algorithm. * libproto/mailer/smtp_send.c (mu_smtp_send_stream): Don't reset state: it is done by _mu_smtp_data_end. * testsuite/smtpsend.c (main): Call mu_smtp_dot after sending message.
Showing
8 changed files
with
102 additions
and
17 deletions
... | @@ -65,6 +65,7 @@ int mu_smtp_rcpt_basic (mu_smtp_t smtp, const char *email, | ... | @@ -65,6 +65,7 @@ int mu_smtp_rcpt_basic (mu_smtp_t smtp, const char *email, |
65 | 65 | ||
66 | int mu_smtp_data (mu_smtp_t smtp, mu_stream_t *pstream); | 66 | int mu_smtp_data (mu_smtp_t smtp, mu_stream_t *pstream); |
67 | int mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t str); | 67 | int mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t str); |
68 | int mu_smtp_dot (mu_smtp_t smtp); | ||
68 | int mu_smtp_rset (mu_smtp_t smtp); | 69 | int mu_smtp_rset (mu_smtp_t smtp); |
69 | int mu_smtp_quit (mu_smtp_t smtp); | 70 | int mu_smtp_quit (mu_smtp_t smtp); |
70 | 71 | ... | ... |
... | @@ -36,6 +36,7 @@ libmu_mailer_la_SOURCES = \ | ... | @@ -36,6 +36,7 @@ libmu_mailer_la_SOURCES = \ |
36 | smtp_create.c\ | 36 | smtp_create.c\ |
37 | smtp_data.c\ | 37 | smtp_data.c\ |
38 | smtp_disconnect.c\ | 38 | smtp_disconnect.c\ |
39 | smtp_dot.c\ | ||
39 | smtp_ehlo.c\ | 40 | smtp_ehlo.c\ |
40 | $(SMTP_GSASL)\ | 41 | $(SMTP_GSASL)\ |
41 | smtp_io.c\ | 42 | smtp_io.c\ | ... | ... |
... | @@ -375,8 +375,8 @@ static int | ... | @@ -375,8 +375,8 @@ static int |
375 | smtp_send_message (mu_mailer_t mailer, mu_message_t msg, | 375 | smtp_send_message (mu_mailer_t mailer, mu_message_t msg, |
376 | mu_address_t argfrom, mu_address_t argto) | 376 | mu_address_t argfrom, mu_address_t argto) |
377 | { | 377 | { |
378 | struct _smtp_mailer *smp = mailer->data; | 378 | struct _smtp_mailer *smp; |
379 | mu_smtp_t smtp = smp->smtp; | 379 | mu_smtp_t smtp; |
380 | int status; | 380 | int status; |
381 | size_t size, lines, count; | 381 | size_t size, lines, count; |
382 | const char *mail_from, *size_str; | 382 | const char *mail_from, *size_str; |
... | @@ -388,7 +388,8 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, | ... | @@ -388,7 +388,8 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, |
388 | smp = mailer->data; | 388 | smp = mailer->data; |
389 | if (!smp) | 389 | if (!smp) |
390 | return EINVAL; | 390 | return EINVAL; |
391 | 391 | smtp = smp->smtp; | |
392 | |||
392 | if ((status = mu_message_get_header (msg, &header))) | 393 | if ((status = mu_message_get_header (msg, &header))) |
393 | return status; | 394 | return status; |
394 | 395 | ||
... | @@ -400,7 +401,7 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, | ... | @@ -400,7 +401,7 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, |
400 | if (status) | 401 | if (status) |
401 | return status; | 402 | return status; |
402 | 403 | ||
403 | if (mu_smtp_capa_test (smp->smtp, "SIZE", &size_str) == 0 && | 404 | if (mu_smtp_capa_test (smtp, "SIZE", &size_str) == 0 && |
404 | mu_message_size (msg, &size) == 0 && | 405 | mu_message_size (msg, &size) == 0 && |
405 | mu_message_lines (msg, &lines) == 0) | 406 | mu_message_lines (msg, &lines) == 0) |
406 | { | 407 | { |
... | @@ -409,21 +410,33 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, | ... | @@ -409,21 +410,33 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, |
409 | 410 | ||
410 | if (msgsize && msgsize > maxsize) | 411 | if (msgsize && msgsize > maxsize) |
411 | return EFBIG; | 412 | return EFBIG; |
412 | status = mu_smtp_mail_basic (smp->smtp, mail_from, | 413 | status = mu_smtp_mail_basic (smtp, mail_from, |
413 | "SIZE=%lu", | 414 | "SIZE=%lu", |
414 | (unsigned long) msgsize); | 415 | (unsigned long) msgsize); |
415 | } | 416 | } |
416 | else | 417 | else |
417 | status = mu_smtp_mail_basic (smp->smtp, mail_from, NULL); | 418 | status = mu_smtp_mail_basic (smtp, mail_from, NULL); |
418 | if (status) | 419 | if (status) |
419 | return status; | 420 | { |
421 | if (status == MU_ERR_REPLY) | ||
422 | mu_smtp_rset (smtp); | ||
423 | return status; | ||
424 | } | ||
420 | 425 | ||
421 | status = _rcpt_to_addr (smtp, smp->rcpt_to, &count); | 426 | status = _rcpt_to_addr (smtp, smp->rcpt_to, &count); |
422 | if (status && count == 0) | 427 | if (status && count == 0) |
423 | return status; | 428 | { |
429 | if (status == MU_ERR_REPLY) | ||
430 | mu_smtp_rset (smtp); | ||
431 | return status; | ||
432 | } | ||
424 | status = _rcpt_to_addr (smtp, smp->rcpt_bcc, &count); | 433 | status = _rcpt_to_addr (smtp, smp->rcpt_bcc, &count); |
425 | if (status && count == 0) | 434 | if (status && count == 0) |
426 | return status; | 435 | { |
436 | if (status == MU_ERR_REPLY) | ||
437 | mu_smtp_rset (smtp); | ||
438 | return status; | ||
439 | } | ||
427 | 440 | ||
428 | if (mu_header_sget_value (header, MU_HEADER_BCC, NULL)) | 441 | if (mu_header_sget_value (header, MU_HEADER_BCC, NULL)) |
429 | { | 442 | { |
... | @@ -433,7 +446,11 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, | ... | @@ -433,7 +446,11 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, |
433 | 446 | ||
434 | status = mu_smtp_data (smtp, &ostr); | 447 | status = mu_smtp_data (smtp, &ostr); |
435 | if (status) | 448 | if (status) |
436 | return status; | 449 | { |
450 | if (status == MU_ERR_REPLY) | ||
451 | mu_smtp_rset (smtp); | ||
452 | return status; | ||
453 | } | ||
437 | mu_header_get_iterator (header, &itr); | 454 | mu_header_get_iterator (header, &itr); |
438 | for (mu_iterator_first (itr); !mu_iterator_is_done (itr); | 455 | for (mu_iterator_first (itr); !mu_iterator_is_done (itr); |
439 | mu_iterator_next (itr)) | 456 | mu_iterator_next (itr)) |
... | @@ -451,7 +468,7 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, | ... | @@ -451,7 +468,7 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, |
451 | 468 | ||
452 | mu_message_get_body (msg, &body); | 469 | mu_message_get_body (msg, &body); |
453 | mu_body_get_streamref (body, &bstr); | 470 | mu_body_get_streamref (body, &bstr); |
454 | mu_stream_copy (ostr, bstr, 0, NULL); | 471 | status = mu_stream_copy (ostr, bstr, 0, NULL); |
455 | mu_stream_destroy (&bstr); | 472 | mu_stream_destroy (&bstr); |
456 | mu_stream_close (ostr); | 473 | mu_stream_close (ostr); |
457 | mu_stream_destroy (&ostr); | 474 | mu_stream_destroy (&ostr); |
... | @@ -463,13 +480,17 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, | ... | @@ -463,13 +480,17 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg, |
463 | status = mu_smtp_send_stream (smtp, str); | 480 | status = mu_smtp_send_stream (smtp, str); |
464 | mu_stream_destroy (&str); | 481 | mu_stream_destroy (&str); |
465 | } | 482 | } |
466 | mu_smtp_quit (smtp); | ||
467 | mu_address_destroy (&smp->rcpt_to); | 483 | mu_address_destroy (&smp->rcpt_to); |
468 | mu_address_destroy (&smp->rcpt_bcc); | 484 | mu_address_destroy (&smp->rcpt_bcc); |
485 | if (status == 0) | ||
486 | { | ||
487 | status = mu_smtp_dot (smtp); | ||
488 | if (status == MU_ERR_REPLY) | ||
489 | mu_smtp_rset (smtp); | ||
490 | } | ||
469 | return status; | 491 | return status; |
470 | } | 492 | } |
471 | 493 | ||
472 | |||
473 | static int | 494 | static int |
474 | _mailer_smtp_init (mu_mailer_t mailer) | 495 | _mailer_smtp_init (mu_mailer_t mailer) |
475 | { | 496 | { | ... | ... |
... | @@ -76,6 +76,7 @@ _mu_smtp_data_end (mu_smtp_t smtp) | ... | @@ -76,6 +76,7 @@ _mu_smtp_data_end (mu_smtp_t smtp) |
76 | mu_strerror (status)); | 76 | mu_strerror (status)); |
77 | } | 77 | } |
78 | _mu_smtp_xscript_level (smtp, MU_XSCRIPT_NORMAL); | 78 | _mu_smtp_xscript_level (smtp, MU_XSCRIPT_NORMAL); |
79 | smtp->state = MU_SMTP_DOT; | ||
79 | return status; | 80 | return status; |
80 | } | 81 | } |
81 | 82 | ... | ... |
libproto/mailer/smtp_dot.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2010 Free Software Foundation, Inc. | ||
3 | |||
4 | This library is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU Lesser General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Lesser General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Lesser General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #ifdef HAVE_CONFIG_H | ||
18 | # include <config.h> | ||
19 | #endif | ||
20 | |||
21 | #include <errno.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | #include <mailutils/errno.h> | ||
25 | #include <mailutils/cctype.h> | ||
26 | #include <mailutils/list.h> | ||
27 | #include <mailutils/util.h> | ||
28 | #include <mailutils/smtp.h> | ||
29 | #include <mailutils/sys/smtp.h> | ||
30 | |||
31 | int | ||
32 | mu_smtp_dot (mu_smtp_t smtp) | ||
33 | { | ||
34 | int status; | ||
35 | |||
36 | if (!smtp) | ||
37 | return EINVAL; | ||
38 | if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR)) | ||
39 | return MU_ERR_FAILURE; | ||
40 | if (smtp->state != MU_SMTP_DOT) | ||
41 | return MU_ERR_SEQ; | ||
42 | status = mu_smtp_response (smtp); | ||
43 | MU_SMTP_CHECK_ERROR (smtp, status); | ||
44 | if (smtp->replcode[0] != '2') | ||
45 | return MU_ERR_REPLY; | ||
46 | smtp->state = MU_SMTP_MAIL; /* FIXME: Force _EHLO perhaps? */ | ||
47 | return 0; | ||
48 | } |
... | @@ -43,6 +43,21 @@ mu_smtp_rset (mu_smtp_t smtp) | ... | @@ -43,6 +43,21 @@ mu_smtp_rset (mu_smtp_t smtp) |
43 | MU_SMTP_CHECK_ERROR (smtp, status); | 43 | MU_SMTP_CHECK_ERROR (smtp, status); |
44 | if (smtp->replcode[0] != '2') | 44 | if (smtp->replcode[0] != '2') |
45 | return MU_ERR_REPLY; | 45 | return MU_ERR_REPLY; |
46 | smtp->state = MU_SMTP_EHLO; | 46 | |
47 | switch (smtp->state) | ||
48 | { | ||
49 | case MU_SMTP_INIT: | ||
50 | case MU_SMTP_EHLO: | ||
51 | case MU_SMTP_DOT: | ||
52 | /* RFC 2821, 4.1.1.5 RESET (RSET): | ||
53 | [RSET] is effectively equivalent to a NOOP (i.e., if has no effect) | ||
54 | if issued immediately after EHLO, before EHLO is issued in the | ||
55 | session, after an end-of-data indicator has been sent and | ||
56 | acknowledged, or immediately before a QUIT */ | ||
57 | break; | ||
58 | |||
59 | default: | ||
60 | smtp->state = MU_SMTP_MAIL; | ||
61 | } | ||
47 | return 0; | 62 | return 0; |
48 | } | 63 | } | ... | ... |
... | @@ -62,7 +62,5 @@ mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t stream) | ... | @@ -62,7 +62,5 @@ mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t stream) |
62 | 62 | ||
63 | status = _smtp_data_send (smtp, input); | 63 | status = _smtp_data_send (smtp, input); |
64 | mu_stream_destroy (&input); | 64 | mu_stream_destroy (&input); |
65 | if (status == 0) | ||
66 | smtp->state = MU_SMTP_DOT; | ||
67 | return status; | 65 | return status; |
68 | } | 66 | } | ... | ... |
... | @@ -289,7 +289,7 @@ main (int argc, char **argv) | ... | @@ -289,7 +289,7 @@ main (int argc, char **argv) |
289 | mu_stream_close (ostr); | 289 | mu_stream_close (ostr); |
290 | mu_stream_destroy (&ostr); | 290 | mu_stream_destroy (&ostr); |
291 | } | 291 | } |
292 | 292 | MU_ASSERT (mu_smtp_dot (smtp)); | |
293 | MU_ASSERT (mu_smtp_quit (smtp)); | 293 | MU_ASSERT (mu_smtp_quit (smtp)); |
294 | 294 | ||
295 | mu_smtp_destroy (&smtp); | 295 | mu_smtp_destroy (&smtp); | ... | ... |
-
Please register or sign in to post a comment