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,
int mu_smtp_data (mu_smtp_t smtp, mu_stream_t *pstream);
int mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t str);
int mu_smtp_dot (mu_smtp_t smtp);
int mu_smtp_rset (mu_smtp_t smtp);
int mu_smtp_quit (mu_smtp_t smtp);
......
......@@ -36,6 +36,7 @@ libmu_mailer_la_SOURCES = \
smtp_create.c\
smtp_data.c\
smtp_disconnect.c\
smtp_dot.c\
smtp_ehlo.c\
$(SMTP_GSASL)\
smtp_io.c\
......
......@@ -375,8 +375,8 @@ static int
smtp_send_message (mu_mailer_t mailer, mu_message_t msg,
mu_address_t argfrom, mu_address_t argto)
{
struct _smtp_mailer *smp = mailer->data;
mu_smtp_t smtp = smp->smtp;
struct _smtp_mailer *smp;
mu_smtp_t smtp;
int status;
size_t size, lines, count;
const char *mail_from, *size_str;
......@@ -388,7 +388,8 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg,
smp = mailer->data;
if (!smp)
return EINVAL;
smtp = smp->smtp;
if ((status = mu_message_get_header (msg, &header)))
return status;
......@@ -400,7 +401,7 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg,
if (status)
return status;
if (mu_smtp_capa_test (smp->smtp, "SIZE", &size_str) == 0 &&
if (mu_smtp_capa_test (smtp, "SIZE", &size_str) == 0 &&
mu_message_size (msg, &size) == 0 &&
mu_message_lines (msg, &lines) == 0)
{
......@@ -409,21 +410,33 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg,
if (msgsize && msgsize > maxsize)
return EFBIG;
status = mu_smtp_mail_basic (smp->smtp, mail_from,
status = mu_smtp_mail_basic (smtp, mail_from,
"SIZE=%lu",
(unsigned long) msgsize);
}
else
status = mu_smtp_mail_basic (smp->smtp, mail_from, NULL);
status = mu_smtp_mail_basic (smtp, mail_from, NULL);
if (status)
return status;
{
if (status == MU_ERR_REPLY)
mu_smtp_rset (smtp);
return status;
}
status = _rcpt_to_addr (smtp, smp->rcpt_to, &count);
if (status && count == 0)
return status;
{
if (status == MU_ERR_REPLY)
mu_smtp_rset (smtp);
return status;
}
status = _rcpt_to_addr (smtp, smp->rcpt_bcc, &count);
if (status && count == 0)
return status;
{
if (status == MU_ERR_REPLY)
mu_smtp_rset (smtp);
return status;
}
if (mu_header_sget_value (header, MU_HEADER_BCC, NULL))
{
......@@ -433,7 +446,11 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg,
status = mu_smtp_data (smtp, &ostr);
if (status)
return status;
{
if (status == MU_ERR_REPLY)
mu_smtp_rset (smtp);
return status;
}
mu_header_get_iterator (header, &itr);
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
......@@ -451,7 +468,7 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg,
mu_message_get_body (msg, &body);
mu_body_get_streamref (body, &bstr);
mu_stream_copy (ostr, bstr, 0, NULL);
status = mu_stream_copy (ostr, bstr, 0, NULL);
mu_stream_destroy (&bstr);
mu_stream_close (ostr);
mu_stream_destroy (&ostr);
......@@ -463,13 +480,17 @@ smtp_send_message (mu_mailer_t mailer, mu_message_t msg,
status = mu_smtp_send_stream (smtp, str);
mu_stream_destroy (&str);
}
mu_smtp_quit (smtp);
mu_address_destroy (&smp->rcpt_to);
mu_address_destroy (&smp->rcpt_bcc);
if (status == 0)
{
status = mu_smtp_dot (smtp);
if (status == MU_ERR_REPLY)
mu_smtp_rset (smtp);
}
return status;
}
static int
_mailer_smtp_init (mu_mailer_t mailer)
{
......
......@@ -76,6 +76,7 @@ _mu_smtp_data_end (mu_smtp_t smtp)
mu_strerror (status));
}
_mu_smtp_xscript_level (smtp, MU_XSCRIPT_NORMAL);
smtp->state = MU_SMTP_DOT;
return status;
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <mailutils/errno.h>
#include <mailutils/cctype.h>
#include <mailutils/list.h>
#include <mailutils/util.h>
#include <mailutils/smtp.h>
#include <mailutils/sys/smtp.h>
int
mu_smtp_dot (mu_smtp_t smtp)
{
int status;
if (!smtp)
return EINVAL;
if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR))
return MU_ERR_FAILURE;
if (smtp->state != MU_SMTP_DOT)
return MU_ERR_SEQ;
status = mu_smtp_response (smtp);
MU_SMTP_CHECK_ERROR (smtp, status);
if (smtp->replcode[0] != '2')
return MU_ERR_REPLY;
smtp->state = MU_SMTP_MAIL; /* FIXME: Force _EHLO perhaps? */
return 0;
}
......@@ -43,6 +43,21 @@ mu_smtp_rset (mu_smtp_t smtp)
MU_SMTP_CHECK_ERROR (smtp, status);
if (smtp->replcode[0] != '2')
return MU_ERR_REPLY;
smtp->state = MU_SMTP_EHLO;
switch (smtp->state)
{
case MU_SMTP_INIT:
case MU_SMTP_EHLO:
case MU_SMTP_DOT:
/* RFC 2821, 4.1.1.5 RESET (RSET):
[RSET] is effectively equivalent to a NOOP (i.e., if has no effect)
if issued immediately after EHLO, before EHLO is issued in the
session, after an end-of-data indicator has been sent and
acknowledged, or immediately before a QUIT */
break;
default:
smtp->state = MU_SMTP_MAIL;
}
return 0;
}
......
......@@ -62,7 +62,5 @@ mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t stream)
status = _smtp_data_send (smtp, input);
mu_stream_destroy (&input);
if (status == 0)
smtp->state = MU_SMTP_DOT;
return status;
}
......
......@@ -289,7 +289,7 @@ main (int argc, char **argv)
mu_stream_close (ostr);
mu_stream_destroy (&ostr);
}
MU_ASSERT (mu_smtp_dot (smtp));
MU_ASSERT (mu_smtp_quit (smtp));
mu_smtp_destroy (&smtp);
......