Commit 7b5902b4 7b5902b4ffd7acf44934dcdd1d09e70abe26efc3 by Sergey Poznyakoff

Improve smtp sending functions.

* include/mailutils/smtp.h (mu_smtp_write): Mark as printf-like.
(mu_smtp_mail_basic, mu_smtp_rcpt_basic): Take variable number
of arguments.  Mark as printf-like.
(mu_smtp_data): New prototype.
* include/mailutils/sys/smtp.h (_MU_SMTP_SAVEBUF): New flag.
(_mu_smtp) <savebuf>: New member.
(_mu_smtp_data_begin, _mu_smtp_data_end): New protos.
* libproto/mailer/smtp_send.c: New file.
* libproto/mailer/smtp_data.c (_mu_smtp_data_begin)
(_mu_smtp_data_end, mu_smtp_data): New functions.

* libproto/mailer/Makefile.am (libmu_mailer_la_SOURCES): Add smtp_send.c.
* libproto/mailer/smtp_ehlo.c (mu_smtp_ehlo): Switch to MU_SMTP_EHLO
only if in MU_SMTP_MAIL state.
* libproto/mailer/smtp_mail.c (mu_smtp_mail_basic): Take variable number
of arguments.
* libproto/mailer/smtp_param.c (mu_smtp_get_param): Add missing typecast.
* libproto/mailer/smtp_rcpt.c (mu_smtp_rcpt_basic): Take variable number
of arguments.
* libproto/mailer/smtp_send.c (_smtp_data_send): Use _mu_smtp_data_begin and
_mu_smtp_data_end.
* testsuite/smtpsend.c: Emulate sending from a MU message.
1 parent c382e9d0
......@@ -43,7 +43,7 @@ int mu_smtp_get_carrier (mu_smtp_t smtp, mu_stream_t *pcarrier);
int mu_smtp_open (mu_smtp_t);
int mu_smtp_response (mu_smtp_t smtp);
int mu_smtp_write (mu_smtp_t smtp, const char *fmt, ...);
int mu_smtp_write (mu_smtp_t smtp, const char *fmt, ...) MU_PRINTFLIKE(2,3);
#define MU_SMTP_TRACE_CLR 0
#define MU_SMTP_TRACE_SET 1
......@@ -58,8 +58,12 @@ int mu_smtp_get_param (mu_smtp_t smtp, int code, const char **param);
int mu_smtp_capa_test (mu_smtp_t smtp, const char *capa, const char **pret);
int mu_smtp_starttls (mu_smtp_t smtp);
int mu_smtp_mail_basic (mu_smtp_t smtp, const char *email, const char *args);
int mu_smtp_rcpt_basic (mu_smtp_t smtp, const char *email, const char *args);
int mu_smtp_mail_basic (mu_smtp_t smtp, const char *email,
const char *fmt, ...) MU_PRINTFLIKE(3,4);
int mu_smtp_rcpt_basic (mu_smtp_t smtp, const char *email,
const char *fmt, ...) MU_PRINTFLIKE(3,4);
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_rset (mu_smtp_t smtp);
int mu_smtp_quit (mu_smtp_t smtp);
......
......@@ -21,6 +21,7 @@
# include <sys/socket.h>
# include <mailutils/types.h>
# include <mailutils/smtp.h>
# include <mailutils/stream.h>
# define _MU_SMTP_ESMTP 0x01 /* Connection supports ESMTP */
# define _MU_SMTP_TRACE 0x02 /* Session trace required/enabled */
......@@ -29,6 +30,7 @@
# define _MU_SMTP_TLS 0x10 /* TLS initiated */
# define _MU_SMTP_AUTH 0x20 /* Authorization passed */
# define _MU_SMTP_CLNPASS 0x40 /* Password has been de-obfuscated */
# define _MU_SMTP_SAVEBUF 0x80 /* Buffering state saved */
#define MU_SMTP_XSCRIPT_MASK(n) (0x100<<(n))
......@@ -69,6 +71,7 @@ struct _mu_smtp
size_t flsize;
mu_list_t mlrepl;
struct mu_buffer_query savebuf;
};
#define MU_SMTP_FSET(p,f) ((p)->flags |= (f))
......@@ -91,5 +94,7 @@ int _mu_smtp_trace_disable (mu_smtp_t smtp);
int _mu_smtp_xscript_level (mu_smtp_t smtp, int xlev);
int _mu_smtp_gsasl_auth (mu_smtp_t smtp);
int _mu_smtp_mech_impl (mu_smtp_t smtp, mu_list_t list);
int _mu_smtp_data_begin (mu_smtp_t smtp);
int _mu_smtp_data_end (mu_smtp_t smtp);
#endif
......
......@@ -48,6 +48,7 @@ libmu_mailer_la_SOURCES = \
smtp_param.c\
smtp_rcpt.c\
smtp_rset.c\
smtp_send.c\
smtp_starttls.c\
smtp_trace.c\
smtp_quit.c\
......
......@@ -22,18 +22,18 @@
#include <stdlib.h>
#include <string.h>
#include <mailutils/errno.h>
#include <mailutils/diag.h>
#include <mailutils/filter.h>
#include <mailutils/list.h>
#include <mailutils/smtp.h>
#include <mailutils/stream.h>
#include <mailutils/sys/stream.h>
#include <mailutils/sys/smtp.h>
static int
_smtp_data_send (mu_smtp_t smtp, mu_stream_t stream)
int
_mu_smtp_data_begin (mu_smtp_t smtp)
{
int status;
struct mu_buffer_query oldbuf;
int buffer_changed = 0;
status = mu_smtp_write (smtp, "DATA\r\n");
MU_SMTP_CHECK_ERROR (smtp, status);
......@@ -47,34 +47,51 @@ _smtp_data_send (mu_smtp_t smtp, mu_stream_t stream)
_mu_smtp_xscript_level (smtp, MU_XSCRIPT_PAYLOAD);
if (mu_stream_ioctl (smtp->carrier, MU_IOCTL_GET_TRANSPORT_BUFFER,
&oldbuf) == 0)
&smtp->savebuf) == 0)
{
struct mu_buffer_query newbuf;
newbuf.type = MU_TRANSPORT_OUTPUT;
newbuf.buftype = mu_buffer_full;
newbuf.bufsize = 64*1024;
buffer_changed = mu_stream_ioctl (smtp->carrier,
MU_IOCTL_SET_TRANSPORT_BUFFER,
&newbuf) == 0;
if (mu_stream_ioctl (smtp->carrier, MU_IOCTL_SET_TRANSPORT_BUFFER,
&newbuf) == 0)
MU_SMTP_FSET (smtp, _MU_SMTP_SAVEBUF);
}
return 0;
}
status = mu_stream_copy (smtp->carrier, stream, 0, NULL);
int
_mu_smtp_data_end (mu_smtp_t smtp)
{
int status = 0;
/* code is always _MU_STR_EVENT_CLOSE */
if (MU_SMTP_FISSET (smtp, _MU_SMTP_SAVEBUF))
{
status = mu_stream_ioctl (smtp->carrier, MU_IOCTL_SET_TRANSPORT_BUFFER,
&smtp->savebuf);
if (status)
mu_diag_output (MU_DIAG_NOTICE,
"failed to restore buffer state on SMTP carrier: %s",
mu_strerror (status));
}
_mu_smtp_xscript_level (smtp, MU_XSCRIPT_NORMAL);
mu_stream_flush (smtp->carrier);
if (buffer_changed)
mu_stream_ioctl (smtp->carrier, MU_IOCTL_SET_TRANSPORT_BUFFER,
&oldbuf);
return status;
}
static void
_smtp_event_cb (struct _mu_stream *str, int code,
unsigned long lval, void *pval)
{
mu_smtp_t smtp = str->event_cb_data;
_mu_smtp_data_end (smtp);
}
int
mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t stream)
mu_smtp_data (mu_smtp_t smtp, mu_stream_t *pstream)
{
int status;
mu_stream_t input;
if (!smtp)
return EINVAL;
if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR))
......@@ -82,14 +99,17 @@ mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t stream)
if (smtp->state != MU_SMTP_MORE)
return MU_ERR_SEQ;
status = mu_filter_create (&input, stream, "CRLFDOT", MU_FILTER_ENCODE,
MU_STREAM_READ);
status = _mu_smtp_data_begin (smtp);
if (status)
return status;
status = _smtp_data_send (smtp, input);
mu_stream_destroy (&input);
if (status == 0)
smtp->state = MU_SMTP_DOT;
return status;
status = mu_filter_create (&input, smtp->carrier, "CRLFDOT",
MU_FILTER_ENCODE, MU_STREAM_WRITE);
if (status)
return status;
input->event_cb = _smtp_event_cb;
input->event_cb_data = smtp;
input->event_mask = _MU_STR_EVMASK (_MU_STR_EVENT_CLOSE);
*pstream = input;
return 0;
}
......
......@@ -94,6 +94,7 @@ mu_smtp_ehlo (mu_smtp_t smtp)
if (smtp->replcode[0] != '2')
return MU_ERR_REPLY;
}
smtp->state = MU_SMTP_MAIL;
if (smtp->state == MU_SMTP_EHLO)
smtp->state = MU_SMTP_MAIL;
return 0;
}
......
......@@ -19,6 +19,7 @@
#endif
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <mailutils/errno.h>
......@@ -26,10 +27,11 @@
#include <mailutils/list.h>
#include <mailutils/mutil.h>
#include <mailutils/smtp.h>
#include <mailutils/stream.h>
#include <mailutils/sys/smtp.h>
int
mu_smtp_mail_basic (mu_smtp_t smtp, const char *email, const char *args)
mu_smtp_mail_basic (mu_smtp_t smtp, const char *email, const char *fmt, ...)
{
int status;
......@@ -41,9 +43,14 @@ mu_smtp_mail_basic (mu_smtp_t smtp, const char *email, const char *args)
return MU_ERR_SEQ;
status = mu_smtp_write (smtp, "MAIL FROM:<%s>", email);
MU_SMTP_CHECK_ERROR (smtp, status);
if (args)
if (fmt)
{
status = mu_smtp_write (smtp, " %s", args);
va_list ap;
status = mu_smtp_write (smtp, " ");
va_start (ap, fmt);
status = mu_stream_vprintf (smtp->carrier, fmt, ap);
va_end (ap);
MU_SMTP_CHECK_ERROR (smtp, status);
}
status = mu_smtp_write (smtp, "\r\n");
......
......@@ -24,6 +24,7 @@
#include <mailutils/errno.h>
#include <mailutils/cctype.h>
#include <mailutils/list.h>
#include <mailutils/secret.h>
#include <mailutils/smtp.h>
#include <mailutils/sys/smtp.h>
......@@ -69,7 +70,7 @@ mu_smtp_get_param (mu_smtp_t smtp, int pcode, const char **pparam)
if (pcode == MU_SMTP_PARAM_PASSWORD && smtp->secret &&
!MU_SMTP_FISSET (smtp, _MU_SMTP_CLNPASS))
{
smtp->param[pcode] = mu_secret_password (smtp->secret);
smtp->param[pcode] = (char*) mu_secret_password (smtp->secret);
MU_SMTP_FSET (smtp, _MU_SMTP_CLNPASS);
}
......
......@@ -26,10 +26,11 @@
#include <mailutils/list.h>
#include <mailutils/mutil.h>
#include <mailutils/smtp.h>
#include <mailutils/stream.h>
#include <mailutils/sys/smtp.h>
int
mu_smtp_rcpt_basic (mu_smtp_t smtp, const char *email, const char *args)
mu_smtp_rcpt_basic (mu_smtp_t smtp, const char *email, const char *fmt, ...)
{
int status;
......@@ -41,9 +42,14 @@ mu_smtp_rcpt_basic (mu_smtp_t smtp, const char *email, const char *args)
return MU_ERR_SEQ;
status = mu_smtp_write (smtp, "RCPT TO:<%s>", email);
MU_SMTP_CHECK_ERROR (smtp, status);
if (args)
if (fmt)
{
status = mu_smtp_write (smtp, " %s", args);
va_list ap;
status = mu_smtp_write (smtp, " ");
va_start (ap, fmt);
status = mu_stream_vprintf (smtp->carrier, fmt, ap);
va_end (ap);
MU_SMTP_CHECK_ERROR (smtp, status);
}
status = mu_smtp_write (smtp, "\r\n");
......@@ -56,5 +62,3 @@ mu_smtp_rcpt_basic (mu_smtp_t smtp, const char *email, const char *args)
smtp->state = MU_SMTP_MORE;
return 0;
}
......
/* 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/filter.h>
#include <mailutils/list.h>
#include <mailutils/smtp.h>
#include <mailutils/stream.h>
#include <mailutils/sys/smtp.h>
static int
_smtp_data_send (mu_smtp_t smtp, mu_stream_t stream)
{
int status = _mu_smtp_data_begin (smtp);
if (status)
return status;
status = mu_stream_copy (smtp->carrier, stream, 0, NULL);
_mu_smtp_data_end (smtp);
return status;
}
int
mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t stream)
{
int status;
mu_stream_t input;
if (!smtp)
return EINVAL;
if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR))
return MU_ERR_FAILURE;
if (smtp->state != MU_SMTP_MORE)
return MU_ERR_SEQ;
status = mu_filter_create (&input, stream, "CRLFDOT", MU_FILTER_ENCODE,
MU_STREAM_READ);
if (status)
return status;
status = _smtp_data_send (smtp, input);
mu_stream_destroy (&input);
if (status == 0)
smtp->state = MU_SMTP_DOT;
return status;
}
......@@ -20,6 +20,7 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <mailutils/cctype.h>
#include <mailutils/mailutils.h>
#include <mailutils/smtp.h>
......@@ -27,7 +28,8 @@ static char usage_text[] =
"usage: %s hostname [port=N] [trace=N] [tls=N] [from=STRING] [rcpt=STRING]\n"
" [domain=STRING] [user=STRING] [pass=STRING]\n"
" [service=STRING] [realm=STRING] [host=STRING]\n"
" [auth=method[,...]] [url=STRING] [input=FILE] [raw=N]\n";
" [auth=method[,...]] [url=STRING] [input=FILE] [raw=N]\n"
" [skiphdr=name[,...]]\n";
static void
usage ()
......@@ -45,12 +47,40 @@ send_rcpt_command (void *item, void *data)
MU_ASSERT (mu_smtp_rcpt_basic (smtp, email, NULL));
return 0;
}
static void
update_list (mu_list_t *plist, const char *arg)
{
int mc, j;
char **mv;
mu_list_t list = *plist;
if (!list)
{
MU_ASSERT (mu_list_create (&list));
*plist = list;
}
MU_ASSERT (mu_argcv_get_np (arg, strlen (arg),
",", NULL,
0,
&mc, &mv, NULL));
for (j = 0; j < mc; j++)
MU_ASSERT (mu_list_append (list, mv[j]));
free (mv);
}
static int
headercmp (const void *item, const void *data)
{
return mu_c_strcasecmp (item, data);
}
int
main (int argc, char **argv)
{
int i;
char *host;
char *host = NULL;
char *infile = NULL;
int port = 25;
int tls = 0;
......@@ -62,6 +92,7 @@ main (int argc, char **argv)
char *from = NULL;
mu_list_t rcpt_list = NULL;
mu_list_t meth_list = NULL;
mu_list_t skiphdr_list = NULL;
mu_set_program_name (argv[0]);
#ifdef WITH_TLS
......@@ -85,8 +116,17 @@ main (int argc, char **argv)
}
}
else if (strncmp (argv[i], "trace=", 6) == 0)
mu_smtp_trace (smtp, atoi (argv[i] + 6) ?
MU_SMTP_TRACE_SET : MU_SMTP_TRACE_CLR);
{
char *arg = argv[i] + 6;
if (mu_isdigit (arg[0]))
mu_smtp_trace (smtp, atoi (argv[i] + 6) ?
MU_SMTP_TRACE_SET : MU_SMTP_TRACE_CLR);
else if (strcmp (arg, "secure") == 0)
mu_smtp_trace_mask (smtp, MU_SMTP_TRACE_SET, MU_XSCRIPT_SECURE);
else if (strcmp (arg, "payload") == 0)
mu_smtp_trace_mask (smtp, MU_SMTP_TRACE_SET, MU_XSCRIPT_PAYLOAD);
}
else if (strncmp (argv[i], "tls=", 4) == 0)
tls = atoi (argv[i] + 4);
else if (strncmp (argv[i], "domain=", 7) == 0)
......@@ -110,8 +150,8 @@ main (int argc, char **argv)
else if (strncmp (argv[i], "url=", 4) == 0)
MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_URL,
argv[i] + 4));
else if (strncmp (argv[i], "infile=", 7) == 0)
infile = argv[i] + 7;
else if (strncmp (argv[i], "input=", 6) == 0)
infile = argv[i] + 6;
else if (strncmp (argv[i], "raw=", 4) == 0)
raw = atoi (argv[i] + 4);
else if (strncmp (argv[i], "rcpt=", 5) == 0)
......@@ -123,20 +163,17 @@ main (int argc, char **argv)
else if (strncmp (argv[i], "from=", 5) == 0)
from = argv[i] + 5;
else if (strncmp (argv[i], "auth=", 5) == 0)
update_list (&meth_list, argv[i] + 5);
else if (strncmp (argv[i], "skiphdr=", 8) == 0)
{
int mc, j;
char **mv;
if (!meth_list)
MU_ASSERT (mu_list_create (&meth_list));
MU_ASSERT (mu_argcv_get_np (argv[i] + 5, strlen (argv[i] + 5),
",", NULL,
0,
&mc, &mv, NULL));
for (j = 0; j < mc; j++)
MU_ASSERT (mu_list_append (meth_list, mv[j]));
free (mv);
update_list (&skiphdr_list, argv[i] + 8);
raw = 0;
}
else if (host)
{
mu_error ("server name already given: %s, new name %s?",
host, argv[i]);
exit (1);
}
else
host = argv[i];
......@@ -209,20 +246,55 @@ main (int argc, char **argv)
}
}
MU_ASSERT (mu_smtp_mail_basic (smtp, from, NULL));
mu_list_do (rcpt_list, send_rcpt_command, smtp);
if (raw)
{
/* Raw sending mode: send from the stream directly */
MU_ASSERT (mu_smtp_mail_basic (smtp, from, NULL));
mu_list_do (rcpt_list, send_rcpt_command, smtp);
MU_ASSERT (mu_smtp_send_stream (smtp, instr));
MU_ASSERT (mu_smtp_quit (smtp));
}
else
{
/* Message (standard) sending mode: send a MU message. */
//FIXME;
mu_message_t msg;
mu_stream_t ostr, bstr;
mu_header_t hdr;
mu_iterator_t itr;
mu_body_t body;
if (skiphdr_list)
mu_list_set_comparator (skiphdr_list, headercmp);
MU_ASSERT (mu_stream_to_message (instr, &msg));
MU_ASSERT (mu_smtp_data (smtp, &ostr));
MU_ASSERT (mu_message_get_header (msg, &hdr));
MU_ASSERT (mu_header_get_iterator (hdr, &itr));
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
const char *name;
void *value;
mu_iterator_current_kv (itr, (void*) &name, &value);
if (mu_list_locate (skiphdr_list, (void*) name, NULL) == 0)
continue;
mu_stream_printf (ostr, "%s: %s\n", name, (char*)value);
}
mu_iterator_destroy (&itr);
MU_ASSERT (mu_stream_write (ostr, "\n", 1, NULL));
MU_ASSERT (mu_message_get_body (msg, &body));
MU_ASSERT (mu_body_get_streamref (body, &bstr));
MU_ASSERT (mu_stream_copy (ostr, bstr, 0, NULL));
mu_stream_destroy (&bstr);
mu_stream_close (ostr);
mu_stream_destroy (&ostr);
}
MU_ASSERT (mu_smtp_quit (smtp));
mu_smtp_destroy (&smtp);
mu_stream_close (instr);
......