[evolution-mapi] Use fast-transfer for message fetching in camel



commit 6f0c329838389f562a8038b4c686a14b82c7bc7b
Author: Milan Crha <mcrha redhat com>
Date:   Thu Nov 10 13:01:45 2011 +0100

    Use fast-transfer for message fetching in camel

 src/camel/camel-mapi-folder.c                |  364 ++++++++-----
 src/camel/camel-mapi-store.c                 |   71 +--
 src/libexchangemapi/e-mapi-cal-recur-utils.c |    8 +-
 src/libexchangemapi/e-mapi-cal-recur-utils.h |    2 +-
 src/libexchangemapi/e-mapi-cal-tz-utils.c    |    5 +-
 src/libexchangemapi/e-mapi-cal-tz-utils.h    |    2 +-
 src/libexchangemapi/e-mapi-cal-utils.c       |  630 ++++++++++++++++++++-
 src/libexchangemapi/e-mapi-cal-utils.h       |   10 +-
 src/libexchangemapi/e-mapi-connection.c      |  289 ++++++++++-
 src/libexchangemapi/e-mapi-connection.h      |   10 +-
 src/libexchangemapi/e-mapi-debug.c           |    8 +-
 src/libexchangemapi/e-mapi-fast-transfer.c   |   40 ++-
 src/libexchangemapi/e-mapi-fast-transfer.h   |    9 +
 src/libexchangemapi/e-mapi-mail-utils.c      |  774 ++++++++++++++++++++++++++
 src/libexchangemapi/e-mapi-mail-utils.h      |   28 +-
 src/libexchangemapi/e-mapi-utils.c           |   63 +++
 src/libexchangemapi/e-mapi-utils.h           |   18 +-
 17 files changed, 2106 insertions(+), 225 deletions(-)
---
diff --git a/src/camel/camel-mapi-folder.c b/src/camel/camel-mapi-folder.c
index 4c3221b..46fd125 100644
--- a/src/camel/camel-mapi-folder.c
+++ b/src/camel/camel-mapi-folder.c
@@ -377,6 +377,48 @@ mapi_utils_do_flags_diff (flags_diff_t *diff, guint32 old, guint32 _new)
 	diff->bits = _new & diff->changed;
 }
 
+static void
+add_message_to_cache (CamelMapiFolder *mapi_folder, const gchar *uid, CamelMimeMessage **msg, GCancellable *cancellable)
+{
+	CamelFolder *folder;
+	CamelStream *cache_stream;
+
+	g_return_if_fail (mapi_folder != NULL);
+	g_return_if_fail (msg != NULL);
+	g_return_if_fail (*msg != NULL);
+
+	folder = CAMEL_FOLDER (mapi_folder);
+	g_return_if_fail (folder != NULL);
+
+	camel_folder_summary_lock (folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+	if ((cache_stream = camel_data_cache_add (mapi_folder->cache, "cache", uid, NULL))) {
+		if (camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) (*msg), cache_stream, cancellable, NULL) == -1
+		    || camel_stream_flush (cache_stream, cancellable, NULL) == -1) {
+			camel_data_cache_remove (mapi_folder->cache, "cache", uid, NULL);
+		} else {
+			CamelMimeMessage *msg2;
+
+			/* workaround to get message back from cache, as that one is properly
+			   encoded with attachments and so on. Not sure what's going wrong when
+			   composing message in memory, but when they are read from the cache
+			   they appear properly in the UI. */
+			msg2 = camel_mime_message_new ();
+			g_seekable_seek (G_SEEKABLE (cache_stream), 0, G_SEEK_SET, NULL, NULL);
+			if (!camel_data_wrapper_construct_from_stream_sync (CAMEL_DATA_WRAPPER (msg2), cache_stream, cancellable, NULL)) {
+				g_object_unref (msg2);
+			} else {
+				g_object_unref (*msg);
+				*msg = msg2;
+			}
+		}
+
+		g_object_unref (cache_stream);
+	}
+
+	camel_folder_summary_unlock (folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+}
+
 static gboolean
 build_last_modify_restriction (EMapiConnection *conn,
 		               mapi_id_t fid,
@@ -518,6 +560,114 @@ remove_removed_uids_cb (gpointer uid_str, gpointer value, gpointer user_data)
 }
 
 static gboolean
+gather_object_offline_cb (EMapiConnection *conn,
+			  TALLOC_CTX *mem_ctx,
+			  /* const */ EMapiObject *object,
+			  guint32 obj_index,
+			  guint32 obj_total,
+			  gpointer user_data,
+			  GCancellable *cancellable,
+			  GError **perror)
+{
+	struct GatherObjectSummaryData *gos = user_data;
+	CamelMimeMessage *msg;
+
+	g_return_val_if_fail (gos != NULL, FALSE);
+	g_return_val_if_fail (gos->folder != NULL, FALSE);
+	g_return_val_if_fail (object != NULL, FALSE);
+
+	msg = e_mapi_mail_utils_object_to_message (conn, object);
+	if (msg) {
+		gchar *uid_str;
+		const mapi_id_t *pmid;
+		const uint32_t *pmsg_flags;
+		const struct FILETIME *last_modified;
+		uint32_t msg_flags;
+		CamelMessageInfo *info;
+		gboolean is_new;
+
+		pmid = e_mapi_util_find_array_propval (&object->properties, PR_MID);
+		pmsg_flags = e_mapi_util_find_array_propval (&object->properties, PR_MESSAGE_FLAGS);
+		last_modified = e_mapi_util_find_array_propval (&object->properties, PR_LAST_MODIFICATION_TIME);
+
+		if (!pmid) {
+			g_debug ("%s: Received message [%d/%d] without PR_MID", G_STRFUNC, obj_index, obj_total);
+			e_mapi_debug_dump_object (object, TRUE, 3);
+			return TRUE;
+		}
+
+		if (!last_modified) {
+			g_debug ("%s: Received message [%d/%d] without PR_LAST_MODIFICATION_TIME", G_STRFUNC, obj_index, obj_total);
+			e_mapi_debug_dump_object (object, TRUE, 3);
+		}
+
+		uid_str = e_mapi_util_mapi_id_to_string (*pmid);
+		if (!uid_str)
+			return FALSE;
+
+		msg_flags = pmsg_flags ? *pmsg_flags : 0;
+
+		is_new = !camel_folder_summary_check_uid (gos->folder->summary, uid_str);
+		if (!is_new)
+			camel_folder_summary_remove_uid (gos->folder->summary, uid_str);
+
+		info = camel_folder_summary_info_new_from_message (gos->folder->summary, msg, NULL);
+		if (info) {
+			CamelMapiMessageInfo *minfo = (CamelMapiMessageInfo *) info;
+			guint32 flags = 0, mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_ATTACHMENTS;
+
+			minfo->info.uid = camel_pstring_strdup (uid_str);
+
+			if (last_modified) {
+				minfo->last_modified = e_mapi_util_filetime_to_time_t (last_modified);
+			} else {
+				minfo->last_modified = 0;
+			}
+
+			if ((msg_flags & MSGFLAG_READ) != 0)
+				flags |= CAMEL_MESSAGE_SEEN;
+			if ((msg_flags & MSGFLAG_HASATTACH) != 0)
+				flags |= CAMEL_MESSAGE_ATTACHMENTS;
+
+			if ((camel_message_info_flags (info) & mask) != flags) {
+				if (is_new)
+					minfo->info.flags = flags;
+				else
+					camel_message_info_set_flags (info, mask, flags);
+				minfo->server_flags = camel_message_info_flags (info);
+				minfo->info.dirty = TRUE;
+			}
+
+			if (is_new) {
+				camel_folder_summary_add (gos->folder->summary, info);
+				camel_folder_change_info_add_uid (gos->changes, camel_message_info_uid (info));
+				camel_folder_change_info_recent_uid (gos->changes, camel_message_info_uid (info));
+
+				camel_message_info_ref (info);
+			} else {
+				camel_folder_change_info_change_uid (gos->changes, camel_message_info_uid (info));
+			}
+
+			add_message_to_cache (CAMEL_MAPI_FOLDER (gos->folder), uid_str, &msg, cancellable);
+
+			camel_message_info_free (info);
+		} else {
+			g_debug ("%s: Failed to create message info from message", G_STRFUNC);
+		}
+
+		g_free (uid_str);
+		g_object_unref (msg);
+	} else {
+		g_debug ("%s: Failed to create message from object", G_STRFUNC);
+	}
+
+	if (obj_total > 0)
+		camel_operation_progress (cancellable, obj_index * 100 / obj_total);
+
+	return TRUE;
+}
+
+static gboolean
 gather_object_summary_cb (EMapiConnection *conn,
 			  TALLOC_CTX *mem_ctx,
 			  /* const */ EMapiObject *object,
@@ -594,11 +744,10 @@ gather_object_summary_cb (EMapiConnection *conn,
 		if (!info) {
 			CamelMapiMessageInfo *minfo;
 			const gchar *subject, *message_id, *references, *in_reply_to, *display_to, *display_cc;
-			const gchar *from_addr_type, *from_name, *from_email;
 			const struct FILETIME *delivery_time;
 			const uint32_t *msg_size;
-			EMapiRecipient *recipient;
-			gchar *to = NULL, *cc = NULL, *formatted_addr;
+			gchar *formatted_addr, *from_name, *from_email;
+			CamelAddress *to_addr, *cc_addr, *bcc_addr;
 
 			subject = e_mapi_util_find_array_propval (&object->properties, PR_SUBJECT_UNICODE);
 			delivery_time = e_mapi_util_find_array_propval (&object->properties, PR_MESSAGE_DELIVERY_TIME);
@@ -608,9 +757,6 @@ gather_object_summary_cb (EMapiConnection *conn,
 			in_reply_to = e_mapi_util_find_array_propval (&object->properties, PR_IN_REPLY_TO_ID);
 			display_to = e_mapi_util_find_array_propval (&object->properties, PR_DISPLAY_TO_UNICODE);
 			display_cc = e_mapi_util_find_array_propval (&object->properties, PR_DISPLAY_CC_UNICODE);
-			from_addr_type = e_mapi_util_find_array_propval (&object->properties, PR_SENT_REPRESENTING_ADDRTYPE);
-			from_name = e_mapi_util_find_array_propval (&object->properties, PR_SENT_REPRESENTING_NAME_UNICODE);
-			from_email = e_mapi_util_find_array_propval (&object->properties, PR_SENT_REPRESENTING_EMAIL_ADDRESS_UNICODE);
 
 			info = camel_message_info_new (gos->folder->summary);
 			minfo = (CamelMapiMessageInfo *) info;
@@ -626,78 +772,51 @@ gather_object_summary_cb (EMapiConnection *conn,
 				mapi_set_message_references (minfo, references, in_reply_to);
 
 			/* Recipients */
-			for (recipient = object->recipients; recipient; recipient = recipient->next) {
-				const uint32_t *recip_type = e_mapi_util_find_array_propval (&recipient->properties, PR_RECIPIENT_TYPE);
-				const gchar *name, *email;
-				gchar **dest = NULL;
-
-				if (!recip_type)
-					continue;
-
-				switch (*recip_type) {
-				case MAPI_TO:
-					dest = &to;
-					break;
-				case MAPI_CC:
-					dest = &cc;
-					break;
-				default:
-					break;
-				}
+			to_addr = (CamelAddress *) camel_internet_address_new ();
+			cc_addr = (CamelAddress *) camel_internet_address_new ();
+			bcc_addr = (CamelAddress *) camel_internet_address_new ();
 
-				if (!dest)
-					continue;
-
-				/* PidTagNickname for Recipients table */
-				name = e_mapi_util_find_array_propval (&recipient->properties, PROP_TAG (PT_UNICODE, 0x6001));
-				name = name ? name : e_mapi_util_find_array_propval (&recipient->properties, PidTagNickname);
-				name = name ? name : e_mapi_util_find_array_propval (&recipient->properties, PR_DISPLAY_NAME_UNICODE);
-				name = name ? name : e_mapi_util_find_array_propval (&recipient->properties, PR_RECIPIENT_DISPLAY_NAME_UNICODE);
-				name = name ? name : e_mapi_util_find_array_propval (&recipient->properties, PR_7BIT_DISPLAY_NAME_UNICODE);
-
-				email = e_mapi_util_find_array_propval (&recipient->properties, PidTagPrimarySmtpAddress);
-				email = email ? email : e_mapi_util_find_array_propval (&recipient->properties, PidTagSmtpAddress);
-
-				formatted_addr = camel_internet_address_format_address (name, email ? email : "");
-				if (*dest) {
-					gchar *tmp = *dest;
-					*dest = g_strconcat (*dest, ", ", formatted_addr, NULL);
-					g_free (formatted_addr);
-					g_free (tmp);
-				} else {
-					*dest = formatted_addr;
-				}
-			}
+			e_mapi_mail_utils_decode_recipients (conn, object->recipients, to_addr, cc_addr, bcc_addr);
 
-			minfo->info.to = to ? camel_pstring_strdup (to) : camel_pstring_strdup (display_to);
-			minfo->info.cc = cc ? camel_pstring_strdup (cc) : camel_pstring_strdup (display_cc);
+			if (camel_address_length (to_addr) > 0) {
+				formatted_addr = camel_address_format (to_addr);
+				minfo->info.to = camel_pstring_strdup (formatted_addr);
+				g_free (formatted_addr);
+			} else {
+				minfo->info.to = camel_pstring_strdup (display_to);
+			}
 
-			if (from_addr_type && g_ascii_strcasecmp (from_addr_type, "EX") == 0) {
-				gchar *email = NULL, *name = NULL;
+			if (camel_address_length (cc_addr) > 0) {
+				formatted_addr = camel_address_format (cc_addr);
+				minfo->info.cc = camel_pstring_strdup (formatted_addr);
+				g_free (formatted_addr);
+			} else {
+				minfo->info.cc = camel_pstring_strdup (display_cc);
+			}
 
-				email = e_mapi_connection_ex_to_smtp (conn, from_email, &name, cancellable, perror);
-				if (email && *email) {
-					gchar *from = camel_internet_address_format_address (name, email);
+			g_object_unref (to_addr);
+			g_object_unref (cc_addr);
+			g_object_unref (bcc_addr);
 
-					minfo->info.from = camel_pstring_strdup (from);
+			from_name = NULL;
+			from_email = NULL;
 
-					g_free (from);
-				} else if (from_name && *from_name) {
-					minfo->info.from = camel_pstring_strdup (from_name);
-				}
+			e_mapi_mail_utils_decode_email_address1 (conn, &object->properties,
+				PR_SENT_REPRESENTING_NAME_UNICODE,
+				PR_SENT_REPRESENTING_EMAIL_ADDRESS_UNICODE,
+				PR_SENT_REPRESENTING_ADDRTYPE,
+				&from_name, &from_email);
 
-				g_free (name);
-				g_free (email);
-			} else if (from_email) {
-				gchar *from = camel_internet_address_format_address (from_name, from_email);
+			if (from_email && *from_email) {
+				formatted_addr = camel_internet_address_format_address (from_name, from_email);
 
-				minfo->info.from = camel_pstring_strdup (from);
+				minfo->info.from = camel_pstring_strdup (formatted_addr);
 
-				g_free (from);
+				g_free (formatted_addr);
 			}
-
-			g_free (to);
-			g_free (cc);
+			
+			g_free (from_name);
+			g_free (from_email);
 		}
 	}
 
@@ -770,10 +889,7 @@ camel_mapi_folder_fetch_summary (CamelFolder *folder, GCancellable *cancellable,
 		camel_offline_settings_get_stay_synchronized (CAMEL_OFFLINE_SETTINGS (settings)) ||
 		camel_offline_folder_get_offline_sync (CAMEL_OFFLINE_FOLDER (folder));
 
-	if (full_download)
-		camel_operation_push_message (cancellable, _("Downloading messages in folder '%s'"), camel_folder_get_display_name (folder));
-	else
-		camel_operation_push_message (cancellable, _("Refreshing folder '%s'"), camel_folder_get_display_name (folder));
+	camel_operation_push_message (cancellable, _("Refreshing folder '%s'"), camel_folder_get_display_name (folder));
 
 	camel_service_lock (CAMEL_SERVICE (mapi_store), CAMEL_SERVICE_REC_CONNECT_LOCK);
 
@@ -829,7 +945,15 @@ camel_mapi_folder_fetch_summary (CamelFolder *folder, GCancellable *cancellable,
 		if (gco.removed_uids)
 			g_hash_table_foreach (gco.removed_uids, remove_removed_uids_cb, &gos);
 
-		status = e_mapi_connection_transfer_summary (conn, &obj_folder, uids, gather_object_summary_cb, &gos, cancellable, mapi_error);
+		if (full_download) {
+			camel_operation_push_message (cancellable, _("Downloading messages in folder '%s'"), camel_folder_get_display_name (folder));
+
+			status = e_mapi_connection_transfer_objects (conn, &obj_folder, uids, gather_object_offline_cb, &gos, cancellable, mapi_error);
+
+			camel_operation_pop_message (cancellable);
+		} else {
+			status = e_mapi_connection_transfer_summary (conn, &obj_folder, uids, gather_object_summary_cb, &gos, cancellable, mapi_error);
+		}
 
 		g_slist_free (uids);
 
@@ -1370,6 +1494,29 @@ mapi_folder_get_message_cached (CamelFolder *folder,
 	return msg;
 }
 
+static gboolean
+transfer_mail_object_cb (EMapiConnection *conn,
+			 TALLOC_CTX *mem_ctx,
+			 /* const */ EMapiObject *object,
+			 guint32 obj_index,
+			 guint32 obj_total,
+			 gpointer user_data,
+			 GCancellable *cancellable,
+			 GError **perror)
+{
+	CamelMimeMessage **pmessage = user_data;
+
+	g_return_val_if_fail (object != NULL, FALSE);
+	g_return_val_if_fail (pmessage != NULL, FALSE);
+
+	*pmessage = e_mapi_mail_utils_object_to_message (conn, object);
+
+	if (obj_total > 0)
+		camel_operation_progress (cancellable, obj_index * 100 / obj_total);
+
+	return TRUE;
+}
+
 static CamelMimeMessage *
 mapi_folder_get_message_sync (CamelFolder *folder,
                               const gchar *uid,
@@ -1380,11 +1527,11 @@ mapi_folder_get_message_sync (CamelFolder *folder,
 	CamelMapiFolder *mapi_folder;
 	CamelMapiStore *mapi_store;
 	CamelMapiMessageInfo *mi = NULL;
-	CamelStream *cache_stream;
 	CamelStore *parent_store;
 	mapi_id_t id_message;
-	MailItem *item = NULL;
-	guint32 options = 0;
+	EMapiConnection *conn;
+	mapi_object_t obj_folder;
+	gboolean success;
 	GError *mapi_error = NULL;
 
 	parent_store = camel_folder_get_parent_store (folder);
@@ -1431,23 +1578,22 @@ mapi_folder_get_message_sync (CamelFolder *folder,
 		return NULL;
 	}
 
-	options = MAPI_OPTIONS_FETCH_ALL | MAPI_OPTIONS_FETCH_BODY_STREAM |
-		MAPI_OPTIONS_GETBESTBODY | MAPI_OPTIONS_FETCH_RECIPIENTS;
-
 	e_mapi_util_mapi_id_from_string (uid, &id_message);
 
-	if (((CamelMapiFolder *)folder)->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC) {
-		options |= MAPI_OPTIONS_USE_PFSTORE;
-	}
+	conn = camel_mapi_store_get_connection (mapi_store);
 
-	camel_service_lock (CAMEL_SERVICE (mapi_store), CAMEL_SERVICE_REC_CONNECT_LOCK);
-	e_mapi_connection_fetch_item (camel_mapi_store_get_connection (mapi_store), mapi_folder->folder_id, id_message,
-					mapi_mail_get_item_prop_list, NULL,
-					fetch_props_to_mail_item_cb, &item,
-					options, cancellable, &mapi_error);
-	camel_service_unlock (CAMEL_SERVICE (mapi_store), CAMEL_SERVICE_REC_CONNECT_LOCK);
+	if (mapi_folder->mapi_folder_flags & CAMEL_MAPI_STORE_FOLDER_FLAG_PUBLIC)
+		success = e_mapi_connection_open_public_folder (conn, mapi_folder->folder_id, &obj_folder, cancellable, &mapi_error);
+	else
+		success = e_mapi_connection_open_personal_folder (conn, mapi_folder->folder_id, &obj_folder, cancellable, &mapi_error);
 
-	if (item == NULL) {
+	if (success) {
+		success = e_mapi_connection_transfer_object (conn, &obj_folder, id_message, transfer_mail_object_cb, &msg, cancellable, &mapi_error);
+
+		e_mapi_connection_close_folder (conn, &obj_folder, cancellable, NULL);
+	}
+
+	if (!msg) {
 		if (mapi_error) {
 			g_set_error (
 				error, CAMEL_SERVICE_ERROR,
@@ -1464,45 +1610,7 @@ mapi_folder_get_message_sync (CamelFolder *folder,
 		return NULL;
 	}
 
-	msg = mapi_mail_item_to_mime_message (camel_mapi_store_get_connection (mapi_store), item);
-	mail_item_free (item);
-
-	if (!msg) {
-		g_set_error (
-			error, CAMEL_SERVICE_ERROR,
-			CAMEL_SERVICE_ERROR_INVALID,
-			_("Could not get message"));
-		camel_message_info_free (&mi->info);
-
-		return NULL;
-	}
-
-	/* add to cache */
-	camel_folder_summary_lock (folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
-	if ((cache_stream = camel_data_cache_add (mapi_folder->cache, "cache", uid, NULL))) {
-		if (camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) msg, cache_stream, cancellable, NULL) == -1
-				|| camel_stream_flush (cache_stream, cancellable, NULL) == -1) {
-			camel_data_cache_remove (mapi_folder->cache, "cache", uid, NULL);
-		} else {
-			CamelMimeMessage *msg2;
-
-			/* workaround to get message back from cache, as that one is properly
-			   encoded with attachments and so on. Not sure what's going wrong when
-			   composing message in memory, but when they are read from the cache
-			   they appear properly in the UI. */
-			msg2 = camel_mime_message_new ();
-			g_seekable_seek (G_SEEKABLE (cache_stream), 0, G_SEEK_SET, NULL, NULL);
-			if (!camel_data_wrapper_construct_from_stream_sync (CAMEL_DATA_WRAPPER (msg2), cache_stream, cancellable, NULL)) {
-				g_object_unref (msg2);
-			} else {
-				g_object_unref (msg);
-				msg = msg2;
-			}
-		}
-		g_object_unref (cache_stream);
-	}
-
-	camel_folder_summary_unlock (folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+	add_message_to_cache (mapi_folder, uid, &msg, cancellable);
 
 	camel_message_info_free (&mi->info);
 
diff --git a/src/camel/camel-mapi-store.c b/src/camel/camel-mapi-store.c
index 8057860..30c3435 100644
--- a/src/camel/camel-mapi-store.c
+++ b/src/camel/camel-mapi-store.c
@@ -926,50 +926,6 @@ mapi_store_get_folder_sync (CamelStore *store,
 	return folder;
 }
 
-static void
-mapi_update_folder_info_cb (CamelSession *session,
-			    GCancellable *cancellable,
-			    gpointer store,
-			    GError **error)
-{
-	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (store);
-	CamelServiceConnectionStatus status;
-	CamelService *service;
-	gchar *name;
-
-	service = CAMEL_SERVICE (store);
-
-	camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
-
-	name = camel_service_get_name (service, TRUE);
-	camel_operation_push_message (cancellable, _("Scanning folders in '%s'"), name);
-
-	status = camel_service_get_connection_status (service);
-	if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
-		if (status == CAMEL_SERVICE_DISCONNECTED) {
-			camel_operation_push_message (cancellable, _("Connecting to '%s'"), name);
-			camel_service_connect_sync (service, NULL);
-			camel_operation_pop_message (cancellable); 
-		}
-
-		/* update folders from the server only when asking for the top most or the 'top' is not known;
-		   otherwise believe the local cache, because folders sync is pretty slow operation to be done
-		   one every single question on the folder info */
-		status = camel_service_get_connection_status (service);
-		if (check_for_connection (service, NULL) || status == CAMEL_SERVICE_CONNECTING) {
-			if (mapi_folders_sync (mapi_store, CAMEL_STORE_FOLDER_INFO_RECURSIVE, cancellable, error)) {
-				camel_store_summary_touch (mapi_store->summary);
-				camel_store_summary_save (mapi_store->summary);
-			}
-		}
-	}
-
-	g_free (name);
-	camel_operation_pop_message (cancellable); 
-
-	camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
-}
-
 static CamelFolderInfo*
 mapi_store_get_folder_info_sync (CamelStore *store,
                                  const gchar *top,
@@ -995,24 +951,31 @@ mapi_store_get_folder_info_sync (CamelStore *store,
 		if ((flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0 ||
 		    (!(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED)) ||
 		    (top && *top && !camel_mapi_store_folder_id_lookup (mapi_store, top)) ||
-		    camel_store_summary_count (mapi_store->summary) <= 1) {
-			if (status == CAMEL_SERVICE_DISCONNECTED)
+		    camel_store_summary_count (mapi_store->summary) <= 1 ||
+		    !mapi_store->priv->folders_synced) {
+			if (status == CAMEL_SERVICE_DISCONNECTED) {
+				gchar *name = camel_service_get_name (service, TRUE);
+
+				camel_operation_push_message (cancellable, _("Connecting to '%s'"), name);
 				camel_service_connect_sync (service, NULL);
+				camel_operation_pop_message (cancellable);
+
+				g_free (name);
+			}
 
 			if (check_for_connection (service, NULL) || status == CAMEL_SERVICE_CONNECTING) {
+				gboolean first_check = !mapi_store->priv->folders_synced;
+
 				if (!mapi_folders_sync (mapi_store, flags, cancellable, error)) {
 					camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
 					return NULL;
 				}
+
+				if (first_check) {
+					camel_store_summary_touch (mapi_store->summary);
+					camel_store_summary_save (mapi_store->summary);
+				}
 			}
-		} else if (!mapi_store->priv->folders_synced) {
-			mapi_store->priv->folders_synced = TRUE;
-
-			camel_session_submit_job (
-				camel_service_get_session (CAMEL_SERVICE (store)),
-				mapi_update_folder_info_cb,
-				g_object_ref (store),
-				g_object_unref);
 		}
 	}
 
diff --git a/src/libexchangemapi/e-mapi-cal-recur-utils.c b/src/libexchangemapi/e-mapi-cal-recur-utils.c
index f424b5d..d9580fc 100644
--- a/src/libexchangemapi/e-mapi-cal-recur-utils.c
+++ b/src/libexchangemapi/e-mapi-cal-recur-utils.c
@@ -699,7 +699,7 @@ check_calendar_type (guint16 type)
 }
 
 gboolean
-e_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp, GSList **extra_detached, icaltimezone *recur_zone)
+e_mapi_cal_util_bin_to_rrule (const guint8 *lpb, guint32 cb, ECalComponent *comp, GSList **extra_detached, icaltimezone *recur_zone)
 {
 	struct icalrecurrencetype rt;
 	struct ema_AppointmentRecurrencePattern arp;
@@ -708,11 +708,15 @@ e_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp, GSList **extr
 	gint i;
 	ptrdiff_t off = 0;
 	GSList *exdate_list = NULL;
+	GByteArray fake_ba;
+
+	fake_ba.data = (guint8 *) lpb;
+	fake_ba.len = cb;
 
 	icalrecurrencetype_clear (&rt);
 
 	memset(&arp, 0, sizeof (struct ema_AppointmentRecurrencePattern));
-	if (! gba_to_arp (ba, &off, &arp))
+	if (! gba_to_arp (&fake_ba, &off, &arp))
 		goto cleanup;
 
 	rp = &arp.RecurrencePattern;
diff --git a/src/libexchangemapi/e-mapi-cal-recur-utils.h b/src/libexchangemapi/e-mapi-cal-recur-utils.h
index 29c149d..0c2dfff 100644
--- a/src/libexchangemapi/e-mapi-cal-recur-utils.h
+++ b/src/libexchangemapi/e-mapi-cal-recur-utils.h
@@ -30,7 +30,7 @@
 
 G_BEGIN_DECLS
 
-gboolean	e_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp, GSList **extra_detached, icaltimezone *recur_zone);
+gboolean	e_mapi_cal_util_bin_to_rrule (const guint8 *lpb, guint32 cb, ECalComponent *comp, GSList **extra_detached, icaltimezone *recur_zone);
 
 GByteArray *	e_mapi_cal_util_rrule_to_bin (ECalComponent *comp, GSList *modified_comps);
 
diff --git a/src/libexchangemapi/e-mapi-cal-tz-utils.c b/src/libexchangemapi/e-mapi-cal-tz-utils.c
index f992c72..7cf3513 100644
--- a/src/libexchangemapi/e-mapi-cal-tz-utils.c
+++ b/src/libexchangemapi/e-mapi-cal-tz-utils.c
@@ -344,12 +344,11 @@ e_mapi_cal_util_mapi_tz_to_bin (const gchar *mapi_tzid, struct Binary_r *sb)
 }
 
 gchar *
-e_mapi_cal_util_bin_to_mapi_tz (GByteArray *ba)
+e_mapi_cal_util_bin_to_mapi_tz (const guint8 *lpb, guint32 cb)
 {
 	guint8 flag8;
 	guint16 flag16, cbHeader = 0;
-	guint8 *ptr = ba->data;
-//	guint len = ba->len;
+	const guint8 *ptr = lpb;
 	gchar *buf = NULL;
 
 	d(g_message ("New timezone stream.. Length: %d bytes.. Info follows:", ba->len));
diff --git a/src/libexchangemapi/e-mapi-cal-tz-utils.h b/src/libexchangemapi/e-mapi-cal-tz-utils.h
index 5a789b4..0e097bf 100644
--- a/src/libexchangemapi/e-mapi-cal-tz-utils.h
+++ b/src/libexchangemapi/e-mapi-cal-tz-utils.h
@@ -37,7 +37,7 @@ void		e_mapi_cal_tz_util_destroy		(void);
 void		e_mapi_cal_tz_util_dump			(void);
 void		e_mapi_cal_util_mapi_tz_to_bin		(const gchar *mapi_tzid, struct Binary_r *sb);
 int		e_mapi_cal_util_mapi_tz_pidlidtimezone	(icaltimezone *ictz);
-gchar *		e_mapi_cal_util_bin_to_mapi_tz		(GByteArray *ba);
+gchar *		e_mapi_cal_util_bin_to_mapi_tz		(const guint8 *lpb, guint32 cb);
 
 G_END_DECLS
 
diff --git a/src/libexchangemapi/e-mapi-cal-utils.c b/src/libexchangemapi/e-mapi-cal-utils.c
index 9223bce..79f884b 100644
--- a/src/libexchangemapi/e-mapi-cal-utils.c
+++ b/src/libexchangemapi/e-mapi-cal-utils.c
@@ -30,6 +30,8 @@
 #include <fcntl.h>
 #include <libecal/e-cal-util.h>
 #include <libedataserver/e-data-server-util.h>
+
+#include "e-mapi-mail-utils.h"
 #include "e-mapi-cal-utils.h"
 
 #ifndef O_BINARY
@@ -650,28 +652,27 @@ e_mapi_cal_util_generate_globalobjectid (gboolean is_clean, const gchar *uid, co
 
 /* returns complete globalid as base64 encoded string */
 static gchar *
-globalid_to_string (GByteArray *ba)
+globalid_to_string (const guint8 *lpb, guint32 cb)
 {
-	guint8 *ptr;
-	guint len;
+	const guint8 *ptr;
 	guint32 i, j;
 
-	g_return_val_if_fail (ba != NULL, NULL);
+	g_return_val_if_fail (lpb != NULL, NULL);
 
 	/* MSDN docs: the globalID must have an even number of bytes */
-	if ((ba->len) % 2 != 0)
+	if ((cb) % 2 != 0)
 		return NULL;
 
-	ptr = ba->data;
-	len = ba->len;
+	ptr = lpb;
 
 	/* starting seq - len = 16 bytes */
-	for (i = 0, j = 0;(i < len) && (j < sizeof (GID_START_SEQ)); ++i, ++ptr, ++j)
+	for (i = 0, j = 0; i < cb && j < sizeof (GID_START_SEQ); i++, ptr++, j++) {
 		if (*ptr != GID_START_SEQ[j])
 			return NULL;
+	}
 
 	/* take complete global id */
-	return g_base64_encode (ba->data, ba->len);
+	return g_base64_encode (lpb, cb);
 }
 
 ECalComponent *
@@ -765,8 +766,8 @@ e_mapi_cal_util_mapi_props_to_comp (EMapiConnection *conn, mapi_id_t fid, icalco
 
 		/* GlobalObjectId */
 		stream = e_mapi_util_find_stream_namedid (streams, conn, fid, PidLidGlobalObjectId);
-		if (stream) {
-			gchar *value = globalid_to_string (stream->value);
+		if (stream && stream->value) {
+			gchar *value = globalid_to_string (stream->value->data, stream->value->len);
 			prop = icalproperty_new_x (value);
 			icalproperty_set_x_name (prop, "X-EVOLUTION-MAPI-GLOBALID");
 			icalcomponent_add_property (ical_comp, prop);
@@ -811,8 +812,8 @@ e_mapi_cal_util_mapi_props_to_comp (EMapiConnection *conn, mapi_id_t fid, icalco
 		all_day = b && *b;
 
 		stream = e_mapi_util_find_stream_namedid (streams, conn, fid, PidLidAppointmentTimeZoneDefinitionStartDisplay);
-		if (stream) {
-			gchar *buf = e_mapi_cal_util_bin_to_mapi_tz (stream->value);
+		if (stream && stream->value) {
+			gchar *buf = e_mapi_cal_util_bin_to_mapi_tz (stream->value->data, stream->value->len);
 			dtstart_tz_location = e_mapi_cal_tz_util_get_ical_equivalent (buf);
 			g_free (buf);
 		}
@@ -828,8 +829,8 @@ e_mapi_cal_util_mapi_props_to_comp (EMapiConnection *conn, mapi_id_t fid, icalco
 		}
 
 		stream = e_mapi_util_find_stream_namedid (streams, conn, fid, PidLidAppointmentTimeZoneDefinitionEndDisplay);
-		if (stream) {
-			gchar *buf = e_mapi_cal_util_bin_to_mapi_tz (stream->value);
+		if (stream && stream->value) {
+			gchar *buf = e_mapi_cal_util_bin_to_mapi_tz (stream->value->data, stream->value->len);
 			dtend_tz_location = e_mapi_cal_tz_util_get_ical_equivalent (buf);
 			g_free (buf);
 		}
@@ -966,7 +967,7 @@ e_mapi_cal_util_mapi_props_to_comp (EMapiConnection *conn, mapi_id_t fid, icalco
 		b = e_mapi_util_find_array_namedid (properties, conn, fid, PidLidRecurring);
 		if (b && *b) {
 			stream = e_mapi_util_find_stream_namedid (streams, conn, fid, PidLidAppointmentRecur);
-			if (stream) {
+			if (stream && stream->value) {
 				icaltimezone *recur_zone;
 				const gchar *recur_tz_location;
 
@@ -975,7 +976,7 @@ e_mapi_cal_util_mapi_props_to_comp (EMapiConnection *conn, mapi_id_t fid, icalco
 					recur_tz_location = e_mapi_cal_tz_util_get_ical_equivalent (recur_tz_location);
 				recur_zone = recur_tz_location ? icaltimezone_get_builtin_timezone (recur_tz_location) : (icaltimezone *) default_zone;
 
-				e_mapi_cal_util_bin_to_rrule (stream->value, comp, detached_components, recur_zone);
+				e_mapi_cal_util_bin_to_rrule (stream->value->data, stream->value->len, comp, detached_components, recur_zone);
 			}
 		}
 
@@ -2422,3 +2423,598 @@ e_mapi_cal_utils_get_icomp_x_prop (icalcomponent *comp, const gchar *key)
 	return NULL;
 }
 
+static void
+populate_ical_attendees (EMapiConnection *conn,
+			 EMapiRecipient *recipients,
+			 icalcomponent *icalcomp,
+			 gboolean rsvp)
+{
+	const uint32_t name_proptags[] = {
+		PROP_TAG (PT_UNICODE, 0x6001), /* PidTagNickname for Recipients table */
+		PidTagNickname,
+		PidTagRecipientDisplayName,
+		PidTagDisplayName,
+		PidTag7BitDisplayName
+	};
+
+	const uint32_t email_proptags[] = {
+		PidTagPrimarySmtpAddress,
+		PidTagSmtpAddress
+	};
+
+	EMapiRecipient *recipient;
+
+	g_return_if_fail (conn != NULL);
+	g_return_if_fail (icalcomp != NULL);
+
+	for (recipient = recipients; recipient; recipient = recipient->next) {
+		gchar *name = NULL, *email = NULL, *icalemail;
+		icalproperty *prop;
+		icalparameter *param;
+		const uint32_t *ui32;
+		const uint32_t *flags;
+
+		e_mapi_mail_utils_decode_email_address (conn, &recipient->properties,
+					name_proptags, G_N_ELEMENTS (name_proptags),
+					email_proptags, G_N_ELEMENTS (email_proptags),
+					PidTagAddressType, PidTagEmailAddress,
+					&name, &email);
+
+		if (!email) {
+			g_free (name);
+			g_debug ("%s: Skipping event recipient without email", G_STRFUNC);
+			continue;
+		}
+
+		icalemail = g_strdup_printf ("MAILTO:%s", email);
+
+		flags = e_mapi_util_find_array_propval (&recipient->properties, PidTagRecipientFlags);
+
+		if (flags && (*flags & RECIP_ORGANIZER)) {
+			prop = icalproperty_new_organizer (icalemail);
+
+			/* CN */
+			if (name && *name) {
+				param = icalparameter_new_cn (name);
+				icalproperty_add_parameter (prop, param);
+			}
+		} else {
+			prop = icalproperty_new_attendee (icalemail);
+
+			/* CN */
+			if (name && *name) {
+				param = icalparameter_new_cn (name);
+				icalproperty_add_parameter (prop, param);
+			}
+
+			/* RSVP */
+			param = icalparameter_new_rsvp (rsvp ? ICAL_RSVP_TRUE : ICAL_RSVP_FALSE);
+			icalproperty_add_parameter (prop, param);
+
+			/* PARTSTAT */
+			ui32 = e_mapi_util_find_array_propval (&recipient->properties, PidTagRecipientTrackStatus);
+			param = icalparameter_new_partstat (get_partstat_from_trackstatus (ui32 ? *ui32 : olResponseNone));
+			icalproperty_add_parameter (prop, param);
+
+			/* ROLE */
+			ui32 = e_mapi_util_find_array_propval (&recipient->properties, PidTagRecipientType);
+			param = icalparameter_new_role (get_role_from_type (ui32 ? *ui32 : olTo));
+			icalproperty_add_parameter (prop, param);
+
+			/* CALENDAR USER TYPE */
+			param = NULL;
+			if (ui32 && *ui32 == 0x03)
+				param = icalparameter_new_cutype (ICAL_CUTYPE_RESOURCE);
+			if (!param)
+				param = icalparameter_new_cutype (ICAL_CUTYPE_INDIVIDUAL);
+
+			icalproperty_add_parameter (prop, param);
+		}
+
+		icalcomponent_add_property (icalcomp, prop);
+
+		g_free (icalemail);
+		g_free (email);
+		g_free (name);
+	}
+}
+
+static void
+set_attachments_to_comp (EMapiConnection *conn, EMapiAttachment *attachments, ECalComponent *comp, const gchar *local_store_path)
+{
+	GSList *comp_attach_list = NULL;
+	EMapiAttachment *attach;
+	const gchar *uid;
+
+	g_return_if_fail (comp != NULL);
+	g_return_if_fail (local_store_path != NULL);
+
+	if (!attachments)
+		return;
+
+	e_cal_component_get_uid (comp, &uid);
+
+	for (attach = attachments; attach; attach = attach->next) {
+		const struct SBinary_short *data_bin;
+		const gchar *filename;
+		const uint32_t *ui32;
+		gchar *path, *attach_uri;
+		GError *error = NULL;
+
+		data_bin = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachDataBinary);
+		if (!data_bin) {
+			g_debug ("%s: Skipping calendar attachment without data", G_STRFUNC);
+			continue;
+		}
+
+		filename = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachLongFilename);
+		if (!filename || !*filename)
+			filename = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachFilename);
+
+		ui32 = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachNumber);
+		path = e_filename_mkdir_encoded (local_store_path, uid, filename, ui32 ? *ui32 : 0);
+
+		attach_uri = g_filename_to_uri (path, NULL, &error);
+		if (!attach_uri) {
+			g_debug ("%s: Could not get attach_uri from '%s': %s", G_STRFUNC, path, error ? error->message : "Unknown error");
+			g_clear_error (&error);
+			g_free (path);
+			continue;
+		}
+
+		if (!g_file_set_contents (path, (const gchar *) data_bin->lpb, data_bin->cb, &error)) {
+			g_debug ("%s: Failed to write attachment content to '%s': %s", G_STRFUNC, path, error ? error->message : "Unknown error");
+			g_free (attach_uri);
+			g_clear_error (&error);
+		} else {
+			comp_attach_list = g_slist_append (comp_attach_list, attach_uri);
+		}
+
+		g_free (path);
+	}
+
+	e_cal_component_set_attachment_list (comp, comp_attach_list);
+
+	g_slist_free_full (comp_attach_list, g_free);
+}
+
+ECalComponent *
+e_mapi_cal_util_object_to_comp (EMapiConnection *conn,
+				EMapiObject *object,
+				icalcomponent_kind kind,
+				gboolean is_reply,
+				const gchar *local_store_uri,
+				const gchar *use_uid,
+				GSList **detached_components)
+{
+	ECalComponent *comp = NULL;
+	struct timeval t;
+	const gchar *str;
+	const struct mapi_SPLSTRArrayW *categories_array;
+	const struct SBinary_short *bin;
+	const uint32_t *ui32;
+	const bool *b;
+	icalcomponent *ical_comp;
+	icalproperty *prop = NULL;
+	icalparameter *param = NULL;
+	icaltimezone *utc_zone;
+
+	g_return_val_if_fail (conn != NULL, NULL);
+	g_return_val_if_fail (object != NULL, NULL);
+	g_return_val_if_fail (use_uid != NULL, NULL);
+
+	switch (kind) {
+		case ICAL_VEVENT_COMPONENT:
+		case ICAL_VTODO_COMPONENT:
+		case ICAL_VJOURNAL_COMPONENT:
+			comp = e_cal_component_new ();
+			ical_comp = icalcomponent_new (kind);
+			if (!e_cal_component_set_icalcomponent (comp, ical_comp)) {
+				icalcomponent_free (ical_comp);
+				g_object_unref (comp);
+				return NULL;
+			}
+			e_cal_component_set_uid (comp, use_uid);
+			break;
+		default:
+			return NULL;
+	}
+
+	utc_zone = icaltimezone_get_utc_timezone ();
+	if (!local_store_uri)
+		local_store_uri = g_get_tmp_dir ();
+
+	str = e_mapi_util_find_array_propval (&object->properties, PidTagSubject);
+	str = str ? str : e_mapi_util_find_array_propval (&object->properties, PidTagNormalizedSubject);
+	str = str ? str : e_mapi_util_find_array_propval (&object->properties, PidTagConversationTopic);
+	str = str ? str : "";
+	icalcomponent_set_summary (ical_comp, str);
+
+	ui32 = e_mapi_util_find_array_propval (&object->properties, PidTagInternetCodepage);
+	str = e_mapi_util_find_array_propval (&object->properties, PidTagBody);
+	if (str) {
+		gchar *utf8_str = NULL;
+		uint32_t proptag = e_mapi_util_find_array_proptag (&object->properties, PidTagBody);
+
+		if (e_mapi_utils_ensure_utf8_string (proptag, ui32, (const guint8 *) str, strlen (str), &utf8_str))
+			str = utf8_str;
+
+		icalcomponent_set_description (ical_comp, str);
+
+		g_free (utf8_str);
+	} else {
+		const struct SBinary_short *html_bin = e_mapi_util_find_array_propval (&object->properties, PidTagHtml);
+
+		if (html_bin) {
+			gchar *utf8_str = NULL;
+
+			if (e_mapi_utils_ensure_utf8_string (PidTagHtml, ui32, html_bin->lpb, html_bin->cb, &utf8_str))
+				icalcomponent_set_description (ical_comp, utf8_str);
+
+			g_free (utf8_str);
+		}
+	}
+
+	/* set dtstamp - in UTC */
+	if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidTagCreationTime) == MAPI_E_SUCCESS) {
+		icalcomponent_set_dtstamp (ical_comp, icaltime_from_timet_with_zone (t.tv_sec, 0, utc_zone));
+
+		prop = icalproperty_new_created (icaltime_from_timet_with_zone (t.tv_sec, 0, utc_zone));
+		icalcomponent_add_property (ical_comp, prop);
+	} else {
+		/* created - in UTC */
+		prop = icalproperty_new_created (icaltime_current_time_with_zone (utc_zone));
+		icalcomponent_add_property (ical_comp, prop);
+	}
+
+	/* last modified - in UTC */
+	if (get_mapi_SPropValue_array_date_timeval (&t, &object->properties, PidTagLastModificationTime) == MAPI_E_SUCCESS) {
+		prop = icalproperty_new_lastmodified (icaltime_from_timet_with_zone (t.tv_sec, 0, utc_zone));
+		icalcomponent_add_property (ical_comp, prop);
+	}
+
+	categories_array = e_mapi_util_find_array_propval (&object->properties, PidNameKeywords);
+	if (categories_array) {
+		GSList *categories = NULL;
+		gint ii;
+
+		for (ii = 0; ii < categories_array->cValues; ii++) {
+			const gchar *category = categories_array->strings[ii].lppszW;
+
+			if (!category || !*category)
+				continue;
+
+			categories = g_slist_append (categories, (gpointer) category);
+		}
+
+		e_cal_component_set_categories_list (comp, categories);
+
+		g_slist_free (categories);
+	}
+
+	if (icalcomponent_isa (ical_comp) == ICAL_VEVENT_COMPONENT) {
+		const gchar *location = NULL;
+		const gchar *dtstart_tz_location = NULL, *dtend_tz_location = NULL;
+		gboolean all_day;
+
+		/* GlobalObjectId */
+		bin = e_mapi_util_find_array_propval (&object->properties, PidLidGlobalObjectId);
+		if (bin) {
+			gchar *value = globalid_to_string (bin->lpb, bin->cb);
+			prop = icalproperty_new_x (value);
+			icalproperty_set_x_name (prop, "X-EVOLUTION-MAPI-GLOBALID");
+			icalcomponent_add_property (ical_comp, prop);
+			if (value && *value) {
+				e_cal_component_set_uid (comp, value);
+
+				if (!g_str_equal (value, use_uid)) {
+					prop = icalproperty_new_x (use_uid);
+					icalproperty_set_x_name (prop, "X-EVOLUTION-MAPI-MID");
+					icalcomponent_add_property (ical_comp, prop);
+				}
+			}
+
+			g_free (value);
+		}
+
+		ui32 = e_mapi_util_find_array_propval (&object->properties, PidTagOwnerAppointmentId);
+		if (ui32) {
+			gchar *value = e_mapi_util_mapi_id_to_string ((mapi_id_t) (*ui32));
+
+			prop = icalproperty_new_x (value);
+			icalproperty_set_x_name (prop, "X-EVOLUTION-MAPI-OWNER-APPT-ID");
+			icalcomponent_add_property (ical_comp, prop);
+			g_free (value);
+		}
+
+		/* AppointmentSequence */
+		ui32 = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentSequence);
+		if (ui32) {
+			gchar *value = g_strdup_printf ("%d", *ui32);
+			prop = icalproperty_new_x (value);
+			icalproperty_set_x_name (prop, "X-EVOLUTION-MAPI-APPTSEQ");
+			icalcomponent_add_property (ical_comp, prop);
+			g_free (value);
+		}
+
+		location = e_mapi_util_find_array_propval (&object->properties, PidLidLocation);
+		if (location && *location)
+			icalcomponent_set_location (ical_comp, location);
+
+		b = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentSubType);;
+		all_day = b && *b;
+
+		bin = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentTimeZoneDefinitionStartDisplay);
+		if (bin) {
+			gchar *buf = e_mapi_cal_util_bin_to_mapi_tz (bin->lpb, bin->cb);
+			dtstart_tz_location = e_mapi_cal_tz_util_get_ical_equivalent (buf);
+			g_free (buf);
+		}
+
+		if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidLidAppointmentStartWhole) == MAPI_E_SUCCESS) {
+			icaltimezone *zone = dtstart_tz_location ? icaltimezone_get_builtin_timezone (dtstart_tz_location) : utc_zone;
+			prop = icalproperty_new_dtstart (icaltime_from_timet_with_zone (t.tv_sec, all_day, zone));
+			if (!all_day && zone && icaltimezone_get_tzid (zone)) {
+				icalproperty_add_parameter (prop, icalparameter_new_tzid (icaltimezone_get_tzid (zone)));
+			}
+
+			icalcomponent_add_property (ical_comp, prop);
+		}
+
+		bin = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentTimeZoneDefinitionEndDisplay);
+		if (bin) {
+			gchar *buf = e_mapi_cal_util_bin_to_mapi_tz (bin->lpb, bin->cb);
+			dtend_tz_location = e_mapi_cal_tz_util_get_ical_equivalent (buf);
+			g_free (buf);
+		}
+
+		if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidLidAppointmentEndWhole) == MAPI_E_SUCCESS) {
+			icaltimezone *zone;
+
+			if (!dtend_tz_location)
+				dtend_tz_location = dtstart_tz_location;
+
+			zone = dtend_tz_location ? icaltimezone_get_builtin_timezone (dtend_tz_location) : utc_zone;
+			prop = icalproperty_new_dtend (icaltime_from_timet_with_zone (t.tv_sec, all_day, zone));
+			if (!all_day && zone && icaltimezone_get_tzid (zone)) {
+				icalproperty_add_parameter (prop, icalparameter_new_tzid (icaltimezone_get_tzid (zone)));
+			}
+
+			icalcomponent_add_property (ical_comp, prop);
+		}
+
+		ui32 = e_mapi_util_find_array_propval (&object->properties, PidLidBusyStatus);
+		if (ui32) {
+			prop = icalproperty_new_transp (get_transp_from_prop (*ui32));
+			icalcomponent_add_property (ical_comp, prop);
+		}
+
+		if (object->recipients) {
+			gchar *name = NULL, *email = NULL;
+			gchar *val;
+
+			b = e_mapi_util_find_array_propval (&object->properties, PidTagResponseRequested);
+			populate_ical_attendees (conn, object->recipients, ical_comp, (b && *b));
+			if (is_reply) {
+				if (icalcomponent_get_first_property (ical_comp, ICAL_ORGANIZER_PROPERTY) == NULL) {
+					name = NULL;
+					email = NULL;
+
+					e_mapi_mail_utils_decode_email_address1	(conn, &object->properties,
+						PidTagReceivedRepresentingName,
+						PidTagReceivedRepresentingEmailAddress,
+						PidTagReceivedRepresentingAddressType,
+						&name, &email);
+
+					if (email) {
+						val = g_strdup_printf ("MAILTO:%s", email);
+						prop = icalproperty_new_organizer (val);
+						g_free (val);
+
+						if (name && g_strcmp0 (name, email) != 0) {
+							/* CN */
+							param = icalparameter_new_cn (name);
+							icalproperty_add_parameter (prop, param);
+						}
+
+						icalcomponent_add_property (ical_comp, prop);
+					}
+
+					g_free (name);
+					g_free (email);
+				}
+
+				if (icalcomponent_get_first_property (ical_comp, ICAL_ATTENDEE_PROPERTY) == NULL) {
+					name = NULL;
+					email = NULL;
+
+					e_mapi_mail_utils_decode_email_address1	(conn, &object->properties,
+						PidTagSentRepresentingName,
+						PidTagSentRepresentingEmailAddress,
+						PidTagSentRepresentingAddressType,
+						&name, &email);
+
+					if (email) {
+						val = g_strdup_printf ("MAILTO:%s", email);
+						prop = icalproperty_new_attendee (val);
+						g_free (val);
+
+						if (name && g_strcmp0 (name, email) != 0) {
+							/* CN */
+							param = icalparameter_new_cn (name);
+							icalproperty_add_parameter (prop, param);
+						}
+
+						ui32 = e_mapi_util_find_array_propval (&object->properties, PidLidResponseStatus);
+						param = icalparameter_new_partstat (get_partstat_from_trackstatus (ui32 ? *ui32 : olResponseNone));
+						icalproperty_add_parameter (prop, param);
+
+						icalcomponent_add_property (ical_comp, prop);
+					}
+
+					g_free (name);
+					g_free (email);
+				}
+			} else if (icalcomponent_get_first_property (ical_comp, ICAL_ORGANIZER_PROPERTY) == NULL) {
+				gchar *sent_name = NULL, *sent_email = NULL;
+
+				name = NULL;
+				email = NULL;
+
+				e_mapi_mail_utils_decode_email_address1	(conn, &object->properties,
+					PidTagSenderName,
+					PidTagSenderEmailAddress,
+					PidTagSenderAddressType,
+					&name, &email);
+
+				e_mapi_mail_utils_decode_email_address1	(conn, &object->properties,
+					PidTagSentRepresentingName,
+					PidTagSentRepresentingEmailAddress,
+					PidTagSentRepresentingAddressType,
+					&sent_name, &sent_email);
+
+				if (sent_email) {
+					val = g_strdup_printf ("MAILTO:%s", sent_email);
+					prop = icalproperty_new_organizer (val);
+					g_free (val);
+
+					if (sent_name && g_strcmp0 (sent_name, sent_email) != 0) {
+						/* CN */
+						param = icalparameter_new_cn (sent_name);
+						icalproperty_add_parameter (prop, param);
+					}
+
+					/* SENTBY */
+					if (email && g_utf8_collate (sent_email, email)) {
+						val = g_strdup_printf ("MAILTO:%s", email);
+						param = icalparameter_new_sentby (val);
+						icalproperty_add_parameter (prop, param);
+						g_free (val);
+					}
+
+					icalcomponent_add_property (ical_comp, prop);
+				}
+
+
+				g_free (name);
+				g_free (email);
+				g_free (sent_name);
+				g_free (sent_email);
+			}
+		}
+
+		b = e_mapi_util_find_array_propval (&object->properties, PidLidRecurring);
+		if (b && *b) {
+			bin = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentRecur);
+			if (bin) {
+				icaltimezone *recur_zone;
+				const gchar *recur_tz_location;
+
+				recur_tz_location = e_mapi_util_find_array_propval (&object->properties, PidLidTimeZoneDescription);
+				if (recur_tz_location)
+					recur_tz_location = e_mapi_cal_tz_util_get_ical_equivalent (recur_tz_location);
+				recur_zone = recur_tz_location ? icaltimezone_get_builtin_timezone (recur_tz_location) : utc_zone;
+
+				e_mapi_cal_util_bin_to_rrule (bin->lpb, bin->cb, comp, detached_components, recur_zone);
+			}
+		}
+
+		b = e_mapi_util_find_array_propval (&object->properties, PidLidReminderSet);
+		if (b && *b) {
+			struct timeval start, displaytime;
+
+			if ((e_mapi_util_find_array_datetime_propval (&start, &object->properties, PidLidReminderTime) == MAPI_E_SUCCESS)
+			 && (e_mapi_util_find_array_datetime_propval (&displaytime, &object->properties, PidLidReminderSignalTime) == MAPI_E_SUCCESS)) {
+				ECalComponentAlarm *e_alarm = e_cal_component_alarm_new ();
+				ECalComponentAlarmTrigger trigger;
+
+				trigger.type = E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START;
+				trigger.u.rel_duration = icaltime_subtract (icaltime_from_timet_with_zone (displaytime.tv_sec, 0, 0),
+									    icaltime_from_timet_with_zone (start.tv_sec, 0, 0));
+
+				e_cal_component_alarm_set_action (e_alarm, E_CAL_COMPONENT_ALARM_DISPLAY);
+				e_cal_component_alarm_set_trigger (e_alarm, trigger);
+
+				e_cal_component_add_alarm (comp, e_alarm);
+			}
+		} else
+			e_cal_component_remove_all_alarms (comp);
+
+	} else if (icalcomponent_isa (ical_comp) == ICAL_VTODO_COMPONENT) {
+		const double *complete = NULL;
+		const uint64_t *status = NULL;
+
+		/* NOTE: Exchange tasks are DATE values, not DATE-TIME values, but maybe someday, we could expect Exchange to support it;) */
+		if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidLidTaskStartDate) == MAPI_E_SUCCESS)
+			icalcomponent_set_dtstart (ical_comp, icaltime_from_timet_with_zone (t.tv_sec, 1, utc_zone));
+		if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidLidTaskDueDate) == MAPI_E_SUCCESS)
+			icalcomponent_set_due (ical_comp, icaltime_from_timet_with_zone (t.tv_sec, 1, utc_zone));
+
+		status = e_mapi_util_find_array_propval (&object->properties, PidLidTaskStatus);
+		if (status) {
+			icalcomponent_set_status (ical_comp, get_taskstatus_from_prop (*status));
+			if (*status == olTaskComplete
+			    && e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidLidTaskDateCompleted) == MAPI_E_SUCCESS) {
+				prop = icalproperty_new_completed (icaltime_from_timet_with_zone (t.tv_sec, 1, utc_zone));
+				icalcomponent_add_property (ical_comp, prop);
+			}
+		}
+
+		complete = e_mapi_util_find_array_propval (&object->properties, PidLidPercentComplete);
+		if (complete) {
+			prop = icalproperty_new_percentcomplete ((gint) ((*complete) * 100 + 1e-9));
+			icalcomponent_add_property (ical_comp, prop);
+		}
+
+		b = e_mapi_util_find_array_propval (&object->properties, PidLidTaskFRecurring);
+		if (b && *b) {
+			g_debug ("%s: Evolution does not support recurring tasks.", G_STRFUNC);
+		}
+
+		b = e_mapi_util_find_array_propval (&object->properties, PidLidReminderSet);
+		if (b && *b) {
+			struct timeval abs;
+
+			if (e_mapi_util_find_array_datetime_propval (&abs, &object->properties, PidLidReminderTime) == MAPI_E_SUCCESS) {
+				ECalComponentAlarm *e_alarm = e_cal_component_alarm_new ();
+				ECalComponentAlarmTrigger trigger;
+
+				trigger.type = E_CAL_COMPONENT_ALARM_TRIGGER_ABSOLUTE;
+				trigger.u.abs_time = icaltime_from_timet_with_zone (abs.tv_sec, 0, utc_zone);
+
+				e_cal_component_alarm_set_action (e_alarm, E_CAL_COMPONENT_ALARM_DISPLAY);
+				e_cal_component_alarm_set_trigger (e_alarm, trigger);
+
+				e_cal_component_add_alarm (comp, e_alarm);
+			}
+		} else
+			e_cal_component_remove_all_alarms (comp);
+
+	} else if (icalcomponent_isa (ical_comp) == ICAL_VJOURNAL_COMPONENT) {
+		if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidTagLastModificationTime) == MAPI_E_SUCCESS)
+			icalcomponent_set_dtstart (ical_comp, icaltime_from_timet_with_zone (t.tv_sec, 1, utc_zone));
+	}
+
+	if (icalcomponent_isa (ical_comp) == ICAL_VEVENT_COMPONENT ||
+	    icalcomponent_isa (ical_comp) == ICAL_VTODO_COMPONENT) {
+		/* priority */
+		ui32 = e_mapi_util_find_array_propval (&object->properties, PidTagPriority);
+		if (ui32) {
+			prop = icalproperty_new_priority (get_priority_from_prop (*ui32));
+			icalcomponent_add_property (ical_comp, prop);
+		}
+	}
+
+	/* classification */
+	ui32 = e_mapi_util_find_array_propval (&object->properties, PidTagSensitivity);
+	if (ui32) {
+		prop = icalproperty_new_class (get_class_from_prop (*ui32));
+		icalcomponent_add_property (ical_comp, prop);
+	}
+
+	set_attachments_to_comp (conn, object->attachments, comp, local_store_uri);
+
+	e_cal_component_rescan (comp);
+
+	return comp;
+}
diff --git a/src/libexchangemapi/e-mapi-cal-utils.h b/src/libexchangemapi/e-mapi-cal-utils.h
index 2091c0a..b512bdb 100644
--- a/src/libexchangemapi/e-mapi-cal-utils.h
+++ b/src/libexchangemapi/e-mapi-cal-utils.h
@@ -128,7 +128,15 @@ gboolean	e_mapi_cal_utils_get_free_busy_data		(EMapiConnection *conn,
 								 GCancellable *cancellable,
 								 GError **mapi_error);
 
-gchar *e_mapi_cal_utils_get_icomp_x_prop (icalcomponent *comp, const gchar *key);
+ECalComponent *	e_mapi_cal_util_object_to_comp			(EMapiConnection *conn,
+								 EMapiObject *object,
+								 icalcomponent_kind kind,
+								 gboolean is_reply,
+								 const gchar *local_store_uri,
+								 const gchar *use_uid,
+								 GSList **detached_components);
+
+gchar *	e_mapi_cal_utils_get_icomp_x_prop (icalcomponent *comp, const gchar *key);
 
 G_END_DECLS
 
diff --git a/src/libexchangemapi/e-mapi-connection.c b/src/libexchangemapi/e-mapi-connection.c
index 5aefef7..e1f89a4 100644
--- a/src/libexchangemapi/e-mapi-connection.c
+++ b/src/libexchangemapi/e-mapi-connection.c
@@ -2195,6 +2195,269 @@ e_mapi_connection_list_objects (EMapiConnection *conn,
 	return ms == MAPI_E_SUCCESS;
 }
 
+static gboolean
+has_embedded_message_with_html (EMapiObject *object)
+{
+	EMapiAttachment *attach;
+
+	if (!object)
+		return FALSE;
+
+	for (attach = object->attachments; attach; attach = attach->next) {
+		if (!attach->embedded_object)
+			continue;
+
+		if (e_mapi_util_find_array_propval (&attach->embedded_object->properties, PidTagHtml) &&
+		    !e_mapi_util_find_array_propval (&attach->embedded_object->properties, PidTagBody))
+			return TRUE;
+
+		if (has_embedded_message_with_html (attach->embedded_object))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gboolean
+get_additional_properties_cb (EMapiConnection *conn,
+			      TALLOC_CTX *mem_ctx,
+			      /* const */ EMapiObject *object,
+			      guint32 obj_index,
+			      guint32 obj_total,
+			      gpointer user_data,
+			      GCancellable *cancellable,
+			      GError **perror)
+{
+	uint32_t ii;
+	EMapiObject *dest_object = user_data;
+
+	g_return_val_if_fail (object != NULL, FALSE);
+	g_return_val_if_fail (dest_object != NULL, FALSE);
+
+	for (ii = 0; ii < object->properties.cValues; ii++) {
+		uint32_t proptag = object->properties.lpProps[ii].ulPropTag;
+
+		if ((proptag & 0xFFFF) == PT_ERROR
+		    || e_mapi_util_find_array_propval (&dest_object->properties, proptag))
+			continue;
+
+		dest_object->properties.cValues++;
+		dest_object->properties.lpProps = talloc_realloc (mem_ctx,
+				    dest_object->properties.lpProps,
+				    struct mapi_SPropValue,
+				    dest_object->properties.cValues + 1);
+		dest_object->properties.lpProps[dest_object->properties.cValues - 1] = object->properties.lpProps[ii];
+
+		#define steal_ptr(x) (x) = talloc_steal (dest_object, (x))
+		switch (proptag & 0xFFFF) {
+		case PT_BOOLEAN:
+		case PT_I2:
+		case PT_LONG:
+		case PT_DOUBLE:
+		case PT_I8:
+		case PT_SYSTIME:
+			break;
+		case PT_STRING8:
+			steal_ptr (dest_object->properties.lpProps[dest_object->properties.cValues - 1].value.lpszA);
+			break;
+		case PT_UNICODE:
+			steal_ptr (dest_object->properties.lpProps[dest_object->properties.cValues - 1].value.lpszW);
+			break;
+		default:
+			g_debug ("%s: Do not know how to steal property type 0x%x, skipping it", G_STRFUNC, proptag & 0xFFFF);
+			dest_object->properties.cValues--;
+			break;
+		}
+		#undef steal_ptr
+
+		dest_object->properties.lpProps[dest_object->properties.cValues].ulPropTag = 0;
+	}
+
+	return TRUE;
+}
+
+static void
+traverse_attachments_for_body (EMapiConnection *conn,
+			       TALLOC_CTX *mem_ctx,
+			       EMapiObject *object,
+			       mapi_object_t *obj_message,
+			       GCancellable *cancellable,
+			       GError **perror)
+{
+	EMapiAttachment *attach;
+
+	g_return_if_fail (conn != NULL);
+	g_return_if_fail (mem_ctx != NULL);
+	g_return_if_fail (obj_message != NULL);
+
+	if (!has_embedded_message_with_html (object))
+		return;
+
+	for (attach = object->attachments; attach && !g_cancellable_is_cancelled (cancellable); attach = attach->next) {
+		if (attach->embedded_object) {
+			const uint32_t *pattach_num;
+			mapi_object_t obj_attach;
+			mapi_object_t obj_embedded;
+			gboolean have_embedded = FALSE;
+
+			pattach_num = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachNumber);
+			if (!pattach_num)
+				continue;
+
+			mapi_object_init (&obj_attach);
+			mapi_object_init (&obj_embedded);
+
+			if (e_mapi_util_find_array_propval (&attach->embedded_object->properties, PidTagHtml) &&
+			    !e_mapi_util_find_array_propval (&attach->embedded_object->properties, PidTagBody)) {
+				struct SPropTagArray *tags;
+
+				if (OpenAttach (obj_message, *pattach_num, &obj_attach) != MAPI_E_SUCCESS)
+					continue;
+
+				if (OpenEmbeddedMessage (&obj_attach, &obj_embedded, MAPI_READONLY) != MAPI_E_SUCCESS) {
+					mapi_object_release (&obj_attach);
+					continue;
+				}
+
+				have_embedded = TRUE;
+
+				tags = set_SPropTagArray (mem_ctx, 1, PidTagBody);
+
+				e_mapi_fast_transfer_properties (conn, mem_ctx, &obj_embedded, tags, get_additional_properties_cb, attach->embedded_object, cancellable, perror);
+
+				talloc_free (tags);
+			}
+
+			if (has_embedded_message_with_html (attach->embedded_object)) {
+				if (!have_embedded) {
+					if (OpenAttach (obj_message, *pattach_num, &obj_attach) != MAPI_E_SUCCESS)
+						continue;
+
+					if (OpenEmbeddedMessage (&obj_attach, &obj_embedded, MAPI_READONLY) != MAPI_E_SUCCESS) {
+						mapi_object_release (&obj_attach);
+						continue;
+					}
+
+					have_embedded = TRUE;
+				}
+
+				traverse_attachments_for_body (conn, mem_ctx, attach->embedded_object, &obj_embedded, cancellable, perror);
+			}
+
+			mapi_object_release (&obj_embedded);
+			mapi_object_release (&obj_attach);
+		}
+	}
+}
+
+struct EnsureAdditionalPropertiesData
+{
+	TransferObjectCB cb;
+	gpointer cb_user_data;
+	mapi_object_t *obj_folder;
+};
+
+static gboolean
+ensure_additional_properties_cb (EMapiConnection *conn,
+				 TALLOC_CTX *mem_ctx,
+				 /* const */ EMapiObject *object,
+				 guint32 obj_index,
+				 guint32 obj_total,
+				 gpointer user_data,
+				 GCancellable *cancellable,
+				 GError **perror)
+{
+	struct ap_data {
+		uint32_t orig_proptag, use_proptag;
+	} additional_properties[] = {
+		{ PidTagBody, MAPI_E_RESERVED },
+		{ PidNameContentClass, MAPI_E_RESERVED }
+	};
+	struct EnsureAdditionalPropertiesData *eap = user_data;
+	gboolean need_any = FALSE, need_attachments;
+	uint32_t ii;
+
+	g_return_val_if_fail (eap != NULL, FALSE);
+	g_return_val_if_fail (eap->cb != NULL, FALSE);
+	g_return_val_if_fail (object != NULL, FALSE);
+
+	for (ii = 0; ii < G_N_ELEMENTS (additional_properties); ii++) {
+		uint32_t prop = additional_properties[ii].orig_proptag;
+
+		if (!e_mapi_util_find_array_propval (&object->properties, prop)) {
+			if (((prop >> 16) & 0xFFFF) >= 0x8000) {
+				prop = e_mapi_connection_resolve_named_prop (conn, mapi_object_get_id (eap->obj_folder), prop, cancellable, NULL);
+			}
+		} else {
+			prop = MAPI_E_RESERVED;
+		}
+
+		additional_properties[ii].use_proptag = prop;
+		need_any = need_any || prop != MAPI_E_RESERVED;
+	}
+
+	need_attachments = has_embedded_message_with_html (object);
+
+	/* Fast-transfer transfers only Html or Body, never both */
+	if (need_any || need_attachments) {
+		const mapi_id_t *mid;
+
+		mid = e_mapi_util_find_array_propval (&object->properties, PidTagMid);
+		if (mid && *mid) {
+			mapi_object_t obj_message;
+			
+			mapi_object_init (&obj_message);
+
+			if (OpenMessage (eap->obj_folder, mapi_object_get_id (eap->obj_folder), *mid, &obj_message, 0) == MAPI_E_SUCCESS) {
+				struct SPropTagArray *tags = NULL;
+
+				for (ii = 0; ii < G_N_ELEMENTS (additional_properties); ii++) {
+					uint32_t prop = additional_properties[ii].use_proptag;
+
+					if (prop == MAPI_E_RESERVED)
+						continue;
+
+					if (!tags)
+						tags = set_SPropTagArray (mem_ctx, 1, prop);
+					else
+						SPropTagArray_add (mem_ctx, tags, prop);
+				}
+
+				if (tags) {
+					uint32_t jj = object->properties.cValues;
+
+					e_mapi_fast_transfer_properties	(conn, mem_ctx, &obj_message, tags, get_additional_properties_cb, object, cancellable, perror);
+
+					while (jj < object->properties.cValues) {
+						for (ii = 0; ii < G_N_ELEMENTS (additional_properties); ii++) {
+							uint32_t proptag = object->properties.lpProps[jj].ulPropTag;
+
+							if (additional_properties[ii].use_proptag == proptag ||
+							    (((proptag & 0xFFFF) == PT_STRING8 || (proptag & 0xFFFF) == PT_UNICODE) &&
+							        (proptag & ~0xFFFF) == (additional_properties[ii].use_proptag & ~0xFFFF))) {
+								/* string8 and unicode properties are interchangeable in the union, luckily */
+								object->properties.lpProps[jj].ulPropTag = additional_properties[ii].orig_proptag;
+								break;
+							}
+						}
+
+						jj++;
+					}
+
+					talloc_free (tags);
+				}
+
+				if (need_attachments)
+					traverse_attachments_for_body (conn, mem_ctx, object, &obj_message, cancellable, perror);
+			}
+
+			mapi_object_release (&obj_message);
+		}
+	}
+
+	return eap->cb (conn, mem_ctx, object, obj_index, obj_total, eap->cb_user_data, cancellable, perror);
+}
+
 /* deals with named IDs transparently, thus it's OK to check with PidLid and PidName constants only */
 gboolean
 e_mapi_connection_transfer_objects (EMapiConnection *conn,
@@ -2209,6 +2472,7 @@ e_mapi_connection_transfer_objects (EMapiConnection *conn,
 	TALLOC_CTX *mem_ctx;
 	mapi_id_array_t ids;
 	const GSList *iter;
+	struct EnsureAdditionalPropertiesData eap;
 
 	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
 	e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
@@ -2237,7 +2501,11 @@ e_mapi_connection_transfer_objects (EMapiConnection *conn,
 		goto cleanup;
 	}
 
-	ms = e_mapi_fast_transfer_objects (conn, mem_ctx, obj_folder, &ids, cb, cb_user_data, cancellable, perror);
+	eap.cb = cb;
+	eap.cb_user_data = cb_user_data;
+	eap.obj_folder = obj_folder;
+
+	ms = e_mapi_fast_transfer_objects (conn, mem_ctx, obj_folder, &ids, ensure_additional_properties_cb, &eap, cancellable, perror);
 
 	mapi_id_array_release (&ids);
 
@@ -2248,6 +2516,25 @@ e_mapi_connection_transfer_objects (EMapiConnection *conn,
 	return ms == MAPI_E_SUCCESS;
 }
 
+gboolean
+e_mapi_connection_transfer_object (EMapiConnection *conn,
+				   mapi_object_t *obj_folder,
+				   mapi_id_t message_id,
+				   TransferObjectCB cb,
+				   gpointer cb_user_data,
+				   GCancellable *cancellable,
+				   GError **perror)
+{
+	GSList *mids;
+	gboolean res;
+
+	mids = g_slist_append (NULL, &message_id);
+	res = e_mapi_connection_transfer_objects (conn, obj_folder, mids, cb, cb_user_data, cancellable, perror);
+	g_slist_free (mids);
+
+	return res;
+}
+
 struct GetSummaryData {
 	guint32 obj_index;
 	guint32 obj_total;
diff --git a/src/libexchangemapi/e-mapi-connection.h b/src/libexchangemapi/e-mapi-connection.h
index 15afe6a..46ce521 100644
--- a/src/libexchangemapi/e-mapi-connection.h
+++ b/src/libexchangemapi/e-mapi-connection.h
@@ -166,7 +166,7 @@ struct _EMapiRecipient
 struct _EMapiAttachment
 {
 	struct mapi_SPropValue_array properties;
-	EMapiObject *embeded_object;
+	EMapiObject *embedded_object;
 
 	EMapiAttachment *next;
 };
@@ -328,6 +328,14 @@ gboolean		e_mapi_connection_transfer_objects	(EMapiConnection *conn,
 								 GCancellable *cancellable,
 								 GError **perror);
 
+gboolean		e_mapi_connection_transfer_object	(EMapiConnection *conn,
+								 mapi_object_t *obj_folder,
+								 mapi_id_t message_id,
+								 TransferObjectCB cb,
+								 gpointer cb_user_data,
+								 GCancellable *cancellable,
+								 GError **perror);
+
 gboolean		e_mapi_connection_transfer_summary	(EMapiConnection *conn,
 								 mapi_object_t *obj_folder,
 								 const GSList *mids,
diff --git a/src/libexchangemapi/e-mapi-debug.c b/src/libexchangemapi/e-mapi-debug.c
index 2508747..a715895 100644
--- a/src/libexchangemapi/e-mapi-debug.c
+++ b/src/libexchangemapi/e-mapi-debug.c
@@ -867,16 +867,16 @@ e_mapi_debug_dump_object (EMapiObject *object, gboolean with_properties, gint in
 	for (index = 0, recipient = object->recipients; recipient; index++, recipient = recipient->next) {
 		g_print ("%*sRecipient[%d]:\n", indent + 2, "", index);
 		if (with_properties)
-			e_mapi_debug_dump_properties (NULL, 0, &recipient->properties, indent + 3);
+			e_mapi_debug_dump_properties (NULL, 0, &recipient->properties, indent + 5);
 	}
 
 	for (index = 0, attachment = object->attachments; attachment; index++, attachment = attachment->next) {
 		g_print ("%*sAttachment[%d]:\n", indent + 2, "", index);
 		if (with_properties)
 			e_mapi_debug_dump_properties (NULL, 0, &attachment->properties, indent + 3);
-		if (attachment->embeded_object) {
-			g_print ("%*sEmbeded object:\n", indent + 3, "");
-			e_mapi_debug_dump_object (attachment->embeded_object, indent + 5, with_properties);
+		if (attachment->embedded_object) {
+			g_print ("%*sEmbedded object:\n", indent + 3, "");
+			e_mapi_debug_dump_object (attachment->embedded_object, with_properties, indent + 5);
 		}
 	}
 }
diff --git a/src/libexchangemapi/e-mapi-fast-transfer.c b/src/libexchangemapi/e-mapi-fast-transfer.c
index 57be53e..fb44646 100644
--- a/src/libexchangemapi/e-mapi-fast-transfer.c
+++ b/src/libexchangemapi/e-mapi-fast-transfer.c
@@ -95,7 +95,7 @@ e_mapi_attachment_new (TALLOC_CTX *mem_ctx)
 
 	attachment->properties.cValues = 0;
 	attachment->properties.lpProps = talloc_zero_array (mem_ctx, struct mapi_SPropValue, 1);
-	attachment->embeded_object = NULL;
+	attachment->embedded_object = NULL;
 	attachment->next = NULL;
 
 	g_assert (attachment->properties.lpProps != NULL);
@@ -109,7 +109,7 @@ e_mapi_attachment_free (EMapiAttachment *attachment)
 	if (!attachment)
 		return;
 
-	e_mapi_object_free (attachment->embeded_object);
+	e_mapi_object_free (attachment->embedded_object);
 	talloc_free (attachment->properties.lpProps);
 	talloc_free (attachment);
 }
@@ -291,15 +291,15 @@ parse_marker_cb (uint32_t marker, void *closure)
 				g_debug ("%s: PidTagStartEmbed no object started", G_STRFUNC);
 			} else if (!data->current_object->attachments) {
 				g_debug ("%s: PidTagStartEmbed no attachment started", G_STRFUNC);
-			} else if (data->current_object->attachments->embeded_object) {
-				g_debug ("%s: PidTagStartEmbed attachment has embeded object already", G_STRFUNC);
+			} else if (data->current_object->attachments->embedded_object) {
+				g_debug ("%s: PidTagStartEmbed attachment has embedded object already", G_STRFUNC);
 			} else {
 				EMapiObject *object;
 
 				object = e_mapi_object_new (data->mem_ctx);
 
 				object->parent = data->current_object;
-				data->current_object->attachments->embeded_object = object;
+				data->current_object->attachments->embedded_object = object;
 				data->current_object = object;
 				data->current_properties = &object->properties;
 			}
@@ -560,3 +560,33 @@ e_mapi_fast_transfer_object (EMapiConnection *conn,
 
 	return ms;
 }
+
+enum MAPISTATUS
+e_mapi_fast_transfer_properties	(EMapiConnection *conn,
+				 TALLOC_CTX *mem_ctx,
+				 mapi_object_t *object,
+				 struct SPropTagArray *tags,
+				 TransferObjectCB cb,
+				 gpointer cb_user_data,
+				 GCancellable *cancellable,
+				 GError **perror)
+{
+	enum MAPISTATUS ms;
+	mapi_object_t fasttransfer_ctx;
+
+	g_return_val_if_fail (tags != NULL, MAPI_E_INVALID_PARAMETER);
+	g_return_val_if_fail (tags->cValues > 0, MAPI_E_INVALID_PARAMETER);
+
+	mapi_object_init (&fasttransfer_ctx);
+
+	ms = FXCopyProperties (object, 0, 0, FastTransfer_Unicode, tags, &fasttransfer_ctx);
+	if (ms == MAPI_E_SUCCESS)
+		ms = e_mapi_fast_transfer_internal (conn, mem_ctx, cb, cb_user_data, 1, FALSE, &fasttransfer_ctx, cancellable, perror);
+
+	mapi_object_release (&fasttransfer_ctx);
+
+	if (perror && !*perror && ms != MAPI_E_SUCCESS)
+		make_mapi_error (perror, G_STRFUNC, ms);
+
+	return ms;
+}
diff --git a/src/libexchangemapi/e-mapi-fast-transfer.h b/src/libexchangemapi/e-mapi-fast-transfer.h
index 7e1d4fb..b604076 100644
--- a/src/libexchangemapi/e-mapi-fast-transfer.h
+++ b/src/libexchangemapi/e-mapi-fast-transfer.h
@@ -58,6 +58,15 @@ enum MAPISTATUS		e_mapi_fast_transfer_object	(EMapiConnection *conn,
 							 GCancellable *cancellable,
 							 GError **perror);
 
+enum MAPISTATUS		e_mapi_fast_transfer_properties	(EMapiConnection *conn,
+							 TALLOC_CTX *mem_ctx,
+							 mapi_object_t *object,
+							 struct SPropTagArray *tags,
+							 TransferObjectCB cb,
+							 gpointer cb_user_data,
+							 GCancellable *cancellable,
+							 GError **perror);
+
 G_END_DECLS
 
 #endif /* E_MAPI_FAST_TRANSFER_H */
diff --git a/src/libexchangemapi/e-mapi-mail-utils.c b/src/libexchangemapi/e-mapi-mail-utils.c
index 77e893d..2f12040 100644
--- a/src/libexchangemapi/e-mapi-mail-utils.c
+++ b/src/libexchangemapi/e-mapi-mail-utils.c
@@ -22,6 +22,7 @@
 #endif
 
 #include <camel/camel.h>
+#include <libecal/e-cal-util.h>
 
 #include "e-mapi-defs.h"
 #include "e-mapi-utils.h"
@@ -977,6 +978,779 @@ mapi_mail_item_to_mime_message (EMapiConnection *conn, MailItem *item)
 	return msg;
 }
 
+void
+e_mapi_mail_utils_decode_email_address (EMapiConnection *conn,
+					struct mapi_SPropValue_array *properties,
+					const uint32_t *name_proptags,
+					guint name_proptags_len,
+					const uint32_t *smtp_proptags,
+					guint smtp_proptags_len,
+					uint32_t email_type_proptag,
+					uint32_t email_proptag,
+					gchar **name,
+					gchar **email)
+{
+	gint ii;
+	const gchar *cname = NULL, *cemail = NULL;
+
+	g_return_if_fail (conn != NULL);
+	g_return_if_fail (properties != NULL);
+	g_return_if_fail (name_proptags_len == 0 || name_proptags != NULL);
+	g_return_if_fail (smtp_proptags_len == 0 || smtp_proptags != NULL);
+	g_return_if_fail (name != NULL);
+	g_return_if_fail (email != NULL);
+
+	*name = NULL;
+	*email = NULL;
+
+	for (ii = 0; ii < name_proptags_len && !cname; ii++) {
+		cname = e_mapi_util_find_array_propval (properties, name_proptags[ii]);
+	}
+
+	for (ii = 0; ii < smtp_proptags_len && !cemail; ii++) {
+		cemail = e_mapi_util_find_array_propval (properties, smtp_proptags[ii]);
+	}
+
+	if (!cemail) {
+		const gchar *addr_type = e_mapi_util_find_array_propval (properties, email_type_proptag);
+		const gchar *email_addr = e_mapi_util_find_array_propval (properties, email_proptag);
+
+		if (addr_type && g_ascii_strcasecmp (addr_type, "EX") == 0 && email_addr)
+			*email = e_mapi_connection_ex_to_smtp (conn, email_addr, name, NULL, NULL);
+		else if (addr_type && g_ascii_strcasecmp (addr_type, "SMTP") == 0)
+			cemail = email_addr;
+	}
+
+	if (!*email) {
+		*name = g_strdup (cname);
+		*email = g_strdup (cemail);
+	}
+}
+
+void
+e_mapi_mail_utils_decode_email_address1 (EMapiConnection *conn,
+					 struct mapi_SPropValue_array *properties,
+					 uint32_t name_proptag,
+					 uint32_t email_proptag,
+					 uint32_t email_type_proptag,
+					 gchar **name,
+					 gchar **email)
+{
+	uint32_t names[1];
+
+	names[0] = name_proptag;
+
+	e_mapi_mail_utils_decode_email_address (conn, properties, names, 1, NULL, 0, email_type_proptag, email_proptag, name, email);
+}
+
+void
+e_mapi_mail_utils_decode_recipients (EMapiConnection *conn,
+				     EMapiRecipient *recipients,
+				     CamelAddress *to_addr,
+				     CamelAddress *cc_addr,
+				     CamelAddress *bcc_addr)
+{
+	const uint32_t name_proptags[] = {
+		PROP_TAG (PT_UNICODE, 0x6001), /* PidTagNickname for Recipients table */
+		PidTagNickname,
+		PidTagDisplayName,
+		PidTagRecipientDisplayName,
+		PidTag7BitDisplayName
+	};
+
+	const uint32_t email_proptags[] = {
+		PidTagPrimarySmtpAddress,
+		PidTagSmtpAddress
+	};
+
+	EMapiRecipient *recipient;
+
+	g_return_if_fail (conn != NULL);
+	g_return_if_fail (to_addr != NULL);
+	g_return_if_fail (cc_addr != NULL);
+	g_return_if_fail (bcc_addr != NULL);
+
+	for (recipient = recipients; recipient; recipient = recipient->next) {
+		const uint32_t *recip_type = e_mapi_util_find_array_propval (&recipient->properties, PidTagRecipientType);
+		gchar *name = NULL, *email = NULL;
+		CamelAddress *addr = NULL;
+
+		if (!recip_type)
+			continue;
+
+		switch (*recip_type) {
+		case MAPI_TO:
+			addr = to_addr;
+			break;
+		case MAPI_CC:
+			addr = cc_addr;
+			break;
+		case MAPI_BCC:
+			addr = bcc_addr;
+			break;
+		default:
+			break;
+		}
+
+		if (!addr)
+			continue;
+
+		e_mapi_mail_utils_decode_email_address (conn, &recipient->properties,
+					name_proptags, G_N_ELEMENTS (name_proptags),
+					email_proptags, G_N_ELEMENTS (email_proptags),
+					PidTagAddressType, PidTagEmailAddress,
+					&name, &email);
+
+		camel_internet_address_add (CAMEL_INTERNET_ADDRESS (addr), name, email ? email : "");
+
+		g_free (name);
+		g_free (email);
+	}
+}
+
+static void
+build_body_part_content (CamelMimePart *part, EMapiObject *object, uint32_t proptag)
+{
+	gconstpointer value;
+
+	g_return_if_fail (part != NULL);
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (proptag == PidTagHtml || proptag == PidTagBody);
+
+	camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_8BIT);
+
+	value = e_mapi_util_find_array_propval (&object->properties, proptag);
+	if (value) {
+		const gchar *type = NULL;
+		gchar *buff = NULL, *in_utf8;
+		const uint32_t *pcpid = e_mapi_util_find_array_propval (&object->properties, PidTagInternetCodepage);
+
+		if (proptag == PidTagBody) {
+			type = "text/plain";
+		} else {
+			type = "text/html";
+		}
+
+		proptag = e_mapi_util_find_array_proptag (&object->properties, proptag);
+		if (pcpid && *pcpid && (proptag & 0xFFFF) != PT_UNICODE) {
+			uint32_t cpid = *pcpid;
+	
+			if (cpid == 20127)
+				buff = g_strdup_printf ("%s; charset=\"us-ascii\"", type);
+			else if (cpid >= 28591 && cpid <= 28599)
+				buff = g_strdup_printf ("%s; charset=\"ISO-8859-%d\"", type, cpid % 10);
+			else if (cpid == 28603)
+				buff = g_strdup_printf ("%s; charset=\"ISO-8859-13\"", type);
+			else if (cpid == 28605)
+				buff = g_strdup_printf ("%s; charset=\"ISO-8859-15\"", type);
+			else if (cpid == 65000)
+				buff = g_strdup_printf ("%s; charset=\"UTF-7\"", type);
+			else if (cpid == 65001)
+				buff = g_strdup_printf ("%s; charset=\"UTF-8\"", type);
+			else
+				buff = g_strdup_printf ("%s; charset=\"CP%d\"", type, cpid);
+			type = buff;
+		}
+
+		in_utf8 = NULL;
+
+		if (proptag == PidTagHtml) {
+			const struct SBinary_short *html_bin = value;
+
+			if (e_mapi_utils_ensure_utf8_string (proptag, pcpid, html_bin->lpb, html_bin->cb, &in_utf8))
+				camel_mime_part_set_content (part, in_utf8, strlen (in_utf8), type);
+			else
+				camel_mime_part_set_content (part, (const gchar *) html_bin->lpb, html_bin->cb, type);
+			
+		} else {
+			const gchar *str = value;
+
+			if (e_mapi_utils_ensure_utf8_string (proptag, pcpid, (const guint8 *) str, strlen (str), &in_utf8))
+				str = in_utf8;
+
+			camel_mime_part_set_content (part, str, strlen (str), type);
+		}
+
+		g_free (in_utf8);
+		g_free (buff);
+	} else
+		camel_mime_part_set_content (part, " ", strlen (" "), "text/plain");
+}
+
+static gboolean
+is_apple_attach (EMapiAttachment *attach, guint32 *data_len, guint32 *resource_len)
+{
+	gboolean is_apple = FALSE;
+	const struct SBinary_short *encoding_bin = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachEncoding);
+	guint8 apple_enc_magic[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x14, 0x03, 0x0B, 0x01 };
+
+	if (encoding_bin && encoding_bin->lpb && encoding_bin->cb == G_N_ELEMENTS (apple_enc_magic)) {
+		gint idx;
+
+		is_apple = TRUE;
+		for (idx = 0; idx < encoding_bin->cb && is_apple; idx++) {
+			is_apple = apple_enc_magic[idx] == encoding_bin->lpb[idx];
+		}
+	}
+
+	if (is_apple) {
+		/* check boundaries too */
+		const struct SBinary_short *data_bin = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachDataBinary);
+
+		is_apple = data_bin && data_bin->lpb && data_bin->cb > 128;
+
+		if (is_apple) {
+			const guint8 *bin = data_bin->lpb;
+
+			/* 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_bin->cb && bin[1] < 64;
+		}
+	}
+
+	return is_apple;
+}
+
+static void
+classify_attachments (EMapiConnection *conn, EMapiAttachment *attachments, const gchar *msg_class, GSList **inline_attachments, GSList **noninline_attachments)
+{
+	EMapiAttachment *attach;
+	gboolean is_smime = msg_class && strstr (msg_class, ".SMIME.") > msg_class;
+
+	g_return_if_fail (inline_attachments != NULL);
+	g_return_if_fail (noninline_attachments != NULL);
+
+	for (attach = attachments; attach != NULL; attach = attach->next) {
+		const gchar *filename, *mime_type, *content_id = NULL;
+		CamelContentType *content_type;
+		CamelMimePart *part;
+		const uint32_t *ui32;
+		const struct SBinary_short *data_bin;
+		gboolean is_apple;
+		guint32 apple_data_len = 0, apple_resource_len = 0;
+
+		data_bin = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachDataBinary);
+		if (!data_bin && !attach->embedded_object) {
+			g_debug ("%s: Skipping attachment without data and without embedded object", G_STRFUNC);
+			continue;
+		}
+
+		is_apple = is_apple_attach (attach, &apple_data_len, &apple_resource_len);
+
+		/* Content-Type */
+		ui32 = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachMethod);
+		if (ui32 && *ui32 == ATTACH_EMBEDDED_MSG) {
+			mime_type = "message/rfc822";
+		} else {
+			mime_type = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachMimeTag);
+			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 = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachLongFilename);
+		if (!filename || !*filename)
+			filename = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachFilename);
+		camel_mime_part_set_filename (part, filename);
+		camel_content_type_set_param (((CamelDataWrapper *) part)->mime_type, "name", filename);
+
+		if (is_apple) {
+			CamelMultipart *mp;
+			gchar *apple_filename;
+			const struct SBinary_short *mac_info_bin;
+
+			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);
+
+			mac_info_bin = e_mapi_util_find_array_propval (&attach->properties, PidNameAttachmentMacInfo);
+			if (mac_info_bin && mac_info_bin->lpb && mac_info_bin->cb > 0) {
+				camel_mime_part_set_content (part, (const gchar *) mac_info_bin->lpb, mac_info_bin->cb, 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, data_bin->lpb + 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);
+			g_object_unref (part);
+
+			part = camel_mime_part_new ();
+
+			apple_filename = g_strndup ((const gchar *) data_bin->lpb + 2, data_bin->lpb[1]);
+			camel_mime_part_set_filename (part, (apple_filename && *apple_filename) ? apple_filename : filename);
+			g_free (apple_filename);
+
+			mime_type = e_mapi_util_find_array_propval (&attach->properties, PidNameAttachmentMacContentType);
+			if (!mime_type)
+				mime_type = "application/octet-stream";
+
+			camel_mime_part_set_content (part, (const gchar *) data_bin->lpb + 128, apple_data_len, mime_type);
+			camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
+			camel_multipart_add_part (mp, part);
+			g_object_unref (part);
+
+			part = camel_mime_part_new ();
+			camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (mp));
+			g_object_unref (mp);
+		} else if (is_smime) {
+			CamelMimeParser *parser;
+			CamelStream *mem;
+
+			mem = camel_stream_mem_new ();
+			camel_stream_write (mem, (const gchar *) data_bin->lpb, data_bin->cb, NULL, NULL);
+			g_seekable_seek (G_SEEKABLE (mem), 0, G_SEEK_SET, NULL, NULL);
+
+			parser = camel_mime_parser_new ();
+			camel_mime_parser_scan_from (parser, FALSE);
+			camel_mime_parser_scan_pre_from (parser, FALSE);
+			camel_mime_parser_init_with_stream (parser, mem, NULL);
+
+			if (camel_mime_parser_step (parser, NULL, NULL) == CAMEL_MIME_PARSER_STATE_HEADER
+			    && camel_mime_parser_content_type (parser) != NULL) {
+				g_object_unref (part);
+				part = camel_mime_part_new ();
+
+				camel_data_wrapper_set_mime_type_field (CAMEL_DATA_WRAPPER (part), camel_mime_parser_content_type (parser));
+				camel_mime_part_construct_content_from_parser (part, parser, NULL, NULL);
+			} else {
+				is_smime = FALSE;
+			}
+
+			g_object_unref (parser);
+			g_object_unref (mem);
+		} 
+
+		if (!is_smime && !is_apple) {
+			if (ui32 && *ui32 == ATTACH_EMBEDDED_MSG && attach->embedded_object) {
+				CamelMimeMessage *embedded_msg;
+
+				embedded_msg = e_mapi_mail_utils_object_to_message (conn, attach->embedded_object);
+				if (embedded_msg) {
+					CamelStream *mem = camel_stream_mem_new ();
+					GByteArray *data;
+
+					data = g_byte_array_new ();
+
+					mem = camel_stream_mem_new ();
+					camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (mem), data);
+					camel_data_wrapper_write_to_stream_sync (
+						CAMEL_DATA_WRAPPER (embedded_msg), mem, NULL, NULL);
+
+					g_object_unref (mem);
+					g_object_unref (embedded_msg);
+
+					camel_mime_part_set_content (part, (const gchar *) data->data, data->len, mime_type);
+
+					g_byte_array_free (data, TRUE);
+				} else {
+					camel_mime_part_set_content (part, (const gchar *) data_bin->lpb, data_bin->cb, mime_type);
+				}
+			} else {
+				camel_mime_part_set_content (part, (const gchar *) data_bin->lpb, data_bin->cb, 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 if (!ui32 || *ui32 != ATTACH_EMBEDDED_MSG)
+				camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
+		}
+
+		/* Content-ID */
+		content_id = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachContentId);
+
+		/* TODO : Add disposition */
+		if (content_id && !is_apple && !is_smime) {
+			camel_mime_part_set_content_id (part, content_id);
+			*inline_attachments = g_slist_append (*inline_attachments, part);
+		} else
+			*noninline_attachments = g_slist_append (*noninline_attachments, part);
+	}
+}
+
+static void
+add_multipart_attachments (CamelMultipart *multipart, GSList *attachments)
+{
+	CamelMimePart *part;
+	while (attachments) {
+		part = attachments->data;
+		camel_multipart_add_part (multipart, part);
+		attachments = attachments->next;
+	}
+}
+
+static CamelMultipart *
+build_multipart_related (EMapiObject *object, GSList *inline_attachments)
+{
+	CamelMimePart *part;
+	CamelMultipart *m_related = camel_multipart_new ();
+	camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_related), "multipart/related");
+	camel_multipart_set_boundary (m_related, NULL);
+
+	if (e_mapi_util_find_array_propval (&object->properties, PidTagHtml)) {
+		part = camel_mime_part_new ();
+		build_body_part_content (part, object, PidTagHtml);
+		camel_multipart_add_part (m_related, part);
+		g_object_unref (part);
+	} else if (e_mapi_util_find_array_propval (&object->properties, PidTagBody)) {
+		part = camel_mime_part_new ();
+		build_body_part_content (part, object, PidTagBody);
+		camel_multipart_add_part (m_related, part);
+		g_object_unref (part);
+	}
+
+	add_multipart_attachments (m_related, inline_attachments);
+
+	return m_related;
+}
+
+static CamelMultipart *
+build_multipart_alternative (EMapiObject *object, GSList *inline_attachments)
+{
+	CamelMimePart *part;
+	CamelMultipart *m_alternative;
+
+	m_alternative = camel_multipart_new ();
+	camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_alternative), "multipart/alternative");
+	camel_multipart_set_boundary (m_alternative, NULL);
+
+	if (e_mapi_util_find_array_propval (&object->properties, PidTagBody)) {
+		part = camel_mime_part_new ();
+		build_body_part_content (part, object, PidTagBody);
+		camel_multipart_add_part (m_alternative, part);
+		g_object_unref (part);
+	}
+
+	if (e_mapi_util_find_array_propval (&object->properties, PidTagHtml)) {
+		part = camel_mime_part_new ();
+		if (inline_attachments) {
+			CamelMultipart *m_related;
+
+			m_related = build_multipart_related (object, inline_attachments);
+			camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (m_related));
+			g_object_unref (m_related);
+		} else {
+			build_body_part_content (part, object, PidTagHtml);
+		}
+		camel_multipart_add_part (m_alternative, part);
+		g_object_unref (part);
+	}
+
+	return m_alternative;
+}
+
+static CamelMultipart *
+build_multipart_mixed (CamelMultipart *content, GSList *attachments)
+{
+	CamelMimePart *part = camel_mime_part_new ();
+	CamelMultipart *m_mixed = camel_multipart_new ();
+	camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_mixed), "multipart/mixed");
+	camel_multipart_set_boundary (m_mixed, NULL);
+
+	camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (content));
+	camel_multipart_add_part (m_mixed, part);
+
+	add_multipart_attachments (m_mixed, attachments);
+
+	return m_mixed;
+}
+
+static gchar *
+build_ical_string (EMapiConnection *conn,
+		   EMapiObject *object,
+		   const gchar *msg_class)
+{
+	gchar *ical_string = NULL, *use_uid;
+	icalcomponent_kind ical_kind = ICAL_NO_COMPONENT;
+	icalproperty_method ical_method = ICAL_METHOD_NONE;
+	const uint64_t *pmid;
+	ECalComponent *comp;
+	icalcomponent *icalcomp;
+	GSList *detached_components = NULL, *iter;
+
+	g_return_val_if_fail (conn != NULL, NULL);
+	g_return_val_if_fail (object != NULL, NULL);
+	g_return_val_if_fail (msg_class != NULL, NULL);
+
+	if (!g_ascii_strcasecmp (msg_class, IPM_SCHEDULE_MEETING_REQUEST)) {
+		ical_method = ICAL_METHOD_REQUEST;
+		ical_kind = ICAL_VEVENT_COMPONENT;
+	} else if (!g_ascii_strcasecmp (msg_class, IPM_SCHEDULE_MEETING_CANCELED)) {
+		ical_method = ICAL_METHOD_CANCEL;
+		ical_kind = ICAL_VEVENT_COMPONENT;
+	} else if (g_str_has_prefix (msg_class, IPM_SCHEDULE_MEETING_RESP_PREFIX)) {
+		ical_method = ICAL_METHOD_REPLY;
+		ical_kind = ICAL_VEVENT_COMPONENT;
+	} else {
+		return NULL;
+	}
+
+	pmid = e_mapi_util_find_array_propval (&object->properties, PidTagMid);
+	if (pmid)
+		use_uid = e_mapi_util_mapi_id_to_string (*pmid);
+	else
+		use_uid = e_cal_component_gen_uid ();
+
+	comp = e_mapi_cal_util_object_to_comp (conn, object, ical_kind, ical_method == ICAL_METHOD_REPLY, NULL, use_uid, &detached_components);
+
+	g_free (use_uid);
+
+	if (!comp)
+		return NULL;
+
+	icalcomp = e_cal_util_new_top_level ();
+	icalcomponent_set_method (icalcomp, ical_method);
+	if (comp)
+		icalcomponent_add_component (icalcomp,
+			icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp)));
+	for (iter = detached_components; iter; iter = g_slist_next (iter)) {
+		icalcomponent_add_component (icalcomp,
+				icalcomponent_new_clone (e_cal_component_get_icalcomponent (iter->data)));
+	}
+
+	ical_string = icalcomponent_as_ical_string_r (icalcomp);
+
+	icalcomponent_free (icalcomp);
+	g_slist_free_full (detached_components, g_object_unref);
+	g_object_unref (comp);
+
+	return ical_string;
+}
+
+CamelMimeMessage *
+e_mapi_mail_utils_object_to_message (EMapiConnection *conn, /* const */ EMapiObject *object)
+{
+	CamelMimeMessage *msg;
+	CamelMultipart *multipart_body = NULL;
+	GSList *inline_attachments, *noninline_attachments;
+	gboolean build_alternative, build_related, build_calendar;
+	const gchar *str, *msg_class;
+	gboolean skip_set_content = FALSE;
+	gchar *ical_string = NULL;
+
+	g_return_val_if_fail (conn != NULL, NULL);
+	g_return_val_if_fail (object != NULL, NULL);
+
+	msg = camel_mime_message_new ();
+
+	str = e_mapi_util_find_array_propval (&object->properties, PidTagTransportMessageHeaders);
+	if (str && *str) {
+		CamelMimePart *part = camel_mime_part_new ();
+		CamelStream *stream;
+		CamelMimeParser *parser;
+
+		stream = camel_stream_mem_new_with_buffer (str, strlen (str));
+		parser = camel_mime_parser_new ();
+		camel_mime_parser_init_with_stream (parser, stream, NULL);
+		camel_mime_parser_scan_from (parser, FALSE);
+		g_object_unref (stream);
+
+		if (camel_mime_part_construct_from_parser_sync (part, parser, NULL, NULL)) {
+			struct _camel_header_raw *h;
+
+			for (h = part->headers; h; h = h->next) {
+				const gchar *value = h->value;
+
+				/* skip all headers describing content of a message,
+				   because it's overwritten on message decomposition */
+				if (g_ascii_strncasecmp (h->name, "Content", 7) == 0)
+					continue;
+
+				while (value && camel_mime_is_lwsp (*value))
+					value++;
+
+				camel_medium_add_header (CAMEL_MEDIUM (msg), h->name, value);
+			}
+		}
+
+		g_object_unref (parser);
+		g_object_unref (part);
+	} else {
+		CamelInternetAddress *to_addr, *cc_addr, *bcc_addr;
+		const struct FILETIME *delivery_time;
+		gchar *name, *email;
+
+		to_addr = camel_internet_address_new ();
+		cc_addr = camel_internet_address_new ();
+		bcc_addr = camel_internet_address_new ();
+
+		e_mapi_mail_utils_decode_recipients (conn, object->recipients, (CamelAddress *) to_addr, (CamelAddress *) cc_addr, (CamelAddress *) bcc_addr);
+
+		camel_mime_message_set_recipients (msg, CAMEL_RECIPIENT_TYPE_TO, to_addr);
+		camel_mime_message_set_recipients (msg, CAMEL_RECIPIENT_TYPE_CC, cc_addr);
+		camel_mime_message_set_recipients (msg, CAMEL_RECIPIENT_TYPE_BCC, bcc_addr);
+
+		g_object_unref (to_addr);
+		g_object_unref (cc_addr);
+		g_object_unref (bcc_addr);
+
+		delivery_time = e_mapi_util_find_array_propval (&object->properties, PidTagMessageDeliveryTime);
+		if (delivery_time) {
+			time_t received_time, actual_time;
+			gint offset = 0;
+
+			received_time = e_mapi_util_filetime_to_time_t (delivery_time);
+			actual_time = camel_header_decode_date (ctime (&received_time), &offset);
+			camel_mime_message_set_date (msg, actual_time, offset);
+		}
+
+		str = e_mapi_util_find_array_propval (&object->properties, PidTagSubject);
+		if (str)
+			camel_mime_message_set_subject (msg, str);
+
+		name = NULL;
+		email = NULL;
+
+		e_mapi_mail_utils_decode_email_address1 (conn, &object->properties,
+			PidTagSentRepresentingName,
+			PidTagSentRepresentingEmailAddress,
+			PidTagSentRepresentingAddressType,
+			&name, &email);
+
+		if (email && *email) {
+			CamelInternetAddress *addr;
+
+			addr = camel_internet_address_new();
+			camel_internet_address_add (addr, name, email);
+			camel_mime_message_set_from (msg, addr);
+		}
+		
+		g_free (name);
+		g_free (email);
+
+		/* Threading */
+		str = e_mapi_util_find_array_propval (&object->properties, PidTagInternetMessageId);
+		if (str)
+			camel_medium_add_header (CAMEL_MEDIUM (msg), "Message-ID", str);
+
+		str = e_mapi_util_find_array_propval (&object->properties, PidTagInternetReferences);
+		if (str)
+			camel_medium_add_header (CAMEL_MEDIUM (msg), "References", str);
+
+		str = e_mapi_util_find_array_propval (&object->properties, PidTagInReplyToId);
+		if (str)
+			camel_medium_add_header (CAMEL_MEDIUM (msg), "In-Reply-To", str);
+	}
+
+	str = e_mapi_util_find_array_propval (&object->properties, PidNameContentClass);
+	if (str)
+		camel_medium_add_header (CAMEL_MEDIUM (msg), "Content-class", str);
+
+	inline_attachments = NULL;
+	noninline_attachments = NULL;
+	msg_class = e_mapi_util_find_array_propval (&object->properties, PidTagMessageClass);
+	classify_attachments (conn, object->attachments, msg_class, &inline_attachments, &noninline_attachments);
+
+	build_calendar = msg_class && g_str_has_prefix (msg_class, IPM_SCHEDULE_MEETING_PREFIX);
+	if (build_calendar) {
+		ical_string = build_ical_string (conn, object, msg_class);
+		if (!ical_string)
+			build_calendar = FALSE;
+	}
+
+	build_alternative = !build_calendar
+		&& e_mapi_util_find_array_propval (&object->properties, PidTagHtml)
+		&& e_mapi_util_find_array_propval (&object->properties, PidTagBody);
+	build_related = !build_calendar && !build_alternative && inline_attachments;
+
+	if (build_calendar) {
+		g_return_val_if_fail (ical_string != NULL, msg);
+
+		camel_mime_part_set_content (CAMEL_MIME_PART (msg), ical_string, strlen (ical_string), "text/calendar");
+	} else if (build_alternative) {
+		multipart_body = build_multipart_alternative (object, inline_attachments);
+	} else if (build_related) {
+		multipart_body = build_multipart_related (object, inline_attachments);
+	} else if (noninline_attachments) {
+		/* Simple multipart/mixed */
+		CamelMimePart *part = camel_mime_part_new ();
+
+		multipart_body = camel_multipart_new ();
+		camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_body), "multipart/mixed");
+		camel_multipart_set_boundary (multipart_body, NULL);
+		if (e_mapi_util_find_array_propval (&object->properties, PidTagHtml))
+			build_body_part_content (part, object, PidTagHtml);
+		else
+			build_body_part_content (part, object, PidTagBody);
+		camel_multipart_add_part (multipart_body, part);
+		g_object_unref (part);
+	} else {
+		/* Flat message */
+		if (e_mapi_util_find_array_propval (&object->properties, PidTagHtml))
+			build_body_part_content (CAMEL_MIME_PART (msg), object, PidTagHtml);
+		else
+			build_body_part_content (CAMEL_MIME_PART (msg), object, PidTagBody);
+	}
+
+	if (noninline_attachments) { /* multipart/mixed */
+		if (build_alternative || build_related || build_calendar) {
+			multipart_body = build_multipart_mixed (multipart_body, noninline_attachments);
+		} else if (g_slist_length (noninline_attachments) == 1 && msg_class && strstr (msg_class, ".SMIME") > msg_class) {
+			CamelMimePart *part = noninline_attachments->data;
+
+			skip_set_content = TRUE;
+
+			camel_medium_set_content (CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER (part));
+
+			if (!strstr (msg_class, ".SMIME.")) {
+				/* encrypted */
+				camel_medium_set_content (CAMEL_MEDIUM (msg), camel_medium_get_content (CAMEL_MEDIUM (part)));
+				camel_mime_part_set_encoding (CAMEL_MIME_PART (msg), camel_mime_part_get_encoding (part));
+			} else {
+				/* signed */
+				camel_medium_set_content (CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER (part));
+			}
+		} else {
+			add_multipart_attachments (multipart_body, noninline_attachments);
+		}
+	}
+
+	if (!skip_set_content && multipart_body)
+		camel_medium_set_content (CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER (multipart_body));
+
+	if (multipart_body)
+		g_object_unref (multipart_body);
+	g_slist_free_full (inline_attachments, g_object_unref);
+	g_slist_free_full (noninline_attachments, g_object_unref);
+	g_free (ical_string);
+
+	return msg;
+}
+
 #define STREAM_SIZE 4000
 
 static void
diff --git a/src/libexchangemapi/e-mapi-mail-utils.h b/src/libexchangemapi/e-mapi-mail-utils.h
index 01c9cf7..0723633 100644
--- a/src/libexchangemapi/e-mapi-mail-utils.h
+++ b/src/libexchangemapi/e-mapi-mail-utils.h
@@ -97,10 +97,36 @@ gboolean mapi_mail_get_item_prop_list (EMapiConnection *conn,
 				       GCancellable *cancellable,
 				       GError **perror);
 
+struct _CamelAddress;
 struct _CamelMimeMessage;
+
 struct _CamelMimeMessage *mapi_mail_item_to_mime_message (EMapiConnection *conn, MailItem *item);
 
-struct _CamelAddress;
+struct _CamelMimeMessage *e_mapi_mail_utils_object_to_message	(EMapiConnection *conn,
+								 /* const */ EMapiObject *object);
+void			e_mapi_mail_utils_decode_email_address	(EMapiConnection *conn,
+								 struct mapi_SPropValue_array *properties,
+								 const uint32_t *name_proptags,
+								 guint name_proptags_len,
+								 const uint32_t *email_proptags,
+								 guint email_proptags_len,
+								 uint32_t email_type_proptag,
+								 uint32_t email_proptag,
+								 gchar **name,
+								 gchar **email);
+void			e_mapi_mail_utils_decode_email_address1	(EMapiConnection *conn,
+								 struct mapi_SPropValue_array *properties,
+								 uint32_t name_proptag,
+								 uint32_t email_proptag,
+								 uint32_t email_type_proptag,
+								 gchar **name,
+								 gchar **email);
+void			e_mapi_mail_utils_decode_recipients	(EMapiConnection *conn,
+								 EMapiRecipient *recipients,
+								 struct _CamelAddress *to,
+								 struct _CamelAddress *cc,
+								 struct _CamelAddress *bcc);
+
 MailItem *mapi_mime_message_to_mail_item (struct _CamelMimeMessage *message, gint32 message_camel_flags, struct _CamelAddress *from, GCancellable *cancellable, GError **error);
 
 /* uses MailItem * as 'data' pointer */
diff --git a/src/libexchangemapi/e-mapi-utils.c b/src/libexchangemapi/e-mapi-utils.c
index 6f5b766..95318dc 100644
--- a/src/libexchangemapi/e-mapi-utils.c
+++ b/src/libexchangemapi/e-mapi-utils.c
@@ -263,6 +263,31 @@ e_mapi_util_find_array_namedid (struct mapi_SPropValue_array *properties, EMapiC
 	return res;
 }
 
+uint32_t
+e_mapi_util_find_array_proptag (struct mapi_SPropValue_array *properties, uint32_t proptag)
+{
+	g_return_val_if_fail (properties != NULL, proptag);
+
+	if ((proptag & 0xFFFF) == PT_STRING8 ||
+	    (proptag & 0xFFFF) == PT_UNICODE) {
+		gint ii;
+		uint32_t tag1, tag2;
+
+		tag1 = (proptag & 0xFFFF0000) | PT_STRING8;
+		tag2 = (proptag & 0xFFFF0000) | PT_UNICODE;
+
+		for (ii = 0; ii < properties->cValues; ii++) {
+			uint32_t tag = properties->lpProps[ii].ulPropTag;
+			if (tag == tag1 || tag == tag2) {
+				proptag = tag;
+				break;
+			}
+		}
+	}
+
+	return proptag;
+}
+
 enum MAPISTATUS
 e_mapi_util_find_array_datetime_propval (struct timeval *tv, struct mapi_SPropValue_array *properties, uint32_t proptag)
 {
@@ -1255,3 +1280,41 @@ e_mapi_utils_destroy_mapi_context (struct mapi_context *mapi_ctx)
 	MAPIUninitialize (mapi_ctx);
 	e_mapi_utils_global_unlock ();
 }
+
+gboolean
+e_mapi_utils_ensure_utf8_string (uint32_t proptag,
+				 const uint32_t *cpid,
+				 const guint8 *buf_data,
+				 guint32 buf_len,
+				 gchar **out_utf8)
+{
+	g_return_val_if_fail (buf_data != NULL, FALSE);
+	g_return_val_if_fail (out_utf8 != NULL, FALSE);
+
+	if (proptag != PidTagHtml && (proptag & 0xFFFF) != PT_UNICODE)
+		return FALSE;
+
+	*out_utf8 = NULL;
+
+	if ((cpid && (*cpid == 1200 || *cpid == 1201)) || (buf_len > 5 && buf_data[3] == '\0')) {
+		/* this is special, get the CPID and transform to utf8 when it's utf16 */
+		gsize written = 0;
+		gchar *in_utf8;
+
+		/* skip Unicode marker, if there */
+		if (buf_len >= 2 && buf_data[0] == 0xFF && buf_data[1] == 0xFE)
+			in_utf8 = g_convert ((const gchar *) buf_data + 2, buf_len - 2, "UTF-8", "UTF-16", NULL, &written, NULL);
+		else
+			in_utf8 = g_convert ((const gchar *) buf_data, buf_len, "UTF-8", "UTF-16", NULL, &written, NULL);
+
+		if (in_utf8 && written > 0) {
+			*out_utf8 = g_strndup (in_utf8, written);
+			g_free (in_utf8);
+		}
+	}
+
+	if (!*out_utf8)
+		*out_utf8 = g_strndup ((const gchar *) buf_data, buf_len);
+
+	return TRUE;
+}
diff --git a/src/libexchangemapi/e-mapi-utils.h b/src/libexchangemapi/e-mapi-utils.h
index 0d47066..83fd432 100644
--- a/src/libexchangemapi/e-mapi-utils.h
+++ b/src/libexchangemapi/e-mapi-utils.h
@@ -34,12 +34,13 @@ gboolean e_mapi_util_mapi_id_from_string (const gchar *str, mapi_id_t *id);
 gchar *  e_mapi_util_mapi_ids_to_uid (mapi_id_t fid, mapi_id_t mid);
 gboolean e_mapi_util_mapi_ids_from_uid (const gchar *str, mapi_id_t *fid, mapi_id_t *mid);
 
-gconstpointer e_mapi_util_find_SPropVal_array_propval (struct SPropValue *values, uint32_t proptag);
-gconstpointer e_mapi_util_find_SPropVal_array_namedid (struct SPropValue *values, EMapiConnection *conn, mapi_id_t fid, uint32_t namedid);
-gconstpointer e_mapi_util_find_row_propval (struct SRow *aRow, uint32_t proptag);
-gconstpointer e_mapi_util_find_row_namedid (struct SRow *aRow, EMapiConnection *conn, mapi_id_t fid, uint32_t namedid);
-gconstpointer e_mapi_util_find_array_propval (struct mapi_SPropValue_array *properties, uint32_t proptag);
-gconstpointer e_mapi_util_find_array_namedid (struct mapi_SPropValue_array *properties, EMapiConnection *conn, mapi_id_t fid, uint32_t namedid);
+gconstpointer	e_mapi_util_find_SPropVal_array_propval (struct SPropValue *values, uint32_t proptag);
+gconstpointer	e_mapi_util_find_SPropVal_array_namedid (struct SPropValue *values, EMapiConnection *conn, mapi_id_t fid, uint32_t namedid);
+gconstpointer	e_mapi_util_find_row_propval (struct SRow *aRow, uint32_t proptag);
+gconstpointer	e_mapi_util_find_row_namedid (struct SRow *aRow, EMapiConnection *conn, mapi_id_t fid, uint32_t namedid);
+gconstpointer	e_mapi_util_find_array_propval (struct mapi_SPropValue_array *properties, uint32_t proptag);
+gconstpointer	e_mapi_util_find_array_namedid (struct mapi_SPropValue_array *properties, EMapiConnection *conn, mapi_id_t fid, uint32_t namedid);
+uint32_t	e_mapi_util_find_array_proptag (struct mapi_SPropValue_array *properties, uint32_t proptag);
 
 enum MAPISTATUS e_mapi_util_find_array_datetime_propval (struct timeval *tv, struct mapi_SPropValue_array *properties, uint32_t proptag);
 enum MAPISTATUS e_mapi_util_find_array_datetime_namedid (struct timeval *tv, struct mapi_SPropValue_array *properties, EMapiConnection *conn, mapi_id_t fid, uint32_t namedid);
@@ -91,6 +92,11 @@ gboolean	e_mapi_utils_add_spropvalue_namedid		(EMapiConnection *conn,
 								 gconstpointer prop_value,
 								 GCancellable *cancellable,
 								 GError **perror);
+gboolean	e_mapi_utils_ensure_utf8_string			(uint32_t proptag,
+								 const uint32_t *cpid,
+								 const guint8 *buf_data,
+								 guint32 buf_len,
+								 gchar **out_utf8);
 
 uint32_t e_mapi_utils_push_crc32 (uint32_t crc32, uint8_t *bytes, uint32_t n_bytes);
 



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