diff options
author | Jeffrey Stedfast <fejj@ximian.com> | 2003-07-24 01:21:57 +0800 |
---|---|---|
committer | Jeffrey Stedfast <fejj@src.gnome.org> | 2003-07-24 01:21:57 +0800 |
commit | baf3f78660a144ce364d8a27b5d41a7600b7ef21 (patch) | |
tree | aa13c6fea8f8eac840fc7c80397fe9fff3c9854e /camel | |
parent | dbd246a88ee84e6aaf36e78d2ab8a6ba5693a63d (diff) | |
download | gsoc2013-evolution-baf3f78660a144ce364d8a27b5d41a7600b7ef21.tar.gz gsoc2013-evolution-baf3f78660a144ce364d8a27b5d41a7600b7ef21.tar.zst gsoc2013-evolution-baf3f78660a144ce364d8a27b5d41a7600b7ef21.zip |
Revert my previous changes to this function.
2003-07-23 Jeffrey Stedfast <fejj@ximian.com>
* camel-mime-message.c (find_best_encoding): Revert my previous
changes to this function.
* camel-mime-utils.h: Revert previous changes.
* camel-mime-part.h: Revert previous changes.
* camel-mime-part-utils.c: Revert previous changes.
* camel-data-wrapper.c (camel_data_wrapper_init): Revert previous
changes.
(write_to_stream): Revert previous changes.
svn path=/trunk/; revision=21920
Diffstat (limited to 'camel')
-rw-r--r-- | camel/ChangeLog | 15 | ||||
-rw-r--r-- | camel/camel-data-wrapper.c | 36 | ||||
-rw-r--r-- | camel/camel-data-wrapper.h | 4 | ||||
-rw-r--r-- | camel/camel-mime-message.c | 58 | ||||
-rw-r--r-- | camel/camel-mime-part-utils.c | 361 | ||||
-rw-r--r-- | camel/camel-mime-part.c | 127 | ||||
-rw-r--r-- | camel/camel-mime-part.h | 19 | ||||
-rw-r--r-- | camel/camel-mime-utils.h | 12 |
8 files changed, 486 insertions, 146 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index 50d88a7a67..f33507b81f 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,18 @@ +2003-07-23 Jeffrey Stedfast <fejj@ximian.com> + + * camel-mime-message.c (find_best_encoding): Revert my previous + changes to this function. + + * camel-mime-utils.h: Revert previous changes. + + * camel-mime-part.h: Revert previous changes. + + * camel-mime-part-utils.c: Revert previous changes. + + * camel-data-wrapper.c (camel_data_wrapper_init): Revert previous + changes. + (write_to_stream): Revert previous changes. + 2003-07-23 Dan Winship <danw@ximian.com> * camel-block-file.c: #include camel-file-utils.h for camel_read() diff --git a/camel/camel-data-wrapper.c b/camel/camel-data-wrapper.c index ba898e0308..de4d1bf5bf 100644 --- a/camel/camel-data-wrapper.c +++ b/camel/camel-data-wrapper.c @@ -28,9 +28,8 @@ #include <errno.h> #include "camel-data-wrapper.h" +#include "camel-mime-utils.h" #include "camel-stream.h" -#include "camel-stream-filter.h" -#include "camel-mime-filter-basic.h" #include "camel-exception.h" #include "camel-private.h" @@ -41,9 +40,9 @@ static CamelObjectClass *parent_class = NULL; /* Returns the class for a CamelDataWrapper */ #define CDW_CLASS(so) CAMEL_DATA_WRAPPER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -static int construct_from_stream(CamelDataWrapper *, CamelStream *); +static int construct_from_stream (CamelDataWrapper *, CamelStream *); static int write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream); -static void set_mime_type (CamelDataWrapper *data_wrapper, const gchar *mime_type); +static void set_mime_type (CamelDataWrapper *data_wrapper, const char *mime_type); static gchar *get_mime_type (CamelDataWrapper *data_wrapper); static CamelContentType *get_mime_type_field (CamelDataWrapper *data_wrapper); static void set_mime_type_field (CamelDataWrapper *data_wrapper, CamelContentType *mime_type); @@ -73,8 +72,8 @@ camel_data_wrapper_init (gpointer object, gpointer klass) pthread_mutex_init (&camel_data_wrapper->priv->stream_lock, NULL); camel_data_wrapper->mime_type = header_content_type_new ("application", "octet-stream"); - camel_data_wrapper->encoding = CAMEL_MIME_PART_ENCODING_DEFAULT; camel_data_wrapper->offline = FALSE; + camel_data_wrapper->rawtext = TRUE; } static void @@ -115,8 +114,6 @@ camel_data_wrapper_get_type (void) static int write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream) { - CamelMimeFilter *filter; - CamelStream *fstream; int ret; if (data_wrapper->stream == NULL) { @@ -129,30 +126,7 @@ write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream) return -1; } - fstream = (CamelStream *) camel_stream_filter_new_with_stream (data_wrapper->stream); - - switch (data_wrapper->encoding) { - case CAMEL_MIME_PART_ENCODING_BASE64: - filter = (CamelMimeFilter *) camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_BASE64_DEC); - camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter); - camel_object_unref (filter); - break; - case CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE: - filter = (CamelMimeFilter *) camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_QP_DEC); - camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter); - camel_object_unref (filter); - break; - case CAMEL_MIME_PART_ENCODING_UUENCODE: - filter = (CamelMimeFilter *) camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_UU_DEC); - camel_stream_filter_add (CAMEL_STREAM_FILTER (fstream), filter); - camel_object_unref (filter); - break; - default: - break; - } - - ret = camel_stream_write_to_stream (fstream, stream); - camel_object_unref (fstream); + ret = camel_stream_write_to_stream (data_wrapper->stream, stream); CAMEL_DATA_WRAPPER_UNLOCK (data_wrapper, stream_lock); diff --git a/camel/camel-data-wrapper.h b/camel/camel-data-wrapper.h index 03fbd013d3..ca6f7a8452 100644 --- a/camel/camel-data-wrapper.h +++ b/camel/camel-data-wrapper.h @@ -33,7 +33,6 @@ extern "C" { #include <glib.h> #include <camel/camel-object.h> -#include <camel/camel-mime-utils.h> #define CAMEL_DATA_WRAPPER_TYPE (camel_data_wrapper_get_type ()) #define CAMEL_DATA_WRAPPER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_DATA_WRAPPER_TYPE, CamelDataWrapper)) @@ -44,12 +43,11 @@ struct _CamelDataWrapper { CamelObject parent_object; struct _CamelDataWrapperPrivate *priv; - CamelMimePartEncodingType encoding; - CamelContentType *mime_type; CamelStream *stream; unsigned int offline:1; + unsigned int rawtext:1; }; typedef struct { diff --git a/camel/camel-mime-message.c b/camel/camel-mime-message.c index 0d5824ce4c..88ab643720 100644 --- a/camel/camel-mime-message.c +++ b/camel/camel-mime-message.c @@ -673,17 +673,17 @@ camel_mime_message_has_8bit_parts (CamelMimeMessage *msg) static CamelMimePartEncodingType find_best_encoding (CamelMimePart *part, CamelBestencRequired required, CamelBestencEncoding enctype, char **charsetp) { - CamelMimeFilterCharset *charenc = NULL; - CamelMimePartEncodingType encoding; - CamelMimeFilterBestenc *bestenc; - unsigned int flags, callerflags; - CamelDataWrapper *content; - CamelStreamFilter *filter; - const char *charsetin; + const char *charsetin = NULL; char *charset = NULL; CamelStream *null; + CamelStreamFilter *filter; + CamelMimeFilterCharset *charenc = NULL; + CamelMimeFilterBestenc *bestenc; int idb, idc = -1; gboolean istext; + unsigned int flags, callerflags; + CamelMimePartEncodingType encoding; + CamelDataWrapper *content; /* we use all these weird stream things so we can do it with streams, and not have to read the whole lot into memory - although i have a feeling @@ -717,10 +717,12 @@ find_best_encoding (CamelMimePart *part, CamelBestencRequired required, CamelBes null = (CamelStream *)camel_stream_null_new (); filter = camel_stream_filter_new_with_stream (null); - /* if we're looking for the best charset, then we need to convert to UTF-8 */ - if (istext && (required & CAMEL_BESTENC_GET_CHARSET) != 0 - && (charsetin = header_content_type_param (content->mime_type, "charset"))) { - charenc = camel_mime_filter_charset_new_convert (charsetin, "UTF-8"); + /* if we're not looking for the best charset, then use the one we have */ + if (istext && (required & CAMEL_BESTENC_GET_CHARSET) == 0 + && (charsetin = header_content_type_param (part->content_type, "charset"))) { + /* if libunicode doesn't support it, we dont really have utf8 anyway, so + we dont need a converter */ + charenc = camel_mime_filter_charset_new_convert ("UTF-8", charsetin); if (charenc != NULL) idc = camel_stream_filter_add (filter, (CamelMimeFilter *)charenc); charsetin = NULL; @@ -733,29 +735,31 @@ find_best_encoding (CamelMimePart *part, CamelBestencRequired required, CamelBes camel_stream_filter_remove (filter, idb); if (idc != -1) { camel_stream_filter_remove (filter, idc); - camel_object_unref (charenc); + camel_object_unref ((CamelObject *)charenc); charenc = NULL; } - if (istext && (required & CAMEL_BESTENC_GET_CHARSET) != 0) { + if (istext) charsetin = camel_mime_filter_bestenc_get_best_charset (bestenc); - d(printf("best charset = %s\n", charsetin ? charsetin : "(null)")); - charset = g_strdup (charsetin); - - charsetin = header_content_type_param (content->mime_type, "charset"); - } else { - charset = NULL; - } + + d(printf("charsetin = %s\n", charsetin ? charsetin : "(null)")); /* if we have US-ASCII, or we're not doing text, we dont need to bother with the rest */ - if (istext && charsetin && charset && (required & CAMEL_BESTENC_GET_CHARSET) != 0) { + if (charsetin != NULL && (required & CAMEL_BESTENC_GET_CHARSET) != 0) { + charset = g_strdup (charsetin); + d(printf("have charset, trying conversion/etc\n")); - /* now that 'bestenc' has told us what the best encoding is, we can use that to create + /* now the 'bestenc' can has told us what the best encoding is, we can use that to create a charset conversion filter as well, and then re-add the bestenc to filter the result to find the best encoding to use as well */ - charenc = camel_mime_filter_charset_new_convert (charsetin, charset); + charenc = camel_mime_filter_charset_new_convert ("UTF-8", charset); + + /* eek, libunicode doesn't undertand this charset anyway, then the 'utf8' we + thought we had is really the native format, in which case, we just treat + it as binary data (and take the result we have so far) */ + if (charenc != NULL) { /* otherwise, try another pass, converting to the real charset */ @@ -769,15 +773,15 @@ find_best_encoding (CamelMimePart *part, CamelBestencRequired required, CamelBes /* and write it to the new stream */ camel_data_wrapper_write_to_stream (content, (CamelStream *)filter); - camel_object_unref (charenc); + camel_object_unref ((CamelObject *)charenc); } } encoding = camel_mime_filter_bestenc_get_best_encoding (bestenc, enctype); - camel_object_unref (filter); - camel_object_unref (bestenc); - camel_object_unref (null); + camel_object_unref ((CamelObject *)filter); + camel_object_unref ((CamelObject *)bestenc); + camel_object_unref ((CamelObject *)null); d(printf("done, best encoding = %d\n", encoding)); diff --git a/camel/camel-mime-part-utils.c b/camel/camel-mime-part-utils.c index af4d7c1161..800f23372e 100644 --- a/camel/camel-mime-part-utils.c +++ b/camel/camel-mime-part-utils.c @@ -5,7 +5,7 @@ * Michael Zucchi <notzed@ximian.com> * Jeffrey Stedfast <fejj@ximian.com> * - * Copyright 1999-2003 Ximian, Inc. (www.ximian.com) + * Copyright 1999, 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 @@ -34,6 +34,7 @@ #include <gal/util/e-iconv.h> +#include "camel-string-utils.h" #include "camel-charset-map.h" #include "camel-mime-part-utils.h" #include "camel-mime-message.h" @@ -53,21 +54,278 @@ #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x)) #include <stdio.h>*/ +/* example: <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> */ + +static const char * +check_html_charset(char *buffer, int length) +{ + CamelHTMLParser *hp; + const char *charset = NULL; + camel_html_parser_t state; + struct _header_content_type *ct; + + /* if we need to first base64/qp decode, do this here, sigh */ + hp = camel_html_parser_new(); + camel_html_parser_set_data(hp, buffer, length, TRUE); + + do { + const char *data; + int len; + const char *val; + + state = camel_html_parser_step(hp, &data, &len); + + /* example: <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> */ + + switch(state) { + case CAMEL_HTML_PARSER_ELEMENT: + val = camel_html_parser_tag(hp); + d(printf("Got tag: %s\n", val)); + if (strcasecmp(val, "meta") == 0 + && (val = camel_html_parser_attr(hp, "http-equiv")) + && strcasecmp(val, "content-type") == 0 + && (val = camel_html_parser_attr(hp, "content")) + && (ct = header_content_type_decode(val))) { + charset = header_content_type_param(ct, "charset"); + charset = e_iconv_charset_name (charset); + header_content_type_unref(ct); + } + break; + default: + /* ignore everything else */ + break; + } + } while (charset == NULL && state != CAMEL_HTML_PARSER_EOF); + + camel_object_unref (hp); + + return charset; +} + +static GByteArray * +convert_buffer (GByteArray *in, const char *to, const char *from) +{ + size_t inleft, outleft, outlen, converted = 0; + GByteArray *out = NULL; + const char *inbuf; + char *outbuf; + iconv_t cd; + + if (in->len == 0) + return g_byte_array_new(); + + d(printf("converting buffer from %s to %s:\n", from, to)); + d(fwrite(in->data, 1, (int)in->len, stdout)); + d(printf("\n")); + + cd = e_iconv_open(to, from); + if (cd == (iconv_t) -1) { + g_warning ("Cannot convert from '%s' to '%s': %s", from, to, strerror (errno)); + return NULL; + } + + outlen = in->len * 2 + 16; + out = g_byte_array_new (); + g_byte_array_set_size (out, outlen); + + inbuf = in->data; + inleft = in->len; + + do { + outbuf = out->data + converted; + outleft = outlen - converted; + + converted = e_iconv (cd, &inbuf, &inleft, &outbuf, &outleft); + if (converted == (size_t) -1) { + if (errno != E2BIG && errno != EINVAL) + goto fail; + } + + /* + * E2BIG There is not sufficient room at *outbuf. + * + * We just need to grow our outbuffer and try again. + */ + + converted = outbuf - (char *)out->data; + if (errno == E2BIG) { + outlen += inleft * 2 + 16; + out = g_byte_array_set_size (out, outlen); + outbuf = out->data + converted; + } + + } while (errno == E2BIG && inleft > 0); + + /* + * EINVAL An incomplete multibyte sequence has been encoun + * tered in the input. + * + * We'll just have to ignore it... + */ + + /* flush the iconv conversion */ + e_iconv (cd, NULL, NULL, &outbuf, &outleft); + + /* now set the true length on the GByteArray */ + converted = outbuf - (char *)out->data; + g_byte_array_set_size (out, converted); + + d(printf("converted data:\n")); + d(fwrite(out->data, 1, (int)out->len, stdout)); + d(printf("\n")); + + e_iconv_close (cd); + + return out; + + fail: + g_warning ("Cannot convert from '%s' to '%s': %s", from, to, strerror (errno)); + + g_byte_array_free (out, TRUE); + + e_iconv_close (cd); + + return NULL; +} + +/* We don't really use the charset argument except for debugging... */ +static gboolean +broken_windows_charset (GByteArray *buffer, const char *charset) +{ + register unsigned char *inptr; + unsigned char *inend; + + inptr = buffer->data; + inend = inptr + buffer->len; + + while (inptr < inend) { + register unsigned char c = *inptr++; + + if (c >= 128 && c <= 159) { + g_warning ("Encountered Windows charset parading as %s", charset); + return TRUE; + } + } + + return FALSE; +} + +static gboolean +is_7bit (GByteArray *buffer) +{ + register unsigned int i; + + for (i = 0; i < buffer->len; i++) + if (buffer->data[i] > 127) + return FALSE; + + return TRUE; +} + +static const char *iso_charsets[] = { + "us-ascii", + "iso-8859-1", + "iso-8859-2", + "iso-8859-3", + "iso-8859-4", + "iso-8859-5", + "iso-8859-6", + "iso-8859-7", + "iso-8859-8", + "iso-8859-9", + "iso-8859-10", + "iso-8859-11", + "iso-8859-12", + "iso-8859-13", + "iso-8859-14", + "iso-8859-15", + "iso-8859-16" +}; + +#define NUM_ISO_CHARSETS (sizeof (iso_charsets) / sizeof (iso_charsets[0])) + +static const char * +canon_charset_name (const char *charset) +{ + const char *ptr; + char *endptr; + int iso; + + if (strncasecmp (charset, "iso", 3) != 0) + return charset; + + ptr = charset + 3; + if (*ptr == '-' || *ptr == '_') + ptr++; + + /* if it's not an iso-8859-# charset, we don't care about it */ + if (strncmp (ptr, "8859", 4) != 0) + return charset; + + ptr += 4; + if (*ptr == '-' || *ptr == '_') + ptr++; + + iso = strtoul (ptr, &endptr, 10); + if (endptr == ptr || *endptr != '\0') + return charset; + + if (iso >= NUM_ISO_CHARSETS) + return charset; + + return iso_charsets[iso]; +} + /* simple data wrapper */ static void simple_data_wrapper_construct_from_parser (CamelDataWrapper *dw, CamelMimeParser *mp) { + CamelMimeFilter *fdec = NULL, *fcrlf = NULL; + CamelMimeFilterBasicType enctype = 0; + size_t len; + int decid = -1, crlfid = -1; struct _header_content_type *ct; const char *charset = NULL; char *encoding, *buf; GByteArray *buffer; CamelStream *mem; - size_t len; d(printf ("simple_data_wrapper_construct_from_parser()\n")); /* first, work out conversion, if any, required, we dont care about what we dont know about */ encoding = header_content_encoding_decode (camel_mime_parser_header (mp, "Content-Transfer-Encoding", NULL)); + if (encoding) { + if (!strcasecmp (encoding, "base64")) { + d(printf("Adding base64 decoder ...\n")); + enctype = CAMEL_MIME_FILTER_BASIC_BASE64_DEC; + } else if (!strcasecmp (encoding, "quoted-printable")) { + d(printf("Adding quoted-printable decoder ...\n")); + enctype = CAMEL_MIME_FILTER_BASIC_QP_DEC; + } else if (!strcasecmp (encoding, "x-uuencode")) { + d(printf("Adding uudecoder ...\n")); + enctype = CAMEL_MIME_FILTER_BASIC_UU_DEC; + } + g_free (encoding); + + if (enctype != 0) { + fdec = (CamelMimeFilter *)camel_mime_filter_basic_new_type(enctype); + decid = camel_mime_parser_filter_add (mp, fdec); + } + } + + /* If we're doing text, we also need to do CRLF->LF and may have to convert it to UTF8 as well. */ + ct = camel_mime_parser_content_type (mp); + if (header_content_type_is (ct, "text", "*")) { + charset = header_content_type_param (ct, "charset"); + charset = e_iconv_charset_name (charset); + + if (fdec) { + d(printf ("Adding CRLF conversion filter\n")); + fcrlf = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_DECODE, + CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); + crlfid = camel_mime_parser_filter_add (mp, fcrlf); + } + } /* read in the entire content */ buffer = g_byte_array_new (); @@ -76,22 +334,86 @@ simple_data_wrapper_construct_from_parser (CamelDataWrapper *dw, CamelMimeParser g_byte_array_append (buffer, buf, len); } - d(printf("message part kept in memory!\n")); + /* check for broken Outlook/Web mailers that like to send html marked as text/plain */ + if (header_content_type_is (ct, "text", "plain")) { + register const unsigned char *inptr; + const unsigned char *inend; + + inptr = buffer->data; + inend = inptr + buffer->len; + + while (inptr < inend && isspace ((int) *inptr)) + inptr++; + + if (((inend-inptr) > 5 && g_ascii_strncasecmp(inptr, "<html", 5) == 0) + || ((inend-inptr) > 9 && g_ascii_strncasecmp(inptr, "<!doctype", 9) == 0)) { + /* re-tag as text/html */ + g_free (ct->subtype); + ct->subtype = g_strdup ("html"); + } + } - mem = camel_stream_mem_new_with_byte_array (buffer); - camel_data_wrapper_construct_from_stream (dw, mem); - camel_object_unref (mem); + /* Possible Lame Mailer Alert... check the META tags for a charset */ + if (!charset && header_content_type_is (ct, "text", "html")) { + if ((charset = check_html_charset (buffer->data, buffer->len))) + header_content_type_set_param (ct, "charset", charset); + } - if (encoding) { - if (!strcasecmp (encoding, "base64")) { - dw->encoding = CAMEL_MIME_PART_ENCODING_BASE64; - } else if (!strcasecmp (encoding, "quoted-printable")) { - dw->encoding = CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE; - } else if (!strcasecmp (encoding, "x-uuencode")) { - dw->encoding = CAMEL_MIME_PART_ENCODING_UUENCODE; + /* if we need to do charset conversion, see if we can/it works/etc */ + if (charset && !(strcasecmp (charset, "us-ascii") == 0 + || strcasecmp (charset, "utf-8") == 0 + || strncasecmp (charset, "x-", 2) == 0)) { + GByteArray *out; + + /* You often see Microsoft Windows users announcing their texts + * as being in ISO-8859-1 even when in fact they contain funny + * characters from the Windows-CP1252 superset. + */ + charset = canon_charset_name (charset); + if (!strncasecmp (charset, "iso-8859", 8)) { + /* check for Windows-specific chars... */ + if (broken_windows_charset (buffer, charset)) + charset = camel_charset_iso_to_windows (charset); + } + + out = convert_buffer (buffer, "UTF-8", charset); + if (out) { + /* converted ok, use this data instead */ + g_byte_array_free(buffer, TRUE); + dw->rawtext = FALSE; + buffer = out; + } else { + /* else failed to convert, leave as raw? */ + g_warning("Storing text as raw, unknown charset '%s' or invalid format", charset); + dw->rawtext = TRUE; + } + } else if (header_content_type_is (ct, "text", "*")) { + if (charset == NULL || !strcasecmp (charset, "us-ascii")) { + /* check that it's 7bit */ + dw->rawtext = !is_7bit (buffer); + } else if (!strncasecmp (charset, "x-", 2)) { + /* we're not even going to bother trying to convert, so set the + rawtext bit to TRUE and let the mailer deal with it. */ + dw->rawtext = TRUE; + } else if (!strcasecmp (charset, "utf-8") && buffer->len) { + /* check that it is valid utf8 */ + dw->rawtext = !g_utf8_validate (buffer->data, buffer->len, NULL); } - g_free (encoding); } + + d(printf("message part kept in memory!\n")); + + mem = camel_stream_mem_new_with_byte_array(buffer); + camel_data_wrapper_construct_from_stream(dw, mem); + camel_object_unref((CamelObject *)mem); + + camel_mime_parser_filter_remove(mp, decid); + camel_mime_parser_filter_remove(mp, crlfid); + + if (fdec) + camel_object_unref((CamelObject *)fdec); + if (fcrlf) + camel_object_unref((CamelObject *)fcrlf); } /* This replaces the data wrapper repository ... and/or could be replaced by it? */ @@ -102,7 +424,7 @@ camel_mime_part_construct_content_from_parser (CamelMimePart *dw, CamelMimeParse CamelContentType *ct; ct = camel_mime_parser_content_type (mp); - + switch (camel_mime_parser_state (mp)) { case HSCAN_HEADER: d(printf("Creating body part\n")); @@ -139,6 +461,15 @@ camel_mime_part_construct_content_from_parser (CamelMimePart *dw, CamelMimeParse /* would you believe you have to set this BEFORE you set the content object??? oh my god !!!! */ camel_data_wrapper_set_mime_type_field (content, camel_mime_part_get_content_type (dw)); camel_medium_set_content_object ((CamelMedium *)dw, content); + + /* Note: we don't set ct as the content-object's mime-type above because + * camel_medium_set_content_object() may re-write the Content-Type header + * (see CamelMimePart::set_content_object) if we did that (which is a Bad Thing). + * However, if we set it *afterward*, we can still use any special auto-detections + * that we found in simple_data_wrapper_construct_from_parser(). This is important + * later when we go to render the MIME parts in mail-format.c */ + camel_data_wrapper_set_mime_type_field (content, ct); + camel_object_unref (content); } } diff --git a/camel/camel-mime-part.c b/camel/camel-mime-part.c index e6ab427f49..343248715b 100644 --- a/camel/camel-mime-part.c +++ b/camel/camel-mime-part.c @@ -75,7 +75,7 @@ static CamelMediumClass *parent_class=NULL; static int write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream); static int construct_from_stream (CamelDataWrapper *dw, CamelStream *s); -/* from CamelMedium */ +/* from CamelMedia */ static void add_header (CamelMedium *medium, const char *header_name, const void *header_value); static void set_header (CamelMedium *medium, const char *header_name, const void *header_value); static void remove_header (CamelMedium *medium, const char *header_name); @@ -626,6 +626,7 @@ write_to_stream(CamelDataWrapper *data_wrapper, CamelStream *stream) { CamelMimePart *mp = CAMEL_MIME_PART(data_wrapper); CamelMedium *medium = CAMEL_MEDIUM(data_wrapper); + CamelStream *ostream = stream; CamelDataWrapper *content; int total = 0; int count; @@ -666,75 +667,89 @@ write_to_stream(CamelDataWrapper *data_wrapper, CamelStream *stream) return -1; total += count; - content = camel_medium_get_content_object (medium); + content = camel_medium_get_content_object(medium); if (content) { - if (mp->encoding != content->encoding) { - /* we need to (re)encode the content stream */ - CamelStream *filter_stream = NULL; - CamelMimeFilter *filter = NULL; - const char *filename; - - filter_stream = (CamelStream *) camel_stream_filter_new_with_stream (stream); - switch (mp->encoding) { - case CAMEL_MIME_PART_ENCODING_BASE64: - filter = (CamelMimeFilter *) camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_BASE64_ENC); - camel_stream_filter_add (CAMEL_STREAM_FILTER (filter_stream), filter); - camel_object_unref (filter); - break; - case CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE: - filter = (CamelMimeFilter *) camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_QP_ENC); - camel_stream_filter_add (CAMEL_STREAM_FILTER (filter_stream), filter); - camel_object_unref (filter); - break; - case CAMEL_MIME_PART_ENCODING_UUENCODE: - filename = camel_mime_part_get_filename (mp); - count = camel_stream_printf (stream, "begin 0644 %s\n", filename ? filename : "unknown"); - if (count == -1) { - camel_object_unref (filter_stream); - return -1; - } - - total += count; - - filter = (CamelMimeFilter *) camel_mime_filter_basic_new_type (CAMEL_MIME_FILTER_BASIC_UU_ENC); - camel_stream_filter_add (CAMEL_STREAM_FILTER (filter_stream), filter); - camel_object_unref (filter); - break; - default: - break; - } - - count = camel_data_wrapper_write_to_stream (content, filter_stream); - camel_stream_flush (filter_stream); - camel_object_unref (filter_stream); - + /* I dont really like this here, but i dont know where else it might go ... */ +#define CAN_THIS_GO_ELSEWHERE +#ifdef CAN_THIS_GO_ELSEWHERE + CamelMimeFilter *filter = NULL; + CamelStreamFilter *filter_stream = NULL; + CamelMimeFilter *charenc = NULL; + const char *filename; + const char *charset; + + switch (mp->encoding) { + case CAMEL_MIME_PART_ENCODING_BASE64: + filter = (CamelMimeFilter *)camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_BASE64_ENC); + break; + case CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE: + filter = (CamelMimeFilter *)camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_QP_ENC); + break; + case CAMEL_MIME_PART_ENCODING_UUENCODE: + filename = camel_mime_part_get_filename (mp); + count = camel_stream_printf (ostream, "begin 644 %s\n", filename ? filename : "untitled"); if (count == -1) return -1; - total += count; + filter = (CamelMimeFilter *)camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_UU_ENC); + break; + default: + break; + } + + if (!content->rawtext && header_content_type_is(mp->content_type, "text", "*")) { + charset = header_content_type_param(mp->content_type, "charset"); + if (charset && !(!strcasecmp(charset, "us-ascii") || !strcasecmp(charset, "utf-8"))) { + charenc = (CamelMimeFilter *)camel_mime_filter_charset_new_convert("UTF-8", charset); + } + } + + if (filter || charenc) { + filter_stream = camel_stream_filter_new_with_stream(stream); - if (mp->encoding == CAMEL_MIME_PART_ENCODING_UUENCODE) { - /* FIXME: get rid of this special-case x-uuencode crap */ - count = camel_stream_write (stream, "end\n", 4); - if (count == -1) - return -1; + /* if we have a character encoder, add that always */ + if (charenc) { + camel_stream_filter_add(filter_stream, charenc); + camel_object_unref((CamelObject *)charenc); + } + + /* we only re-do crlf on encoded blocks */ + if (filter && header_content_type_is(mp->content_type, "text", "*")) { + CamelMimeFilter *crlf = camel_mime_filter_crlf_new(CAMEL_MIME_FILTER_CRLF_ENCODE, + CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); - total += count; + camel_stream_filter_add(filter_stream, crlf); + camel_object_unref((CamelObject *)crlf); } - } else { - /* write the content out raw... */ - if (camel_stream_reset (content->stream) == -1) - return -1; - count = camel_stream_write_to_stream (content->stream, stream); + if (filter) { + camel_stream_filter_add(filter_stream, filter); + camel_object_unref((CamelObject *)filter); + } + stream = (CamelStream *)filter_stream; + } + +#endif + + count = camel_data_wrapper_write_to_stream(content, stream); + + if (filter_stream) { + camel_stream_flush((CamelStream *)filter_stream); + camel_object_unref((CamelObject *)filter_stream); + } + if (count == -1) + return -1; + total += count; + + if (mp->encoding == CAMEL_MIME_PART_ENCODING_UUENCODE) { + count = camel_stream_write (ostream, "end\n", 4); if (count == -1) return -1; - total += count; } } else { - g_warning ("No content for medium, nothing to write"); + g_warning("No content for medium, nothing to write"); } return total; diff --git a/camel/camel-mime-part.h b/camel/camel-mime-part.h index d53b660f50..c925643f24 100644 --- a/camel/camel-mime-part.h +++ b/camel/camel-mime-part.h @@ -31,7 +31,7 @@ #ifdef __cplusplus extern "C" { #pragma } -#endif /* __cplusplus */ +#endif /* __cplusplus }*/ #include <camel/camel-medium.h> #include <camel/camel-mime-utils.h> @@ -42,8 +42,23 @@ extern "C" { #define CAMEL_MIME_PART_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MIME_PART_TYPE, CamelMimePartClass)) #define CAMEL_IS_MIME_PART(o) (CAMEL_CHECK_TYPE((o), CAMEL_MIME_PART_TYPE)) +/* note, if you change this, make sure you change the 'encodings' array in camel-mime-part.c */ +enum _CamelMimePartEncodingType { + CAMEL_MIME_PART_ENCODING_DEFAULT, + CAMEL_MIME_PART_ENCODING_7BIT, + CAMEL_MIME_PART_ENCODING_8BIT, + CAMEL_MIME_PART_ENCODING_BASE64, + CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE, + CAMEL_MIME_PART_ENCODING_BINARY, + CAMEL_MIME_PART_ENCODING_UUENCODE, + CAMEL_MIME_PART_NUM_ENCODINGS +}; +typedef enum _CamelMimePartEncodingType CamelMimePartEncodingType; + + /* Do not change these values directly, you would regret it one day */ -struct _CamelMimePart { +struct _CamelMimePart +{ CamelMedium parent_object; CamelContentType *content_type; diff --git a/camel/camel-mime-utils.h b/camel/camel-mime-utils.h index b58bcbea72..b949ffcf98 100644 --- a/camel/camel-mime-utils.h +++ b/camel/camel-mime-utils.h @@ -42,18 +42,6 @@ extern "C" { #define CAMEL_UUDECODE_STATE_END (1 << 17) #define CAMEL_UUDECODE_STATE_MASK (CAMEL_UUDECODE_STATE_BEGIN | CAMEL_UUDECODE_STATE_END) -/* note, if you change this, make sure you change the 'encodings' array in camel-mime-part.c */ -typedef enum _CamelMimePartEncodingType { - CAMEL_MIME_PART_ENCODING_DEFAULT, - CAMEL_MIME_PART_ENCODING_7BIT, - CAMEL_MIME_PART_ENCODING_8BIT, - CAMEL_MIME_PART_ENCODING_BASE64, - CAMEL_MIME_PART_ENCODING_QUOTEDPRINTABLE, - CAMEL_MIME_PART_ENCODING_BINARY, - CAMEL_MIME_PART_ENCODING_UUENCODE, - CAMEL_MIME_PART_NUM_ENCODINGS -} CamelMimePartEncodingType; - /* a list of references for this message */ struct _header_references { struct _header_references *next; |