aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/smtp/camel-smtp-transport.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/smtp/camel-smtp-transport.c')
-rw-r--r--camel/providers/smtp/camel-smtp-transport.c1150
1 files changed, 0 insertions, 1150 deletions
diff --git a/camel/providers/smtp/camel-smtp-transport.c b/camel/providers/smtp/camel-smtp-transport.c
deleted file mode 100644
index c54e0821d8..0000000000
--- a/camel/providers/smtp/camel-smtp-transport.c
+++ /dev/null
@@ -1,1150 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* camel-smtp-transport.c : class for a smtp transport */
-
-/*
- * Authors: Jeffrey Stedfast <fejj@ximian.com>
- *
- * Copyright (C) 2000 Ximian, Inc. (www.ximian.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program 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 this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#undef MIN
-#undef MAX
-#include "camel-mime-filter-crlf.h"
-#include "camel-mime-filter-linewrap.h"
-#include "camel-stream-filter.h"
-#include "camel-smtp-transport.h"
-#include "camel-mime-message.h"
-#include "camel-multipart.h"
-#include "camel-mime-part.h"
-#include "camel-operation.h"
-#include "camel-stream-buffer.h"
-#include "camel-tcp-stream.h"
-#include "camel-tcp-stream-raw.h"
-#ifdef HAVE_NSS
-#include "camel-tcp-stream-ssl.h"
-#include <prnetdb.h>
-#endif
-#ifdef HAVE_OPENSSL
-#include "camel-tcp-stream-openssl.h"
-#endif
-#include "camel-session.h"
-#include "camel-exception.h"
-#include "camel-sasl.h"
-#include "string-utils.h"
-
-#define d(x) x
-
-/* Specified in RFC 821 */
-#define SMTP_PORT 25
-
-/* camel smtp transport class prototypes */
-static gboolean smtp_can_send (CamelTransport *transport, CamelMedium *message);
-static gboolean smtp_send (CamelTransport *transport, CamelMedium *message, CamelException *ex);
-static gboolean smtp_send_to (CamelTransport *transport, CamelMedium *message,
- CamelAddress *from, CamelAddress *recipients, CamelException *ex);
-
-/* support prototypes */
-static void smtp_construct (CamelService *service, CamelSession *session,
- CamelProvider *provider, CamelURL *url,
- CamelException *ex);
-static gboolean smtp_connect (CamelService *service, CamelException *ex);
-static gboolean smtp_disconnect (CamelService *service, gboolean clean, CamelException *ex);
-static GHashTable *esmtp_get_authtypes (gchar *buffer);
-static GList *query_auth_types (CamelService *service, CamelException *ex);
-static char *get_name (CamelService *service, gboolean brief);
-
-static gboolean smtp_helo (CamelSmtpTransport *transport, CamelException *ex);
-static gboolean smtp_auth (CamelSmtpTransport *transport, const char *mech, CamelException *ex);
-static gboolean smtp_mail (CamelSmtpTransport *transport, const char *sender,
- gboolean has_8bit_parts, CamelException *ex);
-static gboolean smtp_rcpt (CamelSmtpTransport *transport, const char *recipient, CamelException *ex);
-static gboolean smtp_data (CamelSmtpTransport *transport, CamelMedium *message,
- gboolean has_8bit_parts, CamelException *ex);
-static gboolean smtp_rset (CamelSmtpTransport *transport, CamelException *ex);
-static gboolean smtp_quit (CamelSmtpTransport *transport, CamelException *ex);
-
-/* private data members */
-static CamelTransportClass *parent_class = NULL;
-
-static void
-camel_smtp_transport_class_init (CamelSmtpTransportClass *camel_smtp_transport_class)
-{
- CamelTransportClass *camel_transport_class =
- CAMEL_TRANSPORT_CLASS (camel_smtp_transport_class);
- CamelServiceClass *camel_service_class =
- CAMEL_SERVICE_CLASS (camel_smtp_transport_class);
-
- parent_class = CAMEL_TRANSPORT_CLASS (camel_type_get_global_classfuncs (camel_transport_get_type ()));
-
- /* virtual method overload */
- camel_service_class->construct = smtp_construct;
- camel_service_class->connect = smtp_connect;
- camel_service_class->disconnect = smtp_disconnect;
- camel_service_class->query_auth_types = query_auth_types;
- camel_service_class->get_name = get_name;
-
- camel_transport_class->can_send = smtp_can_send;
- camel_transport_class->send = smtp_send;
- camel_transport_class->send_to = smtp_send_to;
-}
-
-static void
-camel_smtp_transport_init (gpointer object)
-{
- CamelTransport *transport = CAMEL_TRANSPORT (object);
-
- transport->supports_8bit = FALSE;
-}
-
-CamelType
-camel_smtp_transport_get_type (void)
-{
- static CamelType camel_smtp_transport_type = CAMEL_INVALID_TYPE;
-
- if (camel_smtp_transport_type == CAMEL_INVALID_TYPE) {
- camel_smtp_transport_type =
- camel_type_register (CAMEL_TRANSPORT_TYPE,
- "CamelSmtpTransport",
- sizeof (CamelSmtpTransport),
- sizeof (CamelSmtpTransportClass),
- (CamelObjectClassInitFunc) camel_smtp_transport_class_init,
- NULL,
- (CamelObjectInitFunc) camel_smtp_transport_init,
- NULL);
- }
-
- return camel_smtp_transport_type;
-}
-
-static void
-smtp_construct (CamelService *service, CamelSession *session,
- CamelProvider *provider, CamelURL *url,
- CamelException *ex)
-{
- CamelSmtpTransport *smtp_transport = CAMEL_SMTP_TRANSPORT (service);
-
- CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
-
- if (camel_url_get_param (url, "use_ssl"))
- smtp_transport->use_ssl = TRUE;
-}
-
-static const char *
-get_smtp_error_string (int error)
-{
- /* SMTP error codes grabbed from rfc821 */
- switch (error) {
- case 0:
- /* looks like a read problem, check errno */
- if (errno)
- return g_strerror (errno);
- else
- return _("Unknown");
- case 500:
- return _("Syntax error, command unrecognized");
- case 501:
- return _("Syntax error in parameters or arguments");
- case 502:
- return _("Command not implemented");
- case 504:
- return _("Command parameter not implemented");
- case 211:
- return _("System status, or system help reply");
- case 214:
- return _("Help message");
- case 220:
- return _("Service ready");
- case 221:
- return _("Service closing transmission channel");
- case 421:
- return _("Service not available, closing transmission channel");
- case 250:
- return _("Requested mail action okay, completed");
- case 251:
- return _("User not local; will forward to <forward-path>");
- case 450:
- return _("Requested mail action not taken: mailbox unavailable");
- case 550:
- return _("Requested action not taken: mailbox unavailable");
- case 451:
- return _("Requested action aborted: error in processing");
- case 551:
- return _("User not local; please try <forward-path>");
- case 452:
- return _("Requested action not taken: insufficient system storage");
- case 552:
- return _("Requested mail action aborted: exceeded storage allocation");
- case 553:
- return _("Requested action not taken: mailbox name not allowed");
- case 354:
- return _("Start mail input; end with <CRLF>.<CRLF>");
- case 554:
- return _("Transaction failed");
-
- /* AUTH error codes: */
- case 432:
- return _("A password transition is needed");
- case 534:
- return _("Authentication mechanism is too weak");
- case 538:
- return _("Encryption required for requested authentication mechanism");
- case 454:
- return _("Temporary authentication failure");
- case 530:
- return _("Authentication required");
-
- default:
- return _("Unknown");
- }
-}
-
-static gboolean
-connect_to_server (CamelService *service, CamelException *ex)
-{
- CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
- CamelStream *tcp_stream;
- gchar *respbuf = NULL;
- struct hostent *h;
- guint32 addrlen;
- int port, ret;
-
- if (!CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex))
- return FALSE;
-
- h = camel_service_gethost (service, ex);
- if (!h)
- return FALSE;
-
- /* set some smtp transport defaults */
- transport->is_esmtp = FALSE;
- transport->authtypes = NULL;
- CAMEL_TRANSPORT (transport)->supports_8bit = FALSE;
-
- port = service->url->port ? service->url->port : SMTP_PORT;
-
-#if defined(HAVE_NSS) || defined(HAVE_OPENSSL)
- if (transport->use_ssl) {
- port = service->url->port ? service->url->port : 465;
-#ifdef HAVE_NSS
- /* use the preferred implementation - NSS */
- tcp_stream = camel_tcp_stream_ssl_new (service, service->url->host);
-#else
- tcp_stream = camel_tcp_stream_openssl_new (service, service->url->host);
-#endif /* HAVE_NSS */
- } else {
- tcp_stream = camel_tcp_stream_raw_new ();
- }
-#else
- tcp_stream = camel_tcp_stream_raw_new ();
-#endif /* HAVE_NSS || HAVE_OPENSSL */
-
- ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port);
- camel_free_host(h);
- if (ret == -1) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
- _("Could not connect to %s (port %d): %s"),
- service->url->host, port,
- g_strerror (errno));
-
- return FALSE;
- }
-
- /* get the localaddr - needed later by smtp_helo */
- addrlen = sizeof (transport->localaddr);
-#ifdef HAVE_NSS
- if (transport->use_ssl) {
- PRFileDesc *sockfd = camel_tcp_stream_get_socket (CAMEL_TCP_STREAM (tcp_stream));
- PRNetAddr addr;
- char hname[1024];
-
- PR_GetSockName (sockfd, &addr);
- memset (hname, 0, sizeof (hname));
- PR_NetAddrToString (&addr, hname, 1023);
-
- inet_aton (hname, (struct in_addr *)&transport->localaddr.sin_addr);
- } else {
- int sockfd = GPOINTER_TO_INT (camel_tcp_stream_get_socket (CAMEL_TCP_STREAM (tcp_stream)));
-
- getsockname (sockfd, (struct sockaddr *)&transport->localaddr, &addrlen);
- }
-#else
- getsockname (CAMEL_TCP_STREAM_RAW (tcp_stream)->sockfd,
- (struct sockaddr *)&transport->localaddr, &addrlen);
-#endif /* HAVE_NSS */
-
- transport->ostream = tcp_stream;
- transport->istream = camel_stream_buffer_new (tcp_stream, CAMEL_STREAM_BUFFER_READ);
-
- /* Read the greeting, note whether the server is ESMTP or not. */
- do {
- /* Check for "220" */
- g_free (respbuf);
- respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
- if (!respbuf || strncmp (respbuf, "220", 3)) {
- int error;
-
- error = respbuf ? atoi (respbuf) : 0;
- g_free (respbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Welcome response error: %s: possibly non-fatal"),
- get_smtp_error_string (error));
- return FALSE;
- }
- if (strstr (respbuf, "ESMTP"))
- transport->is_esmtp = TRUE;
- } while (*(respbuf+3) == '-'); /* if we got "220-" then loop again */
- g_free (respbuf);
-
- /* send HELO (or EHLO, depending on the service type) */
- if (!transport->is_esmtp) {
- /* If we did not auto-detect ESMTP, we should still send EHLO */
- transport->is_esmtp = TRUE;
- if (!smtp_helo (transport, NULL)) {
- /* Okay, apprently this server doesn't support ESMTP */
- transport->is_esmtp = FALSE;
- smtp_helo (transport, ex);
- }
- } else {
- /* send EHLO */
- smtp_helo (transport, ex);
- }
-
- return TRUE;
-}
-
-static gboolean
-smtp_connect (CamelService *service, CamelException *ex)
-{
- CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
-
- /* We (probably) need to check popb4smtp before we connect ... */
- if (service->url->authmech && !strcmp (service->url->authmech, "POPB4SMTP")) {
- int truth;
- GByteArray *chal;
- CamelSasl *sasl;
-
- sasl = camel_sasl_new ("smtp", "POPB4SMTP", service);
- chal = camel_sasl_challenge (sasl, NULL, ex);
- truth = camel_sasl_authenticated (sasl);
- if (chal)
- g_byte_array_free (chal, TRUE);
- camel_object_unref (CAMEL_OBJECT (sasl));
-
- if (!truth)
- return FALSE;
-
- return connect_to_server (service, ex);
- }
-
- if (!connect_to_server (service, ex))
- return FALSE;
-
- /* check to see if AUTH is required, if so...then AUTH ourselves */
- if (service->url->authmech) {
- CamelSession *session = camel_service_get_session (service);
- CamelServiceAuthType *authtype;
- gboolean authenticated = FALSE;
- char *errbuf = NULL;
-
- if (!transport->is_esmtp || !g_hash_table_lookup (transport->authtypes, service->url->authmech)) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
- _("SMTP server %s does not support requested "
- "authentication type %s"), service->url->host,
- service->url->authmech);
- camel_service_disconnect (service, TRUE, NULL);
- return FALSE;
- }
-
- authtype = camel_sasl_authtype (service->url->authmech);
- if (!authtype) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
- _("No support for authentication type %s"),
- service->url->authmech);
- camel_service_disconnect (service, TRUE, NULL);
- return FALSE;
- }
-
- if (!authtype->need_password) {
- /* authentication mechanism doesn't need a password,
- so if it fails there's nothing we can do */
- authenticated = smtp_auth (transport, authtype->authproto, ex);
- if (!authenticated) {
- camel_service_disconnect (service, TRUE, NULL);
- return FALSE;
- }
- }
-
- /* keep trying to login until either we succeed or the user cancels */
- while (!authenticated) {
- if (errbuf) {
- /* We need to un-cache the password before prompting again */
- camel_session_forget_password (session, service, "password", ex);
- g_free (service->url->passwd);
- service->url->passwd = NULL;
- }
-
- if (!service->url->passwd) {
- char *prompt;
-
- prompt = g_strdup_printf (_("%sPlease enter the SMTP password for %s@%s"),
- errbuf ? errbuf : "", service->url->user,
- service->url->host);
-
- service->url->passwd = camel_session_get_password (session, prompt, TRUE,
- service, "password", ex);
-
- g_free (prompt);
- g_free (errbuf);
- errbuf = NULL;
-
- if (!service->url->passwd) {
- camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
- _("You didn't enter a password."));
- camel_service_disconnect (service, TRUE, NULL);
- return FALSE;
- }
- }
-
- authenticated = smtp_auth (transport, authtype->authproto, ex);
- if (!authenticated) {
- errbuf = g_strdup_printf (_("Unable to authenticate "
- "to SMTP server.\n%s\n\n"),
- camel_exception_get_description (ex));
- camel_exception_clear (ex);
- }
- }
-
- /* The spec says we have to re-EHLO, but some servers
- * we won't bother to name don't want you to... so ignore
- * errors.
- */
- smtp_helo (transport, NULL);
- }
-
- return TRUE;
-}
-
-static gboolean
-authtypes_free (gpointer key, gpointer value, gpointer data)
-{
- g_free (key);
- g_free (value);
-
- return TRUE;
-}
-
-static gboolean
-smtp_disconnect (CamelService *service, gboolean clean, CamelException *ex)
-{
- CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
-
- /*if (!service->connected)
- * return TRUE;
- */
-
- if (clean) {
- /* send the QUIT command to the SMTP server */
- smtp_quit (transport, ex);
- }
-
- if (!CAMEL_SERVICE_CLASS (parent_class)->disconnect (service, clean, ex))
- return FALSE;
-
- if (transport->authtypes) {
- g_hash_table_foreach_remove (transport->authtypes, authtypes_free, NULL);
- g_hash_table_destroy (transport->authtypes);
- transport->authtypes = NULL;
- }
-
- camel_object_unref (CAMEL_OBJECT (transport->ostream));
- camel_object_unref (CAMEL_OBJECT (transport->istream));
-
- transport->ostream = NULL;
- transport->istream = NULL;
-
- return TRUE;
-}
-
-static GHashTable *
-esmtp_get_authtypes (char *buffer)
-{
- GHashTable *table = NULL;
- gchar *start, *end;
-
- /* advance to the first token */
- for (start = buffer; isspace (*start) || *start == '='; start++);
-
- if (!*start) return NULL;
-
- table = g_hash_table_new (g_str_hash, g_str_equal);
-
- for ( ; *start; ) {
- char *type;
-
- /* advance to the end of the token */
- for (end = start; *end && !isspace (*end); end++);
-
- type = g_strndup (start, end - start);
- g_hash_table_insert (table, g_strdup (type), type);
-
- /* advance to the next token */
- for (start = end; isspace (*start); start++);
- }
-
- return table;
-}
-
-static GList *
-query_auth_types (CamelService *service, CamelException *ex)
-{
- CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
- CamelServiceAuthType *authtype;
- GList *types, *t, *next;
-
- if (!connect_to_server (service, ex))
- return NULL;
-
- types = g_list_copy (service->provider->authtypes);
- for (t = types; t; t = next) {
- authtype = t->data;
- next = t->next;
-
- if (!g_hash_table_lookup (transport->authtypes, authtype->authproto)) {
- types = g_list_remove_link (types, t);
- g_list_free_1 (t);
- }
- }
-
- smtp_disconnect (service, TRUE, NULL);
- return types;
-}
-
-static char *
-get_name (CamelService *service, gboolean brief)
-{
- if (brief)
- return g_strdup_printf (_("SMTP server %s"), service->url->host);
- else {
- return g_strdup_printf (_("SMTP mail delivery via %s"),
- service->url->host);
- }
-}
-
-static gboolean
-smtp_can_send (CamelTransport *transport, CamelMedium *message)
-{
- return CAMEL_IS_MIME_MESSAGE (message);
-}
-
-static gboolean
-smtp_send_to (CamelTransport *transport, CamelMedium *message,
- CamelAddress *from, CamelAddress *recipients,
- CamelException *ex)
-{
- CamelSmtpTransport *smtp_transport = CAMEL_SMTP_TRANSPORT (transport);
- const CamelInternetAddress *cia;
- gboolean has_8bit_parts;
- const char *addr;
- int i, len;
-
- if (!from) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot send message: "
- "sender address not defined."));
- return FALSE;
- }
-
- if (!camel_internet_address_get (CAMEL_INTERNET_ADDRESS (from), 0, NULL, &addr)) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot send message: "
- "sender address not valid."));
- return FALSE;
- }
-
- camel_operation_start (NULL, _("Sending message"));
-
- /* find out if the message has 8bit mime parts */
- has_8bit_parts = camel_mime_message_has_8bit_parts (CAMEL_MIME_MESSAGE (message));
-
- /* rfc1652 (8BITMIME) requires that you notify the ESMTP daemon that
- you'll be sending an 8bit mime message at "MAIL FROM:" time. */
- smtp_mail (smtp_transport, addr, has_8bit_parts, ex);
-
- if (!recipients) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot send message: "
- "no recipients defined."));
- camel_operation_end (NULL);
- return FALSE;
- }
-
- len = camel_address_length (recipients);
- cia = CAMEL_INTERNET_ADDRESS (recipients);
- for (i = 0; i < len; i++) {
- if (!camel_internet_address_get (cia, i, NULL, &addr)) {
- camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot send message: one or more invalid recipients"));
- camel_operation_end (NULL);
- return FALSE;
- }
-
- if (!smtp_rcpt (smtp_transport, addr, ex)) {
- camel_operation_end (NULL);
- return FALSE;
- }
- }
-
- /* passing in has_8bit_parts saves time as we don't have to
- recurse through the message all over again if the user is
- not sending 8bit mime parts */
- if (!smtp_data (smtp_transport, message, has_8bit_parts, ex)) {
- camel_operation_end (NULL);
- return FALSE;
- }
-
- /* reset the service for our next transfer session */
- smtp_rset (smtp_transport, ex);
-
- camel_operation_end (NULL);
-
- return TRUE;
-}
-
-static gboolean
-smtp_send (CamelTransport *transport, CamelMedium *message, CamelException *ex)
-{
- const CamelInternetAddress *from, *to, *cc, *bcc;
- CamelInternetAddress *recipients = NULL;
- gboolean status;
-
- from = camel_mime_message_get_from (CAMEL_MIME_MESSAGE (message));
-
- to = camel_mime_message_get_recipients (CAMEL_MIME_MESSAGE (message), CAMEL_RECIPIENT_TYPE_TO);
- cc = camel_mime_message_get_recipients (CAMEL_MIME_MESSAGE (message), CAMEL_RECIPIENT_TYPE_CC);
- bcc = camel_mime_message_get_recipients (CAMEL_MIME_MESSAGE (message), CAMEL_RECIPIENT_TYPE_BCC);
-
- recipients = camel_internet_address_new ();
- camel_address_cat (CAMEL_ADDRESS (recipients), CAMEL_ADDRESS (to));
- camel_address_cat (CAMEL_ADDRESS (recipients), CAMEL_ADDRESS (cc));
- camel_address_cat (CAMEL_ADDRESS (recipients), CAMEL_ADDRESS (bcc));
-
- status = smtp_send_to (transport, message, CAMEL_ADDRESS (from), CAMEL_ADDRESS (recipients), ex);
-
- camel_object_unref (CAMEL_OBJECT (recipients));
-
- return status;
-}
-
-static gboolean
-smtp_helo (CamelSmtpTransport *transport, CamelException *ex)
-{
- /* say hello to the server */
- gchar *cmdbuf, *respbuf = NULL;
- struct hostent *host;
-
- camel_operation_start_transient (NULL, _("SMTP Greeting"));
-
- /* get the local host name */
- host = gethostbyaddr ((gchar *)&transport->localaddr.sin_addr, sizeof (transport->localaddr.sin_addr), AF_INET);
-
- /* hiya server! how are you today? */
- if (transport->is_esmtp) {
- if (host && host->h_name)
- cmdbuf = g_strdup_printf ("EHLO %s\r\n", host->h_name);
- else
- cmdbuf = g_strdup_printf ("EHLO [%s]\r\n", inet_ntoa (transport->localaddr.sin_addr));
- } else {
- if (host && host->h_name)
- cmdbuf = g_strdup_printf ("HELO %s\r\n", host->h_name);
- else
- cmdbuf = g_strdup_printf ("HELO [%s]\r\n", inet_ntoa (transport->localaddr.sin_addr));
- }
-
- d(fprintf (stderr, "sending : %s", cmdbuf));
- if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
- g_free (cmdbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("HELO request timed out: %s: non-fatal"),
- g_strerror (errno));
- camel_operation_end (NULL);
- return FALSE;
- }
- g_free (cmdbuf);
-
- do {
- /* Check for "250" */
- g_free (respbuf);
- respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
-
- d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
-
- if (!respbuf || strncmp (respbuf, "250", 3)) {
- int error;
-
- error = respbuf ? atoi (respbuf) : 0;
- g_free (respbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("HELO response error: %s: non-fatal"),
- get_smtp_error_string (error));
- camel_operation_end (NULL);
- return FALSE;
- }
-
- if (strstrcase (respbuf, "8BITMIME")) {
- d(fprintf (stderr, "This server supports 8bit MIME\n"));
- CAMEL_TRANSPORT (transport)->supports_8bit = TRUE;
- }
-
- /* Only parse authtypes if we don't already have them */
- if (transport->is_esmtp && strstr (respbuf, "AUTH") && !transport->authtypes) {
- /* parse for supported AUTH types */
- char *auths = strstr (respbuf, "AUTH") + 4;
-
- transport->authtypes = esmtp_get_authtypes (auths);
- }
- } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
- g_free (respbuf);
-
- camel_operation_end (NULL);
-
- return TRUE;
-}
-
-static gboolean
-smtp_auth (CamelSmtpTransport *transport, const char *mech, CamelException *ex)
-{
- gchar *cmdbuf, *respbuf = NULL, *challenge;
- CamelSasl *sasl = NULL;
-
- camel_operation_start_transient (NULL, _("SMTP Authentication"));
-
- sasl = camel_sasl_new ("smtp", mech, CAMEL_SERVICE (transport));
- if (!sasl) {
- camel_operation_end (NULL);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Error creating SASL authentication object."));
- return FALSE;
- }
-
- challenge = camel_sasl_challenge_base64 (sasl, NULL, ex);
- if (challenge) {
- cmdbuf = g_strdup_printf ("AUTH %s %s\r\n", mech, challenge);
- g_free (challenge);
- } else
- cmdbuf = g_strdup_printf ("AUTH %s\r\n", mech);
-
- d(fprintf (stderr, "sending : %s", cmdbuf));
- if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
- g_free (cmdbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("AUTH request timed out: %s"),
- g_strerror (errno));
- goto lose;
- }
- g_free (cmdbuf);
-
- respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
- d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
-
- while (!camel_sasl_authenticated (sasl)) {
- if (!respbuf) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("AUTH request timed out: %s"),
- g_strerror (errno));
- goto lose;
- }
-
- /* the server challenge/response should follow a 334 code */
- if (strncmp (respbuf, "334", 3)) {
- g_free (respbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("AUTH request failed."));
- goto lose;
- }
-
- /* eat whtspc */
- for (challenge = respbuf + 4; isspace (*challenge); challenge++);
-
- challenge = camel_sasl_challenge_base64 (sasl, challenge, ex);
- g_free (respbuf);
- if (challenge == NULL)
- goto break_and_lose;
-
- /* send our challenge */
- cmdbuf = g_strdup_printf ("%s\r\n", challenge);
- g_free (challenge);
- d(fprintf (stderr, "sending : %s", cmdbuf));
- if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
- g_free (cmdbuf);
- goto lose;
- }
- g_free (cmdbuf);
-
- /* get the server's response */
- respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
- d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
- }
-
- /* check that the server says we are authenticated */
- if (!respbuf || strncmp (respbuf, "235", 3)) {
- g_free (respbuf);
- goto lose;
- }
-
- camel_object_unref (CAMEL_OBJECT (sasl));
- camel_operation_end (NULL);
-
- return TRUE;
-
- break_and_lose:
- /* Get the server out of "waiting for continuation data" mode. */
- d(fprintf (stderr, "sending : *\n"));
- camel_stream_write (transport->ostream, "*\r\n", 3);
- respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
- d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
-
- lose:
- if (!camel_exception_is_set (ex)) {
- camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
- _("Bad authentication response from server.\n"));
- }
-
- camel_object_unref (CAMEL_OBJECT (sasl));
- camel_operation_end (NULL);
-
- return FALSE;
-}
-
-static gboolean
-smtp_mail (CamelSmtpTransport *transport, const char *sender, gboolean has_8bit_parts, CamelException *ex)
-{
- /* we gotta tell the smtp server who we are. (our email addy) */
- gchar *cmdbuf, *respbuf = NULL;
-
- /* enclose address in <>'s since some SMTP daemons *require* that */
- if (CAMEL_TRANSPORT (transport)->supports_8bit && has_8bit_parts)
- cmdbuf = g_strdup_printf ("MAIL FROM: <%s> BODY=8BITMIME\r\n", sender);
- else
- cmdbuf = g_strdup_printf ("MAIL FROM: <%s>\r\n", sender);
-
- d(fprintf (stderr, "sending : %s", cmdbuf));
-
- if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
- g_free (cmdbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("MAIL FROM request timed out: %s: mail not sent"),
- g_strerror (errno));
- return FALSE;
- }
- g_free (cmdbuf);
-
- do {
- /* Check for "250 Sender OK..." */
- g_free (respbuf);
- respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
-
- d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
-
- if (!respbuf || strncmp (respbuf, "250", 3)) {
- int error;
-
- error = respbuf ? atoi (respbuf) : 0;
- g_free (respbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("MAIL FROM response error: %s: mail not sent"),
- get_smtp_error_string (error));
- return FALSE;
- }
- } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
- g_free (respbuf);
-
- return TRUE;
-}
-
-static gboolean
-smtp_rcpt (CamelSmtpTransport *transport, const char *recipient, CamelException *ex)
-{
- /* we gotta tell the smtp server who we are going to be sending
- * our email to */
- gchar *cmdbuf, *respbuf = NULL;
-
- /* enclose address in <>'s since some SMTP daemons *require* that */
- cmdbuf = g_strdup_printf ("RCPT TO: <%s>\r\n", recipient);
-
- d(fprintf (stderr, "sending : %s", cmdbuf));
-
- if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
- g_free (cmdbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("RCPT TO request timed out: %s: mail not sent"),
- g_strerror (errno));
- return FALSE;
- }
- g_free (cmdbuf);
-
- do {
- /* Check for "250 Sender OK..." */
- g_free (respbuf);
- respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
-
- d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
-
- if (!respbuf || strncmp (respbuf, "250", 3)) {
- int error;
-
- error = respbuf ? atoi (respbuf) : 0;
- g_free (respbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("RCPT TO response error: %s: mail not sent"),
- get_smtp_error_string (error));
- return FALSE;
- }
- } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
- g_free (respbuf);
-
- return TRUE;
-}
-
-static gboolean
-smtp_data (CamelSmtpTransport *transport, CamelMedium *message, gboolean has_8bit_parts, CamelException *ex)
-{
- /* now we can actually send what's important :p */
- char *cmdbuf, *respbuf = NULL;
- CamelStreamFilter *filtered_stream;
- CamelMimeFilter *crlffilter;
- struct _header_raw *header;
- GSList *h, *bcc = NULL;
- int ret;
-
- /* if the message contains 8bit mime parts and the server
- doesn't support it, encode 8bit parts to the best
- encoding. This will also enforce an encoding to keep the lines in limit */
- if (has_8bit_parts && !CAMEL_TRANSPORT (transport)->supports_8bit)
- camel_mime_message_encode_8bit_parts (CAMEL_MIME_MESSAGE (message));
-
- cmdbuf = g_strdup ("DATA\r\n");
-
- d(fprintf (stderr, "sending : %s", cmdbuf));
-
- if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
- g_free (cmdbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("DATA request timed out: %s: mail not sent"),
- g_strerror (errno));
- return FALSE;
- }
- g_free (cmdbuf);
-
- respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
-
- d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
-
- if (!respbuf || strncmp (respbuf, "354", 3)) {
- /* we should have gotten instructions on how to use the DATA command:
- * 354 Enter mail, end with "." on a line by itself
- */
- int error;
-
- error = respbuf ? atoi (respbuf) : 0;
- g_free (respbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("DATA response error: %s: mail not sent"),
- get_smtp_error_string (error));
- return FALSE;
- }
-
- g_free (respbuf);
- respbuf = NULL;
-
- /* setup stream filtering */
- crlffilter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS);
- filtered_stream = camel_stream_filter_new_with_stream (transport->ostream);
- camel_stream_filter_add (filtered_stream, CAMEL_MIME_FILTER (crlffilter));
- camel_object_unref (CAMEL_OBJECT (crlffilter));
-
- /* copy and remove the bcc headers */
- header = CAMEL_MIME_PART (message)->headers;
- while (header) {
- if (!g_strcasecmp (header->name, "Bcc"))
- bcc = g_slist_append (bcc, g_strdup (header->value));
- header = header->next;
- }
-
- camel_medium_remove_header (CAMEL_MEDIUM (message), "Bcc");
-
- /* write the message */
- ret = camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), CAMEL_STREAM (filtered_stream));
-
- /* add the bcc headers back */
- if (bcc) {
- h = bcc;
- while (h) {
- camel_medium_add_header (CAMEL_MEDIUM (message), "Bcc", h->data);
- g_free (h->data);
- h = h->next;
- }
- g_slist_free (bcc);
- }
-
- if (ret == -1) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("DATA send timed out: message termination: "
- "%s: mail not sent"),
- g_strerror (errno));
-
- camel_object_unref (CAMEL_OBJECT (filtered_stream));
-
- return FALSE;
- }
-
- camel_stream_flush (CAMEL_STREAM (filtered_stream));
- camel_object_unref (CAMEL_OBJECT (filtered_stream));
-
- /* terminate the message body */
-
- d(fprintf (stderr, "sending : \\r\\n.\\r\\n\n"));
-
- if (camel_stream_write (transport->ostream, "\r\n.\r\n", 5) == -1) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("DATA send timed out: message termination: "
- "%s: mail not sent"),
- g_strerror (errno));
- return FALSE;
- }
-
- do {
- /* Check for "250 Sender OK..." */
- g_free (respbuf);
- respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
-
- d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
-
- if (!respbuf || strncmp (respbuf, "250", 3)) {
- int error;
-
- error = respbuf ? atoi (respbuf) : 0;
- g_free (respbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("DATA response error: message termination: "
- "%s: mail not sent"),
- get_smtp_error_string (error));
- return FALSE;
- }
- } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
- g_free (respbuf);
-
- return TRUE;
-}
-
-static gboolean
-smtp_rset (CamelSmtpTransport *transport, CamelException *ex)
-{
- /* we are going to reset the smtp server (just to be nice) */
- gchar *cmdbuf, *respbuf = NULL;
-
- cmdbuf = g_strdup ("RSET\r\n");
-
- d(fprintf (stderr, "sending : %s", cmdbuf));
-
- if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
- g_free (cmdbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("RSET request timed out: %s"),
- g_strerror (errno));
- return FALSE;
- }
- g_free (cmdbuf);
-
- do {
- /* Check for "250" */
- g_free (respbuf);
- respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
-
- d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
-
- if (!respbuf || strncmp (respbuf, "250", 3)) {
- int error;
-
- error = respbuf ? atoi (respbuf) : 0;
- g_free (respbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("RSET response error: %s"),
- get_smtp_error_string (error));
- return FALSE;
- }
- } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
- g_free (respbuf);
-
- return TRUE;
-}
-
-static gboolean
-smtp_quit (CamelSmtpTransport *transport, CamelException *ex)
-{
- /* we are going to reset the smtp server (just to be nice) */
- gchar *cmdbuf, *respbuf = NULL;
-
- cmdbuf = g_strdup ("QUIT\r\n");
-
- d(fprintf (stderr, "sending : %s", cmdbuf));
-
- if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
- g_free (cmdbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("QUIT request timed out: %s: non-fatal"),
- g_strerror (errno));
- return FALSE;
- }
- g_free (cmdbuf);
-
- do {
- /* Check for "221" */
- g_free (respbuf);
- respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
-
- d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
-
- if (!respbuf || strncmp (respbuf, "221", 3)) {
- int error;
-
- error = respbuf ? atoi (respbuf) : 0;
- g_free (respbuf);
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("QUIT response error: %s: non-fatal"),
- get_smtp_error_string (error));
- return FALSE;
- }
- } while (*(respbuf+3) == '-'); /* if we got "221-" then loop again */
- g_free (respbuf);
-
- return TRUE;
-}