diff options
author | Wojciech Polak <polak@gnu.org> | 2007-07-17 20:25:07 +0000 |
---|---|---|
committer | Wojciech Polak <polak@gnu.org> | 2007-07-17 20:25:07 +0000 |
commit | 23b38a51e5c21829b7c9972390af4369757c710a (patch) | |
tree | abc12e68ccec62a09c0eee413b75ed93eb03bd50 /mailbox | |
parent | 0e9867f766cca33ed73a25588374404eafdddbe2 (diff) | |
download | mailutils-23b38a51e5c21829b7c9972390af4369757c710a.tar.gz mailutils-23b38a51e5c21829b7c9972390af4369757c710a.tar.bz2 |
Moved to ../libproto/mailer/
Diffstat (limited to 'mailbox')
-rw-r--r-- | mailbox/sendmail.c | 461 | ||||
-rw-r--r-- | mailbox/smtp.c | 1172 |
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"); |