Commit f8a96930 f8a96930b6ec84c63b36e5789c9fdf74285f420c by Sergey Poznyakoff

Implement SMTPS.

* NEWS: Update.
* include/mailutils/registrar.h (mu_smtps_record): New extern.
(mu_register_all_mailer_formats): Register mu_smtps_record.
* include/mailutils/sys/registrar.h (MU_SMTPS_SCHEME)
(MU_SMTPS_SCHEME_LEN,MU_SMTPS_PORT): New defines.
* libmailutils/address/address.c (mu_address_get_count): Don't
count parts with NULL emails.
(mu_address_contains_email): Validate email before comparison.
(mu_list_copy): New static.
(mu_address_union): Reuse last subaddress if its email is NULL.
* libmailutils/base/nullrec.c (mu_smtps_record): New placeholder.
* libproto/mailer/smtp.c (mu_smtps_record): New global.
(smtp_open): Implement SMTPS

* mu/send.c: New file.
* mu/Makefile.am (MODULES): Add send.c
1 parent 356c0754
GNU mailutils NEWS -- history of user-visible changes. 2011-12-23
GNU mailutils NEWS -- history of user-visible changes. 2011-12-31
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
See the end of file for copying conditions.
......@@ -91,6 +91,8 @@ This feature is useful for those system administrators who don't wish
to permit simultaneous access to mailboxes, even when the nature of the
mailbox allows that (e.g. maildir).
** SMTPS support.
** Sieve: new extensions
New extension action `pipe' invokes arbitrary external program and
......
......@@ -122,8 +122,9 @@ extern mu_record_t mu_maildir_record;
#define MU_SENDMAIL_PRIO 10000
#define MU_PROG_PRIO 10000
/* SMTP mailer, "smtp://" */
/* SMTP mailer, "smtp://" and "smtps://" */
extern mu_record_t mu_smtp_record;
extern mu_record_t mu_smtps_record;
/* Sendmail, "sendmail:" */
extern mu_record_t mu_sendmail_record;
/* Program mailer, "prog://", "|" */
......@@ -158,6 +159,7 @@ extern mu_record_t mu_prog_record;
#define mu_register_all_mailer_formats() do {\
mu_registrar_record (mu_sendmail_record);\
mu_registrar_record (mu_smtp_record);\
mu_registrar_record (mu_smtps_record);\
mu_registrar_record (mu_prog_record);\
} while (0)
......
......@@ -74,6 +74,10 @@ extern int _folder_path_init (mu_folder_t);
# define MU_SMTP_SCHEME_LEN (sizeof (MU_SMTP_SCHEME) - 1)
# define MU_SMTP_PORT 25
# define MU_SMTPS_SCHEME "smtps"
# define MU_SMTPS_SCHEME_LEN (sizeof (MU_SMTPS_SCHEME) - 1)
# define MU_SMTPS_PORT 465
# define MU_SENDMAIL_SCHEME "sendmail"
# define MU_SENDMAIL_SCHEME_LEN (sizeof (MU_SENDMAIL_SCHEME) - 1)
extern int _mu_mailer_sendmail_init (mu_mailer_t mailer);
......
......@@ -151,6 +151,18 @@ mu_address_createv (mu_address_t *a, const char *sv[], size_t len)
return status;
}
static void
_address_free (mu_address_t address)
{
free (address->printable);
free (address->comments);
free (address->personal);
free (address->email);
free (address->local_part);
free (address->domain);
free (address->route);
}
void
mu_address_destroy (mu_address_t *paddress)
{
......@@ -160,21 +172,8 @@ mu_address_destroy (mu_address_t *paddress)
mu_address_t current;
for (; address; address = current)
{
if (address->printable)
free (address->printable);
if (address->comments)
free (address->comments);
if (address->personal)
free (address->personal);
if (address->email)
free (address->email);
if (address->local_part)
free (address->local_part);
if (address->domain)
free (address->domain);
if (address->route)
free (address->route);
current = address->next;
_address_free (address);
free (address);
}
*paddress = NULL;
......@@ -642,11 +641,15 @@ mu_address_to_string (mu_address_t addr, char *buf, size_t len, size_t *n)
int
mu_address_get_count (mu_address_t addr, size_t *pcount)
{
size_t j;
for (j = 0; addr; addr = addr->next, j++)
;
size_t i, count = 0;
for (i = 0; addr; addr = addr->next, i++)
{
mu_validate_email (addr);
if (addr->email)
++count;
}
if (pcount)
*pcount = j;
*pcount = count;
return 0;
}
......@@ -696,37 +699,48 @@ int
mu_address_contains_email (mu_address_t addr, const char *email)
{
for (; addr; addr = addr->next)
if (mu_c_strcasecmp (addr->email, email) == 0)
return 1;
{
mu_validate_email (addr);
if (!addr->email)
break;
if (mu_c_strcasecmp (addr->email, email) == 0)
return 1;
}
return 0;
}
mu_address_t
mu_address_dup (mu_address_t src)
static int
mu_list_copy (mu_address_t dst, mu_address_t src)
{
mu_address_t dst = calloc (1, sizeof (*dst));
if (!dst)
return NULL;
/* FIXME: How about:
if (src->printable)
dst->printable = strdup (src->printable);
?
*/
if (src->comments)
dst->comments = strdup (src->comments);
if (src->personal)
dst->personal = strdup (src->personal);
if (src->email)
dst->email = strdup (src->email);
if (src->local_part)
dst->local_part = strdup (src->local_part);
if (src->domain)
dst->domain = strdup (src->domain);
if (src->route)
dst->route = strdup (src->route);
if (src->comments && !(dst->comments = strdup (src->comments)))
return ENOMEM;
if (src->personal && !(dst->personal = strdup (src->personal)))
return ENOMEM;
if (src->email && !(dst->email = strdup (src->email)))
return ENOMEM;
if (src->local_part && !(dst->local_part = strdup (src->local_part)))
return ENOMEM;
if (src->domain && !(dst->domain = strdup (src->domain)))
return ENOMEM;
if (src->route && !(dst->route = strdup (src->route)))
return ENOMEM;
return 0;
}
mu_address_t
mu_address_dup (mu_address_t src)
{
mu_address_t dst = calloc (1, sizeof (*dst));
if (!dst)
return NULL;
if (mu_list_copy (dst, src))
mu_address_destroy (&dst);
return dst;
}
......@@ -760,11 +774,24 @@ mu_address_union (mu_address_t *a, mu_address_t b)
for (; b; b = b->next)
if (!mu_address_contains_email (*a, b->email))
{
mu_address_t next = mu_address_dup (b);
if (!next)
return ENOMEM;
last->next = next;
last = next;
if (last->email)
{
mu_address_t next = mu_address_dup (b);
if (!next)
return ENOMEM;
last->next = next;
last = next;
}
else
{
int rc = mu_list_copy (last, b);
if (rc)
{
_address_free (last);
memset (last, 0, sizeof (last));
return rc;
}
}
}
return 0;
}
......
......@@ -47,3 +47,7 @@ mu_record_t mu_mh_record = NULL;
mu_record_t mu_maildir_record = NULL;
#endif
#ifndef WITH_TLS
mu_record_t mu_smtps_record = NULL;
#endif
......
......@@ -86,6 +86,27 @@ static struct _mu_record _smtp_record = {
the mailbox, via the register entry/record. */
mu_record_t mu_smtp_record = &_smtp_record;
#ifdef WITH_TLS
static struct _mu_record _smtps_record = {
MU_SMTP_PRIO,
MU_SMTPS_SCHEME,
MU_RECORD_DEFAULT,
MU_URL_SCHEME | MU_URL_CRED | MU_URL_INET | MU_URL_PARAM,
MU_URL_HOST,
_url_smtp_init, /* url init. */
_mu_mailer_mailbox_init, /* Mailbox init. */
_mailer_smtp_init, /* Mailer init. */
_mu_mailer_folder_init, /* Folder init. */
NULL, /* No need for a back pointer. */
NULL, /* _is_scheme method. */
NULL, /* _get_url method. */
NULL, /* _get_mailbox method. */
NULL, /* _get_mailer method. */
NULL /* _get_folder method. */
};
mu_record_t mu_smtps_record = &_smtps_record;
#endif
struct _smtp_mailer
{
mu_mailer_t mailer;
......@@ -116,14 +137,19 @@ smtp_mailer_add_auth_mech (struct _smtp_mailer *smtp_mailer, const char *str)
static int
smtp_open (mu_mailer_t mailer, int flags)
{
const char *auth;
const char *auth, *scheme;
struct _smtp_mailer *smtp_mailer = mailer->data;
int rc;
size_t parmc = 0;
char **parmv = NULL;
int notls = 0;
int tls = 0;
int nostarttls = 0;
int noauth = 0;
rc = mu_url_sget_scheme (mailer->url, &scheme);
if (rc == 0)
tls = strcmp (scheme, "smtps") == 0;
rc = mu_smtp_create (&smtp_mailer->smtp);
if (rc)
return rc;
......@@ -150,7 +176,7 @@ smtp_open (mu_mailer_t mailer, int flags)
for (i = 0; i < parmc; i++)
{
if (strcmp (parmv[i], "notls") == 0)
notls = 1;
nostarttls = 1;
else if (strcmp (parmv[i], "noauth") == 0)
noauth = 1;
else if (strncmp (parmv[i], "auth=", 5) == 0)
......@@ -163,23 +189,44 @@ smtp_open (mu_mailer_t mailer, int flags)
{
struct mu_sockaddr *sa;
struct mu_sockaddr_hints hints;
mu_stream_t transport;
memset (&hints, 0, sizeof (hints));
hints.flags = MU_AH_DETECT_FAMILY;
hints.port = 25;
hints.port = tls ? MU_SMTPS_PORT : MU_SMTP_PORT;
hints.protocol = IPPROTO_TCP;
hints.socktype = SOCK_STREAM;
rc = mu_sockaddr_from_url (&sa, mailer->url, &hints);
if (rc)
return rc;
rc = mu_tcp_stream_create_from_sa (&mailer->stream, sa, NULL,
mailer->flags);
rc = mu_tcp_stream_create_from_sa (&transport, sa, NULL, mailer->flags);
if (rc)
{
mu_sockaddr_free (sa);
return rc;
}
#ifdef WITH_TLS
if (tls && mu_tls_enable)
{
mu_stream_t tlsstream;
rc = mu_tls_client_stream_create (&tlsstream, transport, transport,
0);
mu_stream_unref (transport);
if (rc)
{
mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
(_("cannot create TLS stream: %s"),
mu_strerror (rc)));
mu_sockaddr_free (sa);
return rc;
}
transport = tlsstream;
nostarttls = 1;
}
#endif
mailer->stream = transport;
mu_stream_set_buffer (mailer->stream, mu_buffer_line, 0);
}
mu_smtp_set_carrier (smtp_mailer->smtp, mailer->stream);
......@@ -194,7 +241,7 @@ smtp_open (mu_mailer_t mailer, int flags)
return rc;
#ifdef WITH_TLS
if (!notls && mu_tls_enable &&
if (!nostarttls && mu_tls_enable &&
mu_smtp_capa_test (smtp_mailer->smtp, "STARTTLS", NULL) == 0)
{
rc = mu_smtp_starttls (smtp_mailer->smtp);
......
......@@ -51,6 +51,7 @@ MODULES = \
ldflags.c\
logger.c\
$(POP_C)\
send.c\
query.c\
wicket.c
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010, 2011 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <mailutils/cctype.h>
#include <mailutils/mailutils.h>
#include <argp.h>
#include "mu.h"
static int read_recipients;
static mu_address_t rcpt_addr;
static mu_address_t from_addr;
static void
send_address_add (mu_address_t *paddr, const char *value)
{
mu_address_t addr = NULL;
int rc;
rc = mu_address_create (&addr, value);
if (rc)
{
mu_error (_("%s: %s"), value, mu_strerror (rc));
exit (1);
}
MU_ASSERT (mu_address_union (paddr, addr));
mu_address_destroy (&addr);
}
static char send_doc[] = N_("mu send - send a message.");
char send_docstring[] = N_("send a message");
static char send_args_doc[] = "URL-or-HOST [FILE]";
static struct argp_option send_options[] = {
{ "from", 'F', N_("ADDRESS"), 0,
N_("send mail from this ADDRESS") },
{ "rcpt", 'T', N_("ADDRESS"), 0,
N_("send mail to this ADDRESS") },
{ "read-recipients", 't', NULL, 0,
N_("read recipients from the message") },
{ NULL }
};
static error_t
send_parse_opt (int key, char *arg, struct argp_state *state)
{
switch (key)
{
case 'F':
MU_ASSERT (mu_address_create_null (&from_addr));
send_address_add (&from_addr, arg);
break;
case 'T':
send_address_add (&rcpt_addr, arg);
break;
case 't':
read_recipients = 1;
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static struct argp send_argp = {
send_options,
send_parse_opt,
send_args_doc,
send_doc,
NULL,
NULL,
NULL
};
int
mutool_send (int argc, char **argv)
{
int index;
char *infile;
mu_stream_t instr;
mu_message_t msg;
size_t count;
mu_url_t urlhint, url;
mu_mailer_t mailer;
MU_ASSERT (mu_address_create_null (&rcpt_addr));
mu_register_all_mailer_formats ();
if (argp_parse (&send_argp, argc, argv, 0, &index, NULL))
return 1;
argc -= index;
argv += index;
if (argc < 1)
{
mu_error (_("not enough arguments"));
return 1;
}
infile = argv[1];
if (infile)
MU_ASSERT (mu_file_stream_create (&instr, infile,
MU_STREAM_READ|MU_STREAM_SEEK));
else
MU_ASSERT (mu_stdio_stream_create (&instr, MU_STDIN_FD,
MU_STREAM_READ|MU_STREAM_SEEK));
MU_ASSERT (mu_stream_to_message (instr, &msg));
mu_stream_unref (instr);
mu_address_get_count (rcpt_addr, &count);
if (count == 0)
read_recipients = 1;
if (read_recipients)
{
int rc;
mu_header_t header;
const char *value;
MU_ASSERT (mu_message_get_header (msg, &header));
rc = mu_header_sget_value (header, MU_HEADER_TO, &value);
if (rc == 0)
send_address_add (&rcpt_addr, value);
else if (rc != MU_ERR_NOENT)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_header_sget_value",
MU_HEADER_TO, rc);
exit (1);
}
rc = mu_header_sget_value (header, MU_HEADER_CC, &value);
if (rc == 0)
send_address_add (&rcpt_addr, value);
else if (rc != MU_ERR_NOENT)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_header_sget_value",
MU_HEADER_CC, rc);
exit (1);
}
rc = mu_header_sget_value (header, MU_HEADER_BCC, &value);
if (rc == 0)
send_address_add (&rcpt_addr, value);
else if (rc != MU_ERR_NOENT)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_header_sget_value",
MU_HEADER_BCC, rc);
exit (1);
}
}
mu_address_get_count (rcpt_addr, &count);
if (count == 0)
{
mu_error (_("no recipients"));
exit (1);
}
MU_ASSERT (mu_url_create (&urlhint, "smtp://"));
MU_ASSERT (mu_url_create_hint (&url, argv[0], MU_URL_PARSE_DEFAULT,
urlhint));
mu_url_invalidate (url);
MU_ASSERT (mu_mailer_create_from_url (&mailer, url));
MU_ASSERT (mu_mailer_open (mailer, MU_STREAM_RDWR));
MU_ASSERT (mu_mailer_send_message (mailer, msg, from_addr, rcpt_addr));
mu_mailer_close (mailer);
mu_mailer_destroy (&mailer);
return 0;
}
/*
MU Setup: send
mu-handler: mutool_send
mu-docstring: send_docstring
End MU Setup:
*/