1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-smtp-transport.c : class for a smtp transport */
5 * Authors: Jeffrey Stedfast <fejj@helixcode.com>
7 * Copyright (C) 2000 Helix Code, Inc. (www.helixcode.com)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 #include <sys/param.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
40 #include "camel-mime-filter-crlf.h"
41 #include "camel-mime-filter-linewrap.h"
42 #include "camel-stream-filter.h"
43 #include "camel-smtp-transport.h"
44 #include "camel-mime-message.h"
45 #include "camel-multipart.h"
46 #include "camel-mime-part.h"
47 #include "camel-stream-buffer.h"
48 #include "camel-stream-fs.h"
49 #include "camel-session.h"
50 #include "camel-exception.h"
51 #include "camel-sasl.h"
52 #include <gal/util/e-util.h>
56 /* Specified in RFC 821 */
59 /* camel smtp transport class prototypes */
60 static gboolean smtp_can_send (CamelTransport *transport, CamelMedium *message);
61 static gboolean smtp_send (CamelTransport *transport, CamelMedium *message, CamelException *ex);
62 static gboolean smtp_send_to (CamelTransport *transport, CamelMedium *message, GList *recipients, CamelException *ex);
64 /* support prototypes */
65 static gboolean smtp_connect (CamelService *service, CamelException *ex);
66 static gboolean smtp_disconnect (CamelService *service, gboolean clean, CamelException *ex);
67 static GHashTable *esmtp_get_authtypes (gchar *buffer);
68 static GList *query_auth_types (CamelService *service, gboolean connect, CamelException *ex);
69 static void free_auth_types (CamelService *service, GList *authtypes);
70 static char *get_name (CamelService *service, gboolean brief);
72 static gboolean smtp_helo (CamelSmtpTransport *transport, CamelException *ex);
73 static gboolean smtp_auth (CamelSmtpTransport *transport, const char *mech, CamelException *ex);
74 static gboolean smtp_mail (CamelSmtpTransport *transport, const char *sender,
75 gboolean has_8bit_parts, CamelException *ex);
76 static gboolean smtp_rcpt (CamelSmtpTransport *transport, const char *recipient, CamelException *ex);
77 static gboolean smtp_data (CamelSmtpTransport *transport, CamelMedium *message,
78 gboolean has_8bit_parts, CamelException *ex);
79 static gboolean smtp_rset (CamelSmtpTransport *transport, CamelException *ex);
80 static gboolean smtp_quit (CamelSmtpTransport *transport, CamelException *ex);
82 /* private data members */
83 static CamelServiceClass *service_class = NULL;
86 camel_smtp_transport_class_init (CamelSmtpTransportClass *camel_smtp_transport_class)
88 CamelTransportClass *camel_transport_class =
89 CAMEL_TRANSPORT_CLASS (camel_smtp_transport_class);
90 CamelServiceClass *camel_service_class =
91 CAMEL_SERVICE_CLASS (camel_smtp_transport_class);
93 service_class = CAMEL_SERVICE_CLASS (camel_type_get_global_classfuncs (camel_service_get_type ()));
95 /* virtual method overload */
96 camel_service_class->connect = smtp_connect;
97 camel_service_class->disconnect = smtp_disconnect;
98 camel_service_class->query_auth_types = query_auth_types;
99 camel_service_class->free_auth_types = free_auth_types;
100 camel_service_class->get_name = get_name;
102 camel_transport_class->can_send = smtp_can_send;
103 camel_transport_class->send = smtp_send;
104 camel_transport_class->send_to = smtp_send_to;
108 camel_smtp_transport_init (gpointer object)
110 CamelTransport *transport = CAMEL_TRANSPORT (object);
112 transport->supports_8bit = FALSE;
116 camel_smtp_transport_get_type (void)
118 static CamelType camel_smtp_transport_type = CAMEL_INVALID_TYPE;
120 if (camel_smtp_transport_type == CAMEL_INVALID_TYPE) {
121 camel_smtp_transport_type =
122 camel_type_register (CAMEL_TRANSPORT_TYPE, "CamelSmtpTransport",
123 sizeof (CamelSmtpTransport),
124 sizeof (CamelSmtpTransportClass),
125 (CamelObjectClassInitFunc) camel_smtp_transport_class_init,
127 (CamelObjectInitFunc) camel_smtp_transport_init,
131 return camel_smtp_transport_type;
135 get_smtp_error_string (int error)
137 /* SMTP error codes grabbed from rfc821 */
140 /* looks like a read problem, check errno */
141 return g_strerror (errno);
143 return _("Syntax error, command unrecognized");
145 return _("Syntax error in parameters or arguments");
147 return _("Command not implemented");
149 return _("Command parameter not implemented");
151 return _("System status, or system help reply");
153 return _("Help message");
155 return _("Service ready");
157 return _("Service closing transmission channel");
159 return _("Service not available, closing transmission channel");
161 return _("Requested mail action okay, completed");
163 return _("User not local; will forward to <forward-path>");
165 return _("Requested mail action not taken: mailbox unavailable");
167 return _("Requested action not taken: mailbox unavailable");
169 return _("Requested action aborted: error in processing");
171 return _("User not local; please try <forward-path>");
173 return _("Requested action not taken: insufficient system storage");
175 return _("Requested mail action aborted: exceeded storage allocation");
177 return _("Requested action not taken: mailbox name not allowed");
179 return _("Start mail input; end with <CRLF>.<CRLF>");
181 return _("Transaction failed");
183 /* AUTH error codes: */
185 return _("A password transition is needed");
187 return _("Authentication mechanism is too weak");
189 return _("Encryption required for requested authentication mechanism");
191 return _("Temporary authentication failure");
193 return _("Authentication required");
201 smtp_connect (CamelService *service, CamelException *ex)
203 CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
204 gchar *pass = NULL, *respbuf = NULL;
206 struct sockaddr_in sin;
210 if (!service_class->connect (service, ex))
213 h = camel_service_gethost (service, ex);
217 /* set some smtp transport defaults */
218 transport->is_esmtp = FALSE;
219 transport->authtypes = NULL;
220 CAMEL_TRANSPORT (transport)->supports_8bit = FALSE;
222 sin.sin_family = h->h_addrtype;
223 sin.sin_port = htons (service->url->port ? service->url->port : SMTP_PORT);
224 memcpy (&sin.sin_addr, h->h_addr, sizeof (sin.sin_addr));
226 fd = socket (h->h_addrtype, SOCK_STREAM, 0);
227 if (fd == -1 || connect (fd, (struct sockaddr *)&sin, sizeof (sin)) == -1) {
228 camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
229 _("Could not connect to %s (port %d): %s"),
231 service->url->port ? service->url->port : SMTP_PORT,
239 /* get the localaddr - needed later by smtp_helo */
240 addrlen = sizeof (transport->localaddr);
241 getsockname (fd, (struct sockaddr*)&transport->localaddr, &addrlen);
243 transport->ostream = camel_stream_fs_new_with_fd (fd);
244 transport->istream = camel_stream_buffer_new (transport->ostream,
245 CAMEL_STREAM_BUFFER_READ);
247 /* Read the greeting, note whether the server is ESMTP or not. */
249 /* Check for "220" */
251 respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
252 if (!respbuf || strncmp (respbuf, "220", 3)) {
255 error = respbuf ? atoi (respbuf) : 0;
257 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
258 _("Welcome response error: %s: possibly non-fatal"),
259 get_smtp_error_string (error));
262 if (strstr (respbuf, "ESMTP"))
263 transport->is_esmtp = TRUE;
264 } while (*(respbuf+3) == '-'); /* if we got "220-" then loop again */
267 /* send HELO (or EHLO, depending on the service type) */
268 if (!transport->is_esmtp) {
269 /* If we did not auto-detect ESMTP, we should still send EHLO */
270 transport->is_esmtp = TRUE;
271 if (!smtp_helo (transport, NULL)) {
272 /* Okay, apprently this server doesn't support ESMTP */
273 transport->is_esmtp = FALSE;
274 smtp_helo (transport, ex);
278 smtp_helo (transport, ex);
281 /* check to see if AUTH is required, if so...then AUTH ourselves */
282 if (service->url->authmech) {
283 CamelServiceAuthType *authtype;
285 if (!transport->is_esmtp || !g_hash_table_lookup (transport->authtypes, service->url->authmech)) {
286 camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
287 "SMTP server %s does not support requested "
288 "authentication type %s", service->url->host,
289 service->url->authmech);
290 camel_service_disconnect (service, TRUE, NULL);
294 authtype = camel_sasl_authtype (service->url->authmech);
296 camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
297 "No support for authentication type %s",
298 service->url->authmech);
299 camel_service_disconnect (service, TRUE, NULL);
303 if (!smtp_auth (transport, authtype->authproto, ex)) {
304 camel_service_disconnect (service, TRUE, NULL);
308 /* we have to re-EHLO */
309 smtp_helo (transport, ex);
316 authtypes_free (gpointer key, gpointer value, gpointer data)
325 smtp_disconnect (CamelService *service, gboolean clean, CamelException *ex)
327 CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
329 /*if (!service->connected)
334 /* send the QUIT command to the SMTP server */
335 smtp_quit (transport, ex);
338 if (!service_class->disconnect (service, clean, ex))
341 if (transport->authtypes) {
342 g_hash_table_foreach_remove (transport->authtypes, authtypes_free, NULL);
343 g_hash_table_destroy (transport->authtypes);
344 transport->authtypes = NULL;
347 camel_object_unref (CAMEL_OBJECT (transport->ostream));
348 camel_object_unref (CAMEL_OBJECT (transport->istream));
350 transport->ostream = NULL;
351 transport->istream = NULL;
357 esmtp_get_authtypes (char *buffer)
359 GHashTable *table = NULL;
362 /* advance to the first token */
363 for (start = buffer; isspace (*start) || *start == '='; start++);
365 if (!*start) return NULL;
367 table = g_hash_table_new (g_str_hash, g_str_equal);
372 /* advance to the end of the token */
373 for (end = start; *end && !isspace (*end); end++);
375 type = g_strndup (start, end - start);
376 g_hash_table_insert (table, g_strdup (type), type);
378 /* advance to the next token */
379 for (start = end; isspace (*start); start++);
385 static CamelServiceAuthType no_authtype = {
386 N_("No authentication required"),
388 N_("This option will connect to the SMTP server without using any "
389 "kind of authentication. This should be fine for connecting to "
390 "most SMTP servers."),
397 query_auth_types (CamelService *service, gboolean connect, CamelException *ex)
399 CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
400 CamelServiceAuthType *authtype;
403 if (connect && !smtp_connect (service, ex))
406 types = camel_sasl_authtype_list ();
408 for (t = types; t; t = t->next) {
411 if (!g_hash_table_lookup (transport->authtypes, authtype->authproto)) {
412 g_list_remove_link (types, t);
418 return g_list_prepend (types, &no_authtype);
422 free_auth_types (CamelService *service, GList *authtypes)
424 g_list_free (authtypes);
428 get_name (CamelService *service, gboolean brief)
431 return g_strdup_printf (_("SMTP server %s"), service->url->host);
433 return g_strdup_printf (_("SMTP mail delivery via %s"),
439 smtp_can_send (CamelTransport *transport, CamelMedium *message)
441 return CAMEL_IS_MIME_MESSAGE (message);
445 smtp_send_to (CamelTransport *transport, CamelMedium *message,
446 GList *recipients, CamelException *ex)
448 CamelSmtpTransport *smtp_transport = CAMEL_SMTP_TRANSPORT (transport);
449 const CamelInternetAddress *cia;
452 gboolean has_8bit_parts;
455 cia = camel_mime_message_get_from(CAMEL_MIME_MESSAGE (message));
457 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
458 _("Cannot send message: "
459 "sender address not defined."));
463 if (!camel_internet_address_get (cia, 0, NULL, &addr)) {
464 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
465 _("Cannot send message: "
466 "sender address not valid."));
470 /* find out if the message has 8bit mime parts */
471 has_8bit_parts = camel_mime_message_has_8bit_parts (CAMEL_MIME_MESSAGE (message));
473 /* rfc1652 (8BITMIME) requires that you notify the ESMTP daemon that
474 you'll be sending an 8bit mime message at "MAIL FROM:" time. */
475 smtp_mail (smtp_transport, addr, has_8bit_parts, ex);
478 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
479 _("Cannot send message: "
480 "no recipients defined."));
484 for (r = recipients; r; r = r->next) {
485 recipient = (char *) r->data;
486 if (!smtp_rcpt (smtp_transport, recipient, ex)) {
493 /* passing in has_8bit_parts saves time as we don't have to
494 recurse through the message all over again if the user is
495 not sending 8bit mime parts */
496 if (!smtp_data (smtp_transport, message, has_8bit_parts, ex))
499 /* reset the service for our next transfer session */
500 smtp_rset (smtp_transport, ex);
506 smtp_send (CamelTransport *transport, CamelMedium *message, CamelException *ex)
508 const CamelInternetAddress *to, *cc, *bcc;
509 GList *recipients = NULL;
512 to = camel_mime_message_get_recipients (CAMEL_MIME_MESSAGE (message), CAMEL_RECIPIENT_TYPE_TO);
513 cc = camel_mime_message_get_recipients (CAMEL_MIME_MESSAGE (message), CAMEL_RECIPIENT_TYPE_CC);
514 bcc = camel_mime_message_get_recipients (CAMEL_MIME_MESSAGE (message), CAMEL_RECIPIENT_TYPE_BCC);
516 /* get all of the To addresses into our recipient list */
517 len = CAMEL_ADDRESS (to)->addresses->len;
518 for (index = 0; index < len; index++) {
521 if (camel_internet_address_get (to, index, NULL, &addr))
522 recipients = g_list_append (recipients, g_strdup (addr));
525 /* get all of the Cc addresses into our recipient list */
526 len = CAMEL_ADDRESS (cc)->addresses->len;
527 for (index = 0; index < len; index++) {
530 if (camel_internet_address_get (cc, index, NULL, &addr))
531 recipients = g_list_append (recipients, g_strdup (addr));
534 /* get all of the Bcc addresses into our recipient list */
535 len = CAMEL_ADDRESS (bcc)->addresses->len;
536 for (index = 0; index < len; index++) {
539 if (camel_internet_address_get (bcc, index, NULL, &addr))
540 recipients = g_list_append (recipients, g_strdup (addr));
543 return smtp_send_to (transport, message, recipients, ex);
547 smtp_helo (CamelSmtpTransport *transport, CamelException *ex)
549 /* say hello to the server */
550 gchar *cmdbuf, *respbuf = NULL;
551 struct hostent *host;
553 /* get the local host name */
554 host = gethostbyaddr ((gchar *)&transport->localaddr.sin_addr, sizeof (transport->localaddr.sin_addr), AF_INET);
556 /* hiya server! how are you today? */
557 if (transport->is_esmtp) {
558 if (host && host->h_name)
559 cmdbuf = g_strdup_printf ("EHLO %s\r\n", host->h_name);
561 cmdbuf = g_strdup_printf ("EHLO [%s]\r\n", inet_ntoa (transport->localaddr.sin_addr));
563 if (host && host->h_name)
564 cmdbuf = g_strdup_printf ("HELO %s\r\n", host->h_name);
566 cmdbuf = g_strdup_printf ("HELO [%s]\r\n", inet_ntoa (transport->localaddr.sin_addr));
569 d(fprintf (stderr, "sending : %s", cmdbuf));
570 if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
572 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
573 _("HELO request timed out: %s: non-fatal"),
580 /* Check for "250" */
582 respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
584 d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
586 if (!respbuf || strncmp (respbuf, "250", 3)) {
589 error = respbuf ? atoi (respbuf) : 0;
591 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
592 _("HELO response error: %s: non-fatal"),
593 get_smtp_error_string (error));
597 if (e_strstrcase (respbuf, "8BITMIME")) {
598 d(fprintf (stderr, "This server supports 8bit MIME\n"));
599 CAMEL_TRANSPORT (transport)->supports_8bit = TRUE;
602 /* Only parse authtypes if we don't already have them */
603 if (transport->is_esmtp && strstr (respbuf, "AUTH") && !transport->authtypes) {
604 /* parse for supported AUTH types */
605 char *auths = strstr (respbuf, "AUTH") + 4;
607 transport->authtypes = esmtp_get_authtypes (auths);
609 } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
616 smtp_auth (CamelSmtpTransport *transport, const char *mech, CamelException *ex)
618 gchar *cmdbuf, *respbuf = NULL;
621 /* tell the server we want to authenticate... */
622 cmdbuf = g_strdup_printf ("AUTH %s\r\n", mech);
623 d(fprintf (stderr, "sending : %s", cmdbuf));
624 if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
626 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
627 _("AUTH request timed out: %s"),
633 /* get the base64 encoded server challenge which should follow a 334 code */
634 respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
635 d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
636 if (!respbuf || strncmp (respbuf, "334", 3)) {
638 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
639 _("AUTH request timed out: %s"),
644 sasl = camel_sasl_new ("smtp", mech, CAMEL_SERVICE (transport));
650 while (!camel_sasl_authenticated (sasl)) {
657 for (challenge = respbuf + 4; isspace (*challenge); challenge++);
659 challenge = camel_sasl_challenge_base64 (sasl, challenge, ex);
661 if (camel_exception_is_set (ex))
664 /* send our challenge */
665 cmdbuf = g_strdup_printf ("%s\r\n", challenge);
667 d(fprintf (stderr, "sending : %s", cmdbuf));
668 if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
674 /* get the server's response */
675 respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
676 d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
679 /* check that the server says we are authenticated */
680 if (!respbuf || strncmp (respbuf, "235", 3)) {
688 /* Get the server out of "waiting for continuation data" mode. */
689 d(fprintf (stderr, "sending : *\n"));
690 camel_stream_write (transport->ostream, "*\r\n", 3);
691 respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
692 d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
695 if (!camel_exception_is_set (ex)) {
696 camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
697 _("Bad authentication response from server.\n"));
700 camel_object_unref (CAMEL_OBJECT (sasl));
706 smtp_mail (CamelSmtpTransport *transport, const char *sender, gboolean has_8bit_parts, CamelException *ex)
708 /* we gotta tell the smtp server who we are. (our email addy) */
709 gchar *cmdbuf, *respbuf = NULL;
711 /* enclose address in <>'s since some SMTP daemons *require* that */
712 if (CAMEL_TRANSPORT (transport)->supports_8bit && has_8bit_parts)
713 cmdbuf = g_strdup_printf ("MAIL FROM: <%s> BODY=8BITMIME\r\n", sender);
715 cmdbuf = g_strdup_printf ("MAIL FROM: <%s>\r\n", sender);
717 d(fprintf (stderr, "sending : %s", cmdbuf));
719 if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
721 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
722 _("MAIL FROM request timed out: %s: mail not sent"),
729 /* Check for "250 Sender OK..." */
731 respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
733 d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
735 if (!respbuf || strncmp (respbuf, "250", 3)) {
738 error = respbuf ? atoi (respbuf) : 0;
740 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
741 _("MAIL FROM response error: %s: mail not sent"),
742 get_smtp_error_string (error));
745 } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
752 smtp_rcpt (CamelSmtpTransport *transport, const char *recipient, CamelException *ex)
754 /* we gotta tell the smtp server who we are going to be sending
756 gchar *cmdbuf, *respbuf = NULL;
758 /* enclose address in <>'s since some SMTP daemons *require* that */
759 cmdbuf = g_strdup_printf ("RCPT TO: <%s>\r\n", recipient);
761 d(fprintf (stderr, "sending : %s", cmdbuf));
763 if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
765 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
766 _("RCPT TO request timed out: %s: mail not sent"),
773 /* Check for "250 Sender OK..." */
775 respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
777 d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
779 if (!respbuf || strncmp (respbuf, "250", 3)) {
782 error = respbuf ? atoi (respbuf) : 0;
784 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
785 _("RCPT TO response error: %s: mail not sent"),
786 get_smtp_error_string (error));
789 } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
796 smtp_data (CamelSmtpTransport *transport, CamelMedium *message, gboolean has_8bit_parts, CamelException *ex)
798 /* now we can actually send what's important :p */
799 gchar *cmdbuf, *respbuf = NULL;
800 CamelStreamFilter *filtered_stream;
801 CamelMimeFilter *crlffilter;
803 /* if the message contains 8bit mime parts and the server
804 doesn't support it, encode 8bit parts to the best
805 encoding. This will also enforce an encoding to keep the lines in limit */
806 if (has_8bit_parts && !CAMEL_TRANSPORT (transport)->supports_8bit)
807 camel_mime_message_encode_8bit_parts (CAMEL_MIME_MESSAGE (message));
809 cmdbuf = g_strdup ("DATA\r\n");
811 d(fprintf (stderr, "sending : %s", cmdbuf));
813 if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
815 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
816 _("DATA request timed out: %s: mail not sent"),
822 respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
824 d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
826 if (!respbuf || strncmp (respbuf, "354", 3)) {
827 /* we should have gotten instructions on how to use the DATA command:
828 * 354 Enter mail, end with "." on a line by itself
832 error = respbuf ? atoi (respbuf) : 0;
834 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
835 _("DATA response error: %s: mail not sent"),
836 get_smtp_error_string (error));
843 /* setup stream filtering */
844 crlffilter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS);
845 filtered_stream = camel_stream_filter_new_with_stream (transport->ostream);
846 camel_stream_filter_add (filtered_stream, CAMEL_MIME_FILTER (crlffilter));
848 if (camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), CAMEL_STREAM (filtered_stream)) == -1) {
849 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
850 _("DATA send timed out: message termination: "
851 "%s: mail not sent"),
854 camel_object_unref (CAMEL_OBJECT (filtered_stream));
859 camel_stream_flush (CAMEL_STREAM (filtered_stream));
860 camel_object_unref (CAMEL_OBJECT (filtered_stream));
862 /* terminate the message body */
864 d(fprintf (stderr, "sending : \\r\\n.\\r\\n\n"));
866 if (camel_stream_write (transport->ostream, "\r\n.\r\n", 5) == -1) {
867 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
868 _("DATA send timed out: message termination: "
869 "%s: mail not sent"),
875 /* Check for "250 Sender OK..." */
877 respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
879 d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
881 if (!respbuf || strncmp (respbuf, "250", 3)) {
884 error = respbuf ? atoi (respbuf) : 0;
886 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
887 _("DATA response error: message termination: "
888 "%s: mail not sent"),
889 get_smtp_error_string (error));
892 } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
899 smtp_rset (CamelSmtpTransport *transport, CamelException *ex)
901 /* we are going to reset the smtp server (just to be nice) */
902 gchar *cmdbuf, *respbuf = NULL;
904 cmdbuf = g_strdup ("RSET\r\n");
906 d(fprintf (stderr, "sending : %s", cmdbuf));
908 if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
910 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
911 _("RSET request timed out: %s"),
918 /* Check for "250" */
920 respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
922 d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
924 if (!respbuf || strncmp (respbuf, "250", 3)) {
927 error = respbuf ? atoi (respbuf) : 0;
929 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
930 _("RSET response error: %s"),
931 get_smtp_error_string (error));
934 } while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
941 smtp_quit (CamelSmtpTransport *transport, CamelException *ex)
943 /* we are going to reset the smtp server (just to be nice) */
944 gchar *cmdbuf, *respbuf = NULL;
946 cmdbuf = g_strdup ("QUIT\r\n");
948 d(fprintf (stderr, "sending : %s", cmdbuf));
950 if (camel_stream_write (transport->ostream, cmdbuf, strlen (cmdbuf)) == -1) {
952 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
953 _("QUIT request timed out: %s: non-fatal"),
960 /* Check for "221" */
962 respbuf = camel_stream_buffer_read_line (CAMEL_STREAM_BUFFER (transport->istream));
964 d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
966 if (!respbuf || strncmp (respbuf, "221", 3)) {
969 error = respbuf ? atoi (respbuf) : 0;
971 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
972 _("QUIT response error: %s: non-fatal"),
973 get_smtp_error_string (error));
976 } while (*(respbuf+3) == '-'); /* if we got "221-" then loop again */