[evolution-mapi] Provide write functions for EMapiObject and use them in Camel
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-mapi] Provide write functions for EMapiObject and use them in Camel
- Date: Mon, 12 Dec 2011 16:19:49 +0000 (UTC)
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]