From ed3681564ca93350b6c99e393376319a35abefde Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Mon, 2 Oct 2000 23:26:53 +0000 Subject: New convenience function to determine if there are any 8bit mime parts in 2000-10-02 Jeffrey Stedfast * camel-mime-message.c (camel_mime_message_has_8bit_parts): New convenience function to determine if there are any 8bit mime parts in a mime message. (camel_mime_message_encode_8bit_parts): New convenience function to recursively reencode all 8bit mime parts to either quoted-printable or base64 depending on which would be the best encoding for that part. * providers/smtp/camel-smtp-transport.c (smtp_data): If the mime message contains 8bit parts and the server doesn't support 8bit transfers, reencode those parts before proceding with the send. (smtp_mail): If the mime message contains 8bit parts and the server supports the 8BITMIME extension to SMTP, notify the server that we'll be sending it 8bit mime parts. (_send_to): Find out if the message contains 8bit parts. svn path=/trunk/; revision=5677 --- camel/ChangeLog | 18 +++ camel/camel-mime-message.c | 171 +++++++++++++++++++++++++++- camel/camel-mime-message.h | 5 + camel/providers/smtp/camel-smtp-transport.c | 39 +++++-- 4 files changed, 221 insertions(+), 12 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index 36fe81a875..924c5681f1 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,21 @@ +2000-10-02 Jeffrey Stedfast + + * camel-mime-message.c (camel_mime_message_has_8bit_parts): New + convenience function to determine if there are any 8bit mime parts + in a mime message. + (camel_mime_message_encode_8bit_parts): New convenience function + to recursively reencode all 8bit mime parts to either + quoted-printable or base64 depending on which would be the best + encoding for that part. + + * providers/smtp/camel-smtp-transport.c (smtp_data): If the mime + message contains 8bit parts and the server doesn't support 8bit + transfers, reencode those parts before proceding with the send. + (smtp_mail): If the mime message contains 8bit parts and the + server supports the 8BITMIME extension to SMTP, notify the server + that we'll be sending it 8bit mime parts. + (_send_to): Find out if the message contains 8bit parts. + 2000-10-02 Jeffrey Stedfast * providers/smtp/camel-smtp-transport.c (_send_to): Use the diff --git a/camel/camel-mime-message.c b/camel/camel-mime-message.c index b6bd93864e..2cb6fed5a7 100644 --- a/camel/camel-mime-message.c +++ b/camel/camel-mime-message.c @@ -25,11 +25,14 @@ */ #include + #include "camel-mime-message.h" -#include +#include "camel-multipart.h" #include "gmime-content-field.h" +#include "camel-stream-mem.h" #include "string-utils.h" #include "hash-table-utils.h" +#include #define d(x) @@ -548,3 +551,169 @@ remove_header(CamelMedium *medium, const char *header_name) process_header(medium, header_name, NULL); parent_class->parent_class.remove_header (medium, header_name); } + +static gboolean +multipart_has_8bit_parts (CamelMultipart *multipart) +{ + gboolean has_8bit = FALSE; + int i, nparts; + + nparts = camel_multipart_get_number (multipart); + + for (i = 0; i < nparts && !has_8bit; i++) { + GMimeContentField *content; + CamelMimePart *mime_part; + + mime_part = camel_multipart_get_part (multipart, i); + content = camel_mime_part_get_content_type (mime_part); + + if (gmime_content_field_is_type (content, "multipart", "*")) { + CamelDataWrapper *wrapper; + CamelMultipart *mpart; + + wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); + mpart = CAMEL_MULTIPART (wrapper); + + has_8bit = multipart_has_8bit_parts (mpart); + } else { + /* see if this part is 8bit */ + has_8bit = camel_mime_part_get_encoding (mime_part) == CAMEL_MIME_PART_ENCODING_8BIT; + } + } + + return has_8bit; +} + +gboolean +camel_mime_message_has_8bit_parts (CamelMimeMessage *mime_message) +{ + GMimeContentField *content; + gboolean has_8bit = FALSE; + + content = camel_mime_part_get_content_type (CAMEL_MIME_PART (mime_message)); + + if (gmime_content_field_is_type (content, "multipart", "*")) { + CamelDataWrapper *wrapper; + CamelMultipart *multipart; + + wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (CAMEL_MIME_PART (mime_message))); + multipart = CAMEL_MULTIPART (wrapper); + + has_8bit = multipart_has_8bit_parts (multipart); + } else { + /* single-part message so just check this part */ + has_8bit = camel_mime_part_get_encoding (CAMEL_MIME_PART (mime_message)) == CAMEL_MIME_PART_ENCODING_8BIT; + } + + return has_8bit; +} + +static int +best_encoding (const guchar *text) +{ + guchar *ch; + int count = 0; + int total; + + for (ch = (guchar *) text; *ch; ch++) + if (*ch > (guchar) 127) + count++; + + total = (int) (ch - text); + + if ((float) count <= total * 0.17) + return CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE; + else + return CAMEL_MIME_PART_ENCODING_BASE64; +} + +static void +multipart_encode_8bit_parts (CamelMultipart *multipart) +{ + int i, nparts; + + nparts = camel_multipart_get_number (multipart); + + for (i = 0; i < nparts; i++) { + GMimeContentField *content; + CamelMimePart *mime_part; + + mime_part = camel_multipart_get_part (multipart, i); + content = camel_mime_part_get_content_type (mime_part); + + if (gmime_content_field_is_type (content, "multipart", "*")) { + /* ...and the search for Spock continues */ + CamelDataWrapper *wrapper; + CamelMultipart *mpart; + + wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); + mpart = CAMEL_MULTIPART (wrapper); + + multipart_encode_8bit_parts (mpart); + } else { + /* re-encode this if necessary */ + gboolean is_8bit; + + is_8bit = camel_mime_part_get_encoding (mime_part) == CAMEL_MIME_PART_ENCODING_8BIT; + if (is_8bit) { + CamelStream *stream; + GByteArray *array; + guchar *content; + + array = g_byte_array_new (); + stream = camel_stream_mem_new_with_byte_array (array); + camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (mime_part), stream); + g_byte_array_append (array, "", 1); + + content = array->data; + g_byte_array_free (array, FALSE); + + camel_mime_part_set_encoding (mime_part, best_encoding (content)); + g_free (content); + camel_object_unref (CAMEL_OBJECT (stream)); + } + } + } +} + +void +camel_mime_message_encode_8bit_parts (CamelMimeMessage *mime_message) +{ + GMimeContentField *content; + + content = camel_mime_part_get_content_type (CAMEL_MIME_PART (mime_message)); + + if (gmime_content_field_is_type (content, "multipart", "*")) { + /* search for Spock */ + CamelDataWrapper *wrapper; + CamelMultipart *multipart; + + wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (CAMEL_MIME_PART (mime_message))); + multipart = CAMEL_MULTIPART (wrapper); + + multipart_encode_8bit_parts (multipart); + } else { + /* re-encode if we need to */ + gboolean is_8bit; + + is_8bit = camel_mime_part_get_encoding (CAMEL_MIME_PART (mime_message)) == CAMEL_MIME_PART_ENCODING_8BIT; + if (is_8bit) { + /* FIXME: is there a better way of doing this? */ + CamelStream *stream; + GByteArray *array; + guchar *content; + + array = g_byte_array_new (); + stream = camel_stream_mem_new_with_byte_array (array); + camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (CAMEL_MIME_PART (mime_message)), stream); + g_byte_array_append (array, "", 1); + + content = array->data; + g_byte_array_free (array, FALSE); + + camel_mime_part_set_encoding (CAMEL_MIME_PART (mime_message), best_encoding (content)); + g_free (content); + camel_object_unref (CAMEL_OBJECT (stream)); + } + } +} diff --git a/camel/camel-mime-message.h b/camel/camel-mime-message.h index 7e90d7cbcc..33436c6dad 100644 --- a/camel/camel-mime-message.h +++ b/camel/camel-mime-message.h @@ -111,6 +111,11 @@ void camel_mime_message_remove_recipient_name (CamelMimeMessage *mime_message, const CamelInternetAddress *camel_mime_message_get_recipients (CamelMimeMessage *mime_message, const char *type); + +/* utility functions */ +gboolean camel_mime_message_has_8bit_parts (CamelMimeMessage *mime_message); +void camel_mime_message_encode_8bit_parts (CamelMimeMessage *mime_message); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/camel/providers/smtp/camel-smtp-transport.c b/camel/providers/smtp/camel-smtp-transport.c index 02a0198f2f..2aae484c88 100644 --- a/camel/providers/smtp/camel-smtp-transport.c +++ b/camel/providers/smtp/camel-smtp-transport.c @@ -70,9 +70,11 @@ static void free_auth_types (CamelService *service, GList *authtypes); static char *get_name (CamelService *service, gboolean brief); static gboolean smtp_helo (CamelSmtpTransport *transport, CamelException *ex); -static gboolean smtp_mail (CamelSmtpTransport *transport, const char *sender, 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, 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); @@ -350,6 +352,7 @@ _send_to (CamelTransport *transport, CamelMedium *message, CamelInternetAddress *cia; char *recipient, *sender; const char *addr; + gboolean has_8bit_parts; GList *r; sender = g_strdup (camel_mime_message_get_from (CAMEL_MIME_MESSAGE (message))); @@ -371,7 +374,12 @@ _send_to (CamelTransport *transport, CamelMedium *message, return FALSE; } - smtp_mail (smtp_transport, addr, ex); + /* 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, @@ -389,7 +397,10 @@ _send_to (CamelTransport *transport, CamelMedium *message, g_free (recipient); } - if (!smtp_data (smtp_transport, message, ex)) + /* 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)) return FALSE; /* reset the service for our next transfer session */ @@ -507,13 +518,16 @@ smtp_helo (CamelSmtpTransport *transport, CamelException *ex) } static gboolean -smtp_mail (CamelSmtpTransport *transport, const char *sender, CamelException *ex) +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 */ - cmdbuf = g_strdup_printf ("MAIL FROM: <%s>\r\n", sender); + 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)); @@ -591,11 +605,8 @@ smtp_rcpt (CamelSmtpTransport *transport, const char *recipient, CamelException return TRUE; } -/* FIXME: if the message has 8bit mime parts and the server doesn't - support 8bit, we should re-encode those parts to either QP or - Base64 */ static gboolean -smtp_data (CamelSmtpTransport *transport, CamelMedium *message, CamelException *ex) +smtp_data (CamelSmtpTransport *transport, CamelMedium *message, gboolean has_8bit_parts, CamelException *ex) { /* now we can actually send what's important :p */ gchar *cmdbuf, *respbuf = NULL; @@ -603,7 +614,13 @@ smtp_data (CamelSmtpTransport *transport, CamelMedium *message, CamelException * CamelMimeFilter *crlffilter, *lwfilter; gint crlfid, lwid; - /* enclose address in <>'s since some SMTP daemons *require* that */ + + /* if the message contains 8bit mime parts and the server + doesn't support it, encode 8bit parts to the best + encoding. */ + 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)); -- cgit v1.2.3