diff options
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | include/mailutils/registrar.h | 4 | ||||
-rw-r--r-- | include/mailutils/sys/registrar.h | 4 | ||||
-rw-r--r-- | libmailutils/address/address.c | 115 | ||||
-rw-r--r-- | libmailutils/base/nullrec.c | 4 | ||||
-rw-r--r-- | libproto/mailer/smtp.c | 65 | ||||
-rw-r--r-- | mu/Makefile.am | 1 | ||||
-rw-r--r-- | mu/send.c | 202 |
8 files changed, 344 insertions, 55 deletions
@@ -1,4 +1,4 @@ -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 diff --git a/include/mailutils/registrar.h b/include/mailutils/registrar.h index f0fbd0afe..ae1797432 100644 --- a/include/mailutils/registrar.h +++ b/include/mailutils/registrar.h @@ -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) diff --git a/include/mailutils/sys/registrar.h b/include/mailutils/sys/registrar.h index 5d3992bf9..c725b14a0 100644 --- a/include/mailutils/sys/registrar.h +++ b/include/mailutils/sys/registrar.h @@ -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); diff --git a/libmailutils/address/address.c b/libmailutils/address/address.c index 19c33fa46..f77230ac4 100644 --- a/libmailutils/address/address.c +++ b/libmailutils/address/address.c @@ -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; } diff --git a/libmailutils/base/nullrec.c b/libmailutils/base/nullrec.c index a507a245d..80aadbf0a 100644 --- a/libmailutils/base/nullrec.c +++ b/libmailutils/base/nullrec.c @@ -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 + diff --git a/libproto/mailer/smtp.c b/libproto/mailer/smtp.c index 7177f3b7d..1c8042822 100644 --- a/libproto/mailer/smtp.c +++ b/libproto/mailer/smtp.c @@ -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); diff --git a/mu/Makefile.am b/mu/Makefile.am index e28b98485..05408fa6b 100644 --- a/mu/Makefile.am +++ b/mu/Makefile.am @@ -51,6 +51,7 @@ MODULES = \ ldflags.c\ logger.c\ $(POP_C)\ + send.c\ query.c\ wicket.c diff --git a/mu/send.c b/mu/send.c new file mode 100644 index 000000000..0d4402d5e --- /dev/null +++ b/mu/send.c @@ -0,0 +1,202 @@ +/* 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: +*/ |