[evolution-ews/wip/mcrha/office365] Implement read of mail messages
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews/wip/mcrha/office365] Implement read of mail messages
- Date: Wed, 24 Jun 2020 17:47:41 +0000 (UTC)
commit 1fe26995cdfb7086838a025036182fdef152f84c
Author: Milan Crha <mcrha redhat com>
Date: Wed Jun 24 19:46:55 2020 +0200
Implement read of mail messages
src/Office365/camel/camel-o365-folder.c | 642 ++++++++++++++++++++-
src/Office365/camel/camel-o365-store.c | 274 ++++++++-
src/Office365/camel/camel-o365-store.h | 4 +-
src/Office365/common/e-o365-connection.c | 188 +++++-
src/Office365/common/e-o365-connection.h | 40 +-
src/Office365/common/e-o365-json-utils.c | 386 ++++++++++++-
src/Office365/common/e-o365-json-utils.h | 123 +++-
.../evolution/e-mail-config-o365-backend.c | 3 +-
8 files changed, 1590 insertions(+), 70 deletions(-)
---
diff --git a/src/Office365/camel/camel-o365-folder.c b/src/Office365/camel/camel-o365-folder.c
index 7d4f9e42..b51382bc 100644
--- a/src/Office365/camel/camel-o365-folder.c
+++ b/src/Office365/camel/camel-o365-folder.c
@@ -32,6 +32,24 @@
#define O365_LOCAL_CACHE_PATH "cur"
+/* https://docs.microsoft.com/en-us/graph/api/resources/message?view=graph-rest-1.0 */
+#define O365_FETCH_SUMMARY_PROPERTIES "categories," \
+ "ccRecipients," \
+ "changeKey," \
+ "flag," \
+ "from," \
+ "hasAttachments," \
+ "id," \
+ "importance," \
+ "internetMessageHeaders," \
+ "internetMessageId," \
+ "isRead," \
+ "receivedDateTime," \
+ "sender," \
+ "sentDateTime," \
+ "subject," \
+ "toRecipients"
+
#define LOCK_CACHE(_folder) g_rec_mutex_lock (&_folder->priv->cache_lock)
#define UNLOCK_CACHE(_folder) g_rec_mutex_unlock (&_folder->priv->cache_lock)
@@ -44,6 +62,11 @@ struct _CamelO365FolderPrivate {
GMutex search_lock;
CamelFolderSearch *search;
+
+ /* To not download the same message multiple times from different threads */
+ GMutex get_message_lock;
+ GCond get_message_cond;
+ GHashTable *get_message_hash; /* borrowed gchar *uid ~> NULL */
};
G_DEFINE_TYPE_WITH_PRIVATE (CamelO365Folder, camel_o365_folder, CAMEL_TYPE_OFFLINE_FOLDER)
@@ -174,16 +197,6 @@ o365_folder_get_message_from_cache (CamelO365Folder *o365_folder,
return msg;
}
-static gchar *
-o365_folder_get_filename (CamelFolder *folder,
- const gchar *uid,
- GError **error)
-{
- CamelO365Folder *o365_folder = CAMEL_O365_FOLDER (folder);
-
- return o365_folder_cache_dup_filename (o365_folder, uid);
-}
-
static void
o365_folder_save_summary (CamelO365Folder *o365_folder)
{
@@ -325,6 +338,603 @@ o365_folder_cmp_uids (CamelFolder *folder,
return strcmp (uid1, uid2);
}
+static gboolean
+o365_folder_download_message_cb (EO365Connection *cnc,
+ SoupMessage *message,
+ GInputStream *raw_data_stream,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelStream *cache_stream = user_data;
+ gssize expected_size = 0, wrote_size = 0, last_percent = -1;
+ gint last_progress_notify = 0;
+ gsize buffer_size = 65535;
+ gchar *buffer;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_STREAM (cache_stream), FALSE);
+ g_return_val_if_fail (G_IS_INPUT_STREAM (raw_data_stream), FALSE);
+
+ if (message && message->response_headers) {
+ const gchar *content_length_str;
+
+ content_length_str = soup_message_headers_get_one (message->response_headers,
"Content-Length");
+
+ if (content_length_str && *content_length_str)
+ expected_size = (gssize) g_ascii_strtoll (content_length_str, NULL, 10);
+ }
+
+ buffer = g_malloc (buffer_size);
+
+ do {
+ success = !g_cancellable_set_error_if_cancelled (cancellable, error);
+
+ if (success) {
+ gssize n_read, n_wrote;
+
+ n_read = g_input_stream_read (raw_data_stream, buffer, buffer_size, cancellable,
error);
+
+ if (n_read == -1) {
+ success = FALSE;
+ } else if (!n_read) {
+ break;
+ } else {
+ n_wrote = camel_stream_write (cache_stream, buffer, n_read, cancellable,
error);
+ success = n_read == n_wrote;
+
+ if (success && expected_size > 0) {
+ gssize percent;
+
+ wrote_size += n_wrote;
+
+ percent = wrote_size * 100.0 / expected_size;
+
+ if (percent > 100)
+ percent = 100;
+
+ if (percent != last_percent) {
+ gint64 now = g_get_monotonic_time ();
+
+ /* Notify only 10 times per second, not more */
+ if (percent == 100 || now - last_progress_notify >
G_USEC_PER_SEC / 10) {
+ last_progress_notify = now;
+ last_percent = percent;
+
+ camel_operation_progress (cancellable, percent);
+ }
+ }
+ }
+ }
+ }
+ } while (success);
+
+ g_free (buffer);
+
+ if (success)
+ camel_stream_flush (cache_stream, cancellable, NULL);
+
+ return success;
+}
+
+static void
+o365_folder_get_message_cancelled_cb (GCancellable *cancellable,
+ gpointer user_data)
+{
+ CamelO365Folder *o365_folder = user_data;
+
+ g_return_if_fail (CAMEL_IS_O365_FOLDER (o365_folder));
+
+ g_mutex_lock (&o365_folder->priv->get_message_lock);
+ g_cond_broadcast (&o365_folder->priv->get_message_cond);
+ g_mutex_unlock (&o365_folder->priv->get_message_lock);
+}
+
+static CamelMimeMessage *
+o365_folder_get_message_sync (CamelFolder *folder,
+ const gchar *uid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelMimeMessage *message = NULL;
+ CamelO365Folder *o365_folder;
+ CamelO365Store *o365_store;
+ CamelO365StoreSummary *o365_store_summary;
+ CamelStore *parent_store;
+ CamelStream *cache_stream = NULL;
+ EO365Connection *cnc = NULL;
+ GError *local_error = NULL;
+ gchar *folder_id;
+ gboolean success = TRUE, remove_from_hash = FALSE;
+
+ g_return_val_if_fail (CAMEL_IS_O365_FOLDER (folder), NULL);
+ g_return_val_if_fail (uid != NULL, NULL);
+
+ parent_store = camel_folder_get_parent_store (folder);
+
+ if (!parent_store)
+ return NULL;
+
+ o365_folder = CAMEL_O365_FOLDER (folder);
+ o365_store = CAMEL_O365_STORE (parent_store);
+
+ if (!camel_o365_store_ensure_connected (o365_store, &cnc, cancellable, error))
+ return NULL;
+
+ o365_store_summary = camel_o365_store_ref_store_summary (o365_store);
+
+ folder_id = camel_o365_store_summary_dup_folder_id_for_full_name (o365_store_summary,
+ camel_folder_get_full_name (folder));
+
+ if (!folder_id) {
+ g_set_error (error, CAMEL_STORE_ERROR, CAMEL_STORE_ERROR_NO_FOLDER, _("No such folder: %s"),
+ camel_folder_get_full_name (folder));
+
+ g_clear_object (&o365_store_summary);
+ g_clear_object (&cnc);
+
+ return NULL;
+ }
+
+ g_mutex_lock (&o365_folder->priv->get_message_lock);
+
+ if (g_hash_table_contains (o365_folder->priv->get_message_hash, uid)) {
+ gulong handler_id = 0;
+
+ if (cancellable) {
+ handler_id = g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (o365_folder_get_message_cancelled_cb), o365_folder);
+ }
+
+ while (success = !g_cancellable_set_error_if_cancelled (cancellable, error),
+ success && g_hash_table_contains (o365_folder->priv->get_message_hash, uid)) {
+ g_cond_wait (&o365_folder->priv->get_message_cond,
&o365_folder->priv->get_message_lock);
+ }
+
+ if (success)
+ message = o365_folder_get_message_from_cache (o365_folder, uid, cancellable, NULL);
+
+ if (handler_id)
+ g_signal_handler_disconnect (cancellable, handler_id);
+ }
+
+ if (success && !message) {
+ g_hash_table_insert (o365_folder->priv->get_message_hash, (gpointer) uid, NULL);
+ remove_from_hash = TRUE;
+ }
+
+ g_mutex_unlock (&o365_folder->priv->get_message_lock);
+
+ if (success && !message) {
+ cache_stream = o365_folder_cache_add (o365_folder, uid, error);
+
+ success = cache_stream != NULL;
+
+ success = success && e_o365_connection_get_mail_message_sync (cnc, NULL, folder_id, uid,
+ o365_folder_download_message_cb, cache_stream, cancellable, &local_error);
+
+ if (local_error) {
+ camel_o365_store_maybe_disconnect (o365_store, local_error);
+
+ g_propagate_error (error, local_error);
+ success = FALSE;
+ }
+
+ if (success) {
+ /* First free the cache stream, thus the follwing call opens a new instance,
+ which is rewinded at the beginning of the stream. */
+ g_clear_object (&cache_stream);
+
+ message = o365_folder_get_message_from_cache (o365_folder, uid, cancellable, error);
+ }
+ }
+
+ g_clear_object (&o365_store_summary);
+ g_clear_object (&cache_stream);
+ g_clear_object (&cnc);
+ g_free (folder_id);
+
+ if (remove_from_hash) {
+ g_mutex_lock (&o365_folder->priv->get_message_lock);
+ g_hash_table_remove (o365_folder->priv->get_message_hash, uid);
+ g_cond_broadcast (&o365_folder->priv->get_message_cond);
+ g_mutex_unlock (&o365_folder->priv->get_message_lock);
+ }
+
+ return message;
+}
+
+static gboolean
+o365_folder_update_message_info (CamelMessageInfo *mi,
+ EO365MailMessage *mail)
+{
+ CamelO365MessageInfo *o365_mi;
+ guint32 flags = 0;
+ gboolean changed = FALSE;
+
+ g_return_val_if_fail (CAMEL_IS_O365_MESSAGE_INFO (mi), FALSE);
+ g_return_val_if_fail (mail != NULL, FALSE);
+
+ o365_mi = CAMEL_O365_MESSAGE_INFO (mi);
+
+ if (e_o365_mail_message_get_has_attachments (mail))
+ flags |= CAMEL_MESSAGE_ATTACHMENTS;
+
+ if (e_o365_mail_message_get_is_draft (mail))
+ flags |= CAMEL_MESSAGE_DRAFT;
+
+ if (e_o365_mail_message_get_is_read (mail))
+ flags |= CAMEL_MESSAGE_SEEN;
+
+ if (e_o365_mail_message_get_importance (mail) == E_O365_IMPORTANCE_HIGH)
+ flags |= CAMEL_MESSAGE_FLAGGED;
+
+ /* 2020-06-24 - cannot make it work, even with
https://stackoverflow.com/questions/58205494/access-the-replied-forwarded-etc-state-from-rest */
+ /* CAMEL_MESSAGE_ANSWERED
+ CAMEL_MESSAGE_FORWARDED */
+
+ if (camel_o365_message_info_set_server_flags (o365_mi, flags)) {
+ guint32 mask;
+
+ mask = CAMEL_MESSAGE_ATTACHMENTS | CAMEL_MESSAGE_DRAFT | CAMEL_MESSAGE_SEEN |
CAMEL_MESSAGE_FLAGGED;
+
+ camel_message_info_set_flags (mi, mask, flags);
+
+ changed = TRUE;
+ }
+
+ return changed;
+}
+
+static gchar *
+o365_folder_recipients_as_string (JsonArray *recipients) /* EO365Recipient * */
+{
+ CamelInternetAddress *addrs;
+ guint ii, len;
+ gchar *res;
+
+ if (!recipients)
+ return NULL;
+
+ addrs = camel_internet_address_new ();
+
+ len = json_array_get_length (recipients);
+ for (ii = 0; ii < len; ii++) {
+ EO365Recipient *recipient = json_array_get_object_element (recipients, ii);
+ const gchar *name, *address;
+
+ name = e_o365_recipient_get_name (recipient);
+ address = e_o365_recipient_get_address (recipient);
+
+ if (address && *address)
+ camel_internet_address_add (addrs, name, address);
+ }
+
+ if (camel_address_length (CAMEL_ADDRESS (addrs)) > 0) {
+ res = camel_address_format (CAMEL_ADDRESS (addrs));
+ } else {
+ res = NULL;
+ }
+
+ g_clear_object (&addrs);
+
+ return res;
+}
+
+static CamelMessageInfo *
+o365_folder_new_message_info_from_mail_message (CamelFolder *folder,
+ EO365MailMessage *mail)
+{
+ CamelMessageInfo *mi = NULL;
+ CamelNameValueArray *headers = NULL;
+ JsonArray *json_headers;
+
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+ g_return_val_if_fail (mail != NULL, NULL);
+
+ json_headers = e_o365_mail_message_get_internet_message_headers (mail);
+
+ if (json_headers && json_array_get_length (json_headers) > 0) {
+ guint ii, len = json_array_get_length (json_headers);
+
+ headers = camel_name_value_array_new_sized (len);
+
+ for (ii = 0; ii < len; ii++) {
+ EO365InternetMessageHeader *header = json_array_get_object_element (json_headers, ii);
+ const gchar *name, *value;
+
+ name = e_o365_internet_message_header_get_name (header);
+ value = e_o365_internet_message_header_get_value (header);
+
+ if (name && *name)
+ camel_name_value_array_append (headers, name, value ? value : "");
+ }
+
+ if (camel_name_value_array_get_length (headers)) {
+ mi = camel_message_info_new_from_headers (camel_folder_get_folder_summary (folder),
headers);
+ } else {
+ camel_name_value_array_free (headers);
+ headers = NULL;
+ }
+ }
+
+ if (!mi) {
+ EO365Recipient *from;
+ const gchar *ctmp;
+ time_t tt;
+ gchar *tmp;
+
+ mi = camel_message_info_new (camel_folder_get_folder_summary (folder));
+
+ camel_message_info_set_abort_notifications (mi, TRUE);
+
+ ctmp = e_o365_mail_message_get_subject (mail);
+
+ if (ctmp)
+ camel_message_info_set_subject (mi, ctmp);
+
+ from = e_o365_mail_message_get_from (mail);
+
+ if (from) {
+ const gchar *name, *address;
+
+ name = e_o365_recipient_get_name (from);
+ address = e_o365_recipient_get_address (from);
+
+ if (address && *address) {
+ tmp = camel_internet_address_format_address (name, address);
+
+ if (tmp) {
+ camel_message_info_set_from (mi, tmp);
+
+ g_free (tmp);
+ }
+ }
+ }
+
+ tmp = o365_folder_recipients_as_string (e_o365_mail_message_get_to_recipients (mail));
+
+ if (tmp) {
+ camel_message_info_set_to (mi, tmp);
+ g_free (tmp);
+ }
+
+ tmp = o365_folder_recipients_as_string (e_o365_mail_message_get_cc_recipients (mail));
+
+ if (tmp) {
+ camel_message_info_set_cc (mi, tmp);
+ g_free (tmp);
+ }
+
+ tt = e_o365_mail_message_get_sent_date_time (mail);
+
+ if (tt)
+ camel_message_info_set_date_sent (mi, (gint64) tt);
+
+ tt = e_o365_mail_message_get_received_date_time (mail);
+
+ if (tt)
+ camel_message_info_set_date_received (mi, (gint64) tt);
+
+ ctmp = e_o365_mail_message_get_internet_message_id (mail);
+
+ if (ctmp && *ctmp) {
+ GChecksum *checksum;
+ CamelSummaryMessageID message_id;
+ guint8 *digest;
+ gsize length;
+
+ length = g_checksum_type_get_length (G_CHECKSUM_MD5);
+ digest = g_alloca (length);
+
+ checksum = g_checksum_new (G_CHECKSUM_MD5);
+ g_checksum_update (checksum, (const guchar *) ctmp, -1);
+ g_checksum_get_digest (checksum, digest, &length);
+ g_checksum_free (checksum);
+
+ memcpy (message_id.id.hash, digest, sizeof (message_id.id.hash));
+
+ camel_message_info_set_message_id (mi, message_id.id.id);
+ }
+
+ camel_message_info_set_abort_notifications (mi, FALSE);
+ }
+
+ camel_message_info_set_abort_notifications (mi, TRUE);
+ camel_message_info_set_uid (mi, e_o365_mail_message_get_id (mail));
+
+ if (headers)
+ camel_message_info_take_headers (mi, headers);
+
+ camel_message_info_set_abort_notifications (mi, FALSE);
+
+ o365_folder_update_message_info (mi, mail);
+
+ return mi;
+}
+
+typedef struct _SummaryDeltaData {
+ CamelFolder *folder;
+ CamelFolderChangeInfo *changes;
+ GList *removed_uids; /* gchar * - from the Camel string pool */
+} SummaryDeltaData;
+
+static gboolean
+o365_folder_got_summary_messages_cb (EO365Connection *cnc,
+ const GSList *results, /* JsonObject * - the returned objects from the
server */
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SummaryDeltaData *sdd = user_data;
+ CamelFolderSummary *summary;
+ GSList *link;
+
+ g_return_val_if_fail (sdd != NULL, FALSE);
+
+ summary = camel_folder_get_folder_summary (sdd->folder);
+
+ if (!summary)
+ return FALSE;
+
+ for (link = (GSList *) results; link; link = g_slist_next (link)) {
+ EO365MailMessage *mail = link->data;
+ const gchar *id;
+
+ id = e_o365_mail_message_get_id (mail);
+
+ if (!id)
+ continue;
+
+ if (!sdd->changes)
+ sdd->changes = camel_folder_change_info_new ();
+
+ if (e_o365_delta_is_removed_object (mail)) {
+ sdd->removed_uids = g_list_prepend (sdd->removed_uids, (gpointer)
camel_pstring_strdup (id));
+
+ camel_folder_change_info_remove_uid (sdd->changes, id);
+ } else {
+ CamelMessageInfo *info;
+
+ info = camel_folder_summary_get (summary, id);
+
+ if (info) {
+ if (o365_folder_update_message_info (info, mail))
+ camel_folder_change_info_change_uid (sdd->changes, id);
+
+ g_object_unref (info);
+ } else {
+ info = o365_folder_new_message_info_from_mail_message (sdd->folder, mail);
+
+ if (info) {
+ camel_folder_summary_add (summary, info, TRUE);
+
+ /* Unset folder-flagged flag, which ahd been set by the
camel_folder_summary_add(),
+ to avoid re-sync on the just added message. */
+ camel_message_info_set_folder_flagged (info, FALSE);
+
+ camel_folder_change_info_add_uid (sdd->changes, id);
+ camel_folder_change_info_recent_uid (sdd->changes, id);
+
+ g_object_unref (info);
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+o365_folder_refresh_info_sync (CamelFolder *folder,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelO365Folder *o365_folder;
+ CamelO365FolderSummary *o365_folder_summary;
+ CamelO365Store *o365_store;
+ CamelO365StoreSummary *o365_store_summary;
+ CamelFolderSummary *folder_summary;
+ CamelStore *parent_store;
+ EO365Connection *cnc = NULL;
+ SummaryDeltaData sdd;
+ GError *local_error = NULL;
+ gchar *folder_id, *curr_delta_link, *new_delta_link = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_O365_FOLDER (folder), FALSE);
+
+ parent_store = camel_folder_get_parent_store (folder);
+
+ if (!parent_store)
+ return FALSE;
+
+ o365_folder = CAMEL_O365_FOLDER (folder);
+ o365_store = CAMEL_O365_STORE (parent_store);
+
+ if (!camel_o365_store_ensure_connected (o365_store, &cnc, cancellable, error))
+ return FALSE;
+
+ o365_store_summary = camel_o365_store_ref_store_summary (o365_store);
+
+ folder_id = camel_o365_store_summary_dup_folder_id_for_full_name (o365_store_summary,
+ camel_folder_get_full_name (folder));
+
+ if (!folder_id) {
+ g_set_error (error, CAMEL_STORE_ERROR, CAMEL_STORE_ERROR_NO_FOLDER, _("No such folder: %s"),
+ camel_folder_get_full_name (folder));
+
+ g_clear_object (&o365_store_summary);
+ g_clear_object (&cnc);
+
+ return FALSE;
+ }
+
+ folder_summary = camel_folder_get_folder_summary (folder);
+ o365_folder_summary = CAMEL_O365_FOLDER_SUMMARY (folder_summary);
+
+ curr_delta_link = camel_o365_folder_summary_dup_delta_link (o365_folder_summary);
+
+ sdd.folder = folder;
+ sdd.changes = NULL;
+ sdd.removed_uids = NULL;
+
+ success = e_o365_connection_get_mail_messages_delta_sync (cnc, NULL, folder_id,
O365_FETCH_SUMMARY_PROPERTIES,
+ curr_delta_link, 0, o365_folder_got_summary_messages_cb, &sdd,
+ &new_delta_link, cancellable, &local_error);
+
+ if (success && new_delta_link)
+ camel_o365_folder_summary_set_delta_link (o365_folder_summary, new_delta_link);
+
+ if (sdd.removed_uids) {
+ camel_folder_summary_remove_uids (folder_summary, sdd.removed_uids);
+
+ g_list_free_full (sdd.removed_uids, (GDestroyNotify) camel_pstring_free);
+ }
+
+ o365_folder_save_summary (o365_folder);
+
+ if (sdd.changes) {
+ if (camel_folder_change_info_changed (sdd.changes))
+ camel_folder_changed (folder, sdd.changes);
+
+ camel_folder_change_info_free (sdd.changes);
+ }
+
+ if (local_error) {
+ camel_o365_store_maybe_disconnect (o365_store, local_error);
+
+ g_propagate_error (error, local_error);
+ success = FALSE;
+ }
+
+ g_clear_object (&o365_store_summary);
+ g_clear_object (&cnc);
+ g_free (curr_delta_link);
+ g_free (new_delta_link);
+ g_free (folder_id);
+
+ return success;
+}
+
+static void
+o365_folder_prepare_content_refresh (CamelFolder *folder)
+{
+ g_return_if_fail (CAMEL_IS_O365_FOLDER (folder));
+
+ camel_o365_folder_summary_set_delta_link (CAMEL_O365_FOLDER_SUMMARY (camel_folder_get_folder_summary
(folder)), NULL);
+}
+
+static gchar *
+o365_folder_get_filename (CamelFolder *folder,
+ const gchar *uid,
+ GError **error)
+{
+ CamelO365Folder *o365_folder = CAMEL_O365_FOLDER (folder);
+
+ return o365_folder_cache_dup_filename (o365_folder, uid);
+}
+
static void
o365_folder_constructed (GObject *object)
{
@@ -387,6 +997,10 @@ o365_folder_finalize (GObject *object)
g_rec_mutex_clear (&o365_folder->priv->cache_lock);
g_mutex_clear (&o365_folder->priv->search_lock);
+ g_mutex_clear (&o365_folder->priv->get_message_lock);
+ g_cond_clear (&o365_folder->priv->get_message_cond);
+
+ g_hash_table_destroy (o365_folder->priv->get_message_hash);
/* Chain up to parent's method. */
G_OBJECT_CLASS (camel_o365_folder_parent_class)->finalize (object);
@@ -413,13 +1027,15 @@ camel_o365_folder_class_init (CamelO365FolderClass *klass)
folder_class->cmp_uids = o365_folder_cmp_uids;
#if 0
folder_class->append_message_sync = o365_folder_append_message_sync;
+#endif
folder_class->get_message_sync = o365_folder_get_message_sync;
folder_class->refresh_info_sync = o365_folder_refresh_info_sync;
+#if 0
folder_class->synchronize_sync = o365_folder_synchronize_sync;
folder_class->expunge_sync = o365_folder_expunge_sync;
folder_class->transfer_messages_to_sync = o365_folder_transfer_messages_to_sync;
- folder_class->prepare_content_refresh = o365_folder_prepare_content_refresh;
#endif
+ folder_class->prepare_content_refresh = o365_folder_prepare_content_refresh;
folder_class->get_filename = o365_folder_get_filename;
}
@@ -432,6 +1048,10 @@ camel_o365_folder_init (CamelO365Folder *o365_folder)
g_rec_mutex_init (&o365_folder->priv->cache_lock);
g_mutex_init (&o365_folder->priv->search_lock);
+ g_mutex_init (&o365_folder->priv->get_message_lock);
+ g_cond_init (&o365_folder->priv->get_message_cond);
+
+ o365_folder->priv->get_message_hash = g_hash_table_new (g_str_hash, g_str_equal);
camel_folder_set_flags (folder, CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY);
camel_folder_set_lock_async (folder, TRUE);
diff --git a/src/Office365/camel/camel-o365-store.c b/src/Office365/camel/camel-o365-store.c
index 65596703..4771eec4 100644
--- a/src/Office365/camel/camel-o365-store.c
+++ b/src/Office365/camel/camel-o365-store.c
@@ -22,7 +22,7 @@
#include "common/camel-o365-settings.h"
#include "common/e-o365-connection.h"
-#include "common/e-o365-json-utils.h"
+#include "camel-o365-folder.h"
#include "camel-o365-store-summary.h"
#include "camel-o365-utils.h"
@@ -198,6 +198,7 @@ o365_store_read_default_folders (CamelO365Store *o365_store,
uri = e_o365_connection_construct_uri (cnc, TRUE, NULL, E_O365_API_V1_0, NULL,
"mailFolders",
+ NULL,
default_folders[ii].name,
"$select", "id",
NULL);
@@ -364,6 +365,44 @@ o365_store_authenticate_sync (CamelService *service,
return result;
}
+static CamelFolder *
+o365_store_get_folder_sync (CamelStore *store,
+ const gchar *folder_name,
+ guint32 flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelO365Store *o365_store;
+ CamelFolder *folder = NULL;
+ gchar *fid, *folder_dir, *display_name;
+
+ o365_store = CAMEL_O365_STORE (store);
+
+ fid = camel_o365_store_summary_dup_folder_id_for_full_name (o365_store->priv->summary, folder_name);
+
+ if (!fid) {
+ g_set_error (
+ error, CAMEL_STORE_ERROR,
+ CAMEL_STORE_ERROR_NO_FOLDER,
+ _("No such folder: %s"), folder_name);
+ return NULL;
+ }
+
+ display_name = camel_o365_store_summary_dup_folder_display_name (o365_store->priv->summary, fid);
+ folder_dir = g_build_filename (o365_store->priv->storage_path, "folders", folder_name, NULL);
+
+ folder = camel_o365_folder_new (store, display_name, folder_name, folder_dir, cancellable, error);
+
+ g_free (display_name);
+ g_free (folder_dir);
+ g_free (fid);
+
+ if (folder && (flags & CAMEL_STORE_FOLDER_INFO_REFRESH) != 0)
+ camel_folder_prepare_content_refresh (folder);
+
+ return folder;
+}
+
static void
o365_store_save_summary_locked (CamelO365StoreSummary *summary,
const gchar *where)
@@ -600,6 +639,212 @@ o365_get_folder_info_sync (CamelStore *store,
return fi;
}
+/* Hold the property lock before calling this function */
+static void
+o365_store_save_setup_folder_locked (CamelO365Store *o365_store,
+ GHashTable *save_setup,
+ guint32 folder_type, /* one of TYPE constants from CamelFolderInfoFlags
*/
+ const gchar *property_name)
+{
+ gchar *folder_id;
+
+ g_return_if_fail (CAMEL_IS_O365_STORE (o365_store));
+ g_return_if_fail (save_setup != NULL);
+ g_return_if_fail (folder_type != 0);
+ g_return_if_fail (property_name != NULL);
+
+ folder_id = camel_o365_store_summary_dup_folder_id_for_type (o365_store->priv->summary, folder_type);
+
+ if (folder_id) {
+ gchar *fullname;
+
+ fullname = camel_o365_store_summary_dup_folder_full_name (o365_store->priv->summary,
folder_id);
+
+ if (fullname && *fullname) {
+ g_hash_table_insert (save_setup,
+ g_strdup (property_name),
+ fullname);
+
+ fullname = NULL;
+ }
+
+ g_free (fullname);
+ g_free (folder_id);
+ }
+}
+
+static gboolean
+o365_store_initial_setup_with_connection_sync (CamelStore *store,
+ GHashTable *save_setup,
+ EO365Connection *cnc,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelO365Store *o365_store;
+
+ g_return_val_if_fail (CAMEL_IS_O365_STORE (store), FALSE);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ o365_store = CAMEL_O365_STORE (store);
+
+ if (cnc) {
+ g_object_ref (cnc);
+ } else {
+ if (!camel_o365_store_ensure_connected (o365_store, &cnc, cancellable, error))
+ return FALSE;
+
+ g_return_val_if_fail (cnc != NULL, FALSE);
+ }
+
+ if (!o365_store_read_default_folders (o365_store, cnc, cancellable, error)) {
+ g_clear_object (&cnc);
+ return FALSE;
+ }
+
+ if (save_setup) {
+ LOCK (o365_store);
+
+ o365_store_save_setup_folder_locked (o365_store, save_setup, CAMEL_FOLDER_TYPE_SENT,
CAMEL_STORE_SETUP_SENT_FOLDER);
+ o365_store_save_setup_folder_locked (o365_store, save_setup, CAMEL_FOLDER_TYPE_DRAFTS,
CAMEL_STORE_SETUP_DRAFTS_FOLDER);
+ o365_store_save_setup_folder_locked (o365_store, save_setup, CAMEL_FOLDER_TYPE_ARCHIVE,
CAMEL_STORE_SETUP_ARCHIVE_FOLDER);
+
+ UNLOCK (o365_store);
+ }
+
+ g_clear_object (&cnc);
+
+ return TRUE;
+}
+
+static gboolean
+o365_store_initial_setup_sync (CamelStore *store,
+ GHashTable *save_setup,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return o365_store_initial_setup_with_connection_sync (store, save_setup, NULL, cancellable, error);
+}
+
+static CamelFolder *
+o365_store_get_trash_folder_sync (CamelStore *store,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelO365Store *o365_store;
+ CamelFolder *folder = NULL;
+ gchar *folder_id, *folder_name;
+
+ g_return_val_if_fail (CAMEL_IS_O365_STORE (store), NULL);
+
+ o365_store = CAMEL_O365_STORE (store);
+
+ LOCK (o365_store);
+
+ folder_id = camel_o365_store_summary_dup_folder_id_for_type (o365_store->priv->summary,
CAMEL_FOLDER_TYPE_TRASH);
+
+ if (!folder_id) {
+ UNLOCK (o365_store);
+ g_set_error_literal (error, CAMEL_STORE_ERROR, CAMEL_STORE_ERROR_NO_FOLDER, _("Could not
locate Trash folder"));
+ return NULL;
+ }
+
+ folder_name = camel_o365_store_summary_dup_folder_full_name (o365_store->priv->summary, folder_id);
+
+ UNLOCK (o365_store);
+
+ folder = camel_store_get_folder_sync (store, folder_name, 0, cancellable, error);
+
+ g_free (folder_name);
+ g_free (folder_id);
+
+ if (folder) {
+ GPtrArray *folders;
+ gboolean can = TRUE;
+ guint ii;
+
+ /* Save content of all opened folders, thus any messages deleted in them
+ are moved to the Deleted Items folder first, thus in case of the trash
+ folder instance being used to expunge messages will contain all of them.
+ */
+ folders = camel_store_dup_opened_folders (store);
+
+ for (ii = 0; ii < folders->len; ii++) {
+ CamelFolder *secfolder = folders->pdata[ii];
+
+ if (secfolder != folder && can)
+ can = camel_folder_synchronize_sync (secfolder, FALSE, cancellable, NULL);
+
+ g_object_unref (secfolder);
+ }
+ g_ptr_array_free (folders, TRUE);
+
+ /* To return 'Deleted Items' folder with current content,
+ not with possibly stale locally cached copy. */
+ camel_folder_refresh_info_sync (folder, cancellable, NULL);
+ }
+
+ return folder;
+}
+
+static CamelFolder *
+o365_store_get_junk_folder_sync (CamelStore *store,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelO365Store *o365_store;
+ CamelFolder *folder = NULL;
+ gchar *folder_id, *folder_name;
+
+ g_return_val_if_fail (CAMEL_IS_O365_STORE (store), NULL);
+
+ o365_store = CAMEL_O365_STORE (store);
+
+ folder_id = camel_o365_store_summary_dup_folder_id_for_type (o365_store->priv->summary,
CAMEL_FOLDER_TYPE_JUNK);
+
+ if (!folder_id) {
+ g_set_error_literal (error, CAMEL_STORE_ERROR, CAMEL_STORE_ERROR_NO_FOLDER, _("Could not
locate Junk folder"));
+ return NULL;
+ }
+
+ folder_name = camel_o365_store_summary_dup_folder_full_name (o365_store->priv->summary, folder_id);
+
+ folder = camel_store_get_folder_sync (store, folder_name, 0, cancellable, error);
+
+ g_free (folder_name);
+ g_free (folder_id);
+
+ return folder;
+}
+
+static gboolean
+o365_store_can_refresh_folder (CamelStore *store,
+ CamelFolderInfo *info,
+ GError **error)
+{
+ CamelSettings *settings;
+ CamelO365Settings *o365_settings;
+ gboolean check_all;
+
+ /* Skip unselectable folders from automatic refresh */
+ if (info && (info->flags & CAMEL_FOLDER_NOSELECT) != 0)
+ return FALSE;
+
+ settings = camel_service_ref_settings (CAMEL_SERVICE (store));
+
+ o365_settings = CAMEL_O365_SETTINGS (settings);
+ check_all = camel_o365_settings_get_check_all (o365_settings);
+
+ g_object_unref (settings);
+
+ if (check_all)
+ return TRUE;
+
+ /* Delegate decision to parent class */
+ return CAMEL_STORE_CLASS (camel_o365_store_parent_class)->can_refresh_folder (store, info, error);
+}
+
static void
o365_store_set_property (GObject *object,
guint property_id,
@@ -710,19 +955,17 @@ camel_o365_store_class_init (CamelO365StoreClass *class)
service_class->authenticate_sync = o365_store_authenticate_sync;
store_class = CAMEL_STORE_CLASS (class);
-#if 0
store_class->get_folder_sync = o365_store_get_folder_sync;
+#if 0
store_class->create_folder_sync = o365_store_create_folder_sync;
store_class->delete_folder_sync = o365_store_delete_folder_sync;
store_class->rename_folder_sync = o365_store_rename_folder_sync;
#endif
store_class->get_folder_info_sync = o365_get_folder_info_sync;
-#if 0
store_class->initial_setup_sync = o365_store_initial_setup_sync;
store_class->get_trash_folder_sync = o365_store_get_trash_folder_sync;
store_class->get_junk_folder_sync = o365_store_get_junk_folder_sync;
store_class->can_refresh_folder = o365_store_can_refresh_folder;
-#endif
}
static void
@@ -789,23 +1032,34 @@ camel_o365_store_ref_connection (CamelO365Store *o365_store)
}
gboolean
-camel_o365_store_connected (CamelO365Store *o365_store,
- GCancellable *cancellable,
- GError **error)
+camel_o365_store_ensure_connected (CamelO365Store *o365_store,
+ EO365Connection **out_cnc, /* out, nullable, transfer full */
+ GCancellable *cancellable,
+ GError **error)
{
g_return_val_if_fail (CAMEL_IS_O365_STORE (o365_store), FALSE);
if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (o365_store))) {
- g_set_error (
- error, CAMEL_SERVICE_ERROR,
- CAMEL_SERVICE_ERROR_UNAVAILABLE,
+ g_set_error_literal (error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
_("You must be working online to complete this operation"));
+
return FALSE;
}
if (!camel_service_connect_sync ((CamelService *) o365_store, cancellable, error))
return FALSE;
+ if (out_cnc) {
+ *out_cnc = camel_o365_store_ref_connection (o365_store);
+
+ if (!*out_cnc) {
+ g_set_error_literal (error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE,
+ _("You must be working online to complete this operation"));
+
+ return FALSE;
+ }
+ }
+
return TRUE;
}
diff --git a/src/Office365/camel/camel-o365-store.h b/src/Office365/camel/camel-o365-store.h
index af42cd33..eb6ad5d2 100644
--- a/src/Office365/camel/camel-o365-store.h
+++ b/src/Office365/camel/camel-o365-store.h
@@ -64,7 +64,9 @@ CamelO365StoreSummary *
(CamelO365Store *store);
EO365Connection *
camel_o365_store_ref_connection (CamelO365Store *o365_store);
-gboolean camel_o365_store_connected (CamelO365Store *store,
+gboolean camel_o365_store_ensure_connected
+ (CamelO365Store *store,
+ EO365Connection **out_cnc, /* out, nullable, trasnfer full */
GCancellable *cancellable,
GError **error);
void camel_o365_store_maybe_disconnect
diff --git a/src/Office365/common/e-o365-connection.c b/src/Office365/common/e-o365-connection.c
index c30ba256..e1855790 100644
--- a/src/Office365/common/e-o365-connection.c
+++ b/src/Office365/common/e-o365-connection.c
@@ -1124,7 +1124,8 @@ e_o365_connection_json_node_from_message (SoupMessage *message,
static gboolean
o365_connection_send_request_sync (EO365Connection *cnc,
SoupMessage *message,
- EO365ResponseFunc func,
+ EO365ResponseFunc response_func,
+ EO365ConnectionRawDataFunc raw_data_func,
gpointer func_user_data,
GCancellable *cancellable,
GError **error)
@@ -1135,7 +1136,8 @@ o365_connection_send_request_sync (EO365Connection *cnc,
g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
g_return_val_if_fail (SOUP_IS_MESSAGE (message), FALSE);
- g_return_val_if_fail (func != NULL, FALSE);
+ g_return_val_if_fail (response_func != NULL || raw_data_func != NULL, FALSE);
+ g_return_val_if_fail (response_func == NULL || raw_data_func == NULL, FALSE);
while (need_retry && !g_cancellable_is_cancelled (cancellable) && message->status_code !=
SOUP_STATUS_CANCELLED) {
need_retry = FALSE;
@@ -1265,6 +1267,8 @@ o365_connection_send_request_sync (EO365Connection *cnc,
UNLOCK (cnc);
success = FALSE;
+ } else if (success && raw_data_func && SOUP_STATUS_IS_SUCCESSFUL
(message->status_code)) {
+ success = raw_data_func (cnc, message, input_stream, func_user_data,
cancellable, error);
} else if (success) {
JsonNode *node = NULL;
@@ -1273,7 +1277,7 @@ o365_connection_send_request_sync (EO365Connection *cnc,
if (success) {
gchar *next_link = NULL;
- success = func (cnc, message, input_stream, node, func_user_data,
&next_link, cancellable, error);
+ success = response_func && response_func (cnc, message, input_stream,
node, func_user_data, &next_link, cancellable, error);
if (success && next_link && *next_link) {
SoupURI *suri;
@@ -1332,7 +1336,7 @@ o365_connection_send_request_sync (EO365Connection *cnc,
}
typedef struct _EO365ResponseData {
- EO365ConnectionCallFunc func;
+ EO365ConnectionJsonFunc json_func;
gpointer func_user_data;
gboolean read_only_once; /* To be able to just try authentication */
GSList **out_items; /* JsonObject * */
@@ -1395,8 +1399,8 @@ e_o365_read_valued_response_cb (EO365Connection *cnc,
}
}
- if (response_data->func)
- can_continue = response_data->func (cnc, items, response_data->func_user_data, cancellable,
error);
+ if (response_data->json_func)
+ can_continue = response_data->json_func (cnc, items, response_data->func_user_data,
cancellable, error);
g_slist_free_full (items, (GDestroyNotify) json_object_unref);
@@ -1446,6 +1450,7 @@ e_o365_connection_authenticate_sync (EO365Connection *cnc,
uri = e_o365_connection_construct_uri (cnc, TRUE, NULL, E_O365_API_V1_0, NULL,
"mailFolders",
NULL,
+ NULL,
"$select", "displayName",
"$top", "1",
NULL);
@@ -1466,7 +1471,7 @@ e_o365_connection_authenticate_sync (EO365Connection *cnc,
rd.read_only_once = TRUE;
rd.out_items = &folders;
- success = o365_connection_send_request_sync (cnc, message, e_o365_read_valued_response_cb, &rd,
cancellable, &local_error);
+ success = o365_connection_send_request_sync (cnc, message, e_o365_read_valued_response_cb, NULL, &rd,
cancellable, &local_error);
if (success) {
result = E_SOURCE_AUTHENTICATION_ACCEPTED;
@@ -1529,7 +1534,8 @@ e_o365_connection_disconnect_sync (EO365Connection *cnc,
return TRUE;
}
-/* Expects NULL-terminated pair of parameters 'name', 'value'; if 'value' is NULL, the parameter is skipped
*/
+/* Expects NULL-terminated pair of parameters 'name', 'value'; if 'value' is NULL, the parameter is skipped.
+ An empty 'name' can add the 'value' into the path. These can be only before query parameters. */
gchar *
e_o365_connection_construct_uri (EO365Connection *cnc,
gboolean include_user,
@@ -1537,6 +1543,7 @@ e_o365_connection_construct_uri (EO365Connection *cnc,
EO365ApiVersion api_version,
const gchar *api_part,
const gchar *resource,
+ const gchar *id,
const gchar *path,
...)
{
@@ -1603,6 +1610,11 @@ e_o365_connection_construct_uri (EO365Connection *cnc,
g_string_append (uri, resource);
}
+ if (id && *id) {
+ g_string_append_c (uri, '/');
+ g_string_append (uri, id);
+ }
+
if (path && *path) {
g_string_append_c (uri, '/');
g_string_append (uri, path);
@@ -1632,6 +1644,12 @@ e_o365_connection_construct_uri (EO365Connection *cnc,
g_free (encoded);
}
+ } else if (!*name && value && *value) {
+ /* Warn when adding path after additional query parameters */
+ g_warn_if_fail (first_param);
+
+ g_string_append_c (uri, '/');
+ g_string_append (uri, value);
}
name = va_arg (args, const gchar *);
@@ -1767,7 +1785,7 @@ e_o365_connection_batch_request_internal_sync (EO365Connection *cnc,
g_return_val_if_fail (requests->len <= E_O365_BATCH_MAX_REQUESTS, FALSE);
uri = e_o365_connection_construct_uri (cnc, FALSE, NULL, api_version, "",
- "$batch", NULL, NULL);
+ "$batch", NULL, NULL, NULL);
message = soup_message_new (SOUP_METHOD_POST, uri);
@@ -1887,7 +1905,7 @@ e_o365_connection_batch_request_internal_sync (EO365Connection *cnc,
g_object_unref (builder);
g_object_unref (generator);
- success = o365_connection_send_request_sync (cnc, message, e_o365_read_batch_response_cb, requests,
cancellable, error);
+ success = o365_connection_send_request_sync (cnc, message, e_o365_read_batch_response_cb, NULL,
requests, cancellable, error);
g_clear_object (&message);
@@ -1987,7 +2005,7 @@ e_o365_connection_batch_request_sync (EO365Connection *cnc,
return success;
}
-/* This can be used as a EO365ConnectionCallFunc function, it only
+/* This can be used as a EO365ConnectionJsonFunc function, it only
copies items of 'results' into 'user_data', which is supposed
to be a pointer to a GSList *. */
gboolean
@@ -2011,14 +2029,16 @@ e_o365_connection_call_gather_into_slist (EO365Connection *cnc,
return TRUE;
}
+/* https://docs.microsoft.com/en-us/graph/api/user-list-mailfolders?view=graph-rest-1.0&tabs=http */
+
gboolean
-e_o365_connection_list_folders_sync (EO365Connection *cnc,
- const gchar *user_override, /* for which user, NULL to use the account
user */
- const gchar *from_path, /* path for the folder to read, NULL for top
user folder */
- const gchar *select, /* fields to select, nullable */
- GSList **out_folders, /* JsonObject * - the returned mailFolder objects
*/
- GCancellable *cancellable,
- GError **error)
+e_o365_connection_list_mail_folders_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *from_path, /* path for the folder to read, NULL for
top user folder */
+ const gchar *select, /* properties to select, nullable */
+ GSList **out_folders, /* JsonObject * - the returned mailFolder
objects */
+ GCancellable *cancellable,
+ GError **error)
{
EO365ResponseData rd;
SoupMessage *message;
@@ -2030,6 +2050,7 @@ e_o365_connection_list_folders_sync (EO365Connection *cnc,
uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
"mailFolders",
+ NULL,
from_path,
"$select", select,
NULL);
@@ -2049,7 +2070,7 @@ e_o365_connection_list_folders_sync (EO365Connection *cnc,
rd.out_items = out_folders;
- success = o365_connection_send_request_sync (cnc, message, e_o365_read_valued_response_cb, &rd,
cancellable, error);
+ success = o365_connection_send_request_sync (cnc, message, e_o365_read_valued_response_cb, NULL, &rd,
cancellable, error);
g_clear_object (&message);
@@ -2059,10 +2080,10 @@ e_o365_connection_list_folders_sync (EO365Connection *cnc,
gboolean
e_o365_connection_get_mail_folders_delta_sync (EO365Connection *cnc,
const gchar *user_override, /* for which user, NULL to use the
account user */
- const gchar *select, /* fields to select, nullable */
+ const gchar *select, /* properties to select, nullable */
const gchar *delta_link, /* previous delta link */
guint max_page_size, /* 0 for default by the server */
- EO365ConnectionCallFunc func, /* function to call with each
result set */
+ EO365ConnectionJsonFunc func, /* function to call with each
result set */
gpointer func_user_data, /* user data passed into the 'func' */
gchar **out_delta_link,
GCancellable *cancellable,
@@ -2084,6 +2105,7 @@ e_o365_connection_get_mail_folders_delta_sync (EO365Connection *cnc,
uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
"mailFolders",
+ NULL,
"delta",
"$select", select,
NULL);
@@ -2112,11 +2134,131 @@ e_o365_connection_get_mail_folders_delta_sync (EO365Connection *cnc,
memset (&rd, 0, sizeof (EO365ResponseData));
- rd.func = func;
+ rd.json_func = func;
rd.func_user_data = func_user_data;
rd.out_delta_link = out_delta_link;
- success = o365_connection_send_request_sync (cnc, message, e_o365_read_valued_response_cb, &rd,
cancellable, error);
+ success = o365_connection_send_request_sync (cnc, message, e_o365_read_valued_response_cb, NULL, &rd,
cancellable, error);
+
+ g_clear_object (&message);
+
+ return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/message-delta?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_get_mail_messages_delta_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *folder_id, /* folder ID to get delta messages in
*/
+ const gchar *select, /* properties to select, nullable */
+ const gchar *delta_link, /* previous delta link */
+ guint max_page_size, /* 0 for default by the server */
+ EO365ConnectionJsonFunc func, /* function to call with each
result set */
+ gpointer func_user_data, /* user data passed into the 'func'
*/
+ gchar **out_delta_link,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EO365ResponseData rd;
+ SoupMessage *message = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (folder_id != NULL, FALSE);
+ g_return_val_if_fail (out_delta_link != NULL, FALSE);
+ g_return_val_if_fail (func != NULL, FALSE);
+
+ if (delta_link)
+ message = soup_message_new (SOUP_METHOD_GET, delta_link);
+
+ if (!message) {
+ gchar *uri;
+
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "mailFolders",
+ folder_id,
+ "messages",
+ "", "delta",
+ "$select", select,
+ NULL);
+
+ message = soup_message_new (SOUP_METHOD_GET, uri);
+
+ if (!message) {
+ g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: ā%sā"),
uri);
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+ }
+
+ if (max_page_size > 0) {
+ gchar *prefer_value;
+
+ prefer_value = g_strdup_printf ("odata.maxpagesize=%u", max_page_size);
+
+ soup_message_headers_append (message->request_headers, "Prefer", prefer_value);
+
+ g_free (prefer_value);
+ }
+
+ memset (&rd, 0, sizeof (EO365ResponseData));
+
+ rd.json_func = func;
+ rd.func_user_data = func_user_data;
+ rd.out_delta_link = out_delta_link;
+
+ success = o365_connection_send_request_sync (cnc, message, e_o365_read_valued_response_cb, NULL, &rd,
cancellable, error);
+
+ g_clear_object (&message);
+
+ return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/message-get?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_get_mail_message_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *folder_id,
+ const gchar *message_id,
+ EO365ConnectionRawDataFunc func,
+ gpointer func_user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupMessage *message = NULL;
+ gboolean success;
+ gchar *uri;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (folder_id != NULL, FALSE);
+ g_return_val_if_fail (message_id != NULL, FALSE);
+ g_return_val_if_fail (func != NULL, FALSE);
+
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ /*"mailFolders",
+ folder_id,*/
+ "messages",
+ "", message_id,
+ "", "$value",
+ NULL);
+
+ message = soup_message_new (SOUP_METHOD_GET, uri);
+
+ if (!message) {
+ g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Malformed URI: ā%sā"), uri);
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+
+ success = o365_connection_send_request_sync (cnc, message, NULL, func, func_user_data, cancellable,
error);
g_clear_object (&message);
diff --git a/src/Office365/common/e-o365-connection.h b/src/Office365/common/e-o365-connection.h
index df6a8ae9..9854e02f 100644
--- a/src/Office365/common/e-o365-connection.h
+++ b/src/Office365/common/e-o365-connection.h
@@ -26,6 +26,7 @@
#include "camel-o365-settings.h"
#include "e-o365-enums.h"
+#include "e-o365-json-utils.h"
/* Currently, as of 2020-06-17, there is a limitation to 20 requests:
https://docs.microsoft.com/en-us/graph/known-issues#json-batching */
@@ -62,12 +63,19 @@ typedef struct _EO365ConnectionClass EO365ConnectionClass;
typedef struct _EO365ConnectionPrivate EO365ConnectionPrivate;
/* Returns whether can continue */
-typedef gboolean (* EO365ConnectionCallFunc) (EO365Connection *cnc,
+typedef gboolean (* EO365ConnectionJsonFunc) (EO365Connection *cnc,
const GSList *results, /* JsonObject * - the returned
objects from the server */
gpointer user_data,
GCancellable *cancellable,
GError **error);
+typedef gboolean (* EO365ConnectionRawDataFunc) (EO365Connection *cnc,
+ SoupMessage *message,
+ GInputStream *raw_data_stream,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error);
+
struct _EO365Connection {
GObject parent;
EO365ConnectionPrivate *priv;
@@ -130,6 +138,7 @@ gchar * e_o365_connection_construct_uri (EO365Connection *cnc,
EO365ApiVersion api_version,
const gchar *api_part, /* NULL for 'users', empty string to
skip */
const gchar *resource,
+ const gchar *id, /* NULL to skip */
const gchar *path,
...) G_GNUC_NULL_TERMINATED;
gboolean e_o365_connection_json_node_from_message
@@ -150,25 +159,46 @@ gboolean e_o365_connection_call_gather_into_slist
gpointer user_data, /* expects GSList **, aka pointer to a
GSList *, where it copies the 'results' */
GCancellable *cancellable,
GError **error);
-gboolean e_o365_connection_list_folders_sync
+gboolean e_o365_connection_list_mail_folders_sync
(EO365Connection *cnc,
const gchar *user_override, /* for which user, NULL to use
the account user */
const gchar *from_path, /* path for the folder to read, NULL
for top user folder */
- const gchar *select, /* fields to select, nullable */
+ const gchar *select, /* properties to select, nullable */
GSList **out_folders, /* JsonObject * - the returned
mailFolder objects */
GCancellable *cancellable,
GError **error);
gboolean e_o365_connection_get_mail_folders_delta_sync
(EO365Connection *cnc,
const gchar *user_override, /* for which user, NULL to use
the account user */
- const gchar *select, /* fields to select, nullable */
+ const gchar *select, /* properties to select, nullable */
+ const gchar *delta_link, /* previous delta link */
+ guint max_page_size, /* 0 for default by the server */
+ EO365ConnectionJsonFunc func, /* function to call with each
result set */
+ gpointer func_user_data, /* user data passed into the 'func'
*/
+ gchar **out_delta_link,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_o365_connection_get_mail_messages_delta_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *folder_id, /* folder ID to get delta messages
in */
+ const gchar *select, /* properties to select, nullable */
const gchar *delta_link, /* previous delta link */
guint max_page_size, /* 0 for default by the server */
- EO365ConnectionCallFunc func, /* function to call with each
result set */
+ EO365ConnectionJsonFunc func, /* function to call with each
result set */
gpointer func_user_data, /* user data passed into the 'func'
*/
gchar **out_delta_link,
GCancellable *cancellable,
GError **error);
+gboolean e_o365_connection_get_mail_message_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *folder_id,
+ const gchar *message_id,
+ EO365ConnectionRawDataFunc func,
+ gpointer func_user_data,
+ GCancellable *cancellable,
+ GError **error);
G_END_DECLS
diff --git a/src/Office365/common/e-o365-json-utils.c b/src/Office365/common/e-o365-json-utils.c
index 4cd74854..7e86ea52 100644
--- a/src/Office365/common/e-o365-json-utils.c
+++ b/src/Office365/common/e-o365-json-utils.c
@@ -159,6 +159,29 @@ e_o365_json_get_string_member (JsonObject *object,
return json_node_get_string (node);
}
+time_t
+e_o365_get_date_time_offset_member (JsonObject *object,
+ const gchar *member_name)
+{
+ const gchar *value;
+ time_t res = (time_t) 0;
+
+ value = e_o365_json_get_string_member (object, member_name, NULL);
+
+ if (value) {
+ GDateTime *dt;
+
+ dt = g_date_time_new_from_iso8601 (value, NULL);
+
+ if (dt) {
+ res = (time_t) g_date_time_to_unix (dt);
+ g_date_time_unref (dt);
+ }
+ }
+
+ return res;
+}
+
/* https://docs.microsoft.com/en-us/graph/delta-query-overview */
gboolean
@@ -170,37 +193,376 @@ e_o365_delta_is_removed_object (JsonObject *object)
/* https://docs.microsoft.com/en-us/graph/api/resources/mailfolder?view=graph-rest-1.0 */
const gchar *
-e_o365_mail_folder_get_display_name (JsonObject *object)
+e_o365_mail_folder_get_display_name (EO365MailFolder *folder)
{
- return e_o365_json_get_string_member (object, "displayName", NULL);
+ return e_o365_json_get_string_member (folder, "displayName", NULL);
}
const gchar *
-e_o365_mail_folder_get_id (JsonObject *object)
+e_o365_mail_folder_get_id (EO365MailFolder *folder)
{
- return e_o365_json_get_string_member (object, "id", NULL);
+ return e_o365_json_get_string_member (folder, "id", NULL);
}
const gchar *
-e_o365_mail_folder_get_parent_folder_id (JsonObject *object)
+e_o365_mail_folder_get_parent_folder_id (EO365MailFolder *folder)
{
- return e_o365_json_get_string_member (object, "parentFolderId", NULL);
+ return e_o365_json_get_string_member (folder, "parentFolderId", NULL);
}
gint32
-e_o365_mail_folder_get_child_folder_count (JsonObject *object)
+e_o365_mail_folder_get_child_folder_count (EO365MailFolder *folder)
{
- return (gint32) e_o365_json_get_int_member (object, "childFolderCount", 0);
+ return (gint32) e_o365_json_get_int_member (folder, "childFolderCount", 0);
}
gint32
-e_o365_mail_folder_get_total_item_count (JsonObject *object)
+e_o365_mail_folder_get_total_item_count (EO365MailFolder *folder)
{
- return (gint32) e_o365_json_get_int_member (object, "totalItemCount", 0);
+ return (gint32) e_o365_json_get_int_member (folder, "totalItemCount", 0);
}
gint32
-e_o365_mail_folder_get_unread_item_count (JsonObject *object)
+e_o365_mail_folder_get_unread_item_count (EO365MailFolder *folder)
+{
+ return (gint32) e_o365_json_get_int_member (folder, "unreadItemCount", 0);
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/resources/recipient?view=graph-rest-1.0
+ https://docs.microsoft.com/en-us/graph/api/resources/emailaddress?view=graph-rest-1.0
+ */
+const gchar *
+e_o365_recipient_get_address (EO365Recipient *recipient)
+{
+ JsonObject *email_address;
+
+ email_address = e_o365_json_get_object_member (recipient, "emailAddress");
+
+ if (!email_address)
+ return NULL;
+
+ return e_o365_json_get_string_member (email_address, "address", NULL);
+}
+
+const gchar *
+e_o365_recipient_get_name (EO365Recipient *recipient)
+{
+ JsonObject *email_address;
+
+ email_address = e_o365_json_get_object_member (recipient, "emailAddress");
+
+ if (!email_address)
+ return NULL;
+
+ return e_o365_json_get_string_member (email_address, "name", NULL);
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/resources/datetimetimezone?view=graph-rest-1.0 */
+
+time_t
+e_o365_date_time_get_date_time (EO365DateTimeWithZone *datetime)
+{
+ return e_o365_get_date_time_offset_member (datetime, "dateTime");
+}
+
+const gchar *
+e_o365_date_time_get_time_zone (EO365DateTimeWithZone *datetime)
+{
+ return e_o365_json_get_string_member (datetime, "timeZone", NULL);
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/resources/internetmessageheader?view=graph-rest-1.0 */
+
+const gchar *
+e_o365_internet_message_header_get_name (EO365InternetMessageHeader *header)
+{
+ return e_o365_json_get_string_member (header, "name", NULL);
+}
+
+const gchar *
+e_o365_internet_message_header_get_value (EO365InternetMessageHeader *header)
+{
+ return e_o365_json_get_string_member (header, "value", NULL);
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/resources/followupflag?view=graph-rest-1.0 */
+
+EO365DateTimeWithZone *
+e_o365_followup_flag_get_completed_date_time (EO365FollowupFlag *flag)
+{
+ return e_o365_json_get_object_member (flag, "completedDateTime");
+}
+
+EO365DateTimeWithZone *
+e_o365_followup_flag_get_due_date_time (EO365FollowupFlag *flag)
+{
+ return e_o365_json_get_object_member (flag, "dueDateTime");
+}
+
+EO365FollowupFlagStatusType
+e_o365_followup_flag_get_flag_status (EO365FollowupFlag *flag)
+{
+ const gchar *status;
+
+ status = e_o365_json_get_string_member (flag, "flagStatus", NULL);
+
+ if (!status)
+ return E_O365_FOLLOWUP_FLAG_STATUS_NOT_SET;
+
+ if (g_strcmp0 (status, "notFlagged") == 0)
+ return E_O365_FOLLOWUP_FLAG_STATUS_NOT_FLAGGED;
+
+ if (g_strcmp0 (status, "complete") == 0)
+ return E_O365_FOLLOWUP_FLAG_STATUS_COMPLETE;
+
+ if (g_strcmp0 (status, "flagged") == 0)
+ return E_O365_FOLLOWUP_FLAG_STATUS_FLAGGED;
+
+ return E_O365_FOLLOWUP_FLAG_STATUS_UNKNOWN;
+}
+
+EO365DateTimeWithZone *
+e_o365_followup_flag_get_start_date_time (EO365FollowupFlag *flag)
+{
+ return e_o365_json_get_object_member (flag, "startDateTime");
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/resources/itembody?view=graph-rest-1.0 */
+
+const gchar *
+e_o365_item_body_get_content (EO365ItemBody *item_body)
+{
+ return e_o365_json_get_string_member (item_body, "content", NULL);
+}
+
+EO365ItemBodyContentTypeType
+e_o365_item_body_get_content_type (EO365ItemBody *item_body)
+{
+ const gchar *content_type;
+
+ content_type = e_o365_json_get_string_member (item_body, "contentType", NULL);
+
+ if (!content_type)
+ return E_O365_ITEM_BODY_CONTENT_TYPE_NOT_SET;
+
+ if (g_strcmp0 (content_type, "text") == 0)
+ return E_O365_ITEM_BODY_CONTENT_TYPE_TEXT;
+
+ if (g_strcmp0 (content_type, "html") == 0)
+ return E_O365_ITEM_BODY_CONTENT_TYPE_HTML;
+
+ return E_O365_ITEM_BODY_CONTENT_TYPE_UNKNOWN;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/resources/message?view=graph-rest-1.0 */
+
+JsonArray * /* EO365Recipient * */
+e_o365_mail_message_get_bcc_recipients (EO365MailMessage *mail)
+{
+ return e_o365_json_get_array_member (mail, "bccRecipients");
+}
+
+EO365ItemBody *
+e_o365_mail_message_get_body (EO365MailMessage *mail)
+{
+ return e_o365_json_get_object_member (mail, "body");
+}
+
+const gchar *
+e_o365_mail_message_get_body_preview (EO365MailMessage *mail)
+{
+ return e_o365_json_get_string_member (mail, "bodyPreview", NULL);
+}
+
+JsonArray * /* const gchar * */
+e_o365_mail_message_get_categories (EO365MailMessage *mail)
+{
+ return e_o365_json_get_array_member (mail, "categories");
+}
+
+JsonArray * /* EO365Recipient * */
+e_o365_mail_message_get_cc_recipients (EO365MailMessage *mail)
+{
+ return e_o365_json_get_array_member (mail, "ccRecipients");
+}
+
+const gchar *
+e_o365_mail_message_get_change_key (EO365MailMessage *mail)
+{
+ return e_o365_json_get_string_member (mail, "changeKey", NULL);
+}
+
+const gchar *
+e_o365_mail_message_get_conversation_id (EO365MailMessage *mail)
+{
+ return e_o365_json_get_string_member (mail, "conversationId", NULL);
+}
+
+JsonObject * /* Edm.Binary */
+e_o365_mail_message_get_conversation_index (EO365MailMessage *mail)
+{
+ return e_o365_json_get_object_member (mail, "conversationIndex");
+}
+
+time_t
+e_o365_mail_message_get_created_date_time (EO365MailMessage *mail)
+{
+ return e_o365_get_date_time_offset_member (mail, "createdDateTime");
+}
+
+EO365FollowupFlag *
+e_o365_mail_message_get_flag (EO365MailMessage *mail)
+{
+ return e_o365_json_get_object_member (mail, "flag");
+}
+
+EO365Recipient *
+e_o365_mail_message_get_from (EO365MailMessage *mail)
+{
+ return e_o365_json_get_object_member (mail, "from");
+}
+
+gboolean
+e_o365_mail_message_get_has_attachments (EO365MailMessage *mail)
+{
+ return e_o365_json_get_boolean_member (mail, "hasAttachments", FALSE);
+}
+
+const gchar *
+e_o365_mail_message_get_id (EO365MailMessage *mail)
+{
+ return e_o365_json_get_string_member (mail, "id", NULL);
+}
+
+EO365ImportanceType
+e_o365_mail_message_get_importance (EO365MailMessage *mail)
+{
+ const gchar *value = e_o365_json_get_string_member (mail, "importance", NULL);
+
+ if (!value)
+ return E_O365_IMPORTANCE_NOT_SET;
+
+ if (g_strcmp0 (value, "Low") == 0)
+ return E_O365_IMPORTANCE_LOW;
+
+ if (g_strcmp0 (value, "Normal") == 0)
+ return E_O365_IMPORTANCE_NORMAL;
+
+ if (g_strcmp0 (value, "High") == 0)
+ return E_O365_IMPORTANCE_HIGH;
+
+ return E_O365_IMPORTANCE_UNKNOWN;
+}
+
+EO365InferenceClassificationType
+e_o365_mail_message_get_inference_classification (EO365MailMessage *mail)
+{
+ const gchar *value = e_o365_json_get_string_member (mail, "inferenceClassification", NULL);
+
+ if (!value)
+ return E_O365_INFERENCE_CLASSIFICATION_NOT_SET;
+
+ if (g_strcmp0 (value, "focused") == 0)
+ return E_O365_INFERENCE_CLASSIFICATION_FOCUSED;
+
+ if (g_strcmp0 (value, "other") == 0)
+ return E_O365_INFERENCE_CLASSIFICATION_OTHER;
+
+ return E_O365_INFERENCE_CLASSIFICATION_UNKNOWN;
+}
+
+JsonArray * /* EO365InternetMessageHeader * */
+e_o365_mail_message_get_internet_message_headers (EO365MailMessage *mail)
+{
+ return e_o365_json_get_array_member (mail, "internetMessageHeaders");
+}
+
+const gchar *
+e_o365_mail_message_get_internet_message_id (EO365MailMessage *mail)
+{
+ return e_o365_json_get_string_member (mail, "internetMessageId", NULL);
+}
+
+gboolean
+e_o365_mail_message_get_is_delivery_receipt_requested (EO365MailMessage *mail)
+{
+ return e_o365_json_get_boolean_member (mail, "isDeliveryReceiptRequested", FALSE);
+}
+
+gboolean
+e_o365_mail_message_get_is_draft (EO365MailMessage *mail)
+{
+ return e_o365_json_get_boolean_member (mail, "isDraft", FALSE);
+}
+
+gboolean
+e_o365_mail_message_get_is_read (EO365MailMessage *mail)
+{
+ return e_o365_json_get_boolean_member (mail, "isRead", FALSE);
+}
+
+gboolean
+e_o365_mail_message_get_is_read_receipt_requested (EO365MailMessage *mail)
+{
+ return e_o365_json_get_boolean_member (mail, "isReadReceiptRequested", FALSE);
+}
+
+time_t
+e_o365_mail_message_get_last_modified_date_time (EO365MailMessage *mail)
+{
+ return e_o365_get_date_time_offset_member (mail, "lastModifiedDateTime");
+}
+
+const gchar *
+e_o365_mail_message_get_parent_folder_id (EO365MailMessage *mail)
+{
+ return e_o365_json_get_string_member (mail, "parentFolderId", NULL);
+}
+
+time_t
+e_o365_mail_message_get_received_date_time (EO365MailMessage *mail)
+{
+ return e_o365_get_date_time_offset_member (mail, "receivedDateTime");
+}
+
+JsonArray * /* EO365Recipient * */
+e_o365_mail_message_get_reply_to (EO365MailMessage *mail)
+{
+ return e_o365_json_get_array_member (mail, "replyTo");
+}
+
+EO365Recipient *
+e_o365_mail_message_get_sender (EO365MailMessage *mail)
+{
+ return e_o365_json_get_object_member (mail, "sender");
+}
+
+time_t
+e_o365_mail_message_get_sent_date_time (EO365MailMessage *mail)
+{
+ return e_o365_get_date_time_offset_member (mail, "sentDateTime");
+}
+
+const gchar *
+e_o365_mail_message_get_subject (EO365MailMessage *mail)
+{
+ return e_o365_json_get_string_member (mail, "subject", NULL);
+}
+
+JsonArray * /* EO365Recipient * */
+e_o365_mail_message_get_to_recipients (EO365MailMessage *mail)
+{
+ return e_o365_json_get_array_member (mail, "toRecipients");
+}
+
+EO365ItemBody *
+e_o365_mail_message_get_unique_body (EO365MailMessage *mail)
+{
+ return e_o365_json_get_object_member (mail, "uniqueBody");
+}
+
+const gchar *
+e_o365_mail_message_get_web_link (EO365MailMessage *mail)
{
- return (gint32) e_o365_json_get_int_member (object, "unreadItemCount", 0);
+ return e_o365_json_get_string_member (mail, "webLink", NULL);
}
diff --git a/src/Office365/common/e-o365-json-utils.h b/src/Office365/common/e-o365-json-utils.h
index f1ed0300..12aeecc4 100644
--- a/src/Office365/common/e-o365-json-utils.h
+++ b/src/Office365/common/e-o365-json-utils.h
@@ -18,10 +18,50 @@
#ifndef E_O365_JSON_UTILS_H
#define E_O365_JSON_UTILS_H
+#include <time.h>
#include <json-glib/json-glib.h>
G_BEGIN_DECLS
+typedef enum _EO365InferenceClassificationType {
+ E_O365_INFERENCE_CLASSIFICATION_NOT_SET,
+ E_O365_INFERENCE_CLASSIFICATION_UNKNOWN,
+ E_O365_INFERENCE_CLASSIFICATION_FOCUSED,
+ E_O365_INFERENCE_CLASSIFICATION_OTHER
+} EO365InferenceClassificationType;
+
+typedef enum _EO365ImportanceType {
+ E_O365_IMPORTANCE_NOT_SET,
+ E_O365_IMPORTANCE_UNKNOWN,
+ E_O365_IMPORTANCE_LOW,
+ E_O365_IMPORTANCE_NORMAL,
+ E_O365_IMPORTANCE_HIGH
+} EO365ImportanceType;
+
+typedef enum _EO365FollowupFlagStatusType {
+ E_O365_FOLLOWUP_FLAG_STATUS_NOT_SET,
+ E_O365_FOLLOWUP_FLAG_STATUS_UNKNOWN,
+ E_O365_FOLLOWUP_FLAG_STATUS_NOT_FLAGGED,
+ E_O365_FOLLOWUP_FLAG_STATUS_COMPLETE,
+ E_O365_FOLLOWUP_FLAG_STATUS_FLAGGED
+} EO365FollowupFlagStatusType;
+
+typedef enum _EO365ItemBodyContentTypeType {
+ E_O365_ITEM_BODY_CONTENT_TYPE_NOT_SET,
+ E_O365_ITEM_BODY_CONTENT_TYPE_UNKNOWN,
+ E_O365_ITEM_BODY_CONTENT_TYPE_TEXT,
+ E_O365_ITEM_BODY_CONTENT_TYPE_HTML
+} EO365ItemBodyContentTypeType;
+
+/* Just for better readability */
+#define EO365MailFolder JsonObject
+#define EO365Recipient JsonObject
+#define EO365DateTimeWithZone JsonObject
+#define EO365FollowupFlag JsonObject
+#define EO365InternetMessageHeader JsonObject
+#define EO365ItemBody JsonObject
+#define EO365MailMessage JsonObject
+
JsonArray * e_o365_json_get_array_member (JsonObject *object,
const gchar *member_name);
gboolean e_o365_json_get_boolean_member (JsonObject *object,
@@ -42,15 +82,86 @@ const gchar * e_o365_json_get_string_member (JsonObject *object,
const gchar *member_name,
const gchar *default_value);
+time_t e_o365_get_date_time_offset_member (JsonObject *object,
+ const gchar *member_name);
+
gboolean e_o365_delta_is_removed_object (JsonObject *object);
-const gchar * e_o365_mail_folder_get_display_name (JsonObject *object);
-const gchar * e_o365_mail_folder_get_id (JsonObject *object);
-const gchar * e_o365_mail_folder_get_parent_folder_id (JsonObject *object);
+const gchar * e_o365_mail_folder_get_display_name (EO365MailFolder *folder);
+const gchar * e_o365_mail_folder_get_id (EO365MailFolder *folder);
+const gchar * e_o365_mail_folder_get_parent_folder_id (EO365MailFolder *folder);
gint32 e_o365_mail_folder_get_child_folder_count
- (JsonObject *object);
-gint32 e_o365_mail_folder_get_total_item_count (JsonObject *object);
-gint32 e_o365_mail_folder_get_unread_item_count(JsonObject *object);
+ (EO365MailFolder *folder);
+gint32 e_o365_mail_folder_get_total_item_count (EO365MailFolder *folder);
+gint32 e_o365_mail_folder_get_unread_item_count(EO365MailFolder *folder);
+
+const gchar * e_o365_recipient_get_address (EO365Recipient *recipient);
+const gchar * e_o365_recipient_get_name (EO365Recipient *recipient);
+
+time_t e_o365_date_time_get_date_time (EO365DateTimeWithZone *datetime);
+const gchar * e_o365_date_time_get_time_zone (EO365DateTimeWithZone *datetime);
+
+const gchar * e_o365_internet_message_header_get_name (EO365InternetMessageHeader *header);
+const gchar * e_o365_internet_message_header_get_value(EO365InternetMessageHeader *header);
+
+EO365DateTimeWithZone *
+ e_o365_followup_flag_get_completed_date_time
+ (EO365FollowupFlag *flag);
+EO365DateTimeWithZone *
+ e_o365_followup_flag_get_due_date_time (EO365FollowupFlag *flag);
+EO365FollowupFlagStatusType
+ e_o365_followup_flag_get_flag_status (EO365FollowupFlag *flag);
+EO365DateTimeWithZone *
+ e_o365_followup_flag_get_start_date_time(EO365FollowupFlag *flag);
+
+const gchar * e_o365_item_body_get_content (EO365ItemBody *item_body);
+EO365ItemBodyContentTypeType
+ e_o365_item_body_get_content_type (EO365ItemBody *item_body);
+
+JsonArray * e_o365_mail_message_get_bcc_recipients (EO365MailMessage *mail); /* EO365Recipient * */
+EO365ItemBody * e_o365_mail_message_get_body (EO365MailMessage *mail);
+const gchar * e_o365_mail_message_get_body_preview (EO365MailMessage *mail);
+JsonArray * e_o365_mail_message_get_categories (EO365MailMessage *mail); /* const gchar * */
+JsonArray * e_o365_mail_message_get_cc_recipients (EO365MailMessage *mail); /* EO365Recipient * */
+const gchar * e_o365_mail_message_get_change_key (EO365MailMessage *mail);
+const gchar * e_o365_mail_message_get_conversation_id (EO365MailMessage *mail);
+JsonObject * e_o365_mail_message_get_conversation_index
+ (EO365MailMessage *mail);
+time_t e_o365_mail_message_get_created_date_time
+ (EO365MailMessage *mail);
+EO365FollowupFlag *
+ e_o365_mail_message_get_flag (EO365MailMessage *mail);
+EO365Recipient *
+ e_o365_mail_message_get_from (EO365MailMessage *mail);
+gboolean e_o365_mail_message_get_has_attachments (EO365MailMessage *mail);
+const gchar * e_o365_mail_message_get_id (EO365MailMessage *mail);
+EO365ImportanceType
+ e_o365_mail_message_get_importance (EO365MailMessage *mail);
+EO365InferenceClassificationType
+ e_o365_mail_message_get_inference_classification
+ (EO365MailMessage *mail);
+JsonArray * e_o365_mail_message_get_internet_message_headers
+ (EO365MailMessage *mail); /*
EO365InternetMessageHeader * */
+const gchar * e_o365_mail_message_get_internet_message_id
+ (EO365MailMessage *mail);
+gboolean e_o365_mail_message_get_is_delivery_receipt_requested
+ (EO365MailMessage *mail);
+gboolean e_o365_mail_message_get_is_draft (EO365MailMessage *mail);
+gboolean e_o365_mail_message_get_is_read (EO365MailMessage *mail);
+gboolean e_o365_mail_message_get_is_read_receipt_requested
+ (EO365MailMessage *mail);
+time_t e_o365_mail_message_get_last_modified_date_time
+ (EO365MailMessage *mail);
+const gchar * e_o365_mail_message_get_parent_folder_id(EO365MailMessage *mail);
+time_t e_o365_mail_message_get_received_date_time
+ (EO365MailMessage *mail);
+JsonArray * e_o365_mail_message_get_reply_to (EO365MailMessage *mail); /* EO365Recipient * */
+EO365Recipient *e_o365_mail_message_get_sender (EO365MailMessage *mail);
+time_t e_o365_mail_message_get_sent_date_time (EO365MailMessage *mail);
+const gchar * e_o365_mail_message_get_subject (EO365MailMessage *mail);
+JsonArray * e_o365_mail_message_get_to_recipients (EO365MailMessage *mail); /* EO365Recipient * */
+EO365ItemBody * e_o365_mail_message_get_unique_body (EO365MailMessage *mail);
+const gchar * e_o365_mail_message_get_web_link (EO365MailMessage *mail);
G_END_DECLS
diff --git a/src/Office365/evolution/e-mail-config-o365-backend.c
b/src/Office365/evolution/e-mail-config-o365-backend.c
index 73781265..e0e76b6d 100644
--- a/src/Office365/evolution/e-mail-config-o365-backend.c
+++ b/src/Office365/evolution/e-mail-config-o365-backend.c
@@ -27,7 +27,6 @@
#include "common/camel-o365-settings.h"
#include "common/e-o365-connection.h"
-#include "common/e-o365-json-utils.h"
#include "e-mail-config-o365-backend.h"
@@ -103,7 +102,7 @@ test_clicked_cb (GtkButton *button,
cnc = e_o365_connection_new (source, CAMEL_O365_SETTINGS (settings));
g_return_if_fail (cnc != NULL);
- //success = e_o365_connection_list_folders_sync (cnc, NULL, NULL, NULL, &folders, NULL, &error);
+ //success = e_o365_connection_list_mail_folders_sync (cnc, NULL, NULL, NULL, &folders, NULL, &error);
success = e_o365_connection_get_mail_folders_delta_sync (cnc, NULL, NULL, delta_link, 0,
e_o365_connection_call_gather_into_slist, &folders, &new_delta_link, NULL, &error);
if (success) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]