[evolution-data-server] I#123 - [SMTP] Ignore 8BITMIME extension for Yahoo! servers



commit 76834cf20a8c1139791b17ca8c3182dc2a6cb474
Author: Milan Crha <mcrha redhat com>
Date:   Thu May 30 18:14:10 2019 +0200

    I#123 - [SMTP] Ignore 8BITMIME extension for Yahoo! servers
    
    Closes https://gitlab.gnome.org/GNOME/evolution-data-server/issues/123

 src/camel/camel-mime-message.c                  | 31 +++++++++++-----
 src/camel/camel-mime-message.h                  | 23 ++++++++++++
 src/camel/providers/smtp/camel-smtp-transport.c | 49 +++++++++++++++++++++----
 3 files changed, 85 insertions(+), 18 deletions(-)
---
diff --git a/src/camel/camel-mime-message.c b/src/camel/camel-mime-message.c
index 6b47793a5..319782cea 100644
--- a/src/camel/camel-mime-message.c
+++ b/src/camel/camel-mime-message.c
@@ -860,13 +860,11 @@ camel_mime_message_get_source (CamelMimeMessage *message)
        return src;
 }
 
-typedef gboolean (*CamelPartFunc)(CamelMimeMessage *message, CamelMimePart *part, CamelMimePart 
*parent_part, gpointer data);
-
 static gboolean
 message_foreach_part_rec (CamelMimeMessage *msg,
                           CamelMimePart *part,
                          CamelMimePart *parent_part,
-                          CamelPartFunc callback,
+                          CamelForeachPartFunc callback,
                           gpointer data)
 {
        CamelDataWrapper *containee;
@@ -896,14 +894,27 @@ message_foreach_part_rec (CamelMimeMessage *msg,
        return go;
 }
 
-/* dont make this public yet, it might need some more thinking ... */
-/* MPZ */
-static void
-camel_mime_message_foreach_part (CamelMimeMessage *msg,
-                                 CamelPartFunc callback,
-                                 gpointer data)
+/**
+ * camel_mime_message_foreach_part:
+ * @message: a #CamelMimeMessage
+ * @callback: (scope call): a #CamelForeachPartFunc callback to call for each part
+ * @user_data: (closure callback): user data passed to the @callback
+ *
+ * Calls @callback for each part of the @message, including the message itself.
+ * The traverse of the @message parts can be stopped when the @callback
+ * returns %FALSE.
+ *
+ * Since: 3.34
+ **/
+void
+camel_mime_message_foreach_part (CamelMimeMessage *message,
+                                CamelForeachPartFunc callback,
+                                gpointer user_data)
 {
-       message_foreach_part_rec (msg, (CamelMimePart *) msg, NULL, callback, data);
+       g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+       g_return_if_fail (callback != NULL);
+
+       message_foreach_part_rec (message, CAMEL_MIME_PART (message), NULL, callback, user_data);
 }
 
 static gboolean
diff --git a/src/camel/camel-mime-message.h b/src/camel/camel-mime-message.h
index d10f9c2ac..f6770252e 100644
--- a/src/camel/camel-mime-message.h
+++ b/src/camel/camel-mime-message.h
@@ -119,6 +119,29 @@ void               camel_mime_message_set_source   (CamelMimeMessage *message,
 const gchar *  camel_mime_message_get_source   (CamelMimeMessage *message);
 
 /* utility functions */
+
+/**
+ * CamelForeachPartFunc:
+ * @message: a #CamelMimeMessage
+ * @part: a #CamelMimePart, for which the function is called
+ * @parent_part: (nullable): a #CamelMimePart, parent of the @part; can be %NULL
+ * @user_data: user data, as passed to camel_mime_message_foreach_part()
+ *
+ * Callback used to traverse parts of the @message using camel_mime_message_foreach_part().
+ *
+ * Returns: %TRUE, when the traverse should continue, %FALSE to stop
+ *    traversing parts of the @message
+ *
+ * Since: 3.34
+ **/
+typedef gboolean (* CamelForeachPartFunc)      (CamelMimeMessage *message,
+                                                CamelMimePart *part,
+                                                CamelMimePart *parent_part,
+                                                gpointer user_data);
+
+void           camel_mime_message_foreach_part (CamelMimeMessage *message,
+                                                CamelForeachPartFunc callback,
+                                                gpointer user_data);
 gboolean       camel_mime_message_has_8bit_parts
                                                (CamelMimeMessage *message);
 void           camel_mime_message_set_best_encoding
diff --git a/src/camel/providers/smtp/camel-smtp-transport.c b/src/camel/providers/smtp/camel-smtp-transport.c
index ca3f6a768..b459b14fa 100644
--- a/src/camel/providers/smtp/camel-smtp-transport.c
+++ b/src/camel/providers/smtp/camel-smtp-transport.c
@@ -77,6 +77,7 @@ static GHashTable *   esmtp_get_authtypes     (const guchar *buffer);
 static gboolean                smtp_helo               (CamelSmtpTransport *transport,
                                                 CamelStreamBuffer *istream,
                                                 CamelStream *ostream,
+                                                gboolean ignore_8bitmime,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static gboolean                smtp_mail               (CamelSmtpTransport *transport,
@@ -178,6 +179,7 @@ connect_to_server (CamelService *service,
        GIOStream *tls_stream;
        gchar *respbuf = NULL;
        gboolean success = TRUE;
+       gboolean ignore_8bitmime;
        gchar *host;
 
        if (!CAMEL_SERVICE_CLASS (camel_smtp_transport_parent_class)->
@@ -247,9 +249,11 @@ connect_to_server (CamelService *service,
        } while (*(respbuf+3) == '-'); /* if we got "220-" then loop again */
        g_free (respbuf);
 
+       ignore_8bitmime = host && camel_strstrcase (host, "yahoo.com");
+
        /* Try sending EHLO */
        transport->flags |= CAMEL_SMTP_TRANSPORT_IS_ESMTP;
-       if (!smtp_helo (transport, istream, ostream, cancellable, error)) {
+       if (!smtp_helo (transport, istream, ostream, ignore_8bitmime, cancellable, error)) {
                if (!transport->connected) {
                        success = FALSE;
                        goto exit;
@@ -259,7 +263,7 @@ connect_to_server (CamelService *service,
                g_clear_error (error);
                transport->flags &= ~CAMEL_SMTP_TRANSPORT_IS_ESMTP;
 
-               if (!smtp_helo (transport, istream, ostream, cancellable, error)) {
+               if (!smtp_helo (transport, istream, ostream, ignore_8bitmime, cancellable, error)) {
                        success = FALSE;
                        goto exit;
                }
@@ -331,7 +335,7 @@ connect_to_server (CamelService *service,
 
        /* We are supposed to re-EHLO after a successful STARTTLS to
         * re-fetch any supported extensions. */
-       if (!smtp_helo (transport, istream, ostream, cancellable, error)) {
+       if (!smtp_helo (transport, istream, ostream, ignore_8bitmime, cancellable, error)) {
                success = FALSE;
        }
 
@@ -854,6 +858,25 @@ smtp_transport_query_auth_types_sync (CamelService *service,
        return sasl_types;
 }
 
+static gboolean
+message_has_8bit_or_qp_part_cb (CamelMimeMessage *message,
+                               CamelMimePart *part,
+                               CamelMimePart *parent_part,
+                               gpointer user_data)
+{
+       CamelTransferEncoding encoding;
+       gint *has8bit = user_data;
+
+       /* check this part, and stop as soon as we are done */
+       encoding = camel_mime_part_get_encoding (part);
+
+       *has8bit = encoding == CAMEL_TRANSFER_ENCODING_8BIT ||
+                  encoding == CAMEL_TRANSFER_ENCODING_BINARY ||
+                  encoding == CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE;
+
+       return !(*has8bit);
+}
+
 static gboolean
 smtp_transport_send_to_sync (CamelTransport *transport,
                              CamelMimeMessage *message,
@@ -867,7 +890,7 @@ smtp_transport_send_to_sync (CamelTransport *transport,
        CamelInternetAddress *cia;
        CamelStreamBuffer *istream;
        CamelStream *ostream;
-       gboolean has_8bit_parts;
+       gboolean has_8bit_parts = FALSE;
        const gchar *addr;
        gint i, len;
 
@@ -897,8 +920,8 @@ smtp_transport_send_to_sync (CamelTransport *transport,
 
        camel_operation_push_message (cancellable, _("Sending message"));
 
-       /* find out if the message has 8bit mime parts */
-       has_8bit_parts = camel_mime_message_has_8bit_parts (message);
+       /* find out if the message has 8bit mime parts; quoted-printable are reencoded to 8bit too */
+       camel_mime_message_foreach_part (message, message_has_8bit_or_qp_part_cb, &has_8bit_parts);
 
        /* If the connection needs a ReSET, then do so */
        if (smtp_transport->need_rset &&
@@ -1358,10 +1381,12 @@ static gboolean
 smtp_helo (CamelSmtpTransport *transport,
           CamelStreamBuffer *istream,
           CamelStream *ostream,
+          gboolean ignore_8bitmime,
            GCancellable *cancellable,
            GError **error)
 {
        gchar *name = NULL, *cmdbuf = NULL, *respbuf = NULL;
+       gboolean first_line = TRUE;
        const gchar *token;
        GResolver *resolver;
        GInetAddress *address;
@@ -1446,9 +1471,17 @@ smtp_helo (CamelSmtpTransport *transport,
 
                token = respbuf + 4;
 
+               if (first_line) {
+                       ignore_8bitmime = ignore_8bitmime || camel_strstrcase (token, "yahoo.com") != NULL;
+                       first_line = FALSE;
+               }
+
                if (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP) {
                        if (!g_ascii_strncasecmp (token, "8BITMIME", 8)) {
-                               transport->flags |= CAMEL_SMTP_TRANSPORT_8BITMIME;
+                               if (ignore_8bitmime)
+                                       d (fprintf (stderr, "[SMTP] Ignoring 8BITMIME extension\n"));
+                               else
+                                       transport->flags |= CAMEL_SMTP_TRANSPORT_8BITMIME;
                        } else if (!g_ascii_strncasecmp (token, "ENHANCEDSTATUSCODES", 19)) {
                                transport->flags |= CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES;
                        } else if (!g_ascii_strncasecmp (token, "STARTTLS", 8)) {
@@ -1505,7 +1538,7 @@ smtp_mail (CamelSmtpTransport *transport,
        /* we gotta tell the smtp server who we are. (our email addy) */
        gchar *cmdbuf, *respbuf = NULL;
 
-       if (transport->flags & CAMEL_SMTP_TRANSPORT_8BITMIME && has_8bit_parts)
+       if ((transport->flags & CAMEL_SMTP_TRANSPORT_8BITMIME) && 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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]