summaryrefslogtreecommitdiff
path: root/mailbox
diff options
context:
space:
mode:
authorWojciech Polak <polak@gnu.org>2007-07-17 20:25:07 +0000
committerWojciech Polak <polak@gnu.org>2007-07-17 20:25:07 +0000
commit23b38a51e5c21829b7c9972390af4369757c710a (patch)
treeabc12e68ccec62a09c0eee413b75ed93eb03bd50 /mailbox
parent0e9867f766cca33ed73a25588374404eafdddbe2 (diff)
downloadmailutils-23b38a51e5c21829b7c9972390af4369757c710a.tar.gz
mailutils-23b38a51e5c21829b7c9972390af4369757c710a.tar.bz2
Moved to ../libproto/mailer/
Diffstat (limited to 'mailbox')
-rw-r--r--mailbox/sendmail.c461
-rw-r--r--mailbox/smtp.c1172
2 files changed, 0 insertions, 1633 deletions
diff --git a/mailbox/sendmail.c b/mailbox/sendmail.c
deleted file mode 100644
index 75308461d..000000000
--- a/mailbox/sendmail.c
+++ /dev/null
@@ -1,461 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
- Copyright (C) 1999, 2000, 2001, 2004, 2005,
- 2006, 2007 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 of the License, 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 this library; if not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301 USA */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#ifdef ENABLE_SENDMAIL
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <mailutils/address.h>
-#include <mailutils/debug.h>
-#include <mailutils/message.h>
-#include <mailutils/observer.h>
-#include <mailutils/property.h>
-#include <mailutils/stream.h>
-#include <mailutils/url.h>
-#include <mailutils/header.h>
-#include <mailutils/body.h>
-#include <mailutils/errno.h>
-
-#include <mailer0.h>
-#include <registrar0.h>
-
-static struct _mu_record _sendmail_record =
-{
- MU_SENDMAIL_PRIO,
- MU_SENDMAIL_SCHEME,
- _url_sendmail_init, /* url init. */
- NULL, /* Mailbox entry. */
- _mailer_sendmail_init, /* Mailer entry. */
- NULL, /* Folder entry. */
- 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. */
-};
-/* We export, url parsing and the initialisation of
- the mailbox, via the register entry/record. */
-mu_record_t mu_sendmail_record = &_sendmail_record;
-
-struct _sendmail
-{
- int dsn;
- char *path;
- pid_t pid;
- off_t offset;
- int fd;
- enum sendmail_state { SENDMAIL_CLOSED, SENDMAIL_OPEN, SENDMAIL_SEND } state;
-};
-
-typedef struct _sendmail * sendmail_t;
-
-static void sendmail_destroy (mu_mailer_t);
-static int sendmail_open (mu_mailer_t, int);
-static int sendmail_close (mu_mailer_t);
-static int sendmail_send_message (mu_mailer_t, mu_message_t, mu_address_t, mu_address_t);
-
-int
-_mailer_sendmail_init (mu_mailer_t mailer)
-{
- sendmail_t sendmail;
-
- /* Allocate memory specific to sendmail mailer. */
- sendmail = mailer->data = calloc (1, sizeof (*sendmail));
- if (mailer->data == NULL)
- return ENOMEM;
- sendmail->state = SENDMAIL_CLOSED;
- mailer->_destroy = sendmail_destroy;
- mailer->_open = sendmail_open;
- mailer->_close = sendmail_close;
- mailer->_send_message = sendmail_send_message;
-
- /* Set our properties. */
- {
- mu_property_t property = NULL;
- mu_mailer_get_property (mailer, &property);
- mu_property_set_value (property, "TYPE", "SENDMAIL", 1);
- }
- return 0;
-}
-
-static void
-sendmail_destroy(mu_mailer_t mailer)
-{
- sendmail_t sendmail = mailer->data;
- if (sendmail)
- {
- if (sendmail->path)
- free (sendmail->path);
- free (sendmail);
- mailer->data = NULL;
- }
-}
-
-static int
-sendmail_open (mu_mailer_t mailer, int flags)
-{
- sendmail_t sendmail = mailer->data;
- int status;
- char *path;
-
- /* Sanity checks. */
- if (sendmail == NULL)
- return EINVAL;
-
- mailer->flags = flags;
-
- if ((status = mu_url_aget_path (mailer->url, &path)))
- return status;
-
- if (access (path, X_OK) == -1)
- {
- free (path);
- return errno;
- }
- sendmail->path = path;
- sendmail->state = SENDMAIL_OPEN;
- MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE, "sendmail (%s)\n", sendmail->path);
- return 0;
-}
-
-static int
-sendmail_close (mu_mailer_t mailer)
-{
- sendmail_t sendmail = mailer->data;
-
- /* Sanity checks. */
- if (sendmail == NULL)
- return EINVAL;
-
- if(sendmail->path)
- free(sendmail->path);
-
- sendmail->path = NULL;
- sendmail->state = SENDMAIL_CLOSED;
-
- return 0;
-}
-
-static int
-mailer_property_is_set (mu_mailer_t mailer, const char *name)
-{
- mu_property_t property = NULL;
-
- mu_mailer_get_property (mailer, &property);
- return mu_property_is_set (property, name);
-}
-
-
-/* Close FD unless it is part of pipe P */
-#define SCLOSE(fd,p) if (p[0]!=fd&&p[1]!=fd) close(fd)
-
-static int
-sendmail_send_message (mu_mailer_t mailer, mu_message_t msg, mu_address_t from,
- mu_address_t to)
-{
- sendmail_t sendmail = mailer->data;
- int status = 0;
-
- if (sendmail == NULL || msg == NULL)
- return EINVAL;
-
- switch (sendmail->state)
- {
- case SENDMAIL_CLOSED:
- return EINVAL;
- case SENDMAIL_OPEN:
- {
- int tunnel[2];
- int argc = 0;
- const char **argvec = NULL;
- size_t tocount = 0;
- const char *emailfrom = NULL;
-
- /* Count the length of the arg vec: */
-
- argc++; /* terminating NULL */
- argc++; /* sendmail */
- argc++; /* -oi (do not treat '.' as message
- terminator) */
-
- if (from)
- {
- if ((status = mu_address_sget_email (from, 1, &emailfrom)) != 0)
- goto OPEN_STATE_CLEANUP;
-
- if (!emailfrom)
- {
- /* the address wasn't fully qualified, choke (for now) */
- status = EINVAL;
-
- MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
- "envelope from (%s) not fully qualifed\n",
- emailfrom);
-
- goto OPEN_STATE_CLEANUP;
- }
-
- argc += 2; /* -f from */
- }
-
- if (to)
- {
- status = mu_address_get_email_count (to, &tocount);
-
- assert (!status);
- assert (tocount);
-
- argc += tocount; /* 1 per to address */
- }
-
- argc++; /* -t */
-
- /* Allocate arg vec: */
- if ((argvec = calloc (argc, sizeof (*argvec))) == 0)
- {
- status = ENOMEM;
- goto OPEN_STATE_CLEANUP;
- }
-
- argc = 0;
-
- argvec[argc++] = sendmail->path;
- argvec[argc++] = "-oi";
-
- if (from)
- {
- argvec[argc++] = "-f";
- argvec[argc++] = emailfrom;
- }
-
- if (!to || mailer_property_is_set (mailer, "READ_RECIPIENTS"))
- {
- argvec[argc++] = "-t";
- }
- else
- {
- int i = 1;
- size_t count = 0;
-
- mu_address_get_count (to, &count);
-
- for (; i <= count; i++)
- {
- const char *email;
- if ((status = mu_address_sget_email (to, i, &email)) != 0)
- goto OPEN_STATE_CLEANUP;
- if (!email)
- {
- /* the address wasn't fully qualified, choke (for now) */
- status = EINVAL;
-
- MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
- "envelope to (%s) not fully qualifed\n",
- email);
-
- goto OPEN_STATE_CLEANUP;
- }
- argvec[argc++] = email;
- }
- }
-
- assert (argvec[argc] == NULL);
-
- if (pipe (tunnel) == 0)
- {
- sendmail->fd = tunnel[1];
- sendmail->pid = vfork ();
- if (sendmail->pid == 0) /* Child. */
- {
- SCLOSE (STDIN_FILENO, tunnel);
- SCLOSE (STDOUT_FILENO, tunnel);
- SCLOSE (STDERR_FILENO, tunnel);
- close (tunnel[1]);
- dup2 (tunnel[0], STDIN_FILENO);
- execv (sendmail->path, (char**) argvec);
- exit (errno);
- }
- else if (sendmail->pid == -1)
- {
- status = errno;
-
- MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
- "vfork() failed: %s\n", strerror (status));
- }
- }
- else
- {
- status = errno;
- MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
- "pipe() failed: %s\n", strerror (status));
- }
-
- OPEN_STATE_CLEANUP:
- MAILER_DEBUG0 (mailer, MU_DEBUG_TRACE, "exec argv:");
- for (argc = 0; argvec && argvec[argc]; argc++)
- {
- MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE, " %s", argvec[argc]);
- }
- MAILER_DEBUG0 (mailer, MU_DEBUG_TRACE, "\n");
- free (argvec);
- close (tunnel[0]);
-
- if (status != 0)
- {
- close (sendmail->fd);
- break;
- }
- sendmail->state = SENDMAIL_SEND;
- }
-
- case SENDMAIL_SEND:
- {
- mu_stream_t stream = NULL;
- char buffer[512];
- size_t len = 0;
- int rc;
- size_t offset = 0;
- mu_header_t hdr;
- mu_body_t body;
- int found_nl = 0;
- int exit_status;
-
- mu_message_get_header (msg, &hdr);
- mu_header_get_stream (hdr, &stream);
-
- MAILER_DEBUG0 (mailer, MU_DEBUG_TRACE, "Sending headers...\n");
- while ((status = mu_stream_readline (stream, buffer, sizeof (buffer),
- offset, &len)) == 0
- && len != 0)
- {
- if (strncasecmp (buffer, MU_HEADER_FCC,
- sizeof (MU_HEADER_FCC) - 1))
- {
- MAILER_DEBUG1 (mailer, MU_DEBUG_PROT,
- "Header: %s", buffer);
- if (write (sendmail->fd, buffer, len) == -1)
- {
- status = errno;
-
- MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
- "write() failed: %s\n", strerror (status));
-
- break;
- }
- }
- found_nl = (len == 1 && buffer[0] == '\n');
-
- offset += len;
- sendmail->offset += len;
- }
-
- if (!found_nl)
- {
- if (write (sendmail->fd, "\n", 1) == -1)
- {
- status = errno;
-
- MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
- "write() failed: %s\n", strerror (status));
- }
- }
-
- mu_message_get_body (msg, &body);
- mu_body_get_stream (body, &stream);
-
- MAILER_DEBUG0 (mailer, MU_DEBUG_TRACE, "Sending body...\n");
- offset = 0;
- while ((status = mu_stream_read (stream, buffer, sizeof (buffer),
- offset, &len)) == 0
- && len != 0)
- {
- if (write (sendmail->fd, buffer, len) == -1)
- {
- status = errno;
-
- MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
- "write() failed: %s\n", strerror (status));
-
- break;
- }
- offset += len;
- sendmail->offset += len;
- }
- if (status == EAGAIN)
- return status;
-
- close (sendmail->fd);
-
- rc = waitpid (sendmail->pid, &exit_status, 0);
-
- if (rc < 0)
- {
- if (errno == ECHILD)
- status = 0;
- else
- {
- status = errno;
- MAILER_DEBUG2 (mailer, MU_DEBUG_TRACE,
- "waitpid(%d) failed: %s\n",
- sendmail->pid, strerror (status));
- }
- }
- else if (WIFEXITED (exit_status))
- {
- exit_status = WEXITSTATUS (exit_status);
- MAILER_DEBUG2 (mailer, MU_DEBUG_TRACE,
- "%s exited with: %d\n",
- sendmail->path, exit_status);
- status = (exit_status == 0) ? 0 : MU_ERR_PROCESS_EXITED;
- }
- else if (WIFSIGNALED (exit_status))
- status = MU_ERR_PROCESS_SIGNALED;
- else
- status = MU_ERR_PROCESS_UNKNOWN_FAILURE;
-
- /* Shouldn't this notification only happen on success? */
- mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT);
- }
- default:
- break;
- }
-
- sendmail->state = (status == 0) ? SENDMAIL_OPEN : SENDMAIL_CLOSED;
-
- return status;
-}
-
-#else
-#include <stdio.h>
-#include <registrar0.h>
-mu_record_t mu_sendmail_record = NULL;
-#endif
diff --git a/mailbox/smtp.c b/mailbox/smtp.c
deleted file mode 100644
index 93882f056..000000000
--- a/mailbox/smtp.c
+++ /dev/null
@@ -1,1172 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
- Copyright (C) 1999, 2000, 2001, 2004, 2005,
- 2006, 2007 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 of the License, 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 this library; if not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301 USA */
-
-/** @file smtp.c
-@brief an SMTP mailer
-*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#ifdef ENABLE_SMTP
-
-#include <errno.h>
-#include <ctype.h>
-#include <netdb.h>
-#include <pwd.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <mailutils/address.h>
-#include <mailutils/debug.h>
-#include <mailutils/errno.h>
-#include <mailutils/header.h>
-#include <mailutils/body.h>
-#include <mailutils/message.h>
-#include <mailutils/mutil.h>
-#include <mailutils/observer.h>
-#include <mailutils/property.h>
-#include <mailutils/stream.h>
-#include <mailutils/url.h>
-#include <mailutils/tls.h>
-
-#include <mailer0.h>
-#include <registrar0.h>
-
-static struct _mu_record _smtp_record = {
- MU_SMTP_PRIO,
- MU_SMTP_SCHEME,
- _url_smtp_init, /* url init. */
- NULL, /* Mailbox init. */
- &_mailer_smtp_init, /* Mailer init. */
- NULL, /* 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. */
-};
-/* We export : url parsing and the initialisation of
- the mailbox, via the register entry/record. */
-mu_record_t mu_smtp_record = &_smtp_record;
-
-struct _smtp
-{
- mu_mailer_t mailer;
- char *mailhost;
- char *localhost;
-
- /* IO buffering. */
- char *buffer; /* Must be freed. */
- size_t buflen;
-
- char *ptr;
- char *nl;
- off_t s_offset;
-
- enum smtp_state
- {
- SMTP_NO_STATE, SMTP_OPEN, SMTP_GREETINGS, SMTP_EHLO, SMTP_EHLO_ACK,
- SMTP_HELO, SMTP_HELO_ACK, SMTP_QUIT, SMTP_QUIT_ACK, SMTP_ENV_FROM,
- SMTP_ENV_RCPT, SMTP_MAIL_FROM, SMTP_MAIL_FROM_ACK, SMTP_RCPT_TO,
- SMTP_RCPT_TO_ACK, SMTP_DATA, SMTP_DATA_ACK, SMTP_SEND, SMTP_SEND_ACK,
- SMTP_SEND_DOT, SMTP_STARTTLS, SMTP_STARTTLS_ACK
- }
- state;
-
- int extended;
- unsigned long capa; /* Server capabilities */
-
- const char *mail_from;
- mu_address_t rcpt_to; /* Destroy this if not the same as argto below. */
- mu_address_t rcpt_bcc;
- size_t rcpt_to_count;
- size_t rcpt_bcc_count;
- size_t rcpt_index;
- size_t rcpt_count;
- int bccing;
- mu_message_t msg; /* Destroy this if not same argmsg. */
-
- off_t offset;
-
- /* The mu_mailer_send_message() args. */
- mu_message_t argmsg;
- mu_address_t argfrom;
- mu_address_t argto;
-};
-
-typedef struct _smtp *smtp_t;
-
-/* ESMTP capabilities */
-#define CAPA_STARTTLS 0x00000001
-#define CAPA_8BITMIME 0x00000002
-
-static void smtp_destroy (mu_mailer_t);
-static int smtp_open (mu_mailer_t, int);
-static int smtp_close (mu_mailer_t);
-static int smtp_send_message (mu_mailer_t, mu_message_t, mu_address_t, mu_address_t);
-static int smtp_writeline (smtp_t smtp, const char *format, ...);
-static int smtp_readline (smtp_t);
-static int smtp_read_ack (smtp_t);
-static int smtp_parse_ehlo_ack (smtp_t);
-static int smtp_write (smtp_t);
-static int smtp_starttls (smtp_t);
-
-static int _smtp_set_rcpt (smtp_t, mu_message_t, mu_address_t);
-
-/* Useful little macros, since these are very repetitive. */
-
-static void
-CLEAR_STATE (smtp_t smtp)
-{
- smtp->ptr = NULL;
- smtp->nl = NULL;
- smtp->s_offset = 0;
-
- smtp->state = SMTP_NO_STATE;
-
- smtp->extended = 0;
-
- if (smtp->mail_from)
- smtp->mail_from = NULL;
-
- if (smtp->rcpt_to != smtp->argto)
- mu_address_destroy (&smtp->rcpt_to);
-
- smtp->rcpt_to = NULL;
-
- mu_address_destroy (&smtp->rcpt_bcc);
-
- smtp->rcpt_to_count = 0;
- smtp->rcpt_bcc_count = 0;
- smtp->rcpt_index = 0;
- smtp->rcpt_count = 0;
- smtp->bccing = 0;
-
- if (smtp->msg != smtp->argmsg)
- mu_message_destroy (&smtp->msg, NULL);
-
- smtp->msg = NULL;
-
- smtp->offset = 0;
-
- smtp->argmsg = NULL;
- smtp->argfrom = NULL;
- smtp->argto = NULL;
-}
-
-/* If we are resuming, we should be resuming the SAME operation
- as that which is ongoing. Check this. */
-static int
-smtp_check_send_resumption (smtp_t smtp,
- mu_message_t msg, mu_address_t from, mu_address_t to)
-{
- if (smtp->state == SMTP_NO_STATE)
- return 0;
-
- /* FIXME: state should be one of the "send" states if its not
- "no state" */
- if (msg != smtp->argmsg)
- return MU_ERR_BAD_RESUMPTION;
-
- if (from != smtp->argfrom)
- return MU_ERR_BAD_RESUMPTION;
-
- if (to != smtp->argto)
- return MU_ERR_BAD_RESUMPTION;
-
- return 0;
-}
-
-#define CHECK_SEND_RESUME(smtp, msg, from, to) \
-do { \
- if((status = smtp_check_send_resumption(smtp, msg, from, to)) != 0) \
- return status; \
-} while (0)
-
-/* Clear the state and close the stream. */
-#define CHECK_ERROR_CLOSE(mailer, smtp, status) \
-do \
- { \
- if (status != 0) \
- { \
- mu_stream_close (mailer->stream); \
- CLEAR_STATE (smtp); \
- return status; \
- } \
- } \
-while (0)
-
-/* Clear the state. */
-#define CHECK_ERROR(smtp, status) \
-do \
- { \
- if (status != 0) \
- { \
- CLEAR_STATE (smtp); \
- return status; \
- } \
- } \
-while (0)
-
-/* Clear the state for non recoverable error. */
-#define CHECK_EAGAIN(smtp, status) \
-do \
- { \
- if (status != 0) \
- { \
- if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
- { \
- CLEAR_STATE (smtp); \
- } \
- return status; \
- } \
- } \
-while (0)
-
-int
-_mailer_smtp_init (mu_mailer_t mailer)
-{
- smtp_t smtp;
-
- /* Allocate memory specific to smtp mailer. */
- smtp = mailer->data = calloc (1, sizeof (*smtp));
- if (mailer->data == NULL)
- return ENOMEM;
-
- smtp->mailer = mailer; /* Back pointer. */
- smtp->state = SMTP_NO_STATE;
-
- mailer->_destroy = smtp_destroy;
- mailer->_open = smtp_open;
- mailer->_close = smtp_close;
- mailer->_send_message = smtp_send_message;
-
- /* Set our properties. */
- {
- mu_property_t property = NULL;
- mu_mailer_get_property (mailer, &property);
- mu_property_set_value (property, "TYPE", "SMTP", 1);
- }
-
- return 0;
-}
-
-static void
-smtp_destroy (mu_mailer_t mailer)
-{
- smtp_t smtp = mailer->data;
-
- CLEAR_STATE (smtp);
-
- /* Not our responsability to close. */
-
- if (smtp->mailhost)
- free (smtp->mailhost);
- if (smtp->localhost)
- free (smtp->localhost);
- if (smtp->buffer)
- free (smtp->buffer);
-
- free (smtp);
-
- mailer->data = NULL;
-}
-
-/** Open an SMTP mailer.
-An SMTP mailer must be opened before any messages can be sent.
-@param mailer the mailer created by smtp_create()
-@param flags the mailer flags
-*/
-static int
-smtp_open (mu_mailer_t mailer, int flags)
-{
- smtp_t smtp = mailer->data;
- int status;
- long port;
-
- /* Sanity checks. */
- if (!smtp)
- return EINVAL;
-
- mailer->flags = flags;
-
- if ((status = mu_url_get_port (mailer->url, &port)) != 0)
- return status;
-
- switch (smtp->state)
- {
- case SMTP_NO_STATE:
- if (smtp->mailhost)
- {
- free (smtp->mailhost);
- smtp->mailhost = NULL;
- }
-
- /* Fetch the mailer server name and the port in the mu_url_t. */
- if ((status = mu_url_aget_host (mailer->url, &smtp->mailhost)) != 0)
- return status;
-
- if (smtp->localhost)
- {
- free (smtp->localhost);
- smtp->localhost = NULL;
- }
- /* Fetch our local host name. */
-
- status = mu_get_host_name (&smtp->localhost);
-
- if (status != 0)
- {
- /* gethostname failed, abort. */
- free (smtp->mailhost);
- smtp->mailhost = NULL;
- return status;
- }
-
- /* allocate a working io buffer. */
- if (smtp->buffer == NULL)
- {
- smtp->buflen = 512; /* Initial guess. */
- smtp->buffer = malloc (smtp->buflen + 1);
- if (smtp->buffer == NULL)
- {
- CHECK_ERROR (smtp, ENOMEM);
- }
- smtp->ptr = smtp->buffer;
- }
-
- /* Create a TCP stack if one is not given. */
- if (mailer->stream == NULL)
- {
- status =
- mu_tcp_stream_create (&mailer->stream, smtp->mailhost, port,
- mailer->flags);
- CHECK_ERROR (smtp, status);
- mu_stream_setbufsiz (mailer->stream, BUFSIZ);
- }
- CHECK_ERROR (smtp, status);
- smtp->state = SMTP_OPEN;
-
- case SMTP_OPEN:
- MAILER_DEBUG2 (mailer, MU_DEBUG_PROT, "smtp_open (host: %s port: %ld)\n",
- smtp->mailhost, port);
- status = mu_stream_open (mailer->stream);
- CHECK_EAGAIN (smtp, status);
- smtp->state = SMTP_GREETINGS;
-
- case SMTP_GREETINGS:
- /* Swallow the greetings. */
- status = smtp_read_ack (smtp);
- CHECK_EAGAIN (smtp, status);
-
- if (smtp->buffer[0] != '2')
- {
- mu_stream_close (mailer->stream);
- return EACCES;
- }
- status = smtp_writeline (smtp, "EHLO %s\r\n", smtp->localhost);
- CHECK_ERROR (smtp, status);
-
- smtp->state = SMTP_EHLO;
-
- case SMTP_EHLO:
- /* We first try Extended SMTP. */
- status = smtp_write (smtp);
- CHECK_EAGAIN (smtp, status);
- smtp->state = SMTP_EHLO_ACK;
-
- case SMTP_EHLO_ACK:
- status = smtp_parse_ehlo_ack (smtp);
- CHECK_EAGAIN (smtp, status);
-
- if (smtp->buffer[0] != '2')
- {
- smtp->extended = 0;
- status = smtp_writeline (smtp, "HELO %s\r\n", smtp->localhost);
- CHECK_ERROR (smtp, status);
- smtp->state = SMTP_HELO;
- }
- else
- {
- smtp->extended = 1;
-
- if (smtp->capa & CAPA_STARTTLS)
- smtp->state = SMTP_STARTTLS;
- else
- break;
- }
-
- case SMTP_STARTTLS:
- case SMTP_STARTTLS_ACK:
- smtp_starttls (smtp);
- break;
-
- case SMTP_HELO:
- if (!smtp->extended) /* FIXME: this will always be false! */
- {
- status = smtp_write (smtp);
- CHECK_EAGAIN (smtp, status);
- }
- smtp->state = SMTP_HELO_ACK;
-
- case SMTP_HELO_ACK:
- if (!smtp->extended)
- {
- status = smtp_read_ack (smtp);
- CHECK_EAGAIN (smtp, status);
-
- if (smtp->buffer[0] != '2')
- {
- mu_stream_close (mailer->stream);
- CLEAR_STATE (smtp);
- return EACCES;
- }
- }
-
- default:
- break;
- }
-
- CLEAR_STATE (smtp);
-
- return 0;
-}
-
-static int
-smtp_close (mu_mailer_t mailer)
-{
- smtp_t smtp = mailer->data;
- int status;
- switch (smtp->state)
- {
- case SMTP_NO_STATE:
- status = smtp_writeline (smtp, "QUIT\r\n");
- CHECK_ERROR (smtp, status);
-
- smtp->state = SMTP_QUIT;
-
- case SMTP_QUIT:
- status = smtp_write (smtp);
- CHECK_EAGAIN (smtp, status);
- smtp->state = SMTP_QUIT_ACK;
-
- case SMTP_QUIT_ACK:
- status = smtp_read_ack (smtp);
- CHECK_EAGAIN (smtp, status);
-
- default:
- break;
- }
- return mu_stream_close (mailer->stream);
-}
-
-/*
- Client side STARTTLS support.
- */
-
-static int
-smtp_reader (void *iodata)
-{
- int status = 0;
- smtp_t iop = iodata;
- status = smtp_read_ack (iop);
- CHECK_EAGAIN (iop, status);
- return status;
-}
-
-static int
-smtp_writer (void *iodata, char *buf)
-{
- smtp_t iop = iodata;
- int status;
- if (strncasecmp (buf, "EHLO", 4) == 0)
- status = smtp_writeline (iop, "%s %s\r\n", buf, iop->localhost);
- else
- status = smtp_writeline (iop, "%s\r\n", buf);
- CHECK_ERROR (iop, status);
- status = smtp_write (iop);
- CHECK_EAGAIN (iop, status);
- return status;
-}
-
-static void
-smtp_stream_ctl (void *iodata, mu_stream_t *pold, mu_stream_t new)
-{
- smtp_t iop = iodata;
- if (pold)
- *pold = iop->mailer->stream;
- if (new)
- iop->mailer->stream = new;
-}
-
-static int
-smtp_starttls (smtp_t smtp)
-{
-#ifdef WITH_TLS
- int status;
- mu_mailer_t mailer = smtp->mailer;
- char *keywords[] = { "STARTTLS", "EHLO", NULL };
-
- if (!mu_tls_enable || !(smtp->capa & CAPA_STARTTLS))
- return -1;
-
- smtp->capa = 0;
- status = mu_tls_begin (smtp, smtp_reader, smtp_writer,
- smtp_stream_ctl, keywords);
-
- MAILER_DEBUG1 (mailer, MU_DEBUG_PROT, "TLS negotiation %s\n",
- status == 0 ? "succeeded" : "failed");
-
- return status;
-#else
- return -1;
-#endif /* WITH_TLS */
-}
-
-static int
-message_set_header_value (mu_message_t msg, const char *field, const char *value)
-{
- int status = 0;
- mu_header_t hdr = NULL;
-
- if ((status = mu_message_get_header (msg, &hdr)))
- return status;
-
- if ((status = mu_header_set_value (hdr, field, value, 1)))
- return status;
-
- return status;
-}
-
-static int
-message_has_bcc (mu_message_t msg)
-{
- int status;
- mu_header_t header = NULL;
- size_t bccsz = 0;
-
- if ((status = mu_message_get_header (msg, &header)))
- return status;
-
- status = mu_header_get_value (header, MU_HEADER_BCC, NULL, 0, &bccsz);
-
- /* MU_ERR_NOENT, or there was a Bcc: field. */
- return status == MU_ERR_NOENT ? 0 : 1;
-}
-
-/*
-
-The smtp mailer doesn't deal with mail like:
-
-To: public@com, pub2@com
-Bcc: hidden@there, two@there
-
-It just sends the message to all the addresses, making the
-"blind" cc not particularly blind.
-
-The correct algorithm is
-
-- open smtp connection
-- look as msg, figure out addrto&cc, and addrbcc
-- deliver to the to & cc addresses:
- - if there are bcc addrs, remove the bcc field
- - send the message to to & cc addrs:
- mail from: me
- rcpt to: public@com
- rcpt to: pub2@com
- data
- ...
-
-- deliver to the bcc addrs:
-
- for a in (bccaddrs)
- do
- - add header field to msg, bcc: $a
- - send the msg:
- mail from: me
- rcpt to: $a
- data
- ...
- done
-
-- quit smtp connection
-
-*/
-
-static int
-smtp_send_message (mu_mailer_t mailer, mu_message_t argmsg, mu_address_t argfrom,
- mu_address_t argto)
-{
- smtp_t smtp = NULL;
- int status;
-
- if (mailer == NULL)
- return EINVAL;
-
- smtp = mailer->data;
- if (!smtp)
- return EINVAL;
-
- CHECK_SEND_RESUME (smtp, argmsg, argfrom, argto);
-
- switch (smtp->state)
- {
- case SMTP_NO_STATE:
- if (argmsg == NULL || argfrom == NULL)
- return EINVAL;
-
- smtp->argmsg = smtp->msg = argmsg;
- smtp->argfrom = argfrom;
- smtp->argto = argto;
-
- status = mu_address_sget_email (smtp->argfrom, 1, &smtp->mail_from);
- CHECK_ERROR (smtp, status);
-
- status = _smtp_set_rcpt (smtp, smtp->argmsg, smtp->argto);
- CHECK_ERROR (smtp, status);
-
- /* Clear the Bcc: field if we found one. */
- if (message_has_bcc (smtp->argmsg))
- {
- smtp->msg = NULL;
- status = mu_message_create_copy (&smtp->msg, smtp->argmsg);
- CHECK_ERROR (smtp, status);
-
- status = message_set_header_value (smtp->msg, MU_HEADER_BCC, NULL);
- CHECK_ERROR (smtp, status);
- }
-
- /* Begin bccing if there are not To: recipients. */
- if (smtp->rcpt_to_count == 0)
- smtp->bccing = 1;
-
- smtp->rcpt_index = 1;
-
- smtp->state = SMTP_ENV_FROM;
-
- case SMTP_ENV_FROM:
- ENV_FROM:
- {
- status = smtp_writeline (smtp, "MAIL FROM: <%s>\r\n", smtp->mail_from);
- CHECK_ERROR (smtp, status);
- smtp->state = SMTP_MAIL_FROM;
- }
-
- /* We use a goto, since we may have multiple messages,
- we come back here and doit all over again ... Not pretty. */
- case SMTP_MAIL_FROM:
- status = smtp_write (smtp);
- CHECK_EAGAIN (smtp, status);
- smtp->state = SMTP_MAIL_FROM_ACK;
-
- case SMTP_MAIL_FROM_ACK:
- status = smtp_read_ack (smtp);
- CHECK_EAGAIN (smtp, status);
- if (smtp->buffer[0] != '2')
- {
- mu_stream_close (mailer->stream);
- CLEAR_STATE (smtp);
- return EACCES;
- }
-
- /* We use a goto, since we may have multiple recipients,
- we come back here and do it all over again ... Not pretty. */
- case SMTP_ENV_RCPT:
- ENV_RCPT:
- {
- mu_address_t addr = smtp->rcpt_to;
- const char *to = NULL;
-
- if (smtp->bccing)
- addr = smtp->rcpt_bcc;
- status = mu_address_sget_email (addr, smtp->rcpt_index, &to);
-
- CHECK_ERROR (smtp, status);
-
- /* Add the Bcc: field back in for recipient. */
- if (smtp->bccing)
- {
- status = message_set_header_value (smtp->msg, MU_HEADER_BCC, to);
- CHECK_ERROR (smtp, status);
- }
-
- status = smtp_writeline (smtp, "RCPT TO: <%s>\r\n", to);
-
- CHECK_ERROR (smtp, status);
-
- smtp->state = SMTP_RCPT_TO;
- smtp->rcpt_index++;
- }
-
- case SMTP_RCPT_TO:
- status = smtp_write (smtp);
- CHECK_EAGAIN (smtp, status);
- smtp->state = SMTP_RCPT_TO_ACK;
-
- case SMTP_RCPT_TO_ACK:
- status = smtp_read_ack (smtp);
- CHECK_EAGAIN (smtp, status);
- if (smtp->buffer[0] != '2')
- {
- mu_stream_close (mailer->stream);
- CLEAR_STATE (smtp);
- return MU_ERR_SMTP_RCPT_FAILED;
- }
- /* Redo the receipt sequence for every To: and Cc: recipient. */
- if (!smtp->bccing && smtp->rcpt_index <= smtp->rcpt_to_count)
- goto ENV_RCPT;
-
- /* We are done with the rcpt. */
- status = smtp_writeline (smtp, "DATA\r\n");
- CHECK_ERROR (smtp, status);
- smtp->state = SMTP_DATA;
-
- case SMTP_DATA:
- status = smtp_write (smtp);
- CHECK_EAGAIN (smtp, status);
- smtp->state = SMTP_DATA_ACK;
-
- case SMTP_DATA_ACK:
- status = smtp_read_ack (smtp);
- CHECK_EAGAIN (smtp, status);
- if (smtp->buffer[0] != '3')
- {
- mu_stream_close (mailer->stream);
- CLEAR_STATE (smtp);
- return EACCES;
- }
- smtp->offset = 0;
- smtp->state = SMTP_SEND;
-
- if ((smtp->mailer->flags & MAILER_FLAG_DEBUG_DATA) == 0)
- MAILER_DEBUG0 (smtp->mailer, MU_DEBUG_PROT, "> (data...)\n");