[evolution-mapi/gnome-2-30] Bug #619741 - Support multipart/appledouble attachments
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-mapi/gnome-2-30] Bug #619741 - Support multipart/appledouble attachments
- Date: Wed, 2 Jun 2010 11:19:04 +0000 (UTC)
commit 8b2cd9154035e499284e24cfb8a9df4f05d002f8
Author: Milan Crha <mcrha redhat com>
Date: Wed Jun 2 13:18:18 2010 +0200
Bug #619741 - Support multipart/appledouble attachments
src/camel/camel-mapi-folder.c | 162 +++++++++++++++++++++++++++++++++++++---
1 files changed, 149 insertions(+), 13 deletions(-)
---
diff --git a/src/camel/camel-mapi-folder.c b/src/camel/camel-mapi-folder.c
index 41b6fd3..a413ab8 100644
--- a/src/camel/camel-mapi-folder.c
+++ b/src/camel/camel-mapi-folder.c
@@ -1704,10 +1704,57 @@ mapi_mime_build_multipart_mixed (CamelMultipart *content, GSList *attachs)
return m_mixed;
}
+static gboolean
+is_apple_attachment (ExchangeMAPIAttachment *attach, guint32 *data_len, guint32 *resource_len)
+{
+ gboolean is_apple = FALSE;
+ ExchangeMAPIStream *enc_stream = exchange_mapi_util_find_stream (attach->streams, PR_ATTACH_ENCODING);
+ guint8 apple_enc_magic[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x14, 0x03, 0x0B, 0x01 };
+
+ if (enc_stream && enc_stream->value && enc_stream->value->len == G_N_ELEMENTS (apple_enc_magic)) {
+ gint idx;
+
+ is_apple = TRUE;
+ for (idx = 0; idx < enc_stream->value->len && is_apple; idx++) {
+ is_apple = apple_enc_magic[idx] == enc_stream->value->data[idx];
+ }
+ } else {
+ const struct Binary_r *bin = exchange_mapi_util_find_SPropVal_array_propval (attach->lpProps, PR_ATTACH_ENCODING);
+ if (bin && bin->cb == G_N_ELEMENTS (apple_enc_magic)) {
+ gint idx;
+
+ is_apple = TRUE;
+ for (idx = 0; idx < bin->cb && is_apple; idx++) {
+ is_apple = apple_enc_magic[idx] == bin->lpb[idx];
+ }
+ }
+ }
+
+ if (is_apple) {
+ /* check boundaries too */
+ ExchangeMAPIStream *data_stream = exchange_mapi_util_find_stream (attach->streams, PR_ATTACH_DATA_BIN);
+
+ is_apple = data_stream && data_stream->value && data_stream->value->len > 128;
+
+ if (is_apple) {
+ const guint8 *bin = data_stream->value->data;
+
+ /* in big-endian format */
+ *data_len = (bin[83] << 24) | (bin[84] << 16) | (bin[85] << 8) | (bin[86]);
+ *resource_len = (bin[87] << 24) | (bin[88] << 16) | (bin[89] << 8) | (bin[90]);
+
+ /* +/- mod 128 (but the first 128 is a header length) */
+ is_apple = 128 + *data_len + *resource_len <= data_stream->value->len && bin[1] < 64;
+ }
+ }
+
+ return is_apple;
+}
+
/*Takes raw attachment streams and converts to MIME Parts. Parts are added to
either inline / non-inline lists.*/
static void
-mapi_mime_classify_attachments (GSList *attachments, GSList **inline_attachs, GSList **noninline)
+mapi_mime_classify_attachments (mapi_id_t fid, GSList *attachments, GSList **inline_attachs, GSList **noninline)
{
for (;attachments != NULL; attachments = attachments->next) {
ExchangeMAPIAttachment *attach = (ExchangeMAPIAttachment *)attachments->data;
@@ -1715,6 +1762,8 @@ mapi_mime_classify_attachments (GSList *attachments, GSList **inline_attachs, GS
const char *filename, *mime_type, *content_id = NULL;
CamelContentType *content_type;
CamelMimePart *part;
+ gboolean is_apple;
+ guint32 apple_data_len = 0, apple_resource_len = 0;
stream = exchange_mapi_util_find_stream (attach->streams, PR_ATTACH_DATA_BIN);
@@ -1722,6 +1771,19 @@ mapi_mime_classify_attachments (GSList *attachments, GSList **inline_attachs, GS
continue;
}
+ is_apple = is_apple_attachment (attach, &apple_data_len, &apple_resource_len);
+
+ /*Content-Type*/
+ mime_type = (const gchar *) exchange_mapi_util_find_SPropVal_array_propval (attach->lpProps, PR_ATTACH_MIME_TAG);
+ if (!mime_type)
+ mime_type = "application/octet-stream";
+
+ if (is_apple) {
+ mime_type = "application/applefile";
+ } else if (strstr (mime_type, "apple") != NULL) {
+ mime_type = "application/octet-stream";
+ }
+
part = camel_mime_part_new ();
filename = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps,
@@ -1730,28 +1792,102 @@ mapi_mime_classify_attachments (GSList *attachments, GSList **inline_attachs, GS
if (!(filename && *filename))
filename = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps,
PR_ATTACH_FILENAME_UNICODE);
- camel_mime_part_set_filename(part, g_strdup(filename));
+ camel_mime_part_set_filename (part, filename);
camel_content_type_set_param (((CamelDataWrapper *) part)->mime_type, "name", filename);
- /*Content-Type*/
- mime_type = (const char *) exchange_mapi_util_find_SPropVal_array_propval (attach->lpProps, PR_ATTACH_MIME_TAG);
- if (!mime_type)
- mime_type = "application/octet-stream";
+ if (is_apple) {
+ ExchangeMAPIStream *strm;
+ CamelMultipart *mp;
+ struct SPropTagArray *array;
+ uint32_t proptag;
+ gchar *apple_filename;
- camel_mime_part_set_content (part, (const char *) stream->value->data, stream->value->len, mime_type);
+ mp = camel_multipart_new ();
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (mp), "multipart/appledouble");
+ camel_multipart_set_boundary (mp, NULL);
+ camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
- content_type = camel_mime_part_get_content_type (part);
- if (content_type && camel_content_type_is (content_type, "text", "*"))
- camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE);
- else
+ strm = NULL;
+ array = exchange_mapi_util_resolve_named_prop (olFolderCalendar, fid, 0x0023, PSETID_Meeting);
+ g_return_if_fail (array != NULL);
+
+ proptag = exchange_mapi_util_create_named_prop (0, fid, "AttachmentMacInfo", PT_BINARY);
+ if (proptag != 0)
+ strm = exchange_mapi_util_find_stream (attach->streams, proptag);
+ if (!strm)
+ strm = exchange_mapi_util_find_stream (attach->streams, PidNameAttachmentMacInfo);
+
+ if (strm && strm->value && strm->value->len > 0) {
+ camel_mime_part_set_content (part, (const gchar *) strm->value->data, strm->value->len, mime_type);
+ } else {
+ /* RFC 1740 */
+ guint8 header[] = {
+ 0x00, 0x05, 0x16, 0x07, /* magic */
+ 0x00, 0x02, 0x00, 0x00, /* version */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* filler */
+ 0x00, 0x01, /* number of entries */
+ 0x00, 0x00, 0x00, 0x02, /* entry ID - resource fork */
+ 0x00, 0x00, 0x00, 0x26, /* entry offset - 38th byte*/
+ 0x00, 0x00, 0x00, 0x00 /* entry length */
+ };
+
+ GByteArray *arr = g_byte_array_sized_new (apple_resource_len + G_N_ELEMENTS (header));
+
+ header[34] = (apple_resource_len >> 24) & 0xFF;
+ header[35] = (apple_resource_len >> 16) & 0xFF;
+ header[36] = (apple_resource_len >> 8) & 0xFF;
+ header[37] = (apple_resource_len ) & 0xFF;
+
+ g_byte_array_append (arr, header, G_N_ELEMENTS (header));
+ g_byte_array_append (arr, stream->value->data + 128 + apple_data_len + (apple_data_len % 128), apple_resource_len);
+
+ camel_mime_part_set_content (part, (const gchar *) arr->data, arr->len, mime_type);
+
+ g_byte_array_free (arr, TRUE);
+ }
+
+ camel_multipart_add_part (mp, part);
+ camel_object_unref (part);
+
+ part = camel_mime_part_new ();
+
+ apple_filename = g_strndup ((gchar *)stream->value->data + 2, stream->value->data[1]);
+ camel_mime_part_set_filename (part, (apple_filename && *apple_filename) ? apple_filename : filename);
+ g_free (apple_filename);
+
+ mime_type = NULL;
+ proptag = exchange_mapi_util_create_named_prop (0, fid, "AttachmentMacContentType", PT_UNICODE);
+ if (proptag != 0)
+ mime_type = exchange_mapi_util_find_SPropVal_array_propval (attach->lpProps, proptag);
+ if (!mime_type)
+ mime_type = exchange_mapi_util_find_SPropVal_array_propval (attach->lpProps, PidNameAttachmentMacContentType);
+ if (!mime_type)
+ mime_type = "application/octet-stream";
+
+ camel_mime_part_set_content (part, (const gchar *) stream->value->data + 128, apple_data_len, mime_type);
camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
+ camel_multipart_add_part (mp, part);
+ camel_object_unref (part);
+
+ part = camel_mime_part_new ();
+ camel_medium_set_content_object (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (mp));
+ camel_object_unref (mp);
+ } else {
+ camel_mime_part_set_content (part, (const gchar *) stream->value->data, stream->value->len, mime_type);
+
+ content_type = camel_mime_part_get_content_type (part);
+ if (content_type && camel_content_type_is (content_type, "text", "*"))
+ camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE);
+ else
+ camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
+ }
/*Content-ID*/
content_id = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps,
PR_ATTACH_CONTENT_ID);
/* TODO : Add disposition */
- if (content_id) {
+ if (content_id && !is_apple) {
camel_mime_part_set_content_id (part, content_id);
*inline_attachs = g_slist_append (*inline_attachs, part);
} else
@@ -1777,7 +1913,7 @@ mapi_folder_item_to_msg( CamelFolder *folder, MapiItem *item, CamelException *ex
mapi_mime_set_recipient_list (msg, item);
mapi_mime_set_msg_headers (folder, msg, item);
- mapi_mime_classify_attachments (attach_list, &inline_attachs, &noninline_attachs);
+ mapi_mime_classify_attachments (item->fid, attach_list, &inline_attachs, &noninline_attachs);
build_alternative = (g_slist_length (item->msg.body_parts) > 1) && inline_attachs;
build_related = !build_alternative && inline_attachs;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]