[evolution-ews/wip/mcrha/office365] Detect and configure .source-s for user address books
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews/wip/mcrha/office365] Detect and configure .source-s for user address books
- Date: Wed, 8 Jul 2020 17:53:19 +0000 (UTC)
commit 6ecf61652946ab4c978b95fd67028b07fdf1ef3d
Author: Milan Crha <mcrha redhat com>
Date: Wed Jul 8 19:53:00 2020 +0200
Detect and configure .source-s for user address books
src/Office365/camel/camel-o365-store.c | 28 ++-
src/Office365/common/e-o365-connection.c | 75 +++++-
src/Office365/common/e-o365-connection.h | 11 +-
src/Office365/common/e-o365-json-utils.c | 16 +-
src/Office365/common/e-o365-json-utils.h | 8 +-
src/Office365/common/e-source-o365-folder.c | 96 +++----
src/Office365/common/e-source-o365-folder.h | 12 +-
src/Office365/registry/CMakeLists.txt | 2 +
src/Office365/registry/e-o365-backend.c | 345 ++++++++++++++++++++++----
src/Office365/registry/e-source-o365-deltas.c | 166 +++++++++++++
src/Office365/registry/e-source-o365-deltas.h | 72 ++++++
src/Office365/registry/module-o365-backend.c | 2 +
12 files changed, 686 insertions(+), 147 deletions(-)
---
diff --git a/src/Office365/camel/camel-o365-store.c b/src/Office365/camel/camel-o365-store.c
index 101d74b9..a5c4af67 100644
--- a/src/Office365/camel/camel-o365-store.c
+++ b/src/Office365/camel/camel-o365-store.c
@@ -742,14 +742,14 @@ o365_store_create_folder_sync (CamelStore *store,
flags = e_o365_mail_folder_get_child_folder_count (mail_folder) ? CAMEL_STORE_INFO_FOLDER_CHILDREN :
CAMEL_STORE_INFO_FOLDER_NOCHILDREN;
camel_o365_store_summary_set_folder (o365_store->priv->summary, TRUE,
- e_o365_mail_folder_get_id (mail_folder),
- e_o365_mail_folder_get_parent_folder_id (mail_folder),
- e_o365_mail_folder_get_display_name (mail_folder),
+ e_o365_folder_get_id (mail_folder),
+ e_o365_folder_get_parent_folder_id (mail_folder),
+ e_o365_folder_get_display_name (mail_folder),
e_o365_mail_folder_get_total_item_count (mail_folder),
e_o365_mail_folder_get_unread_item_count (mail_folder),
flags, E_O365_FOLDER_KIND_MAIL, FALSE, FALSE);
- fi = camel_o365_store_summary_build_folder_info_for_id (o365_store->priv->summary,
e_o365_mail_folder_get_id (mail_folder));
+ fi = camel_o365_store_summary_build_folder_info_for_id (o365_store->priv->summary,
e_o365_folder_get_id (mail_folder));
camel_store_folder_created (store, fi);
camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (o365_store), fi);
@@ -801,7 +801,7 @@ o365_store_move_mail_folder (CamelO365Store *o365_store,
fi = camel_o365_store_summary_build_folder_info_for_id (o365_store->priv->summary, folder_id);
- camel_o365_store_summary_set_folder_parent_id (o365_store->priv->summary, folder_id,
e_o365_mail_folder_get_parent_folder_id (moved_mail_folder));
+ camel_o365_store_summary_set_folder_parent_id (o365_store->priv->summary, folder_id,
e_o365_folder_get_parent_folder_id (moved_mail_folder));
camel_o365_store_summary_rebuild_hashes (o365_store->priv->summary);
camel_subscribable_folder_unsubscribed (CAMEL_SUBSCRIBABLE (o365_store), fi);
@@ -1057,7 +1057,7 @@ o365_store_rename_folder_sync (CamelStore *store,
if (mail_folder) {
camel_o365_store_summary_set_folder_display_name (o365_store->priv->summary,
folder_id,
- e_o365_mail_folder_get_display_name (mail_folder), TRUE);
+ e_o365_folder_get_display_name (mail_folder), TRUE);
json_object_unref (mail_folder);
}
@@ -1126,7 +1126,7 @@ typedef struct _FoldersDeltaData {
static gboolean
camel_o365_got_folders_delta_cb (EO365Connection *cnc,
const GSList *results, /* JsonObject * - the returned objects from the
server */
- gpointer user_data, /* expects GSList **, aka pointer to a GSList *, where
it copies the 'results' */
+ gpointer user_data,
GCancellable *cancellable,
GError **error)
{
@@ -1139,7 +1139,7 @@ camel_o365_got_folders_delta_cb (EO365Connection *cnc,
for (link = (GSList *) results; link; link = g_slist_next (link)) {
JsonObject *object = link->data;
- const gchar *id = e_o365_mail_folder_get_id (object);
+ const gchar *id = e_o365_folder_get_id (object);
if (e_o365_delta_is_removed_object (object)) {
CamelFolderInfo *info;
@@ -1162,8 +1162,8 @@ camel_o365_got_folders_delta_cb (EO365Connection *cnc,
flags |= GPOINTER_TO_UINT (g_hash_table_lookup
(fdd->o365_store->priv->default_folders, id));
camel_o365_store_summary_set_folder (fdd->o365_store->priv->summary, FALSE, id,
- e_o365_mail_folder_get_parent_folder_id (object),
- e_o365_mail_folder_get_display_name (object),
+ e_o365_folder_get_parent_folder_id (object),
+ e_o365_folder_get_display_name (object),
e_o365_mail_folder_get_total_item_count (object),
e_o365_mail_folder_get_unread_item_count (object),
flags, E_O365_FOLDER_KIND_MAIL, FALSE, FALSE);
@@ -1266,16 +1266,18 @@ o365_store_get_folder_info_sync (CamelStore *store,
fdd.renamed_data = NULL;
fdd.removed_fis = NULL;
- success = e_o365_connection_get_mail_folders_delta_sync (cnc, NULL, NULL,
old_delta_link, 0,
+ success = e_o365_connection_get_folders_delta_sync (cnc, NULL,
E_O365_FOLDER_KIND_MAIL, NULL, old_delta_link, 0,
camel_o365_got_folders_delta_cb, &fdd, &new_delta_link, cancellable,
&local_error);
- if (old_delta_link && *old_delta_link && g_error_matches (local_error,
SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+ if (old_delta_link && *old_delta_link && (
+ g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)
||
+ g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_BAD_REQUEST)))
{
g_clear_pointer (&old_delta_link, g_free);
g_clear_error (&local_error);
o365_store_forget_all_folders (o365_store);
- success = e_o365_connection_get_mail_folders_delta_sync (cnc, NULL,
NULL, NULL, 0,
+ success = e_o365_connection_get_folders_delta_sync (cnc, NULL,
E_O365_FOLDER_KIND_MAIL, NULL, NULL, 0,
camel_o365_got_folders_delta_cb, &fdd, &new_delta_link,
cancellable, error);
}
diff --git a/src/Office365/common/e-o365-connection.c b/src/Office365/common/e-o365-connection.c
index 4412ed11..ef5be174 100644
--- a/src/Office365/common/e-o365-connection.c
+++ b/src/Office365/common/e-o365-connection.c
@@ -2230,16 +2230,17 @@ e_o365_connection_list_mail_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, /* 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)
+e_o365_connection_get_folders_delta_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ EO365FolderKind kind,
+ 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;
@@ -2253,10 +2254,25 @@ e_o365_connection_get_mail_folders_delta_sync (EO365Connection *cnc,
message = o365_connection_new_soup_message (SOUP_METHOD_GET, delta_link, CSM_DEFAULT, NULL);
if (!message) {
+ const gchar *kind_str = NULL;
gchar *uri;
+ switch (kind) {
+ case E_O365_FOLDER_KIND_CONTACTS:
+ kind_str = "contactFolders";
+ break;
+ case E_O365_FOLDER_KIND_MAIL:
+ kind_str = "mailFolders";
+ break;
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+
+ g_return_val_if_fail (kind_str != NULL, FALSE);
+
uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
- "mailFolders",
+ kind_str,
NULL,
"delta",
"$select", select,
@@ -3140,3 +3156,40 @@ e_o365_connection_send_mail_sync (EO365Connection *cnc,
return success;
}
+
+gboolean
+e_o365_connection_get_contacts_folder_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ EO365Folder **out_folder,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupMessage *message;
+ gchar *uri;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (out_folder != NULL, FALSE);
+
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "contactFolders",
+ "contacts",
+ NULL,
+ NULL);
+
+ message = o365_connection_new_soup_message (SOUP_METHOD_GET, uri, CSM_DEFAULT, error);
+
+ if (!message) {
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+
+ success = o365_connection_send_request_sync (cnc, message, e_o365_read_json_object_response_cb, NULL,
out_folder, cancellable, error);
+
+ g_clear_object (&message);
+
+ return success;
+}
diff --git a/src/Office365/common/e-o365-connection.h b/src/Office365/common/e-o365-connection.h
index 5174641f..a19fbb20 100644
--- a/src/Office365/common/e-o365-connection.h
+++ b/src/Office365/common/e-o365-connection.h
@@ -53,7 +53,7 @@
G_BEGIN_DECLS
-typedef enum {
+typedef enum _EO365ApiVersion {
E_O365_API_V1_0,
E_O365_API_BETA
} EO365ApiVersion;
@@ -173,9 +173,10 @@ gboolean e_o365_connection_list_mail_folders_sync
GSList **out_folders, /* EO365MailFolder * - the returned
mailFolder objects */
GCancellable *cancellable,
GError **error);
-gboolean e_o365_connection_get_mail_folders_delta_sync
+gboolean e_o365_connection_get_folders_delta_sync
(EO365Connection *cnc,
const gchar *user_override, /* for which user, NULL to use
the account user */
+ EO365FolderKind kind,
const gchar *select, /* properties to select, nullable */
const gchar *delta_link, /* previous delta link */
guint max_page_size, /* 0 for default by the server */
@@ -293,6 +294,12 @@ gboolean e_o365_connection_send_mail_sync
JsonBuilder *request, /* filled sendMail object */
GCancellable *cancellable,
GError **error);
+gboolean e_o365_connection_get_contacts_folder_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ EO365Folder **out_folder,
+ 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 d803a26b..a3cdb79f 100644
--- a/src/Office365/common/e-o365-json-utils.c
+++ b/src/Office365/common/e-o365-json-utils.c
@@ -363,24 +363,26 @@ e_o365_category_get_color (EO365Category *category)
return NULL;
}
-/* https://docs.microsoft.com/en-us/graph/api/resources/mailfolder?view=graph-rest-1.0 */
+/* https://docs.microsoft.com/en-us/graph/api/resources/mailfolder?view=graph-rest-1.0
+ https://docs.microsoft.com/en-us/graph/api/resources/contactfolder?view=graph-rest-1.0
+ */
const gchar *
-e_o365_mail_folder_get_display_name (EO365MailFolder *folder)
+e_o365_folder_get_id (EO365Folder *folder)
{
- return e_o365_json_get_string_member (folder, "displayName", NULL);
+ return e_o365_json_get_string_member (folder, "id", NULL);
}
const gchar *
-e_o365_mail_folder_get_id (EO365MailFolder *folder)
+e_o365_folder_get_parent_folder_id (EO365Folder *folder)
{
- return e_o365_json_get_string_member (folder, "id", NULL);
+ return e_o365_json_get_string_member (folder, "parentFolderId", NULL);
}
const gchar *
-e_o365_mail_folder_get_parent_folder_id (EO365MailFolder *folder)
+e_o365_folder_get_display_name (EO365Folder *folder)
{
- return e_o365_json_get_string_member (folder, "parentFolderId", NULL);
+ return e_o365_json_get_string_member (folder, "displayName", NULL);
}
gint32
diff --git a/src/Office365/common/e-o365-json-utils.h b/src/Office365/common/e-o365-json-utils.h
index be33cf8b..0f766d6f 100644
--- a/src/Office365/common/e-o365-json-utils.h
+++ b/src/Office365/common/e-o365-json-utils.h
@@ -65,6 +65,7 @@ typedef enum _EO365ItemBodyContentTypeType {
#define EO365Attachment JsonObject
#define EO365Category JsonObject
#define EO365DateTimeWithZone JsonObject
+#define EO365Folder JsonObject
#define EO365FollowupFlag JsonObject
#define EO365InternetMessageHeader JsonObject
#define EO365ItemBody JsonObject
@@ -124,9 +125,10 @@ const gchar * e_o365_category_get_display_name (EO365Category *category);
const gchar * e_o365_category_get_id (EO365Category *category);
const gchar * e_o365_category_get_color (EO365Category *category);
-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);
+const gchar * e_o365_folder_get_id (EO365Folder *folder);
+const gchar * e_o365_folder_get_parent_folder_id (EO365Folder *folder);
+const gchar * e_o365_folder_get_display_name (EO365Folder *folder);
+
gint32 e_o365_mail_folder_get_child_folder_count
(EO365MailFolder *folder);
gint32 e_o365_mail_folder_get_total_item_count (EO365MailFolder *folder);
diff --git a/src/Office365/common/e-source-o365-folder.c b/src/Office365/common/e-source-o365-folder.c
index 2d1b7a70..8d7ca61e 100644
--- a/src/Office365/common/e-source-o365-folder.c
+++ b/src/Office365/common/e-source-o365-folder.c
@@ -20,14 +20,14 @@
#include "e-source-o365-folder.h"
struct _ESourceO365FolderPrivate {
- gchar *change_key;
gchar *id;
+ gboolean is_default;
};
enum {
PROP_0,
- PROP_CHANGE_KEY,
- PROP_ID
+ PROP_ID,
+ PROP_IS_DEFAULT
};
G_DEFINE_TYPE_WITH_PRIVATE (ESourceO365Folder, e_source_o365_folder, E_TYPE_SOURCE_EXTENSION)
@@ -39,10 +39,10 @@ source_o365_folder_set_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
- case PROP_CHANGE_KEY:
- e_source_o365_folder_set_change_key (
+ case PROP_IS_DEFAULT:
+ e_source_o365_folder_set_is_default (
E_SOURCE_O365_FOLDER (object),
- g_value_get_string (value));
+ g_value_get_boolean (value));
return;
case PROP_ID:
@@ -62,10 +62,10 @@ source_o365_folder_get_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
- case PROP_CHANGE_KEY:
- g_value_take_string (
+ case PROP_IS_DEFAULT:
+ g_value_set_boolean (
value,
- e_source_o365_folder_dup_change_key (
+ e_source_o365_folder_get_is_default (
E_SOURCE_O365_FOLDER (object)));
return;
@@ -85,7 +85,6 @@ source_o365_folder_finalize (GObject *object)
{
ESourceO365Folder *o365_folder = E_SOURCE_O365_FOLDER (object);
- g_free (o365_folder->priv->change_key);
g_free (o365_folder->priv->id);
/* Chain up to parent's method. */
@@ -108,11 +107,11 @@ e_source_o365_folder_class_init (ESourceO365FolderClass *class)
g_object_class_install_property (
object_class,
- PROP_CHANGE_KEY,
+ PROP_ID,
g_param_spec_string (
- "change-key",
- "Change Key",
- "Essentially an entity tag, used when submitting changes",
+ "id",
+ "ID",
+ "The server-assigned folder ID",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
@@ -121,12 +120,12 @@ e_source_o365_folder_class_init (ESourceO365FolderClass *class)
g_object_class_install_property (
object_class,
- PROP_ID,
- g_param_spec_string (
- "id",
- "ID",
- "The server-assigned folder ID",
- NULL,
+ PROP_IS_DEFAULT,
+ g_param_spec_boolean (
+ "is-default",
+ "Is Default",
+ "Whether it's user's default folder (like 'contacts', which are not part of the
contactFolders)",
+ FALSE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS |
@@ -148,15 +147,15 @@ e_source_o365_folder_type_register (GTypeModule *type_module)
}
const gchar *
-e_source_o365_folder_get_change_key (ESourceO365Folder *extension)
+e_source_o365_folder_get_id (ESourceO365Folder *extension)
{
g_return_val_if_fail (E_IS_SOURCE_O365_FOLDER (extension), NULL);
- return extension->priv->change_key;
+ return extension->priv->id;
}
gchar *
-e_source_o365_folder_dup_change_key (ESourceO365Folder *extension)
+e_source_o365_folder_dup_id (ESourceO365Folder *extension)
{
const gchar *protected;
gchar *duplicate;
@@ -165,7 +164,7 @@ e_source_o365_folder_dup_change_key (ESourceO365Folder *extension)
e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
- protected = e_source_o365_folder_get_change_key (extension);
+ protected = e_source_o365_folder_get_id (extension);
duplicate = g_strdup (protected);
e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
@@ -174,69 +173,50 @@ e_source_o365_folder_dup_change_key (ESourceO365Folder *extension)
}
void
-e_source_o365_folder_set_change_key (ESourceO365Folder *extension,
- const gchar *change_key)
+e_source_o365_folder_set_id (ESourceO365Folder *extension,
+ const gchar *id)
{
g_return_if_fail (E_IS_SOURCE_O365_FOLDER (extension));
e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
- if (g_strcmp0 (extension->priv->change_key, change_key) == 0) {
+ if (g_strcmp0 (extension->priv->id, id) == 0) {
e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
return;
}
- g_free (extension->priv->change_key);
- extension->priv->change_key = g_strdup (change_key);
+ g_free (extension->priv->id);
+ extension->priv->id = g_strdup (id);
e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
- g_object_notify (G_OBJECT (extension), "change-key");
-}
-
-const gchar *
-e_source_o365_folder_get_id (ESourceO365Folder *extension)
-{
- g_return_val_if_fail (E_IS_SOURCE_O365_FOLDER (extension), NULL);
-
- return extension->priv->id;
+ g_object_notify (G_OBJECT (extension), "id");
}
-gchar *
-e_source_o365_folder_dup_id (ESourceO365Folder *extension)
+gboolean
+e_source_o365_folder_get_is_default (ESourceO365Folder *extension)
{
- const gchar *protected;
- gchar *duplicate;
-
- g_return_val_if_fail (E_IS_SOURCE_O365_FOLDER (extension), NULL);
-
- e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
+ g_return_val_if_fail (E_IS_SOURCE_O365_FOLDER (extension), FALSE);
- protected = e_source_o365_folder_get_id (extension);
- duplicate = g_strdup (protected);
-
- e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
-
- return duplicate;
+ return extension->priv->is_default;
}
void
-e_source_o365_folder_set_id (ESourceO365Folder *extension,
- const gchar *id)
+e_source_o365_folder_set_is_default (ESourceO365Folder *extension,
+ gboolean value)
{
g_return_if_fail (E_IS_SOURCE_O365_FOLDER (extension));
e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
- if (g_strcmp0 (extension->priv->id, id) == 0) {
+ if ((extension->priv->is_default ? 1 : 0) == (value ? 1 : 0)) {
e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
return;
}
- g_free (extension->priv->id);
- extension->priv->id = g_strdup (id);
+ extension->priv->is_default = value;
e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
- g_object_notify (G_OBJECT (extension), "id");
+ g_object_notify (G_OBJECT (extension), "is-default");
}
diff --git a/src/Office365/common/e-source-o365-folder.h b/src/Office365/common/e-source-o365-folder.h
index f124eca1..4b1ddc63 100644
--- a/src/Office365/common/e-source-o365-folder.h
+++ b/src/Office365/common/e-source-o365-folder.h
@@ -59,17 +59,15 @@ struct _ESourceO365FolderClass {
GType e_source_o365_folder_get_type (void) G_GNUC_CONST;
void e_source_o365_folder_type_register
(GTypeModule *type_module);
-const gchar * e_source_o365_folder_get_change_key
- (ESourceO365Folder *extension);
-gchar * e_source_o365_folder_dup_change_key
- (ESourceO365Folder *extension);
-void e_source_o365_folder_set_change_key
- (ESourceO365Folder *extension,
- const gchar *change_key);
const gchar * e_source_o365_folder_get_id (ESourceO365Folder *extension);
gchar * e_source_o365_folder_dup_id (ESourceO365Folder *extension);
void e_source_o365_folder_set_id (ESourceO365Folder *extension,
const gchar *id);
+gboolean e_source_o365_folder_get_is_default
+ (ESourceO365Folder *extension);
+void e_source_o365_folder_set_is_default
+ (ESourceO365Folder *extension,
+ gboolean value);
G_END_DECLS
diff --git a/src/Office365/registry/CMakeLists.txt b/src/Office365/registry/CMakeLists.txt
index dd8b7be3..dcd7e56c 100644
--- a/src/Office365/registry/CMakeLists.txt
+++ b/src/Office365/registry/CMakeLists.txt
@@ -5,6 +5,8 @@ set(sources
e-o365-backend.h
e-o365-backend-factory.c
e-o365-backend-factory.h
+ e-source-o365-deltas.c
+ e-source-o365-deltas.h
)
set(extra_defines)
set(extra_cflags)
diff --git a/src/Office365/registry/e-o365-backend.c b/src/Office365/registry/e-o365-backend.c
index 1ced46dc..d1b1c3c7 100644
--- a/src/Office365/registry/e-o365-backend.c
+++ b/src/Office365/registry/e-o365-backend.c
@@ -23,11 +23,18 @@
#include "common/e-source-o365-folder.h"
#include "common/camel-o365-settings.h"
+#include "e-source-o365-deltas.h"
+
#include "e-o365-backend.h"
+#define LOCK(_backend) g_mutex_lock (&_backend->priv->property_lock)
+#define UNLOCK(_backend) g_mutex_unlock (&_backend->priv->property_lock)
+
struct _EO365BackendPrivate {
GMutex property_lock;
+ GHashTable *folder_sources; /* gchar *folder_id ~> ESource * */
+
gboolean need_update_folders;
gulong source_changed_id;
@@ -76,6 +83,269 @@ o365_backend_populate (ECollectionBackend *backend)
e_backend_schedule_authenticate (E_BACKEND (backend), NULL);
}
+static void
+o365_backend_update_resource (EO365Backend *o365_backend,
+ const gchar *extension_name,
+ const gchar *id,
+ const gchar *display_name,
+ gboolean is_default,
+ const gchar *calendar_color)
+{
+ ESource *source;
+ gboolean is_new;
+
+ LOCK (o365_backend);
+ source = g_hash_table_lookup (o365_backend->priv->folder_sources, id);
+ if (source)
+ g_object_ref (source);
+ UNLOCK (o365_backend);
+
+ is_new = !source;
+
+ if (is_new)
+ source = e_collection_backend_new_child (E_COLLECTION_BACKEND (o365_backend), id);
+
+ if (source) {
+ e_source_set_display_name (source, display_name);
+
+ if (calendar_color && g_ascii_strcasecmp (calendar_color, "auto") != 0 && (
+ g_strcmp0 (extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0 ||
+ g_strcmp0 (extension_name, E_SOURCE_EXTENSION_TASK_LIST) == 0 ||
+ g_strcmp0 (extension_name, E_SOURCE_EXTENSION_MEMO_LIST) == 0)) {
+ ESourceSelectable *selectable;
+
+ selectable = e_source_get_extension (source, extension_name);
+ e_source_selectable_set_color (selectable, calendar_color);
+ }
+
+ if (is_new) {
+ ESourceRegistryServer *server;
+ gpointer extension;
+
+ extension = e_source_get_extension (source, extension_name);
+ e_source_backend_set_backend_name (E_SOURCE_BACKEND (extension), "office365");
+
+ /* Do not notify with too old reminders */
+ if (g_strcmp0 (extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0 ||
+ g_strcmp0 (extension_name, E_SOURCE_EXTENSION_TASK_LIST) == 0) {
+ ESourceAlarms *alarms;
+ gchar *today;
+ GTimeVal today_tv;
+ GDate dt;
+
+ g_date_clear (&dt, 1);
+ g_get_current_time (&today_tv);
+ g_date_set_time_val (&dt, &today_tv);
+
+ /* midnight UTC */
+ today = g_strdup_printf ("%04d-%02d-%02dT00:00:00Z", g_date_get_year (&dt),
g_date_get_month (&dt), g_date_get_day (&dt));
+
+ alarms = e_source_get_extension (source, E_SOURCE_EXTENSION_ALARMS);
+ e_source_alarms_set_last_notified (alarms, today);
+
+ g_free (today);
+ }
+
+ extension = e_source_get_extension (source, E_SOURCE_EXTENSION_O365_FOLDER);
+ e_source_o365_folder_set_id (extension, id);
+ e_source_o365_folder_set_is_default (extension, is_default);
+
+ server = e_collection_backend_ref_server (E_COLLECTION_BACKEND (o365_backend));
+
+ e_source_registry_server_add_source (server, source);
+
+ g_clear_object (&server);
+ }
+ }
+
+ g_clear_object (&source);
+}
+
+static void
+o365_backend_remove_resource (EO365Backend *o365_backend,
+ const gchar *extension_name,
+ const gchar *id) /* NULL to remove the "is-default" resource for the
extension_name */
+{
+ ESource *existing_source;
+
+ LOCK (o365_backend);
+
+ if (id) {
+ existing_source = g_hash_table_lookup (o365_backend->priv->folder_sources, id);
+ } else {
+ GHashTableIter iter;
+ gpointer value;
+
+ g_hash_table_iter_init (&iter, o365_backend->priv->folder_sources);
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ ESource *source = value;
+
+ if (value && e_source_has_extension (source, extension_name) &&
+ e_source_o365_folder_get_is_default (e_source_get_extension (source,
E_SOURCE_EXTENSION_O365_FOLDER))) {
+ existing_source = source;
+ break;
+ }
+ }
+ }
+
+ if (existing_source)
+ g_object_ref (existing_source);
+
+ UNLOCK (o365_backend);
+
+ if (existing_source)
+ e_source_remove_sync (existing_source, NULL, NULL);
+
+ g_clear_object (&existing_source);
+}
+
+static void
+o365_backend_forget_folders (EO365Backend *o365_backend,
+ const gchar *extension_name)
+{
+ GHashTableIter iter;
+ GSList *ids = NULL, *link;
+ gpointer value;
+
+ LOCK (o365_backend);
+
+ g_hash_table_iter_init (&iter, o365_backend->priv->folder_sources);
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ ESource *source = value;
+
+ if (source && e_source_has_extension (source, extension_name))
+ ids = g_slist_prepend (ids, e_source_o365_folder_dup_id (e_source_get_extension
(source, E_SOURCE_EXTENSION_O365_FOLDER)));
+ }
+
+ UNLOCK (o365_backend);
+
+ for (link = ids; link; link = g_slist_next (link)) {
+ const gchar *id = link->data;
+
+ if (id)
+ o365_backend_remove_resource (o365_backend, extension_name, id);
+ }
+
+ g_slist_free_full (ids, g_free);
+}
+
+static gboolean
+o365_backend_got_contact_folders_delta_cb (EO365Connection *cnc,
+ const GSList *results, /* JsonObject * - the returned objects from
the server */
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EO365Backend *o365_backend = user_data;
+ GSList *link;
+
+ g_return_val_if_fail (E_IS_O365_BACKEND (o365_backend), FALSE);
+
+ for (link = (GSList *) results; link; link = g_slist_next (link)) {
+ JsonObject *object = link->data;
+ const gchar *id = e_o365_folder_get_id (object);
+
+ if (!id)
+ continue;
+
+ if (e_o365_delta_is_removed_object (object)) {
+ o365_backend_remove_resource (o365_backend, E_SOURCE_EXTENSION_ADDRESS_BOOK, id);
+ } else {
+ o365_backend_update_resource (o365_backend, E_SOURCE_EXTENSION_ADDRESS_BOOK,
+ id, e_o365_folder_get_display_name (object),
+ FALSE, NULL);
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+o365_backend_sync_folders_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ EO365Backend *o365_backend = source_object;
+ EO365Connection *cnc = task_data;
+ ESourceO365Deltas *o365_deltas;
+ EO365Folder *user_contacts = NULL;
+ gchar *old_delta_link, *new_delta_link;
+ gboolean success;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_O365_BACKEND (o365_backend));
+ g_return_if_fail (E_IS_O365_CONNECTION (cnc));
+
+ o365_deltas = e_source_get_extension (e_backend_get_source (E_BACKEND (o365_backend)),
E_SOURCE_EXTENSION_O365_DELTAS);
+
+ if (e_o365_connection_get_contacts_folder_sync (cnc, NULL, &user_contacts, cancellable, &error)) {
+ const gchar *id, *display_name;
+
+ id = e_o365_folder_get_id (user_contacts);
+ display_name = e_o365_folder_get_display_name (user_contacts);
+
+ g_warn_if_fail (id != NULL);
+ g_warn_if_fail (display_name != NULL);
+
+ o365_backend_update_resource (o365_backend,
+ E_SOURCE_EXTENSION_ADDRESS_BOOK,
+ id, display_name, TRUE, NULL);
+
+ json_object_unref (user_contacts);
+ } else if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND) ||
+ g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+ o365_backend_remove_resource (o365_backend, E_SOURCE_EXTENSION_ADDRESS_BOOK, NULL);
+ }
+
+ g_clear_error (&error);
+
+ new_delta_link = NULL;
+ old_delta_link = e_source_o365_deltas_dup_contacts_link (o365_deltas);
+
+ success = e_o365_connection_get_folders_delta_sync (cnc, NULL, E_O365_FOLDER_KIND_CONTACTS, NULL,
old_delta_link, 0,
+ o365_backend_got_contact_folders_delta_cb, o365_backend, &new_delta_link, cancellable,
&error);
+
+ if (old_delta_link && *old_delta_link && (
+ g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
+ g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_BAD_REQUEST))) {
+ g_clear_pointer (&old_delta_link, g_free);
+ g_clear_error (&error);
+
+ o365_backend_forget_folders (o365_backend, E_SOURCE_EXTENSION_ADDRESS_BOOK);
+
+ success = e_o365_connection_get_folders_delta_sync (cnc, NULL, E_O365_FOLDER_KIND_CONTACTS,
NULL, NULL, 0,
+ o365_backend_got_contact_folders_delta_cb, o365_backend, &new_delta_link,
cancellable, &error);
+ }
+
+ if (success)
+ e_source_o365_deltas_set_contacts_link (o365_deltas, new_delta_link);
+
+ g_clear_pointer (&old_delta_link, g_free);
+ g_clear_pointer (&new_delta_link, g_free);
+ g_clear_error (&error);
+}
+
+static void
+o365_backend_sync_folders (EO365Backend *o365_backend,
+ EO365Connection *cnc,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ o365_backend->priv->need_update_folders = FALSE;
+
+ task = g_task_new (o365_backend, cancellable, callback, user_data);
+
+ g_task_set_check_cancellable (task, TRUE);
+ g_task_set_task_data (task, g_object_ref (cnc), g_object_unref);
+ g_task_run_in_thread (task, o365_backend_sync_folders_thread);
+
+ g_object_unref (task);
+}
+
static gchar *
o365_backend_dup_resource_id (ECollectionBackend *backend,
ESource *child_source)
@@ -93,35 +363,19 @@ static void
o365_backend_child_added (ECollectionBackend *backend,
ESource *child_source)
{
-#if 0
ESource *collection_source;
- const gchar *extension_name;
- gboolean is_mail = FALSE;
collection_source = e_backend_get_source (E_BACKEND (backend));
- extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
- is_mail |= e_source_has_extension (child_source, extension_name);
-
- extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
- is_mail |= e_source_has_extension (child_source, extension_name);
-
- extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
- is_mail |= e_source_has_extension (child_source, extension_name);
-
- /* Synchronize mail-related user with the collection identity. */
- extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
- if (is_mail && e_source_has_extension (child_source, extension_name)) {
+ if (e_source_has_extension (child_source, E_SOURCE_EXTENSION_AUTHENTICATION) && (
+ e_source_has_extension (child_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT) ||
+ e_source_has_extension (child_source, E_SOURCE_EXTENSION_MAIL_IDENTITY) ||
+ e_source_has_extension (child_source, E_SOURCE_EXTENSION_MAIL_TRANSPORT))) {
ESourceAuthentication *auth_child_extension;
ESourceCollection *collection_extension;
- extension_name = E_SOURCE_EXTENSION_COLLECTION;
- collection_extension = e_source_get_extension (
- collection_source, extension_name);
-
- extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
- auth_child_extension = e_source_get_extension (
- child_source, extension_name);
+ collection_extension = e_source_get_extension (collection_source,
E_SOURCE_EXTENSION_COLLECTION);
+ auth_child_extension = e_source_get_extension (child_source,
E_SOURCE_EXTENSION_AUTHENTICATION);
e_binding_bind_property (
collection_extension, "identity",
@@ -130,22 +384,22 @@ o365_backend_child_added (ECollectionBackend *backend,
}
/* We track O365 folders in a hash table by folder ID. */
- extension_name = E_SOURCE_EXTENSION_O365_FOLDER;
- if (e_source_has_extension (child_source, extension_name)) {
+ if (e_source_has_extension (child_source, E_SOURCE_EXTENSION_O365_FOLDER)) {
ESourceO365Folder *extension;
gchar *folder_id;
- extension = e_source_get_extension (
- child_source, extension_name);
+ extension = e_source_get_extension (child_source, E_SOURCE_EXTENSION_O365_FOLDER);
folder_id = e_source_o365_folder_dup_id (extension);
- if (folder_id != NULL) {
- o365_backend_folders_insert (
- E_O365_BACKEND (backend),
- folder_id, child_source);
- g_free (folder_id);
+
+ if (folder_id) {
+ EO365Backend *o365_backend = E_O365_BACKEND (backend);
+
+ LOCK (o365_backend);
+ g_hash_table_insert (o365_backend->priv->folder_sources, folder_id, g_object_ref
(child_source));
+ UNLOCK (o365_backend);
}
}
-#endif
+
/* Chain up to parent's method. */
E_COLLECTION_BACKEND_CLASS (e_o365_backend_parent_class)->child_added (backend, child_source);
}
@@ -154,23 +408,22 @@ static void
o365_backend_child_removed (ECollectionBackend *backend,
ESource *child_source)
{
-#if 0
- const gchar *extension_name;
-
/* We track O365 folders in a hash table by folder ID. */
- extension_name = E_SOURCE_EXTENSION_O365_FOLDER;
- if (e_source_has_extension (child_source, extension_name)) {
+ if (e_source_has_extension (child_source, E_SOURCE_EXTENSION_O365_FOLDER)) {
ESourceO365Folder *extension;
const gchar *folder_id;
- extension = e_source_get_extension (
- child_source, extension_name);
+ extension = e_source_get_extension (child_source, E_SOURCE_EXTENSION_O365_FOLDER);
folder_id = e_source_o365_folder_get_id (extension);
- if (folder_id != NULL)
- o365_backend_folders_remove (
- E_O365_BACKEND (backend), folder_id);
+
+ if (folder_id) {
+ EO365Backend *o365_backend = E_O365_BACKEND (backend);
+
+ LOCK (o365_backend);
+ g_hash_table_remove (o365_backend->priv->folder_sources, folder_id);
+ UNLOCK (o365_backend);
+ }
}
-#endif
/* Chain up to parent's method. */
E_COLLECTION_BACKEND_CLASS (e_o365_backend_parent_class)->child_removed (backend, child_source);
@@ -379,7 +632,6 @@ o365_backend_authenticate_sync (EBackend *backend,
GError **error)
{
CamelO365Settings *o365_settings;
- /*EO365Backend *o365_backend;*/
EO365Connection *cnc;
ESourceAuthenticationResult result;
@@ -394,8 +646,7 @@ o365_backend_authenticate_sync (EBackend *backend,
if (result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
e_collection_backend_authenticate_children (E_COLLECTION_BACKEND (backend), credentials);
-
- /* e_o365_backend_sync_folders (o365_backend, NULL, o365_backend_folders_synced_cb, NULL); */
+ o365_backend_sync_folders (E_O365_BACKEND (backend), cnc, NULL, NULL, NULL);
} else if (result == E_SOURCE_AUTHENTICATION_REJECTED &&
!e_named_parameters_exists (credentials, E_SOURCE_CREDENTIAL_PASSWORD)) {
result = E_SOURCE_AUTHENTICATION_REQUIRED;
@@ -453,6 +704,7 @@ o365_backend_finalize (GObject *object)
{
EO365Backend *o365_backend = E_O365_BACKEND (object);
+ g_hash_table_destroy (o365_backend->priv->folder_sources);
g_mutex_clear (&o365_backend->priv->property_lock);
/* Chain up to parent's method. */
@@ -496,6 +748,7 @@ static void
e_o365_backend_init (EO365Backend *backend)
{
backend->priv = e_o365_backend_get_instance_private (backend);
+ backend->priv->folder_sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
g_object_unref);
g_mutex_init (&backend->priv->property_lock);
}
diff --git a/src/Office365/registry/e-source-o365-deltas.c b/src/Office365/registry/e-source-o365-deltas.c
new file mode 100644
index 00000000..94b3cffe
--- /dev/null
+++ b/src/Office365/registry/e-source-o365-deltas.c
@@ -0,0 +1,166 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "evolution-ews-config.h"
+
+#include "e-source-o365-deltas.h"
+
+struct _ESourceO365DeltasPrivate {
+ gchar *contacts_link;
+};
+
+enum {
+ PROP_0,
+ PROP_CONTACTS_LINK
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (ESourceO365Deltas, e_source_o365_deltas, E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_o365_deltas_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CONTACTS_LINK:
+ e_source_o365_deltas_set_contacts_link (
+ E_SOURCE_O365_DELTAS (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_o365_deltas_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CONTACTS_LINK:
+ g_value_take_string (
+ value,
+ e_source_o365_deltas_dup_contacts_link (
+ E_SOURCE_O365_DELTAS (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_o365_deltas_finalize (GObject *object)
+{
+ ESourceO365Deltas *o365_deltas = E_SOURCE_O365_DELTAS (object);
+
+ g_free (o365_deltas->priv->contacts_link);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_source_o365_deltas_parent_class)->finalize (object);
+}
+
+static void
+e_source_o365_deltas_class_init (ESourceO365DeltasClass *class)
+{
+ GObjectClass *object_class;
+ ESourceExtensionClass *extension_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = source_o365_deltas_set_property;
+ object_class->get_property = source_o365_deltas_get_property;
+ object_class->finalize = source_o365_deltas_finalize;
+
+ extension_class = E_SOURCE_EXTENSION_CLASS (class);
+ extension_class->name = E_SOURCE_EXTENSION_O365_DELTAS;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CONTACTS_LINK,
+ g_param_spec_string (
+ "contacts-link",
+ "Contacts Link",
+ "The delta link for contacts",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS |
+ E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_o365_deltas_init (ESourceO365Deltas *extension)
+{
+ extension->priv = e_source_o365_deltas_get_instance_private (extension);
+}
+
+void
+e_source_o365_deltas_type_register (GTypeModule *type_module)
+{
+ /* We need to ensure this is registered, because it's looked up
+ * by name in e_source_get_extension(). */
+ g_type_ensure (E_TYPE_SOURCE_O365_DELTAS);
+}
+
+const gchar *
+e_source_o365_deltas_get_contacts_link (ESourceO365Deltas *extension)
+{
+ g_return_val_if_fail (E_IS_SOURCE_O365_DELTAS (extension), NULL);
+
+ return extension->priv->contacts_link;
+}
+
+gchar *
+e_source_o365_deltas_dup_contacts_link (ESourceO365Deltas *extension)
+{
+ const gchar *protected;
+ gchar *duplicate;
+
+ g_return_val_if_fail (E_IS_SOURCE_O365_DELTAS (extension), NULL);
+
+ e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
+
+ protected = e_source_o365_deltas_get_contacts_link (extension);
+ duplicate = g_strdup (protected);
+
+ e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+
+ return duplicate;
+}
+
+void
+e_source_o365_deltas_set_contacts_link (ESourceO365Deltas *extension,
+ const gchar *delta_link)
+{
+ g_return_if_fail (E_IS_SOURCE_O365_DELTAS (extension));
+
+ e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
+
+ if (g_strcmp0 (extension->priv->contacts_link, delta_link) == 0) {
+ e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+ return;
+ }
+
+ g_free (extension->priv->contacts_link);
+ extension->priv->contacts_link = g_strdup (delta_link);
+
+ e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+
+ g_object_notify (G_OBJECT (extension), "contacts-link");
+}
diff --git a/src/Office365/registry/e-source-o365-deltas.h b/src/Office365/registry/e-source-o365-deltas.h
new file mode 100644
index 00000000..dac6e770
--- /dev/null
+++ b/src/Office365/registry/e-source-o365-deltas.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_SOURCE_O365_DELTAS_H
+#define E_SOURCE_O365_DELTAS_H
+
+#include <libedataserver/libedataserver.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_O365_DELTAS \
+ (e_source_o365_deltas_get_type ())
+#define E_SOURCE_O365_DELTAS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SOURCE_O365_DELTAS, ESourceO365Deltas))
+#define E_SOURCE_O365_DELTAS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SOURCE_O365_DELTAS, ESourceO365DeltasClass))
+#define E_IS_SOURCE_O365_DELTAS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SOURCE_O365_DELTAS))
+#define E_IS_SOURCE_O365_DELTAS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SOURCE_O365_DELTAS))
+#define E_SOURCE_O365_DELTAS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SOURCE_O365_DELTAS, ESourceO365DeltasClass))
+
+#define E_SOURCE_EXTENSION_O365_DELTAS "Office365 Deltas"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceO365Deltas ESourceO365Deltas;
+typedef struct _ESourceO365DeltasClass ESourceO365DeltasClass;
+typedef struct _ESourceO365DeltasPrivate ESourceO365DeltasPrivate;
+
+struct _ESourceO365Deltas {
+ ESourceExtension parent;
+ ESourceO365DeltasPrivate *priv;
+};
+
+struct _ESourceO365DeltasClass {
+ ESourceExtensionClass parent_class;
+};
+
+GType e_source_o365_deltas_get_type (void) G_GNUC_CONST;
+void e_source_o365_deltas_type_register
+ (GTypeModule *type_module);
+const gchar * e_source_o365_deltas_get_contacts_link
+ (ESourceO365Deltas *extension);
+gchar * e_source_o365_deltas_dup_contacts_link
+ (ESourceO365Deltas *extension);
+void e_source_o365_deltas_set_contacts_link
+ (ESourceO365Deltas *extension,
+ const gchar *delta_link);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_O365_DELTAS_H */
diff --git a/src/Office365/registry/module-o365-backend.c b/src/Office365/registry/module-o365-backend.c
index 7129b501..1997ee6f 100644
--- a/src/Office365/registry/module-o365-backend.c
+++ b/src/Office365/registry/module-o365-backend.c
@@ -24,6 +24,7 @@
#include "e-o365-backend.h"
#include "e-o365-backend-factory.h"
+#include "e-source-o365-deltas.h"
/* Module Entry Points */
void e_module_load (GTypeModule *type_module);
@@ -38,6 +39,7 @@ e_module_load (GTypeModule *type_module)
e_oauth2_service_office365_type_register (type_module);
e_source_o365_folder_type_register (type_module);
+ e_source_o365_deltas_type_register (type_module);
e_o365_backend_type_register (type_module);
e_o365_backend_factory_type_register (type_module);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]