[evolution-mapi] Provide write functions for EMapiObject and use them in Camel



commit 517be66ee01272c988af85d32255ea3db36b6d15
Author: Milan Crha <mcrha redhat com>
Date:   Mon Dec 12 17:18:51 2011 +0100

    Provide write functions for EMapiObject and use them in Camel

 .../e-mapi-account-listener.c                      |    1 +
 src/camel/camel-mapi-folder.c                      |  280 +-----
 src/camel/camel-mapi-transport.c                   |   55 +-
 src/libexchangemapi/camel-mapi-settings.c          |    2 +
 src/libexchangemapi/e-mapi-connection.c            |  970 +++++++++++++++++++-
 src/libexchangemapi/e-mapi-connection.h            |   45 +-
 src/libexchangemapi/e-mapi-fast-transfer.c         |   42 +
 src/libexchangemapi/e-mapi-folder.c                |    4 +
 src/libexchangemapi/e-mapi-mail-utils.c            |  746 ++++++++++++++--
 src/libexchangemapi/e-mapi-mail-utils.h            |    9 +
 src/libexchangemapi/e-mapi-utils.c                 |   37 +
 src/libexchangemapi/e-mapi-utils.h                 |    4 +
 12 files changed, 1829 insertions(+), 366 deletions(-)
---
diff --git a/src/account-setup-eplugin/e-mapi-account-listener.c b/src/account-setup-eplugin/e-mapi-account-listener.c
index 3498b91..f223c54 100644
--- a/src/account-setup-eplugin/e-mapi-account-listener.c
+++ b/src/account-setup-eplugin/e-mapi-account-listener.c
@@ -887,6 +887,7 @@ add_addressbook_sources (EAccount *account, GSList *folders, mapi_id_t trash_fid
 	g_object_unref (group);
 	g_object_unref (list);
 	g_object_unref (client);
+	camel_url_free (url);
 	g_free (base_uri);
 
 	return TRUE;
diff --git a/src/camel/camel-mapi-folder.c b/src/camel/camel-mapi-folder.c
index 529078a..003367a 100644
--- a/src/camel/camel-mapi-folder.c
+++ b/src/camel/camel-mapi-folder.c
@@ -67,9 +67,6 @@ typedef struct {
 
 /*For collecting summary info from server*/
 
-static void mapi_update_cache (CamelFolder *folder, GSList *list, CamelFolderChangeInfo **changeinfo,
-			       GCancellable *cancellable, GError **error);
-
 static gboolean		mapi_folder_synchronize_sync
 						(CamelFolder *folder,
 						 gboolean expunge,
@@ -184,197 +181,6 @@ mapi_set_message_references (CamelMapiMessageInfo *mapi_mi, const gchar *referen
 }
 
 static void
-mapi_update_cache (CamelFolder *folder, GSList *list, CamelFolderChangeInfo **changeinfo,
-		   GCancellable *cancellable, GError **error)
-{
-	CamelMapiMessageInfo *mi = NULL;
-	CamelMessageInfo *pmi = NULL;
-	CamelMapiStore *mapi_store;
-	CamelStore *parent_store;
-
-	CamelFolderChangeInfo *changes = NULL;
-	gboolean exists = FALSE;
-	GString *str = g_string_new (NULL);
-	const gchar *folder_id = NULL;
-	const gchar *full_name;
-	GSList *item_list = list;
-	gint total_items = g_slist_length (item_list), i=0;
-
-	changes = *changeinfo;
-
-	full_name = camel_folder_get_full_name (folder);
-	parent_store = camel_folder_get_parent_store (folder);
-
-	mapi_store = CAMEL_MAPI_STORE (parent_store);
-
-	folder_id = camel_mapi_store_folder_id_lookup (mapi_store, full_name);
-
-	if (!folder_id) {
-		d(printf("\nERROR - Folder id not present. Cannot refresh info\n"));
-		return;
-	}
-
-	camel_operation_push_message (
-		cancellable,
-		_("Updating local summary cache for new messages in %s"),
-		camel_folder_get_display_name (folder));
-
-	for (; item_list != NULL; item_list = g_slist_next (item_list) ) {
-		MailItem *temp_item;
-		MailItem *item;
-		gchar *msg_uid;
-
-		exists = FALSE;
-
-		temp_item = (MailItem *)item_list->data;
-		item = temp_item;
-
-		camel_operation_progress (cancellable, (100*i)/total_items);
-
-		/************************ First populate summary *************************/
-		mi = NULL;
-		pmi = NULL;
-		msg_uid = e_mapi_util_mapi_id_to_string (item->mid);
-		pmi = camel_folder_summary_get (folder->summary, msg_uid);
-
-		if (pmi) {
-			exists = TRUE;
-			camel_message_info_ref (pmi);
-			mi = (CamelMapiMessageInfo *)pmi;
-		}
-
-		if (!exists) {
-			mi = (CamelMapiMessageInfo *)camel_message_info_new (folder->summary);
-			if (mi->info.content == NULL) {
-				mi->info.content = camel_folder_summary_content_info_new (folder->summary);
-				mi->info.content->type = camel_content_type_new ("multipart", "related");
-			}
-		}
-
-		mi->info.flags = item->header.flags;
-		mi->server_flags = mi->info.flags;
-
-		if (!exists) {
-			GSList *l = NULL;
-			guint32 count_to = 0, count_cc =0;
-			gchar *to = NULL, *cc = NULL;
-
-			mi->info.uid = e_mapi_util_mapi_id_to_string (item->mid);
-			mi->info.subject = camel_pstring_strdup(item->header.subject);
-			mi->info.date_sent = mi->info.date_received = item->header.recieved_time;
-			mi->info.size = (guint32) item->header.size;
-
-			/*Threading related properties*/
-			mapi_set_message_id (mi, item->header.message_id);
-			if (item->header.references || item->header.in_reply_to)
-				mapi_set_message_references (mi, item->header.references, item->header.in_reply_to);
-
-			/*Recipients*/
-			for (l = item->recipients; l; l=l->next) {
-				gchar *formatted_id = NULL;
-				const gchar *name, *display_name;
-				guint32 *type = NULL;
-				struct SRow *aRow;
-				ExchangeMAPIRecipient *recip = (ExchangeMAPIRecipient *)(l->data);
-
-				/* Build a SRow structure */
-				aRow = &recip->out_SRow;
-
-				type = (uint32_t *) e_mapi_util_find_row_propval (aRow, PR_RECIPIENT_TYPE);
-
-				if (type) {
-					name = recip->display_name;
-					name = name ? name : e_mapi_util_find_row_propval (aRow, PR_DISPLAY_NAME_UNICODE);
-					name = name ? name : e_mapi_util_find_row_propval (aRow, PR_RECIPIENT_DISPLAY_NAME_UNICODE);
-					name = name ? name : e_mapi_util_find_row_propval (aRow, PR_7BIT_DISPLAY_NAME_UNICODE);
-					display_name = name ? name : recip->email_id;
-					formatted_id = camel_internet_address_format_address(display_name, recip->email_id ? recip->email_id : "");
-
-					switch (*type) {
-					case MAPI_TO:
-						if (count_to) {
-							gchar *tmp = to;
-							to = g_strconcat (to, ", ", formatted_id, NULL);
-							g_free (formatted_id);
-							g_free (tmp);
-						} else
-							to = formatted_id;
-						count_to++;
-						break;
-
-					case MAPI_CC:
-						if (count_cc) {
-							gchar *tmp = cc;
-							cc = g_strconcat (cc, ", ", formatted_id, NULL);
-							g_free (formatted_id);
-							g_free (tmp);
-						} else
-							cc = formatted_id;
-						count_cc++;
-						break;
-
-					default:
-						continue;
-					}
-				}
-			}
-
-			if ((item->header.from_type != NULL) && !g_utf8_collate (item->header.from_type, "EX")) {
-				gchar *from_email;
-
-				camel_service_lock (CAMEL_SERVICE (mapi_store), CAMEL_SERVICE_REC_CONNECT_LOCK);
-				from_email = e_mapi_connection_ex_to_smtp (camel_mapi_store_get_connection (mapi_store), item->header.from_email, NULL, cancellable, NULL);
-				camel_service_unlock (CAMEL_SERVICE (mapi_store), CAMEL_SERVICE_REC_CONNECT_LOCK);
-
-				g_free (item->header.from_email);
-				item->header.from_email = from_email;
-			}
-
-			item->header.from_email = item->header.from_email ?
-				item->header.from_email : item->header.from;
-
-			if (item->header.from_email) {
-				gchar *from = camel_internet_address_format_address (item->header.from,
-										     item->header.from_email);
-				mi->info.from = camel_pstring_strdup (from);
-
-				g_free (from);
-			} else
-				mi->info.from = NULL;
-
-			/* Fallback */
-			mi->info.to = to ? camel_pstring_strdup (to) : camel_pstring_strdup (item->header.to);
-			mi->info.cc = cc ? camel_pstring_strdup (cc) : camel_pstring_strdup (item->header.cc);
-
-			g_free (to);
-			g_free (cc);
-		}
-
-		if (exists) {
-			camel_folder_change_info_change_uid (changes, mi->info.uid);
-			camel_message_info_free (pmi);
-		} else {
-			camel_folder_summary_lock (folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
-			camel_folder_summary_add (folder->summary,(CamelMessageInfo *)mi);
-			camel_folder_change_info_add_uid (changes, mi->info.uid);
-			camel_folder_change_info_recent_uid (changes, mi->info.uid);
-			camel_folder_summary_unlock (folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
-		}
-
-		/********************* Summary ends *************************/
-		/* FIXME : Don't use folder names for identifying */
-		if (!strcmp (camel_folder_get_full_name (folder), "Junk Mail"))
-			continue;
-
-		g_free (msg_uid);
-		i++;
-	}
-	camel_operation_pop_message (cancellable);
-
-	g_string_free (str, TRUE);
-}
-
-static void
 mapi_utils_do_flags_diff (flags_diff_t *diff, guint32 old, guint32 _new)
 {
 	diff->changed = old ^ _new;
@@ -1153,6 +959,11 @@ mapi_folder_dispose (GObject *object)
 		mapi_folder->cache = NULL;
 	}
 
+	if (mapi_folder->search) {
+		g_object_unref (mapi_folder->search);
+		mapi_folder->search = NULL;
+	}
+
 	parent_store = camel_folder_get_parent_store (CAMEL_FOLDER (mapi_folder));
 	if (parent_store) {
 		camel_store_summary_disconnect_folder_summary (
@@ -1194,6 +1005,31 @@ mapi_folder_constructed (GObject *object)
 	g_free (description);
 }
 
+struct CamelMapiCreateData
+{
+	CamelMimeMessage *message;
+	guint32 message_camel_flags;
+};
+
+static gboolean
+convert_message_to_object_cb (EMapiConnection *conn,
+			      TALLOC_CTX *mem_ctx,
+			      EMapiObject **object, /* out */
+			      gpointer user_data,
+			      GCancellable *cancellable,
+			      GError **perror)
+{
+	struct CamelMapiCreateData *cmc = user_data;
+
+	g_return_val_if_fail (conn != NULL, FALSE);
+	g_return_val_if_fail (mem_ctx != NULL, FALSE);
+	g_return_val_if_fail (object != NULL, FALSE);
+	g_return_val_if_fail (cmc != NULL, FALSE);
+	g_return_val_if_fail (cmc->message != NULL, FALSE);
+
+	return e_mapi_mail_utils_message_to_object (cmc->message, cmc->message_camel_flags, E_MAPI_CREATE_FLAG_NONE, object, mem_ctx, cancellable, perror);
+}
+
 static gboolean
 mapi_folder_append_message_sync (CamelFolder *folder,
                                  CamelMimeMessage *message,
@@ -1204,14 +1040,14 @@ mapi_folder_append_message_sync (CamelFolder *folder,
 {
 	CamelMapiStore *mapi_store;
 	CamelOfflineStore *offline;
-	CamelAddress *from = NULL;
 	CamelStoreInfo *si;
 	CamelStore *parent_store;
-	MailItem *item = NULL;
 	mapi_id_t fid = 0, mid = 0;
 	const gchar *folder_id;
 	const gchar *full_name;
 	guint32 folder_flags = 0;
+	EMapiConnection *conn;
+	mapi_object_t obj_folder;
 	GError *mapi_error = NULL;
 
 	full_name = camel_folder_get_full_name (folder);
@@ -1243,49 +1079,25 @@ mapi_folder_append_message_sync (CamelFolder *folder,
 		return FALSE;
 	}
 
-	folder_id =  camel_mapi_store_folder_id_lookup (mapi_store, full_name);
-
+	folder_id = camel_mapi_store_folder_id_lookup (mapi_store, full_name);
 	e_mapi_util_mapi_id_from_string (folder_id, &fid);
 
 	/* Convert MIME to Item */
-	from = (CamelAddress *) camel_mime_message_get_from (message);
-
-	item = mapi_mime_message_to_mail_item (message, info ? camel_message_info_flags (info) : 0, from, cancellable, error);
-	if (item == NULL)
-		return FALSE;
-
-	mid = e_mapi_connection_create_item (camel_mapi_store_get_connection (mapi_store), -1, fid,
-					 mapi_mail_utils_create_item_build_props, item,
-					 item->recipients, item->attachments,
-					 item->generic_streams, MAPI_OPTIONS_DONT_SUBMIT, cancellable, &mapi_error);
-
-	if (mid) {
-		CamelFolderChangeInfo *changes = camel_folder_change_info_new ();
-		GSList *items = g_slist_append (NULL, item);
-		guint32 flags;
-
-		item->fid = fid;
-		item->mid = mid;
-
-		flags = item->header.flags;
-		item->header.flags = 0;
-		if (flags & MSGFLAG_READ)
-			item->header.flags |= CAMEL_MESSAGE_SEEN;
-		if (flags & MSGFLAG_HASATTACH)
-			item->header.flags |= CAMEL_MESSAGE_ATTACHMENTS;
+	conn = camel_mapi_store_get_connection (mapi_store);
+	if (e_mapi_connection_open_personal_folder (conn, fid, &obj_folder, cancellable, &mapi_error)) {
+		struct CamelMapiCreateData cmc;
 
-		mapi_update_cache (folder, items, &changes, cancellable, error);
+		cmc.message = message;
+		cmc.message_camel_flags = info ? camel_message_info_flags (info) : 0;
 
-		g_slist_free (items);
+		e_mapi_connection_create_object (conn, &obj_folder, E_MAPI_CREATE_FLAG_NONE, convert_message_to_object_cb, &cmc, &mid, cancellable, &mapi_error);
 
-		if (camel_folder_change_info_changed (changes))
-			camel_folder_changed (folder, changes);
-		camel_folder_change_info_free (changes);
+		e_mapi_connection_close_folder (conn, &obj_folder, cancellable, &mapi_error);
 	}
 
-	mail_item_free (item);
-
-	if (!mid) {
+	if (mid) {
+		mapi_refresh_folder (folder, cancellable, error);
+	} else {
 		if (mapi_error) {
 			if (!e_mapi_utils_propagate_cancelled_error (mapi_error, error))
 				g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, mapi_error->message);
@@ -1675,7 +1487,7 @@ mapi_folder_synchronize_sync (CamelFolder *folder,
 			gboolean used = FALSE;
 
 			uid = camel_message_info_uid (info);
-			flags= camel_message_info_flags (info);
+			flags = camel_message_info_flags (info);
 
 			/* Why are we getting so much noise here :-/ */
 			if (!e_mapi_util_mapi_id_from_string (uid, mid)) {
@@ -1782,7 +1594,7 @@ mapi_folder_synchronize_sync (CamelFolder *folder,
 
 	/*Remove messages from local cache*/
 	for (l = deleted_items; l; l = l->next) {
-		gchar * deleted_msg_uid = g_strdup_printf ("%016" G_GINT64_MODIFIER "X%016" G_GINT64_MODIFIER "X", fid, *(mapi_id_t *)l->data);
+		gchar *deleted_msg_uid = e_mapi_util_mapi_id_to_string (*((mapi_id_t *) l->data));
 
 		if (!changes)
 			changes = camel_folder_change_info_new ();
@@ -1792,6 +1604,8 @@ mapi_folder_synchronize_sync (CamelFolder *folder,
 		camel_folder_summary_remove_uid (folder->summary, deleted_msg_uid);
 		camel_data_cache_remove(mapi_folder->cache, "cache", deleted_msg_uid, NULL);
 		camel_folder_summary_unlock (folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+		g_free (deleted_msg_uid);
 	}
 
 	if (changes) {
diff --git a/src/camel/camel-mapi-transport.c b/src/camel/camel-mapi-transport.c
index a39f14c..998c4b8 100644
--- a/src/camel/camel-mapi-transport.c
+++ b/src/camel/camel-mapi-transport.c
@@ -51,37 +51,24 @@
 
 #define STREAM_SIZE 4000
 
-CamelStore *get_store(void);
-
-void	set_store(CamelStore *);
-
 G_DEFINE_TYPE (CamelMapiTransport, camel_mapi_transport, CAMEL_TYPE_TRANSPORT)
 
-/*CreateItem would return the MID of the new message or '0' if we fail.*/
-static mapi_id_t
-mapi_message_item_send (EMapiConnection *conn,
-			MailItem *item,
-			GCancellable *cancellable,
-			GError **perror)
+static gboolean
+convert_message_to_object_cb (EMapiConnection *conn,
+			      TALLOC_CTX *mem_ctx,
+			      EMapiObject **object, /* out */
+			      gpointer user_data,
+			      GCancellable *cancellable,
+			      GError **perror)
 {
-	guint64 fid = 0;
-	mapi_id_t mid = 0;
-
-	#define unset(x) g_free (x); x = NULL
-
-	item->header.flags = MSGFLAG_UNSENT;
-	unset (item->header.from);
-	unset (item->header.from_email);
-	unset (item->header.transport_headers);
-	item->header.recieved_time = 0;
+	CamelMimeMessage *message = user_data;
 
-	#undef unset
+	g_return_val_if_fail (conn != NULL, FALSE);
+	g_return_val_if_fail (mem_ctx != NULL, FALSE);
+	g_return_val_if_fail (object != NULL, FALSE);
+	g_return_val_if_fail (message != NULL, FALSE);
 
-	mid = e_mapi_connection_create_item (conn, olFolderSentMail, fid,
-					 mapi_mail_utils_create_item_build_props, item,
-					 item->recipients, item->attachments, item->generic_streams, MAPI_OPTIONS_DELETE_ON_SUBMIT_FAILURE, cancellable, perror);
-
-	return mid;
+	return e_mapi_mail_utils_message_to_object (message, 0, E_MAPI_CREATE_FLAG_SUBMIT, object, mem_ctx, cancellable, perror);
 }
 
 static gboolean
@@ -93,10 +80,10 @@ mapi_send_to_sync (CamelTransport *transport,
                    GError **error)
 {
 	EMapiConnection *conn;
-	MailItem *item = NULL;
 	const gchar *namep;
 	const gchar *addressp;
-	mapi_id_t st = 0;
+	mapi_id_t mid = 0;
+	mapi_object_t obj_folder;
 	CamelService *service;
 	CamelSettings *settings;
 	const gchar *profile;
@@ -149,15 +136,15 @@ mapi_send_to_sync (CamelTransport *transport,
 		return FALSE;
 	}
 
-	/* Convert MIME to MailItem, attacment lists and recipient list.*/
-	item = mapi_mime_message_to_mail_item (message, 0, from, cancellable, NULL);
+	if (e_mapi_connection_open_default_folder (conn, olFolderSentMail, &obj_folder, cancellable, error)) {
+		e_mapi_connection_create_object (conn, &obj_folder, E_MAPI_CREATE_FLAG_SUBMIT, convert_message_to_object_cb, message, &mid, cancellable, error);
 
-	/* send */
-	st = mapi_message_item_send (conn, item, cancellable, &mapi_error);
+		e_mapi_connection_close_folder (conn, &obj_folder, cancellable, error);
+	}
 
 	g_object_unref (conn);
 
-	if (st == 0) {
+	if (mid == 0) {
 		if (mapi_error) {
 			if (!e_mapi_utils_propagate_cancelled_error (mapi_error, error))
 				g_set_error (
@@ -216,6 +203,4 @@ camel_mapi_transport_class_init (CamelMapiTransportClass *class)
 static void
 camel_mapi_transport_init (CamelMapiTransport *transport)
 {
-
 }
-
diff --git a/src/libexchangemapi/camel-mapi-settings.c b/src/libexchangemapi/camel-mapi-settings.c
index ffeec31..12f8e5a 100644
--- a/src/libexchangemapi/camel-mapi-settings.c
+++ b/src/libexchangemapi/camel-mapi-settings.c
@@ -257,7 +257,9 @@ mapi_settings_finalize (GObject *object)
 
 	priv = CAMEL_MAPI_SETTINGS_GET_PRIVATE (object);
 
+	g_free (priv->domain);
 	g_free (priv->profile);
+	g_free (priv->realm);
 
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (camel_mapi_settings_parent_class)->finalize (object);
diff --git a/src/libexchangemapi/e-mapi-connection.c b/src/libexchangemapi/e-mapi-connection.c
index db7b2de..a607a59 100644
--- a/src/libexchangemapi/e-mapi-connection.c
+++ b/src/libexchangemapi/e-mapi-connection.c
@@ -42,7 +42,10 @@
 #include "e-mapi-fast-transfer.h"
 #include "e-mapi-openchange.h"
 
-#include <param.h>
+//#include <param.h>
+/* how many bytes can be written within one property with SetProps() call;
+   if its size exceeds this limit, it's converted into an EMapiStreamedProp */
+#define MAX_PROPERTY_WRITE_SIZE	2048
 
 static void register_connection (EMapiConnection *conn);
 static void unregister_connection (EMapiConnection *conn);
@@ -2115,7 +2118,7 @@ gather_mapi_SRestriction_named_ids (struct mapi_SRestriction *restriction,
 }
 
 static void
-maybe_replace_named_id_tag (enum MAPITAGS *pproptag,
+maybe_replace_named_id_tag (uint32_t *pproptag,
 			    const ResolveNamedIDsData *named_ids_list,
 			    guint named_ids_len)
 {
@@ -2124,6 +2127,9 @@ maybe_replace_named_id_tag (enum MAPITAGS *pproptag,
 	g_return_if_fail (pproptag != NULL);
 	g_return_if_fail (named_ids_list != NULL);
 
+	if ((((*pproptag) >> 16) & 0xFFFF) < 0x8000)
+		return;
+
 	for (i = 0; i < named_ids_len; i++) {
 		if ((*pproptag) == named_ids_list[i].propid ||
 		    ((((*pproptag) & 0xFFFF) == PT_ERROR) &&
@@ -2140,10 +2146,17 @@ replace_mapi_SRestriction_named_ids (struct mapi_SRestriction *restriction,
 				     guint named_ids_len)
 {
 	guint i;
+	uint32_t proptag;
 
 	g_return_if_fail (restriction != NULL);
 	g_return_if_fail (named_ids_list != NULL);
 
+	#define check_proptag(x) {								\
+			proptag = x;								\
+			maybe_replace_named_id_tag (&proptag, named_ids_list, named_ids_len);	\
+			x = proptag;								\
+		}
+
 	switch (restriction->rt) {
 	case RES_AND:
 		for (i = 0; i < restriction->res.resAnd.cRes; i++) {
@@ -2161,27 +2174,29 @@ replace_mapi_SRestriction_named_ids (struct mapi_SRestriction *restriction,
 		break;
 	#endif
 	case RES_CONTENT:
-		maybe_replace_named_id_tag (&restriction->res.resContent.ulPropTag, named_ids_list, named_ids_len);
-		maybe_replace_named_id_tag (&restriction->res.resContent.lpProp.ulPropTag, named_ids_list, named_ids_len);
+		check_proptag (restriction->res.resContent.ulPropTag);
+		check_proptag (restriction->res.resContent.lpProp.ulPropTag);
 		break;
 	case RES_PROPERTY:
-		maybe_replace_named_id_tag (&restriction->res.resProperty.ulPropTag, named_ids_list, named_ids_len);
-		maybe_replace_named_id_tag (&restriction->res.resProperty.lpProp.ulPropTag, named_ids_list, named_ids_len);
+		check_proptag (restriction->res.resProperty.ulPropTag);
+		check_proptag (restriction->res.resProperty.lpProp.ulPropTag);
 		break;
 	case RES_COMPAREPROPS:
-		maybe_replace_named_id_tag (&restriction->res.resCompareProps.ulPropTag1, named_ids_list, named_ids_len);
-		maybe_replace_named_id_tag (&restriction->res.resCompareProps.ulPropTag2, named_ids_list, named_ids_len);
+		check_proptag (restriction->res.resCompareProps.ulPropTag1);
+		check_proptag (restriction->res.resCompareProps.ulPropTag2);
 		break;
 	case RES_BITMASK:
-		maybe_replace_named_id_tag (&restriction->res.resBitmask.ulPropTag, named_ids_list, named_ids_len);
+		check_proptag (restriction->res.resBitmask.ulPropTag);
 		break;
 	case RES_SIZE:
-		maybe_replace_named_id_tag (&restriction->res.resSize.ulPropTag, named_ids_list, named_ids_len);
+		check_proptag (restriction->res.resSize.ulPropTag);
 		break;
 	case RES_EXIST:
-		maybe_replace_named_id_tag (&restriction->res.resExist.ulPropTag, named_ids_list, named_ids_len);
+		check_proptag (restriction->res.resExist.ulPropTag);
 		break;
 	}
+
+	#undef check_proptag
 }
 
 static gboolean
@@ -3324,13 +3339,940 @@ e_mapi_connection_transfer_summary (EMapiConnection *conn,
 		}
 	}
 
+ cleanup:
+	talloc_free (mem_ctx);
+	UNLOCK ();
+
+	return ms == MAPI_E_SUCCESS;
+}
+
+typedef struct {
+	uint32_t proptag;
+	uint32_t cb;
+	const uint8_t *lpb; /* taken from the original mapi prop, no need to copy the memory */
+} EMapiStreamedProp;
+
+static gboolean
+convert_mapi_props_to_props (EMapiConnection *conn,
+			     mapi_object_t *obj_folder,
+			     const struct mapi_SPropValue_array *mapi_props,
+			     struct SPropValue **props,
+			     uint32_t *propslen,
+			     EMapiStreamedProp **streams, /* can be NULL for no streaming */
+			     guint *streamslen, /* can be NULL only if streams is NULL; is ignored if streams is NULL */
+			     TALLOC_CTX *mem_ctx,
+			     GCancellable *cancellable,
+			     GError **perror)
+{
+	uint16_t ii;
+	ResolveNamedIDsData *named_ids_list = NULL;
+	guint named_ids_len = 0;
+	gboolean res = TRUE;
+
+	e_return_val_mapi_error_if_fail (conn != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (mapi_props != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (props != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (propslen != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (mem_ctx != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	if (streams) {
+		e_return_val_mapi_error_if_fail (streamslen != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	}
+
+	for (ii = 0; ii < mapi_props->cValues; ii++) {
+		gboolean processed = FALSE;
+		uint32_t proptag = mapi_props->lpProps[ii].ulPropTag;
+		gconstpointer propdata = get_mapi_SPropValue_data (&mapi_props->lpProps[ii]);
+
+		maybe_add_named_id_tag (proptag, &named_ids_list, &named_ids_len);
+
+		if (streams && propdata) {
+			/* copy anything longer than 1KB as streams; this doesn't count total packet size needed,
+			   but because this is usually useful only for PidTagBody, PidTagHtml, which are there
+			   only once, then no big deal
+			*/
+
+			uint32_t sz;
+			const gchar *str;
+			const struct SBinary_short *bin;
+
+			#define addstream() {										\
+					if (!*streams) {								\
+						*streams = g_new0 (EMapiStreamedProp, 1);				\
+						*streamslen = 0;							\
+					} else {									\
+						*streams = g_renew (EMapiStreamedProp, *streams, *streamslen + 1);	\
+					}										\
+															\
+					(*streams)[*streamslen].proptag = proptag;					\
+					(*streams)[*streamslen].cb = 0;							\
+					(*streams)[*streamslen].lpb = NULL;						\
+					(*streamslen) += 1;								\
+				}
+
+			switch (proptag & 0xFFFF) {
+			case PT_BINARY:
+				bin = propdata;
+				if (bin->cb > MAX_PROPERTY_WRITE_SIZE) {
+					addstream ();
+					(*streams)[(*streamslen) - 1].cb = bin->cb;
+					(*streams)[(*streamslen) - 1].lpb = bin->lpb;
+					processed = TRUE;
+				}
+				break;
+			case PT_STRING8:
+				str = propdata;
+				sz = get_mapi_property_size (&mapi_props->lpProps[ii]);
+				if (sz > MAX_PROPERTY_WRITE_SIZE) {
+					addstream ();
+					(*streams)[(*streamslen) - 1].cb = sz;
+					(*streams)[(*streamslen) - 1].lpb = (uint8_t *) str;
+					processed = TRUE;
+				}
+				break;
+			case PT_UNICODE:
+				str = propdata;
+				sz = get_mapi_property_size (&mapi_props->lpProps[ii]);
+				if (sz > MAX_PROPERTY_WRITE_SIZE) {
+					gchar *in_unicode;
+					gsize written = 0;
+
+					addstream ();
+
+					in_unicode = g_convert (str, strlen (str), "UTF-16", "UTF-8", NULL, &written, NULL);
+					if (in_unicode && written > 0) {
+						uint8_t *bytes = talloc_zero_size (mem_ctx, written + 2);
+
+						/* skip Unicode marker, if there */
+						if (written >= 2 && (const guchar) in_unicode[0] == 0xFF && (const guchar) in_unicode[1] == 0xFE) {
+							memcpy (bytes, in_unicode + 2, written - 2);
+							written -= 2;
+						} else
+							memcpy (bytes, in_unicode, written);
+
+						/* null-terminated unicode string */
+						(*streams)[(*streamslen) - 1].lpb = bytes;
+						(*streams)[(*streamslen) - 1].cb = written + 2;
+					}
+					g_free (in_unicode);
+					processed = TRUE;
+				}
+				break;
+			}
+
+			#undef addstream
+		}
+
+		if (!processed)
+			e_mapi_utils_add_spropvalue (mem_ctx, props, propslen, proptag, propdata);
+	}
+
+	if (named_ids_list) {
+		res = e_mapi_connection_resolve_named_props (conn, mapi_object_get_id (obj_folder), named_ids_list, named_ids_len, cancellable, perror);
+
+		if (res && *props) {
+			for (ii = 0; ii < *propslen; ii++) {
+				uint32_t proptag = (*props)[ii].ulPropTag;
+
+				maybe_replace_named_id_tag (&proptag, named_ids_list, named_ids_len);
+
+				(*props)[ii].ulPropTag = proptag;
+			}
+		}
+
+		if (res && streams) {
+			for (ii = 0; ii < *streamslen; ii++) {
+				maybe_replace_named_id_tag (&((*streams)[ii].proptag), named_ids_list, named_ids_len);
+			}
+		}
+	}
+
+	g_free (named_ids_list);
+
+	return res;
+}
+
+static gboolean
+write_streamed_prop (EMapiConnection *conn,
+		     mapi_object_t *obj_object,
+		     const EMapiStreamedProp *stream,
+		     GCancellable *cancellable,
+		     GError **perror)
+{
+	enum MAPISTATUS	ms;
+	uint32_t total_written;
+	gboolean done = FALSE;
+	mapi_object_t obj_stream;
+
+	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+	e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (obj_object != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (stream != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+
+	LOCK ();
+
+	mapi_object_init (&obj_stream);
+
 	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
 		ms = MAPI_E_USER_CANCEL;
 		goto cleanup;
 	}
 
+	/* OpenStream on required proptag */
+	ms = OpenStream (obj_object, stream->proptag, STREAM_ACCESS_READWRITE, &obj_stream);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "OpenStream", ms);
+		goto cleanup;
+	}
+
+	/* Set the stream size */
+	ms = SetStreamSize (&obj_stream, stream->cb);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "SetStreamSize", ms);
+		goto cleanup;
+	}
+
+	total_written = 0;
+	/* Write stream */
+	while (!done) {
+		uint16_t cn_written = 0;
+		DATA_BLOB blob;
+
+		if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+			ms = MAPI_E_USER_CANCEL;
+			goto cleanup;
+		}
+
+		blob.length = (stream->cb - total_written) < STREAM_MAX_WRITE_SIZE ?
+			      (stream->cb - total_written) : STREAM_MAX_WRITE_SIZE;
+		blob.data = (uint8_t *) (stream->lpb + total_written);
+
+		ms = WriteStream (&obj_stream, &blob, &cn_written);
+		if (ms != MAPI_E_SUCCESS) {
+			make_mapi_error (perror, "WriteStream", ms);
+			done = TRUE;
+		} else if (cn_written == 0) {
+			done = TRUE;
+		} else {
+			total_written += cn_written;
+			if (total_written >= stream->cb)
+				done = TRUE;
+		}
+	}
+
+	if (ms == MAPI_E_SUCCESS) {
+		/* Commit the stream */
+		ms = CommitStream (&obj_stream);
+		if (ms != MAPI_E_SUCCESS) {
+			make_mapi_error (perror, "CommitStream", ms);
+			goto cleanup;
+		}
+	}
+
  cleanup:
-	talloc_free (mem_ctx);
+	mapi_object_release (&obj_stream);
+
+	UNLOCK ();
+
+	return ms == MAPI_E_SUCCESS;
+}
+
+static gboolean
+update_props_on_object (EMapiConnection *conn,
+			mapi_object_t *obj_folder,
+			mapi_object_t *obj_object,
+			const struct mapi_SPropValue_array *properties,
+			TALLOC_CTX *mem_ctx,
+			GCancellable *cancellable,
+			GError **perror)
+{
+	enum MAPISTATUS	ms;
+	struct SPropValue *props = NULL;
+	uint32_t propslen = 0;
+	EMapiStreamedProp *streams = NULL;
+	guint streamslen = 0;
+
+	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+	e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+
+	LOCK ();
+
+	if (!convert_mapi_props_to_props (conn, obj_folder, properties, &props, &propslen, &streams, &streamslen, mem_ctx, cancellable, perror)) {
+		ms = MAPI_E_CALL_FAILED;
+		make_mapi_error (perror, "convert_mapi_props_to_props", ms);
+		goto cleanup;
+	}
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+		ms = MAPI_E_USER_CANCEL;
+		goto cleanup;
+	}
+
+	if (props) {
+		/* set properties for the item */
+		ms = SetProps (obj_object, MAPI_PROPS_SKIP_NAMEDID_CHECK, props, propslen);
+
+		talloc_free (props);
+
+		if (ms != MAPI_E_SUCCESS) {
+			make_mapi_error (perror, "SetProps", ms);
+			goto cleanup;
+		}
+	}
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+		ms = MAPI_E_USER_CANCEL;
+		goto cleanup;
+	}
+
+	if (streams) {
+		guint ii;
+
+		for (ii = 0; ii < streamslen; ii++) {
+			if (!write_streamed_prop (conn, obj_object, &streams[ii], cancellable, perror)) {
+				ms = MAPI_E_CALL_FAILED;
+				make_mapi_error (perror, "write_streamed_prop", ms);
+				break;
+			}
+
+			if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+				ms = MAPI_E_USER_CANCEL;
+				break;
+			}
+		}
+
+		g_free (streams);
+	}
+ cleanup:
+	UNLOCK ();
+
+	return ms == MAPI_E_SUCCESS;
+}
+
+static gboolean
+update_recipient_properties (EMapiConnection *conn,
+			     mapi_object_t *obj_folder,
+			     struct SRow *aRow,
+			     EMapiRecipient *recipient,
+			     gboolean is_resolved,
+			     TALLOC_CTX *mem_ctx,
+			     GCancellable *cancellable,
+			     GError **perror)
+{
+	struct SPropValue *props = NULL;
+	uint32_t propslen = 0, ii;
+
+	g_return_val_if_fail (recipient != NULL, FALSE);
+
+	if (!convert_mapi_props_to_props (conn, obj_folder, &recipient->properties, &props, &propslen, NULL, NULL, mem_ctx, cancellable, perror))
+		return FALSE;
+
+	for (ii = 0; ii < propslen; ii++) {
+		/* do not overwrite all properties, if recipient was resolved properly */
+		if (!is_resolved
+		    || props[ii].ulPropTag == PidTagRecipientType
+		    || props[ii].ulPropTag == PidTagSendInternetEncoding)
+			SRow_addprop (aRow, props[ii]);
+	}
+
+	return TRUE;
+}
+
+static gboolean
+delete_object_recipients (EMapiConnection *conn,
+			  mapi_object_t *obj_folder,
+			  mapi_object_t *obj_object,
+			  TALLOC_CTX *mem_ctx,
+			  GCancellable *cancellable,
+			  GError **perror)
+{
+	enum MAPISTATUS	ms;
+
+	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+	e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+
+	LOCK ();
+
+	ms = RemoveAllRecipients (obj_object);
+	if (ms != MAPI_E_SUCCESS)
+		make_mapi_error (perror, "RemoveAllRecipients", ms);
+
+	UNLOCK ();
+
+	return ms == MAPI_E_SUCCESS;
+}
+
+static gboolean
+add_object_recipients (EMapiConnection *conn,
+		       mapi_object_t *obj_folder,
+		       mapi_object_t *obj_message,
+		       EMapiRecipient *recipients,
+		       TALLOC_CTX *mem_ctx,
+		       GCancellable *cancellable,
+		       GError **perror)
+{
+	const uint32_t required_tags[] = {PidTagEntryId,
+					  PidTagDisplayName,
+					  PidTagObjectType,
+					  PidTagDisplayType,
+					  PidTagTransmittableDisplayName,
+					  PidTagEmailAddress,
+					  PidTagAddressType,
+					  PidTagSendRichInfo,
+					  PidTag7BitDisplayName/*,
+					  PidTagPrimarySmtpAddress*/};
+	enum MAPISTATUS	ms;
+	struct SPropTagArray *tags;
+	struct SRowSet *rows = NULL;
+	struct PropertyTagArray_r *flagList = NULL;
+	ResolveNamedIDsData *named_ids_list = NULL;
+	guint named_ids_len = 0;
+	const gchar **users = NULL;
+	EMapiRecipient *recipient;
+	EMapiRecipient **recips;
+	uint32_t ii, jj, count = 0;
+	GHashTable *all_proptags;
+	GHashTableIter iter;
+	gpointer key, value;
+
+	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+	e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+
+	count = 0;
+	for (recipient = recipients, ii = 0; recipient; recipient = recipient->next, ii++) {
+		if (!e_mapi_util_find_array_propval (&recipient->properties, PidTagPrimarySmtpAddress)
+		    && !e_mapi_util_find_array_propval (&recipient->properties, PidTagDisplayName))
+			g_debug ("%s: Cannot get email or display name for a recipient %d, skipping it", G_STRFUNC, ii);
+		else
+			count++;
+	}
+
+	if (!count)
+		return TRUE;
+
+	LOCK ();
+
+	all_proptags = g_hash_table_new (g_direct_hash, g_direct_equal);
+	users = g_new0 (const gchar *, count + 1);
+	recips = g_new0 (EMapiRecipient *, count + 1);
+
+	for (ii = 0; ii < G_N_ELEMENTS (required_tags); ii++) {
+		g_hash_table_insert (all_proptags, GUINT_TO_POINTER (required_tags[ii]), GUINT_TO_POINTER (1));
+	}
+
+	for (ii = 0, jj = 0, recipient = recipients; ii < count && recipient != NULL; ii++, recipient = recipient->next) {
+		users[ii] = e_mapi_util_find_array_propval (&recipient->properties, PidTagPrimarySmtpAddress);
+		if (!users[ii])
+			users[ii] = e_mapi_util_find_array_propval (&recipient->properties, PidTagDisplayName);
+		if (!users[ii]) {
+			ii--;
+		} else {
+			uint32_t kk;
+
+			recips[jj] = recipient;
+			jj++;
+
+			for (kk = 0; kk < recipient->properties.cValues; kk++) {
+				g_hash_table_insert (all_proptags, GUINT_TO_POINTER (recipient->properties.lpProps[kk].ulPropTag), GUINT_TO_POINTER (1));
+			}
+		}
+	}
+
+	/* Attempt to resolve names from the server */
+	tags = NULL;
+	g_hash_table_iter_init (&iter, all_proptags);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		uint32_t proptag = GPOINTER_TO_UINT (key);
+
+		maybe_add_named_id_tag (proptag, &named_ids_list, &named_ids_len);
+
+		if (!tags)
+			tags = set_SPropTagArray (mem_ctx, 1, proptag);
+		else
+			SPropTagArray_add (mem_ctx, tags, proptag);
+	}
+
+	if (named_ids_list) {
+		if (!e_mapi_connection_resolve_named_props (conn, mapi_object_get_id (obj_folder), named_ids_list, named_ids_len, cancellable, perror)) {
+			ms = MAPI_E_CALL_FAILED;
+			make_mapi_error (perror, "e_mapi_connection_resolve_named_props", ms);
+			goto cleanup;
+		}
+
+		for (ii = 0; ii < tags->cValues; ii++) {
+			uint32_t proptag = tags->aulPropTag[ii];
+
+			maybe_replace_named_id_tag (&proptag, named_ids_list, named_ids_len);
+
+			tags->aulPropTag[ii] = proptag;
+		}
+	}
+
+	ms = ResolveNames (priv->session, users, tags, &rows, &flagList, MAPI_UNICODE);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "ResolveNames", ms);
+		goto cleanup;
+	}
+
+	g_assert (count == flagList->cValues);
+
+	if (!rows) /* This happens when there are ZERO RESOLVED recipients */
+		rows = talloc_zero (mem_ctx, struct SRowSet);
+
+	for (ii = 0, jj = 0; ii < count; ii++) {
+		recipient = recips[ii];
+
+		if (flagList->aulPropTag[ii] == MAPI_AMBIGUOUS) {
+			/* We should never get an ambiguous resolution as we use the email-id for resolving.
+			 * However, if we do still get an ambiguous entry, we can't handle it :-( */
+			ms = MAPI_E_AMBIGUOUS_RECIP;
+			/* Translators: %s is replaced with an email address which was found ambiguous on a remote server */
+			g_set_error (perror, E_MAPI_ERROR, ms, _("Recipient '%s' is ambiguous"), users[ii]);
+			goto cleanup;
+		} else if (flagList->aulPropTag[ii] == MAPI_UNRESOLVED) {
+			uint32_t last;
+
+			/* If the recipient is unresolved, consider it is a SMTP one */
+			rows->aRow = talloc_realloc (mem_ctx, rows->aRow, struct SRow, rows->cRows + 1);
+			last = rows->cRows;
+			rows->aRow[last].cValues = 0;
+			rows->aRow[last].lpProps = talloc_zero (mem_ctx, struct SPropValue);
+			if (!update_recipient_properties (conn, obj_folder, &rows->aRow[last], recipient, FALSE, mem_ctx, cancellable, perror)) {
+				ms = MAPI_E_CALL_FAILED;
+				goto cleanup;
+			}
+			rows->cRows += 1;
+		} else if (flagList->aulPropTag[ii] == MAPI_RESOLVED) {
+			if (!update_recipient_properties (conn, obj_folder, &rows->aRow[jj], recipient, TRUE, mem_ctx, cancellable, perror)) {
+				ms = MAPI_E_CALL_FAILED;
+				goto cleanup;
+			}
+			jj += 1;
+		}
+	}
+
+	/* Modify the recipient table */
+	ms = ModifyRecipients (obj_message, rows);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "ModifyRecipients", ms);
+		goto cleanup;
+	}
+
+ cleanup:
+	UNLOCK ();
+
+	g_free (users);
+	g_free (recips);
+	g_free (named_ids_list);
+	g_hash_table_destroy (all_proptags);
+
+	return ms == MAPI_E_SUCCESS;
+}
+
+static gboolean
+delete_attachment_cb (EMapiConnection *conn,
+		      mapi_id_t fid,
+		      TALLOC_CTX *mem_ctx,
+		      struct SRow *srow,
+		      guint32 row_index,
+		      guint32 rows_total,
+		      gpointer user_data,
+		      GCancellable *cancellable,
+		      GError **perror)
+{
+	const uint32_t *attach_num;
+	mapi_object_t *obj_object = user_data;
+	enum MAPISTATUS ms;
+
+	g_return_val_if_fail (obj_object != NULL, FALSE);
+
+	attach_num = e_mapi_util_find_row_propval (srow, PidTagAttachNumber);
+	g_return_val_if_fail (attach_num != NULL, FALSE);
+
+	ms = DeleteAttach (obj_object, *attach_num);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "DeleteAttach", ms);
+	}
+
+	return ms == MAPI_E_SUCCESS;
+}
+
+static gboolean
+delete_object_attachments (EMapiConnection *conn,
+			   mapi_object_t *obj_folder,
+			   mapi_object_t *obj_object,
+			   TALLOC_CTX *mem_ctx,
+			   GCancellable *cancellable,
+			   GError **perror)
+{
+	enum MAPISTATUS ms;
+	mapi_object_t obj_table;
+	struct SPropTagArray *proptags;
+
+	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+
+	LOCK ();
+
+	mapi_object_init (&obj_table);
+
+	/* open attachment table */
+	ms = GetAttachmentTable (obj_object, &obj_table);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "GetAttachmentTable", ms);
+		goto cleanup;
+	}
+
+	proptags = set_SPropTagArray (mem_ctx, 1, PidTagAttachNumber);
+
+	ms = SetColumns (&obj_table, proptags);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "SetColumns", ms);
+		goto cleanup;
+	}
+
+	ms = foreach_tablerow (conn, mapi_object_get_id (obj_folder), mem_ctx, &obj_table, delete_attachment_cb, obj_object, cancellable, perror);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "foreach_tablerow", ms);
+	}
+
+ cleanup:
+	mapi_object_release (&obj_table);
+
+	UNLOCK ();
+
+	return ms == MAPI_E_SUCCESS;
+}
+
+static gboolean update_message_with_object (EMapiConnection *conn,
+					    mapi_object_t *obj_folder,
+					    mapi_object_t *obj_message,
+					    EMapiObject *object,
+					    TALLOC_CTX *mem_ctx,
+					    GCancellable *cancellable,
+					    GError **perror);
+
+static gboolean
+add_object_attachments (EMapiConnection *conn,
+			mapi_object_t *obj_folder,
+			mapi_object_t *obj_message,
+			EMapiAttachment *attachments,
+			TALLOC_CTX *mem_ctx,
+			GCancellable *cancellable,
+			GError **perror)
+{
+	enum MAPISTATUS ms = MAPI_E_SUCCESS;
+	EMapiAttachment *attachment;
+
+	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+	e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (obj_folder != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (obj_message != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (mem_ctx != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+
+	LOCK ();
+
+	for (attachment = attachments; attachment && ms == MAPI_E_SUCCESS; attachment = attachment->next) {
+		mapi_object_t obj_attach;
+
+		if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+			ms = MAPI_E_USER_CANCEL;
+			break;
+		}
+
+		mapi_object_init (&obj_attach);
+
+		ms = CreateAttach (obj_message, &obj_attach);
+		if (ms != MAPI_E_SUCCESS) {
+			make_mapi_error (perror, "CreateAttach", ms);
+			goto cleanup;
+		}
+
+		if (!update_props_on_object (conn, obj_folder, &obj_attach, &attachment->properties, mem_ctx, cancellable, perror)) {
+			ms = MAPI_E_CALL_FAILED;
+			make_mapi_error (perror, "update_props_on_object", ms);
+			goto cleanup;
+		}
+
+		if (attachment->embedded_object) {
+			mapi_object_t obj_emb_msg;
+
+			mapi_object_init (&obj_emb_msg);
+
+			ms = OpenEmbeddedMessage (&obj_attach, &obj_emb_msg, MAPI_CREATE);
+			if (ms != MAPI_E_SUCCESS) {
+				make_mapi_error (perror, "OpenEmbeddedMessage", ms);
+				goto cleanup;
+			}
+
+			if (!update_message_with_object (conn, obj_folder, &obj_emb_msg, attachment->embedded_object, mem_ctx, cancellable, perror)) {
+				ms = MAPI_E_CALL_FAILED;
+				make_mapi_error (perror, "SaveChangesMessage", ms);
+				mapi_object_release (&obj_emb_msg);
+				goto cleanup;
+			}
+
+			ms = SaveChangesMessage (&obj_attach, &obj_emb_msg, KeepOpenReadOnly);
+			if (ms != MAPI_E_SUCCESS) {
+				make_mapi_error (perror, "SaveChangesMessage", ms);
+				mapi_object_release (&obj_emb_msg);
+				goto cleanup;
+			}
+
+			mapi_object_release (&obj_emb_msg);
+		}
+
+		ms = SaveChangesAttachment (obj_message, &obj_attach, KeepOpenReadWrite);
+		if (ms != MAPI_E_SUCCESS) {
+			make_mapi_error (perror, "SaveChangesAttachment", ms);
+			goto cleanup;
+		}
+
+	 cleanup:
+		mapi_object_release (&obj_attach);
+	}
+
+	UNLOCK ();
+
+	return ms == MAPI_E_SUCCESS;
+}
+
+static gboolean
+update_message_with_object (EMapiConnection *conn,
+			    mapi_object_t *obj_folder,
+			    mapi_object_t *obj_message,
+			    EMapiObject *object,
+			    TALLOC_CTX *mem_ctx,
+			    GCancellable *cancellable,
+			    GError **perror)
+{
+	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+	e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (obj_folder != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (obj_message != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (object != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+
+	if (!update_props_on_object (conn, obj_folder, obj_message, &object->properties, mem_ctx, cancellable, perror))
+		return FALSE;
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror))
+		return FALSE;
+
+	/* do not touch recipients if not set */
+	if (object->recipients) {
+		/* remove current recipients... */
+		if (!delete_object_recipients (conn, obj_folder, obj_message, mem_ctx, cancellable, perror))
+			return FALSE;
+
+		if (g_cancellable_set_error_if_cancelled (cancellable, perror))
+			return FALSE;
+
+		/* ... and add new */
+		if (!add_object_recipients (conn, obj_folder, obj_message, object->recipients, mem_ctx, cancellable, perror))
+			return FALSE;
+	}
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror))
+		return FALSE;
+
+	/* remove current attachments... */
+	if (!delete_object_attachments (conn, obj_folder, obj_message, mem_ctx, cancellable, perror))
+		return FALSE;
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror))
+		return FALSE;
+
+	/* ... and add new */
+	if (object->attachments && !add_object_attachments (conn, obj_folder, obj_message, object->attachments, mem_ctx, cancellable, perror))
+		return FALSE;
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror))
+		return FALSE;
+
+	return TRUE;
+}
+
+gboolean
+e_mapi_connection_create_object (EMapiConnection *conn,
+				 mapi_object_t *obj_folder,
+				 uint32_t flags, /* bit-or of EMapiCreateFlags */
+				 WriteObjectCB write_object_cb,
+				 gpointer woc_data,
+				 mapi_id_t *out_mid,
+				 GCancellable *cancellable,
+				 GError **perror)
+{
+	enum MAPISTATUS ms;
+	TALLOC_CTX *mem_ctx;
+	EMapiObject *object = NULL;
+	mapi_object_t obj_message;
+
+	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+	e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (obj_folder != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (write_object_cb != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (out_mid != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+
+	LOCK ();
+
+	*out_mid = 0;
+
+	mem_ctx = talloc_new (priv->session);
+	mapi_object_init (&obj_message);
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+		ms = MAPI_E_USER_CANCEL;
+		goto cleanup;
+	}
+
+	if (!write_object_cb (conn, mem_ctx, &object, woc_data, cancellable, perror) || !object) {
+		ms = MAPI_E_CALL_FAILED;
+		make_mapi_error (perror, "write_object_cb", ms);
+		goto cleanup;
+	}
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+		ms = MAPI_E_USER_CANCEL;
+		goto cleanup;
+	}
+
+	ms = CreateMessage (obj_folder, &obj_message);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "CreateMessage", ms);
+		goto cleanup;
+	}
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+		ms = MAPI_E_USER_CANCEL;
+		goto cleanup;
+	}
+
+	if (!update_message_with_object (conn, obj_folder, &obj_message, object, mem_ctx, cancellable, perror)) {
+		ms = MAPI_E_CALL_FAILED;
+		make_mapi_error (perror, "update_message_with_object", ms);
+		goto cleanup;
+	}
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+		ms = MAPI_E_USER_CANCEL;
+		goto cleanup;
+	}
+
+	ms = SaveChangesMessage (obj_folder, &obj_message, KeepOpenReadWrite);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "SaveChangesMessage", ms);
+		goto cleanup;
+	}
+
+	if ((flags & E_MAPI_CREATE_FLAG_SUBMIT) != 0) {
+		/* Mark message as ready to be sent */
+		ms = SubmitMessage (&obj_message);
+		if (ms != MAPI_E_SUCCESS) {
+			mapi_id_t mid;
+			make_mapi_error (perror, "SubmitMessage", ms);
+
+			/*
+			The code is storing message right to Sent items instead of Outbox,
+			because fetching PR_ENTRYID or PR_IPM_SENTMAIL_ENTRYID didn't seem
+			to work in time of doing this change.
+
+			For more information and other possible (correct) approaches see:
+			https://bugzilla.gnome.org/show_bug.cgi?id=561794
+			*/
+			mid = mapi_object_get_id (&obj_message);
+
+			mapi_object_release (&obj_message);
+			/* to not release a message object twice */
+			mapi_object_init (&obj_message);
+
+			ms = DeleteMessage (obj_folder, &mid, 1);
+			if (ms != MAPI_E_SUCCESS) {
+				make_mapi_error (perror, "DeleteMessage", ms);
+			}
+
+			goto cleanup;
+		}
+	}
+
+	*out_mid = mapi_object_get_id (&obj_message);
+
+ cleanup:
+	e_mapi_object_free (object);
+	mapi_object_release (&obj_message);
+	talloc_free (mem_ctx);
+
+	UNLOCK ();
+
+	return ms == MAPI_E_SUCCESS;
+}
+
+gboolean
+e_mapi_connection_modify_object (EMapiConnection *conn,
+				 mapi_object_t *obj_folder,
+				 mapi_id_t mid,
+				 WriteObjectCB write_object_cb,
+				 gpointer woc_data,
+				 GCancellable *cancellable,
+				 GError **perror)
+{
+	enum MAPISTATUS ms;
+	TALLOC_CTX *mem_ctx;
+	EMapiObject *object = NULL;
+	mapi_object_t obj_message;
+
+	CHECK_CORRECT_CONN_AND_GET_PRIV (conn, FALSE);
+	e_return_val_mapi_error_if_fail (priv->session != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (obj_folder != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (write_object_cb != NULL, MAPI_E_INVALID_PARAMETER, FALSE);
+	e_return_val_mapi_error_if_fail (mid != 0, MAPI_E_INVALID_PARAMETER, FALSE);
+
+	LOCK ();
+
+	mem_ctx = talloc_new (priv->session);
+	mapi_object_init (&obj_message);
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+		ms = MAPI_E_USER_CANCEL;
+		goto cleanup;
+	}
+
+	if (!write_object_cb (conn, mem_ctx, &object, woc_data, cancellable, perror)) {
+		ms = MAPI_E_CALL_FAILED;
+		make_mapi_error (perror, "write_object_cb", ms);
+		goto cleanup;
+	}
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+		ms = MAPI_E_USER_CANCEL;
+		goto cleanup;
+	}
+
+	ms = OpenMessage (obj_folder, mapi_object_get_id (obj_folder), mid, &obj_message, MAPI_MODIFY);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "OpenMessage", ms);
+		goto cleanup;
+	}
+
+	if (g_cancellable_set_error_if_cancelled (cancellable, perror)) {
+		ms = MAPI_E_USER_CANCEL;
+		goto cleanup;
+	}
+
+	if (!update_message_with_object (conn, obj_folder, &obj_message, object, mem_ctx, cancellable, perror)) {
+		ms = MAPI_E_CALL_FAILED;
+		make_mapi_error (perror, "update_message_with_object", ms);
+		goto cleanup;
+	}
+
+	ms = SaveChangesMessage (obj_folder, &obj_message, KeepOpenReadOnly);
+	if (ms != MAPI_E_SUCCESS) {
+		make_mapi_error (perror, "SaveChangesMessage", ms);
+		goto cleanup;
+	}
+
+ cleanup:
+	e_mapi_object_free (object);
+	mapi_object_release (&obj_message);
+	talloc_free (mem_ctx);
+
 	UNLOCK ();
 
 	return ms == MAPI_E_SUCCESS;
@@ -5441,14 +6383,14 @@ static void
 set_owner_name (gpointer data, gpointer user_data)
 {
 	EMapiFolder *folder = (EMapiFolder *)(data);
-	folder->owner_name = (gchar *)(user_data);
+	folder->owner_name = g_strdup (user_data);
 }
 
 static void
 set_user_name (gpointer data, gpointer user_data)
 {
 	EMapiFolder *folder = (EMapiFolder *)(data);
-	folder->user_name = (gchar *)(user_data);
+	folder->user_name = g_strdup (user_data);
 }
 
 gboolean
diff --git a/src/libexchangemapi/e-mapi-connection.h b/src/libexchangemapi/e-mapi-connection.h
index 07f40eb..83a9a78 100644
--- a/src/libexchangemapi/e-mapi-connection.h
+++ b/src/libexchangemapi/e-mapi-connection.h
@@ -180,14 +180,23 @@ struct _EMapiObject {
 	EMapiObject *parent; /* chain up to parent's object, if this is embeded attachment */
 };
 
-EMapiRecipient *	e_mapi_recipient_new	(TALLOC_CTX *mem_ctx);
-void			e_mapi_recipient_free	(EMapiRecipient *recipient);
+EMapiRecipient *	e_mapi_recipient_new		(TALLOC_CTX *mem_ctx);
+void			e_mapi_recipient_free		(EMapiRecipient *recipient);
 
-EMapiAttachment *	e_mapi_attachment_new	(TALLOC_CTX *mem_ctx);
-void			e_mapi_attachment_free	(EMapiAttachment *attachment);
+EMapiAttachment *	e_mapi_attachment_new		(TALLOC_CTX *mem_ctx);
+void			e_mapi_attachment_free		(EMapiAttachment *attachment);
 
-EMapiObject *		e_mapi_object_new	(TALLOC_CTX *mem_ctx);
-void			e_mapi_object_free	(EMapiObject *object);
+EMapiObject *		e_mapi_object_new		(TALLOC_CTX *mem_ctx);
+void			e_mapi_object_free		(EMapiObject *object);
+void			e_mapi_object_add_recipient	(EMapiObject *object,
+							 EMapiRecipient *recipient);
+void			e_mapi_object_add_attachment	(EMapiObject *object,
+							 EMapiAttachment *attachment);
+
+typedef enum {
+	E_MAPI_CREATE_FLAG_NONE		= 0,
+	E_MAPI_CREATE_FLAG_SUBMIT	= 1 << 0
+} EMapiCreateFlags;
 
 /* callbacks return whether to continue in transfer of the next object */
 typedef gboolean (*FetchCallback)		(FetchItemsCallbackData *item_data,
@@ -240,6 +249,12 @@ typedef gboolean (*TransferObjectCB)		(EMapiConnection *conn,
 						 gpointer user_data,
 						 GCancellable *cancellable,
 						 GError **perror);
+typedef gboolean (*WriteObjectCB)		(EMapiConnection *conn,
+						 TALLOC_CTX *mem_ctx,
+						 EMapiObject **object, /* out */
+						 gpointer user_data,
+						 GCancellable *cancellable,
+						 GError **perror);
 typedef gboolean (*GetFolderPropertiesCB)	(EMapiConnection *conn,
 						 mapi_id_t fid,
 						 TALLOC_CTX *mem_ctx,
@@ -247,7 +262,6 @@ typedef gboolean (*GetFolderPropertiesCB)	(EMapiConnection *conn,
 						 gpointer user_data,
 						 GCancellable *cancellable,
 						 GError **perror);
-
 typedef gboolean (*ProgressNotifyCB)		(EMapiConnection *conn,
 						 guint32 item_index,
 						 guint32 items_total,
@@ -345,6 +359,23 @@ gboolean		e_mapi_connection_transfer_summary	(EMapiConnection *conn,
 								 GCancellable *cancellable,
 								 GError **perror);
 
+gboolean		e_mapi_connection_create_object		(EMapiConnection *conn,
+								 mapi_object_t *obj_folder,
+								 uint32_t flags, /* bit-or of EMapiCreateFlags */
+								 WriteObjectCB write_object_cb,
+								 gpointer woc_data,
+								 mapi_id_t *out_mid,
+								 GCancellable *cancellable,
+								 GError **perror);
+
+gboolean		e_mapi_connection_modify_object		(EMapiConnection *conn,
+								 mapi_object_t *obj_folder,
+								 mapi_id_t mid,
+								 WriteObjectCB write_object_cb,
+								 gpointer woc_data,
+								 GCancellable *cancellable,
+								 GError **perror);
+
 gboolean		e_mapi_connection_fetch_object_props	(EMapiConnection *conn,
 								 mapi_object_t *obj_folder,
 								 mapi_id_t fid,
diff --git a/src/libexchangemapi/e-mapi-fast-transfer.c b/src/libexchangemapi/e-mapi-fast-transfer.c
index fb44646..1170820 100644
--- a/src/libexchangemapi/e-mapi-fast-transfer.c
+++ b/src/libexchangemapi/e-mapi-fast-transfer.c
@@ -162,6 +162,48 @@ e_mapi_object_free (EMapiObject *object)
 	talloc_free (object);
 }
 
+void
+e_mapi_object_add_recipient (EMapiObject *object,
+			     EMapiRecipient *recipient)
+{
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (recipient != NULL);
+	g_return_if_fail (recipient->next == NULL);
+
+	if (!object->recipients) {
+		object->recipients = recipient;
+	} else {
+		EMapiRecipient *recip = object->recipients;
+
+		while (recip->next) {
+			recip = recip->next;
+		}
+
+		recip->next = recipient;
+	}
+}
+
+void
+e_mapi_object_add_attachment (EMapiObject *object,
+			      EMapiAttachment *attachment)
+{
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (attachment != NULL);
+	g_return_if_fail (attachment->next == NULL);
+
+	if (!object->attachments) {
+		object->attachments = attachment;
+	} else {
+		EMapiAttachment *attach = object->attachments;
+
+		while (attach->next) {
+			attach = attach->next;
+		}
+
+		attach->next = attachment;
+	}
+}
+
 static void
 e_mapi_object_finish_read (EMapiObject *object)
 {
diff --git a/src/libexchangemapi/e-mapi-folder.c b/src/libexchangemapi/e-mapi-folder.c
index babebfb..369db67 100644
--- a/src/libexchangemapi/e-mapi-folder.c
+++ b/src/libexchangemapi/e-mapi-folder.c
@@ -96,6 +96,10 @@ void
 e_mapi_folder_free (EMapiFolder *folder)
 {
 	if (folder) {
+		g_free (folder->owner_name);
+		g_free (folder->owner_email);
+		g_free (folder->user_name);
+		g_free (folder->user_email);
 		g_free (folder->folder_name);
 		g_free (folder);
 	}
diff --git a/src/libexchangemapi/e-mapi-mail-utils.c b/src/libexchangemapi/e-mapi-mail-utils.c
index 34181c1..66912cf 100644
--- a/src/libexchangemapi/e-mapi-mail-utils.c
+++ b/src/libexchangemapi/e-mapi-mail-utils.c
@@ -29,6 +29,8 @@
 #include "e-mapi-cal-utils.h"
 #include "e-mapi-mail-utils.h"
 
+#define STREAM_SIZE 4000
+
 extern gint camel_application_is_exiting;
 
 void
@@ -1361,7 +1363,7 @@ classify_attachments (EMapiConnection *conn, EMapiAttachment *attachments, const
 
 				embedded_msg = e_mapi_mail_utils_object_to_message (conn, attach->embedded_object);
 				if (embedded_msg) {
-					CamelStream *mem = camel_stream_mem_new ();
+					CamelStream *mem;
 					GByteArray *data;
 
 					data = g_byte_array_new ();
@@ -1484,6 +1486,7 @@ build_multipart_mixed (CamelMultipart *content, GSList *attachments)
 
 	camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (content));
 	camel_multipart_add_part (m_mixed, part);
+	g_object_unref (part);
 
 	add_multipart_attachments (m_mixed, attachments);
 
@@ -1752,7 +1755,671 @@ e_mapi_mail_utils_object_to_message (EMapiConnection *conn, /* const */ EMapiObj
 	return msg;
 }
 
-#define STREAM_SIZE 4000
+static void
+e_mapi_mail_add_recipients (EMapiObject *object,
+			    CamelInternetAddress *addresses,
+			    OlMailRecipientType recip_type)
+{
+	gint ii;
+	const gchar *name = NULL, *email = NULL;
+
+	g_return_if_fail (object != NULL);
+
+	for (ii = 0; addresses && camel_internet_address_get (addresses, ii, &name, &email); ii++) {
+		EMapiRecipient *recipient;
+		uint32_t ui32 = 0;
+		bool bl;
+
+		recipient = e_mapi_recipient_new (object);
+		e_mapi_object_add_recipient (object, recipient);
+
+		#define set_value(pt,vl) {								\
+			if (!e_mapi_utils_add_property (&recipient->properties, pt, vl, recipient)) {	\
+				g_warning ("%s: Faield to set property 0x%x", G_STRFUNC, pt);		\
+													\
+				return;									\
+			}										\
+		}
+
+		#define set_str_value(pt,st) set_value (pt, talloc_strdup (recipient, st))
+
+		ui32 = recip_type;
+		set_value (PidTagRecipientType, &ui32);
+
+		if (!name || !*name)
+			name = email;
+
+		if (name && *name) {
+			set_str_value (PidTagDisplayName, name);
+			set_str_value (PidTagRecipientDisplayName, name);
+		}
+		if (email && *email) {
+			set_str_value (PidTagAddressType, "SMTP");
+			set_str_value (PidTagEmailAddress, email);
+
+			set_str_value (PidTagSmtpAddress, email);
+			set_str_value (PidTagPrimarySmtpAddress, email);
+		}
+
+		ui32 = 0;
+		set_value (PidTagSendInternetEncoding, &ui32);
+
+		ui32 = DT_MAILUSER;
+		set_value (PidTagDisplayType, &ui32);
+
+		ui32 = MAPI_MAILUSER;
+		set_value (PidTagObjectType, &ui32);
+
+		bl = false;
+		set_value (PidTagSendRichInfo, &bl);
+
+		#undef set_value
+		#undef set_str_value
+
+		name = NULL;
+		email = NULL;
+	}
+}
+
+static CamelStream *
+get_content_stream (CamelMimePart *part, GCancellable *cancellable)
+{
+	CamelStream *content_stream;
+	CamelStream *filter_stream = NULL;
+	CamelMimeFilterWindows *windows = NULL;
+	CamelDataWrapper *dw;
+
+	g_return_val_if_fail (part != NULL, NULL);
+
+	dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+	g_return_val_if_fail (dw != NULL, NULL);
+
+	content_stream = camel_stream_mem_new();
+
+	if (camel_mime_part_get_content_type (part)) {
+		const gchar *charset = camel_content_type_param (camel_mime_part_get_content_type (part), "charset");
+
+		if (charset && *charset && g_ascii_strcasecmp (charset, "utf8") != 0 && g_ascii_strcasecmp (charset, "utf-8") != 0) {
+			if (g_ascii_strncasecmp (charset, "iso-8859-", 9) == 0) {
+				CamelStream *null;
+
+				/* Since a few Windows mailers like to claim they sent
+				 * out iso-8859-# encoded text when they really sent
+				 * out windows-cp125#, do some simple sanity checking
+				 * before we move on... */
+
+				null = camel_stream_null_new ();
+				filter_stream = camel_stream_filter_new (null);
+				g_object_unref (null);
+
+				windows = (CamelMimeFilterWindows *)camel_mime_filter_windows_new (charset);
+				camel_stream_filter_add (
+					CAMEL_STREAM_FILTER (filter_stream),
+					CAMEL_MIME_FILTER (windows));
+
+				camel_data_wrapper_decode_to_stream_sync (
+					dw, (CamelStream *)filter_stream, cancellable, NULL);
+				camel_stream_flush ((CamelStream *)filter_stream, cancellable, NULL);
+				g_object_unref (filter_stream);
+
+				charset = camel_mime_filter_windows_real_charset (windows);
+			}
+
+			if (charset && *charset) {
+				CamelMimeFilter *filter;
+
+				filter_stream = camel_stream_filter_new (content_stream);
+
+				if ((filter = camel_mime_filter_charset_new (charset, "UTF-8"))) {
+					camel_stream_filter_add (
+						CAMEL_STREAM_FILTER (filter_stream),
+						CAMEL_MIME_FILTER (filter));
+					g_object_unref (filter);
+				} else {
+					g_object_unref (filter_stream);
+					filter_stream = NULL;
+				}
+			}
+		}
+	}
+
+	if (filter_stream) {
+		camel_data_wrapper_decode_to_stream_sync (dw, (CamelStream *) filter_stream, cancellable, NULL);
+		camel_stream_flush (filter_stream, cancellable, NULL);
+		g_object_unref (filter_stream);
+	} else {
+		camel_data_wrapper_decode_to_stream_sync (dw, (CamelStream *) content_stream, cancellable, NULL);
+	}
+
+	if (windows)
+		g_object_unref (windows);
+
+	g_seekable_seek (G_SEEKABLE (content_stream), 0, G_SEEK_SET, NULL, NULL);
+
+	return content_stream;
+}
+
+static void
+e_mapi_mail_content_stream_to_bin (CamelStream *content_stream,
+				   struct SBinary_short *bin,
+				   TALLOC_CTX *mem_ctx,
+				   GCancellable *cancellable)
+{
+	guint8 *buf;
+	guint32	read_size;
+
+	g_return_if_fail (content_stream != NULL);
+	g_return_if_fail (bin != NULL);
+	g_return_if_fail (mem_ctx != NULL);
+
+	buf = g_new0 (guint8 , STREAM_SIZE);
+
+	bin->cb = 0;
+	bin->lpb = NULL;
+
+	g_seekable_seek (G_SEEKABLE (content_stream), 0, G_SEEK_SET, NULL, NULL);
+	while (read_size = camel_stream_read (content_stream, (gchar *) buf, STREAM_SIZE, cancellable, NULL), read_size > 0) {
+		bin->lpb = talloc_realloc (mem_ctx, bin->lpb, uint8_t, bin->cb + read_size);
+		memcpy (bin->lpb + bin->cb, buf, read_size);
+		bin->cb += read_size;
+	}
+
+	g_free (buf);
+}
+
+#define set_attach_value(pt,vl) {						\
+	if (!e_mapi_utils_add_property (&attach->properties, pt, vl, attach)) {	\
+		g_warning ("%s: Failed to set property 0x%x", G_STRFUNC, pt);	\
+		return FALSE;							\
+	}									\
+}
+
+#define set_attach_str_value(pt,st) set_attach_value (pt, talloc_strdup (attach, st))
+
+static gboolean
+e_mapi_mail_add_attach (EMapiObject *object,
+			CamelMimePart *part,
+			CamelStream *content_stream,
+			GCancellable *cancellable)
+{
+	EMapiAttachment *attach;
+	CamelContentType *content_type;
+	const gchar *content_id;
+	const gchar *filename;
+	struct SBinary_short bin;
+	uint32_t ui32;
+
+	g_return_val_if_fail (object != NULL, FALSE);
+	g_return_val_if_fail (part != NULL, FALSE);
+	g_return_val_if_fail (content_stream != NULL, FALSE);
+
+	attach = e_mapi_attachment_new (object);
+	e_mapi_object_add_attachment (object, attach);
+
+	ui32 = ATTACH_BY_VALUE;
+	set_attach_value (PidTagAttachMethod, &ui32);
+	ui32 = -1;
+	set_attach_value (PidTagRenderingPosition, &ui32);
+
+	filename = camel_mime_part_get_filename (part);
+	if (filename) {
+		set_attach_str_value (PidTagAttachFilename, filename);
+		set_attach_str_value (PidTagAttachLongFilename, filename);
+	}
+
+	content_id = camel_mime_part_get_content_id (part);
+	if (content_id)
+		set_attach_str_value (PidTagAttachContentId, content_id);
+
+	content_type  = camel_mime_part_get_content_type (part);
+	if (content_type) {
+		gchar *ct = camel_content_type_simple (content_type);
+		if (ct)
+			set_attach_str_value (PidTagAttachMimeTag, ct);
+		g_free (ct);
+	}
+
+	e_mapi_mail_content_stream_to_bin (content_stream, &bin, attach, cancellable);
+	set_attach_value (PidTagAttachDataBinary, &bin);
+
+	return TRUE;
+}
+
+static gboolean
+e_mapi_mail_add_body (EMapiObject *object,
+		      CamelStream *content_stream,
+		      uint32_t proptag,
+		      GCancellable *cancellable)
+{
+	struct SBinary_short bin = { 0 };
+	gchar *str;
+
+	e_mapi_mail_content_stream_to_bin (content_stream, &bin, object, cancellable);
+	str = talloc_strndup (object, (const gchar *) bin.lpb, bin.cb);
+	talloc_free (bin.lpb);
+
+	if ((proptag & 0xFFFF) == PT_BINARY) {
+		bin.lpb = (uint8_t *) (str ? str : "");
+		bin.cb = strlen ((const gchar *) bin.lpb) + 1;
+		/* include trailing zero ................ ^^^ */
+
+		return e_mapi_utils_add_property (&object->properties, proptag, &bin, object);
+	} else if (str) {
+		if (!e_mapi_utils_add_property (&object->properties, proptag, str, object))
+			return FALSE;
+	} else {
+		return e_mapi_utils_add_property (&object->properties, proptag, talloc_strdup (object, ""), object);
+	}
+
+	return TRUE;
+}
+
+static gboolean
+e_mapi_mail_do_smime_encrypted (EMapiObject *object,
+				CamelMedium *message,
+				gchar **pmsg_class,
+				gchar **ppid_name_content_type,
+				GCancellable *cancellable)
+{
+	EMapiAttachment *attach;
+	CamelStream *content_stream;
+	CamelDataWrapper *dw;
+	CamelContentType *type;
+	uint32_t ui32;
+	struct SBinary_short bin;
+	gchar *content_type_str;
+
+	g_return_val_if_fail (object != NULL, FALSE);
+	g_return_val_if_fail (message != NULL, FALSE);
+	g_return_val_if_fail (pmsg_class != NULL, FALSE);
+	g_return_val_if_fail (ppid_name_content_type != NULL, FALSE);
+
+	g_free (*pmsg_class);
+	*pmsg_class = g_strdup ("IPM.Note.SMIME");
+
+	type = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (message));
+	dw = camel_medium_get_content (message);
+	content_type_str = camel_content_type_format (type);
+
+	g_free (*ppid_name_content_type);
+	*ppid_name_content_type = content_type_str; /* will be freed within the caller */
+
+	content_stream = camel_stream_mem_new ();
+	camel_data_wrapper_decode_to_stream_sync (dw, (CamelStream *) content_stream, cancellable, NULL);
+
+	attach = e_mapi_attachment_new (object);
+	e_mapi_object_add_attachment (object, attach);
+
+	ui32 = ATTACH_BY_VALUE;
+	set_attach_value (PidTagAttachMethod, &ui32);
+	ui32 = -1;
+	set_attach_value (PidTagRenderingPosition, &ui32);
+	set_attach_str_value (PidTagAttachMimeTag, content_type_str);
+	set_attach_str_value (PidTagAttachFilename, "SMIME.txt");
+	set_attach_str_value (PidTagAttachLongFilename, "SMIME.txt");
+	set_attach_str_value (PidTagDisplayName, "SMIME.txt");
+
+	e_mapi_mail_content_stream_to_bin (content_stream, &bin, attach, cancellable);
+	set_attach_value (PidTagAttachDataBinary, &bin);
+
+	g_object_unref (content_stream);
+
+	return TRUE;
+}
+
+static gboolean
+e_mapi_mail_do_smime_signed (EMapiObject *object,
+			     CamelMultipart *multipart,
+			     gchar **pmsg_class,
+			     GCancellable *cancellable)
+{
+	EMapiAttachment *attach;
+	CamelMimePart *content, *signature;
+	CamelStream *content_stream;
+	CamelContentType *type;
+	CamelDataWrapper *dw;
+	uint32_t ui32;
+	struct SBinary_short bin;
+	gchar *content_type_str;
+
+	g_free (*pmsg_class);
+	*pmsg_class = g_strdup ("IPM.Note.SMIME.MultipartSigned");
+
+	content = camel_multipart_get_part (multipart, CAMEL_MULTIPART_SIGNED_CONTENT);
+	signature = camel_multipart_get_part (multipart, CAMEL_MULTIPART_SIGNED_SIGNATURE);
+
+	g_return_val_if_fail (content != NULL, FALSE);
+	g_return_val_if_fail (signature != NULL, FALSE);
+
+	content_stream = get_content_stream (content, cancellable);
+	type = camel_mime_part_get_content_type (content);
+
+	if (camel_content_type_is (type, "text", "plain")) {
+		e_mapi_mail_add_body (object, content_stream, PidTagBody, cancellable);
+	} else if (camel_content_type_is (type, "text", "html")) {
+		e_mapi_mail_add_body (object, content_stream, PidTagHtml, cancellable);
+	} else {
+		e_mapi_mail_add_attach (object, content, content_stream, cancellable);
+	}
+
+	if (content_stream)
+		g_object_unref (content_stream);
+
+	content_stream = camel_stream_mem_new ();
+	dw = CAMEL_DATA_WRAPPER (multipart);
+	type = camel_data_wrapper_get_mime_type_field (dw);
+	content_type_str = camel_content_type_format (type);
+
+	#define wstr(str) camel_stream_write (content_stream, str, strlen (str), cancellable, NULL)
+	wstr("Content-Type: ");
+	wstr(content_type_str);
+	wstr("\n\n");
+	#undef wstr
+
+	g_free (content_type_str);
+
+	camel_data_wrapper_write_to_stream_sync (dw, (CamelStream *) content_stream, cancellable, NULL);
+
+	attach = e_mapi_attachment_new (object);
+	e_mapi_object_add_attachment (object, attach);
+
+	ui32 = ATTACH_BY_VALUE;
+	set_attach_value (PidTagAttachMethod, &ui32);
+	ui32 = -1;
+	set_attach_value (PidTagRenderingPosition, &ui32);
+	set_attach_str_value (PidTagAttachMimeTag, "multipart/signed");
+	set_attach_str_value (PidTagAttachFilename, "SMIME.txt");
+	set_attach_str_value (PidTagAttachLongFilename, "SMIME.txt");
+	set_attach_str_value (PidTagDisplayName, "SMIME.txt");
+
+	e_mapi_mail_content_stream_to_bin (content_stream, &bin, attach, cancellable);
+	set_attach_value (PidTagAttachDataBinary, &bin);
+
+	g_object_unref (content_stream);
+
+	return TRUE;
+}
+
+static gboolean
+e_mapi_mail_do_multipart (EMapiObject *object,
+			  CamelMultipart *mp,
+			  gboolean *is_first,
+			  GCancellable *cancellable)
+{
+	CamelDataWrapper *dw;
+	CamelStream *content_stream;
+	CamelContentType *type;
+	CamelMimePart *part;
+	gint nn, ii;
+
+	g_return_val_if_fail (is_first != NULL, FALSE);
+
+	nn = camel_multipart_get_number (mp);
+	for (ii = 0; ii < nn; ii++) {
+		/* getting part */
+		part = camel_multipart_get_part (mp, ii);
+		if (!part)
+			continue;
+
+		dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+		if (CAMEL_IS_MULTIPART (dw)) {
+			/* recursive */
+			if (!e_mapi_mail_do_multipart (object, CAMEL_MULTIPART (dw), is_first, cancellable))
+				return FALSE;
+			continue;
+		}
+
+		if (CAMEL_IS_MIME_MESSAGE (dw)) {
+			CamelMimeMessage *message;
+			EMapiObject *embedded = NULL;
+			EMapiAttachment *attach;
+
+			attach = e_mapi_attachment_new (object);
+			message = CAMEL_MIME_MESSAGE (dw);
+			if (e_mapi_mail_utils_message_to_object (message, 0, E_MAPI_CREATE_FLAG_NONE, &embedded, attach, cancellable, NULL)) {
+				uint32_t ui32;
+				const gchar *str;
+
+				e_mapi_object_add_attachment (object, attach);
+				attach->embedded_object = embedded;
+				embedded->parent = object;
+
+				ui32 = ATTACH_EMBEDDED_MSG;
+				set_attach_value (PidTagAttachMethod, &ui32);
+				ui32 = 0;
+				set_attach_value (PidTagRenderingPosition, &ui32);
+				set_attach_str_value (PidTagAttachMimeTag, "message/rfc822");
+
+				str = camel_mime_message_get_subject (message);
+				if (str)
+					set_attach_str_value (PidTagAttachFilename, str);
+				continue;
+			} else {
+				e_mapi_attachment_free (attach);
+			}
+		}
+
+		content_stream = get_content_stream (part, cancellable);
+		type = camel_mime_part_get_content_type (part);
+
+		if (ii == 0 && (*is_first) && camel_content_type_is (type, "text", "plain")) {
+			e_mapi_mail_add_body (object, content_stream, PidTagBody, cancellable);
+			*is_first = FALSE;
+		} else if (camel_content_type_is (type, "text", "html")) {
+			e_mapi_mail_add_body (object, content_stream, PidTagHtml, cancellable);
+		} else {
+			e_mapi_mail_add_attach (object, part, content_stream, cancellable);
+		}
+
+		if (content_stream)
+			g_object_unref (content_stream);
+	}
+
+	return TRUE;
+}
+
+#undef set_attach_value
+#undef set_attach_str_value
+
+gboolean
+e_mapi_mail_utils_message_to_object (struct _CamelMimeMessage *message,
+				     guint32 message_camel_flags,
+				     EMapiCreateFlags create_flags,
+				     EMapiObject **pobject,
+				     TALLOC_CTX *mem_ctx,
+				     GCancellable *cancellable,
+				     GError **perror)
+{
+	EMapiObject *object;
+	CamelContentType *content_type;
+	CamelInternetAddress *addresses;
+	const gchar *namep = NULL, *addressp = NULL;
+	const gchar *str;
+	gchar *msg_class = NULL;
+	gchar *pid_name_content_type = NULL;
+	gint ii = 0;
+	uint32_t ui32;
+	bool bl;
+
+	g_return_val_if_fail (message != NULL, FALSE);
+	g_return_val_if_fail (pobject != NULL, FALSE);
+	g_return_val_if_fail (*pobject == NULL, FALSE);
+	g_return_val_if_fail (mem_ctx != NULL, FALSE);
+
+	content_type = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (message));
+	g_return_val_if_fail (content_type != NULL, FALSE);
+
+	/* headers */
+	if ((create_flags & E_MAPI_CREATE_FLAG_SUBMIT) == 0) {
+		/* though invalid, then possible, to pass in a message without any 'from' */
+		CamelInternetAddress *from = camel_mime_message_get_from (message);
+		if (!from || !camel_internet_address_get (from, 0, &namep, &addressp))
+			namep = NULL;
+	}
+
+	object = e_mapi_object_new (mem_ctx);
+
+	#define set_value(pt,vl) {							\
+		if (!e_mapi_utils_add_property (&object->properties, pt, vl, object)) {	\
+			e_mapi_object_free (object);					\
+			g_free (msg_class);						\
+			g_free (pid_name_content_type);					\
+											\
+			g_warning ("%s: Faield to set property 0x%x", G_STRFUNC, pt);	\
+											\
+			return FALSE;							\
+		}									\
+	}
+
+	#define set_str_value(pt,st) set_value (pt, talloc_strdup (object, st))
+
+	ui32 = 65001; /* UTF8 - also used with PR_HTML */
+	set_value (PidTagInternetCodepage, &ui32);
+
+	if ((create_flags & E_MAPI_CREATE_FLAG_SUBMIT) == 0) {
+		ui32 = 0;
+		if (message_camel_flags & CAMEL_MESSAGE_SEEN)
+			ui32 |= MSGFLAG_READ;
+		if (message_camel_flags & CAMEL_MESSAGE_ATTACHMENTS)
+			ui32 |= MSGFLAG_HASATTACH;
+	} else {
+		ui32 = MSGFLAG_UNSENT;
+	}
+	set_value (PidTagMessageFlags, &ui32);
+
+	bl = false;
+	set_value (PidTagSendRichInfo, &bl);
+
+	/* PidTagConversationTopic and PidTagNormalizedSubject, together with PidTagSubjectPrefix
+	   are computed from PidTagSubject by a server */
+	str = camel_mime_message_get_subject (message);
+	if (str)
+		set_str_value (PidTagSubject, str);
+
+	/* some properties may not be set when submitting a message */
+	if ((create_flags & E_MAPI_CREATE_FLAG_SUBMIT) == 0) {
+		time_t msg_time = 0;
+		gint msg_time_offset = 0;
+		GArray *headers;
+
+		if (namep && *namep)
+			set_str_value (PidTagSentRepresentingName, namep);
+
+		if (addressp && *addressp) {
+			set_str_value (PidTagSentRepresentingAddressType, "SMTP");
+			set_str_value (PidTagSentRepresentingEmailAddress, addressp);
+		}
+
+		msg_time = camel_mime_message_get_date (message, &msg_time_offset);
+		if (msg_time == CAMEL_MESSAGE_DATE_CURRENT)
+			msg_time = camel_mime_message_get_date_received (message, &msg_time_offset);
+		if (msg_time != 0) {
+			struct FILETIME msg_date = { 0 };
+
+			e_mapi_util_time_t_to_filetime (msg_time, &msg_date);
+
+			set_value (PidTagMessageDeliveryTime, &msg_date);
+		}
+
+		headers = camel_medium_get_headers (CAMEL_MEDIUM (message));
+		if (headers) {
+			GString *hstr = g_string_new ("");
+
+			for (ii = 0; ii < headers->len; ii++) {
+				CamelMediumHeader *h = &g_array_index (headers, CamelMediumHeader, ii);
+
+				if (!h->name || !*h->name || g_ascii_strncasecmp (h->name, "X-Evolution", 11) == 0)
+					continue;
+
+				g_string_append_printf (hstr, "%s: %s\n", h->name, h->value ? h->value : "");
+			}
+
+			camel_medium_free_headers (CAMEL_MEDIUM (message), headers);
+
+			if (hstr->len && hstr->str)
+				set_str_value (PidTagTransportMessageHeaders, hstr->str);
+
+			g_string_free (hstr, TRUE);
+		}
+	}
+
+	str = camel_medium_get_header ((CamelMedium *) message, "References");
+	if (str)
+		set_str_value (PidTagInternetReferences, str);
+
+	str = camel_medium_get_header ((CamelMedium *) message, "In-Reply-To");
+	if (str)
+		set_str_value (PidTagInReplyToId, str);
+
+	str = camel_medium_get_header ((CamelMedium *) message, "Message-ID");
+	if (str)
+		set_str_value (PidTagInternetMessageId, str);
+
+	addresses = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO);
+	e_mapi_mail_add_recipients (object, addresses, olTo);
+
+	addresses = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC);
+	e_mapi_mail_add_recipients (object, addresses, olCC);
+
+	addresses = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_BCC);
+	e_mapi_mail_add_recipients (object, addresses, olBCC);
+
+	if (camel_content_type_is (content_type, "application", "x-pkcs7-mime") ||
+	    camel_content_type_is (content_type, "application", "pkcs7-mime")) {
+		e_mapi_mail_do_smime_encrypted (object, CAMEL_MEDIUM (message), &msg_class, &pid_name_content_type, cancellable);
+	} else {
+		CamelDataWrapper *dw = NULL;
+		CamelStream *content_stream;
+		CamelMultipart *multipart;
+
+		/* contents body */
+		dw = camel_medium_get_content (CAMEL_MEDIUM (message));
+		if (CAMEL_IS_MULTIPART (dw)) {
+			gboolean is_first = TRUE;
+
+			multipart = CAMEL_MULTIPART (dw);
+
+			if (CAMEL_IS_MULTIPART_SIGNED (multipart) && camel_multipart_get_number (multipart) == 2) {
+				e_mapi_mail_do_smime_signed (object, multipart, &msg_class, cancellable);
+			} else {
+				e_mapi_mail_do_multipart (object, multipart, &is_first, cancellable);
+			}
+		} else if (dw) {
+			CamelContentType *type;
+			CamelMimePart *part = CAMEL_MIME_PART (message);
+
+			content_stream = get_content_stream (part, cancellable);
+			type = camel_data_wrapper_get_mime_type_field (dw);
+
+			if (camel_content_type_is (type, "text", "plain")) {
+				e_mapi_mail_add_body (object, content_stream, PidTagBody, cancellable);
+			} else if (camel_content_type_is (type, "text", "html")) {
+				e_mapi_mail_add_body (object, content_stream, PidTagHtml, cancellable);
+			} else {
+				e_mapi_mail_add_attach (object, part, content_stream, cancellable);
+			}
+
+			if (content_stream)
+				g_object_unref (content_stream);
+		}
+	}
+
+	if (msg_class)
+		set_str_value (PidTagMessageClass, msg_class);
+
+	if (pid_name_content_type)
+		set_str_value (PidNameContentType, pid_name_content_type);
+
+	g_free (msg_class);
+	g_free (pid_name_content_type);
+
+	*pobject = object;
+
+	#undef set_value
+	#undef set_str_value
+
+	return TRUE;
+}
 
 static void
 mail_item_add_recipient (const gchar *recipients, OlMailRecipientType type, GSList **recipient_list)
@@ -1972,81 +2639,6 @@ mail_item_add_attach (MailItem *item, CamelMimePart *part, CamelStream *content_
 	return TRUE;
 }
 
-static CamelStream *
-get_content_stream (CamelMimePart *part, GCancellable *cancellable)
-{
-	CamelStream *content_stream;
-	CamelStream *filter_stream = NULL;
-	CamelMimeFilterWindows *windows = NULL;
-	CamelDataWrapper *dw;
-
-	g_return_val_if_fail (part != NULL, NULL);
-
-	dw = camel_medium_get_content (CAMEL_MEDIUM (part));
-	g_return_val_if_fail (dw != NULL, NULL);
-
-	content_stream = camel_stream_mem_new();
-
-	if (camel_mime_part_get_content_type (part)) {
-		const gchar *charset = camel_content_type_param (camel_mime_part_get_content_type (part), "charset");
-
-		if (charset && *charset && g_ascii_strcasecmp (charset, "utf8") != 0 && g_ascii_strcasecmp (charset, "utf-8") != 0) {
-			if (g_ascii_strncasecmp (charset, "iso-8859-", 9) == 0) {
-				CamelStream *null;
-
-				/* Since a few Windows mailers like to claim they sent
-				 * out iso-8859-# encoded text when they really sent
-				 * out windows-cp125#, do some simple sanity checking
-				 * before we move on... */
-
-				null = camel_stream_null_new ();
-				filter_stream = camel_stream_filter_new (null);
-				g_object_unref (null);
-
-				windows = (CamelMimeFilterWindows *)camel_mime_filter_windows_new (charset);
-				camel_stream_filter_add (
-					CAMEL_STREAM_FILTER (filter_stream),
-					CAMEL_MIME_FILTER (windows));
-
-				camel_data_wrapper_decode_to_stream_sync (
-					dw, (CamelStream *)filter_stream, cancellable, NULL);
-				camel_stream_flush ((CamelStream *)filter_stream, cancellable, NULL);
-				g_object_unref (filter_stream);
-
-				charset = camel_mime_filter_windows_real_charset (windows);
-			}
-
-			if (charset && *charset) {
-				CamelMimeFilter *filter;
-
-				filter_stream = camel_stream_filter_new (content_stream);
-
-				if ((filter = camel_mime_filter_charset_new (charset, "UTF-8"))) {
-					camel_stream_filter_add (
-						CAMEL_STREAM_FILTER (filter_stream),
-						CAMEL_MIME_FILTER (filter));
-					g_object_unref (filter);
-				} else {
-					g_object_unref (filter_stream);
-					filter_stream = NULL;
-				}
-			}
-		}
-	}
-
-	if (filter_stream) {
-		camel_data_wrapper_decode_to_stream_sync (dw, (CamelStream *) filter_stream, cancellable, NULL);
-		camel_stream_flush (filter_stream, cancellable, NULL);
-		g_object_unref (filter_stream);
-	} else {
-		camel_data_wrapper_decode_to_stream_sync (dw, (CamelStream *) content_stream, cancellable, NULL);
-	}
-
-	g_seekable_seek (G_SEEKABLE (content_stream), 0, G_SEEK_SET, NULL, NULL);
-
-	return content_stream;
-}
-
 static void
 mapi_do_smime_signed (MailItem *item, CamelMultipart *multipart, GCancellable *cancellable, GError **error)
 {
diff --git a/src/libexchangemapi/e-mapi-mail-utils.h b/src/libexchangemapi/e-mapi-mail-utils.h
index 0723633..01518fc 100644
--- a/src/libexchangemapi/e-mapi-mail-utils.h
+++ b/src/libexchangemapi/e-mapi-mail-utils.h
@@ -104,6 +104,15 @@ struct _CamelMimeMessage *mapi_mail_item_to_mime_message (EMapiConnection *conn,
 
 struct _CamelMimeMessage *e_mapi_mail_utils_object_to_message	(EMapiConnection *conn,
 								 /* const */ EMapiObject *object);
+
+gboolean		e_mapi_mail_utils_message_to_object	(struct _CamelMimeMessage *message,
+								 guint32 message_camel_flags,
+								 EMapiCreateFlags create_flags,
+								 EMapiObject **pobject,
+								 TALLOC_CTX *mem_ctx,
+								 GCancellable *cancellable,
+								 GError **perror);
+
 void			e_mapi_mail_utils_decode_email_address	(EMapiConnection *conn,
 								 struct mapi_SPropValue_array *properties,
 								 const uint32_t *name_proptags,
diff --git a/src/libexchangemapi/e-mapi-utils.c b/src/libexchangemapi/e-mapi-utils.c
index 1c6e6d8..be5a598 100644
--- a/src/libexchangemapi/e-mapi-utils.c
+++ b/src/libexchangemapi/e-mapi-utils.c
@@ -1058,6 +1058,43 @@ e_mapi_utils_add_spropvalue_namedid (EMapiConnection *conn,
 	return e_mapi_utils_add_spropvalue (mem_ctx, values_array, n_values, prop_tag, prop_value);
 }
 
+gboolean
+e_mapi_utils_add_property (struct mapi_SPropValue_array *properties,
+			   uint32_t proptag,
+			   gconstpointer propvalue,
+			   TALLOC_CTX *mem_ctx)
+{
+	uint32_t ii;
+	struct SPropValue sprop = { 0 };
+
+	g_return_val_if_fail (properties != NULL, FALSE);
+	g_return_val_if_fail (proptag != 0, FALSE);
+	g_return_val_if_fail (propvalue != NULL, FALSE);
+	g_return_val_if_fail (mem_ctx != NULL, FALSE);
+
+	sprop.ulPropTag = proptag;
+	g_return_val_if_fail (set_SPropValue (&sprop, propvalue), FALSE);
+
+	for (ii = 0; ii < properties->cValues; ii++) {
+		if (properties->lpProps[ii].ulPropTag == proptag) {
+			cast_mapi_SPropValue (mem_ctx, &(properties->lpProps[ii]), &sprop);
+			break;
+		}
+	}
+
+	if (ii == properties->cValues) {
+		properties->cValues++;
+		properties->lpProps = talloc_realloc (mem_ctx,
+			properties->lpProps,
+			struct mapi_SPropValue,
+			properties->cValues + 1);
+		cast_mapi_SPropValue (mem_ctx, &(properties->lpProps[properties->cValues - 1]), &sprop);
+		properties->lpProps[properties->cValues].ulPropTag = 0;
+	}
+
+	return TRUE;
+}
+
 /* the first call should be with crc32 set to 0 */
 uint32_t
 e_mapi_utils_push_crc32 (uint32_t crc32, uint8_t *bytes, uint32_t n_bytes)
diff --git a/src/libexchangemapi/e-mapi-utils.h b/src/libexchangemapi/e-mapi-utils.h
index 6be9ac9..04c9459 100644
--- a/src/libexchangemapi/e-mapi-utils.h
+++ b/src/libexchangemapi/e-mapi-utils.h
@@ -89,6 +89,10 @@ gboolean	e_mapi_utils_add_spropvalue_namedid		(EMapiConnection *conn,
 								 gconstpointer prop_value,
 								 GCancellable *cancellable,
 								 GError **perror);
+gboolean	e_mapi_utils_add_property			(struct mapi_SPropValue_array *properties,
+								 uint32_t proptag,
+								 gconstpointer propvalue,
+								 TALLOC_CTX *mem_ctx);
 gboolean	e_mapi_utils_ensure_utf8_string			(uint32_t proptag,
 								 const uint32_t *cpid,
 								 const guint8 *buf_data,



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