Commit d992b1b4 d992b1b4f5d731a3e11a5caaffd22cfd068e5477 by Sergey Poznyakoff

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.
1 parent d9cd8883
...@@ -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
......
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);
......