[evolution-ews/wip/mcrha/office365] Recognize user calendars and add them as ESource-s
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews/wip/mcrha/office365] Recognize user calendars and add them as ESource-s
- Date: Wed, 15 Jul 2020 15:38:02 +0000 (UTC)
commit aa24d61ad92146a9ea9cf5bd419b833db871f0ea
Author: Milan Crha <mcrha redhat com>
Date: Wed Jul 15 17:38:02 2020 +0200
Recognize user calendars and add them as ESource-s
src/Office365/addressbook/e-book-backend-o365.c | 2 +-
src/Office365/camel/camel-o365-store.c | 2 +-
src/Office365/camel/camel-o365-transport.c | 2 +-
src/Office365/common/e-o365-connection.c | 587 ++++++++++++++++++++++--
src/Office365/common/e-o365-connection.h | 93 +++-
src/Office365/common/e-o365-json-utils.c | 302 ++++++++++++
src/Office365/common/e-o365-json-utils.h | 65 +++
src/Office365/common/e-source-o365-folder.c | 78 +++-
src/Office365/common/e-source-o365-folder.h | 7 +
src/Office365/registry/e-o365-backend.c | 161 ++++++-
10 files changed, 1233 insertions(+), 66 deletions(-)
---
diff --git a/src/Office365/addressbook/e-book-backend-o365.c b/src/Office365/addressbook/e-book-backend-o365.c
index 16ba8ddb..1b127c13 100644
--- a/src/Office365/addressbook/e-book-backend-o365.c
+++ b/src/Office365/addressbook/e-book-backend-o365.c
@@ -1423,7 +1423,7 @@ ebb_o365_connect_sync (EBookMetaBackend *meta_backend,
if (folder_id) {
cnc = e_o365_connection_new_for_backend (backend, registry, source, o365_settings);
- *out_auth_result = e_o365_connection_authenticate_sync (cnc, NULL,
E_O365_FOLDER_KIND_CONTACTS, folder_id,
+ *out_auth_result = e_o365_connection_authenticate_sync (cnc, NULL,
E_O365_FOLDER_KIND_CONTACTS, NULL, folder_id,
out_certificate_pem, out_certificate_errors, cancellable, error);
if (*out_auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
diff --git a/src/Office365/camel/camel-o365-store.c b/src/Office365/camel/camel-o365-store.c
index 4142b23a..acae3c8b 100644
--- a/src/Office365/camel/camel-o365-store.c
+++ b/src/Office365/camel/camel-o365-store.c
@@ -597,7 +597,7 @@ o365_store_authenticate_sync (CamelService *service,
if (!cnc)
return CAMEL_AUTHENTICATION_ERROR;
- switch (e_o365_connection_authenticate_sync (cnc, NULL, E_O365_FOLDER_KIND_MAIL, NULL, NULL, NULL,
cancellable, error)) {
+ switch (e_o365_connection_authenticate_sync (cnc, NULL, E_O365_FOLDER_KIND_MAIL, NULL, NULL, NULL,
NULL, cancellable, error)) {
case E_SOURCE_AUTHENTICATION_ERROR:
case E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED:
default:
diff --git a/src/Office365/camel/camel-o365-transport.c b/src/Office365/camel/camel-o365-transport.c
index 7149f975..5be5359f 100644
--- a/src/Office365/camel/camel-o365-transport.c
+++ b/src/Office365/camel/camel-o365-transport.c
@@ -238,7 +238,7 @@ o365_transport_authenticate_sync (CamelService *service,
if (!cnc)
return CAMEL_AUTHENTICATION_ERROR;
- switch (e_o365_connection_authenticate_sync (cnc, NULL, E_O365_FOLDER_KIND_MAIL, NULL, NULL, NULL,
cancellable, error)) {
+ switch (e_o365_connection_authenticate_sync (cnc, NULL, E_O365_FOLDER_KIND_MAIL, NULL, NULL, NULL,
NULL, cancellable, error)) {
case E_SOURCE_AUTHENTICATION_ERROR:
case E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED:
default:
diff --git a/src/Office365/common/e-o365-connection.c b/src/Office365/common/e-o365-connection.c
index 52d6dddd..9c9570e1 100644
--- a/src/Office365/common/e-o365-connection.c
+++ b/src/Office365/common/e-o365-connection.c
@@ -1557,6 +1557,7 @@ ESourceAuthenticationResult
e_o365_connection_authenticate_sync (EO365Connection *cnc,
const gchar *user_override,
EO365FolderKind kind,
+ const gchar *group_id,
const gchar *folder_id,
gchar **out_certificate_pem,
GTlsCertificateFlags *out_certificate_errors,
@@ -1564,57 +1565,37 @@ e_o365_connection_authenticate_sync (EO365Connection *cnc,
GError **error)
{
ESourceAuthenticationResult result = E_SOURCE_AUTHENTICATION_ERROR;
- SoupMessage *message;
JsonObject *object = NULL;
- gchar *uri;
- const gchar *resource = NULL;
- gboolean success;
+ gboolean success = FALSE;
GError *local_error = NULL;
g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), result);
- /* Just pick an inexpensive operation */
switch (kind) {
+ default:
+ g_warn_if_reached ();
+ /* Falls through */
case E_O365_FOLDER_KIND_UNKNOWN:
case E_O365_FOLDER_KIND_MAIL:
- resource = "mailFolders";
-
if (!folder_id || !*folder_id)
folder_id = "inbox";
+
+ success = e_o365_connection_get_mail_folder_sync (cnc, user_override, folder_id,
"displayName", &object, cancellable, &local_error);
break;
case E_O365_FOLDER_KIND_CONTACTS:
- resource = "contactFolders";
-
if (!folder_id || !*folder_id)
folder_id = "contacts";
- break;
- default:
- g_warn_if_reached ();
- resource = "mailFolders";
- folder_id = "inbox";
+ success = e_o365_connection_get_contacts_folder_sync (cnc, user_override, folder_id,
"displayName", &object, cancellable, &local_error);
break;
- }
-
- uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
- resource,
- folder_id,
- NULL,
- "$select", "displayName",
- NULL);
-
- message = o365_connection_new_soup_message (SOUP_METHOD_GET, uri, CSM_DEFAULT, error);
-
- if (!message) {
- g_free (uri);
+ case E_O365_FOLDER_KIND_CALENDAR:
+ if (folder_id && !*folder_id)
+ folder_id = NULL;
- return FALSE;
+ success = e_o365_connection_get_calendar_folder_sync (cnc, user_override, group_id,
folder_id, "name", &object, cancellable, error);
+ break;
}
- g_free (uri);
-
- success = o365_connection_send_request_sync (cnc, message, e_o365_read_json_object_response_cb, NULL,
&object, cancellable, &local_error);
-
if (success) {
result = E_SOURCE_AUTHENTICATION_ACCEPTED;
} else {
@@ -1659,7 +1640,6 @@ e_o365_connection_authenticate_sync (EO365Connection *cnc,
if (object)
json_object_unref (object);
- g_clear_object (&message);
g_clear_error (&local_error);
return result;
@@ -2382,6 +2362,48 @@ e_o365_connection_get_folders_delta_sync (EO365Connection *cnc,
return success;
}
+/* https://docs.microsoft.com/en-us/graph/api/mailfolder-get?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_get_mail_folder_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *folder_id, /* nullable - then the 'inbox' is used */
+ const gchar *select, /* nullable - properties to select */
+ EO365MailFolder **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,
+ "mailFolders",
+ folder_id ? folder_id : "inbox",
+ NULL,
+ "$select", select,
+ 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;
+}
+
/* https://docs.microsoft.com/en-us/graph/api/user-post-mailfolders?view=graph-rest-1.0&tabs=http
https://docs.microsoft.com/en-us/graph/api/mailfolder-post-childfolders?view=graph-rest-1.0&tabs=http */
@@ -3244,9 +3266,13 @@ e_o365_connection_send_mail_sync (EO365Connection *cnc,
return success;
}
+/* https://docs.microsoft.com/en-us/graph/api/contactfolder-get?view=graph-rest-1.0&tabs=http */
+
gboolean
e_o365_connection_get_contacts_folder_sync (EO365Connection *cnc,
const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *folder_id, /* nullable - then the default 'contacts'
folder is returned */
+ const gchar *select, /* nullable - properties to select */
EO365Folder **out_folder,
GCancellable *cancellable,
GError **error)
@@ -3260,7 +3286,7 @@ e_o365_connection_get_contacts_folder_sync (EO365Connection *cnc,
uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
"contactFolders",
- "contacts",
+ folder_id ? folder_id : "contacts",
NULL,
NULL);
@@ -3550,3 +3576,496 @@ e_o365_connection_delete_contact_sync (EO365Connection *cnc,
return success;
}
+
+/* https://docs.microsoft.com/en-us/graph/api/user-list-calendargroups?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_list_calendar_groups_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ GSList **out_groups, /* EO365CalendarGroup * - the returned
calendarGroup objects */
+ GCancellable *cancellable,
+ GError **error)
+{
+ EO365ResponseData rd;
+ SoupMessage *message;
+ gchar *uri;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (out_groups != NULL, FALSE);
+
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendarGroups", NULL, 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);
+
+ memset (&rd, 0, sizeof (EO365ResponseData));
+
+ rd.out_items = out_groups;
+
+ 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/user-post-calendargroups?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_create_calendar_group_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *name,
+ EO365CalendarGroup **out_created_group,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupMessage *message;
+ JsonBuilder *builder;
+ gboolean success;
+ gchar *uri;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (out_created_group != NULL, FALSE);
+
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendarGroups", NULL, NULL, NULL);
+
+ message = o365_connection_new_soup_message (SOUP_METHOD_POST, uri, CSM_DEFAULT, error);
+
+ if (!message) {
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+
+ builder = json_builder_new_immutable ();
+
+ e_o365_json_begin_object_member (builder, NULL);
+ e_o365_json_add_string_member (builder, "name", name);
+ e_o365_json_end_object_member (builder);
+
+ e_o365_connection_set_json_body (message, builder);
+
+ g_object_unref (builder);
+
+ success = o365_connection_send_request_sync (cnc, message, e_o365_read_json_object_response_cb, NULL,
out_created_group, cancellable, error);
+
+ g_clear_object (&message);
+
+ return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/calendargroup-get?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_get_calendar_group_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *group_id,
+ EO365CalendarGroup **out_group,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupMessage *message;
+ gboolean success;
+ gchar *uri;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (group_id != NULL, FALSE);
+ g_return_val_if_fail (out_group != NULL, FALSE);
+
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendarGroups",
+ group_id,
+ 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_group, cancellable, error);
+
+ g_clear_object (&message);
+
+ return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/calendargroup-update?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_update_calendar_group_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *group_id,
+ const gchar *name,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupMessage *message;
+ JsonBuilder *builder;
+ gboolean success;
+ gchar *uri;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (group_id != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendarGroups",
+ group_id,
+ NULL,
+ NULL);
+
+ message = o365_connection_new_soup_message ("PATCH", uri, CSM_DISABLE_RESPONSE, error);
+
+ if (!message) {
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+
+ builder = json_builder_new_immutable ();
+
+ e_o365_json_begin_object_member (builder, NULL);
+ e_o365_json_add_string_member (builder, "name", name);
+ e_o365_json_end_object_member (builder);
+
+ e_o365_connection_set_json_body (message, builder);
+
+ g_object_unref (builder);
+
+ success = o365_connection_send_request_sync (cnc, message, NULL, e_o365_read_no_response_cb, NULL,
cancellable, error);
+
+ g_clear_object (&message);
+
+ return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/calendargroup-delete?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_delete_calendar_group_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *group_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupMessage *message;
+ gboolean success;
+ gchar *uri;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (group_id != NULL, FALSE);
+
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendarGroups", group_id, NULL, NULL);
+
+ message = o365_connection_new_soup_message (SOUP_METHOD_DELETE, uri, CSM_DEFAULT, error);
+
+ if (!message) {
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+
+ success = o365_connection_send_request_sync (cnc, message, NULL, e_o365_read_no_response_cb, NULL,
cancellable, error);
+
+ g_clear_object (&message);
+
+ return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/resources/calendar?view=graph-rest-1.0 */
+
+gboolean
+e_o365_connection_list_calendars_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the account
user */
+ const gchar *group_id, /* nullable, calendar group id for group
calendars */
+ const gchar *select, /* properties to select, nullable */
+ GSList **out_calendars, /* EO365Calendar * - the returned calendar
objects */
+ GCancellable *cancellable,
+ GError **error)
+{
+ EO365ResponseData rd;
+ SoupMessage *message;
+ gchar *uri;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (out_calendars != NULL, FALSE);
+
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ group_id ? "calendarGroups" : "calendars",
+ group_id,
+ group_id ? "calendars" : NULL,
+ "$select", select,
+ NULL);
+
+ message = o365_connection_new_soup_message (SOUP_METHOD_GET, uri, CSM_DEFAULT, error);
+
+ if (!message) {
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+
+ memset (&rd, 0, sizeof (EO365ResponseData));
+
+ rd.out_items = out_calendars;
+
+ 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/calendargroup-post-calendars?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_create_calendar_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *group_id, /* nullable, then the default group is used */
+ JsonBuilder *calendar,
+ EO365Calendar **out_created_calendar,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupMessage *message;
+ gboolean success;
+ gchar *uri;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (calendar != NULL, FALSE);
+ g_return_val_if_fail (out_created_calendar != NULL, FALSE);
+
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ group_id ? "calendarGroups" : "calendarGroup",
+ group_id,
+ "calendars",
+ NULL);
+
+ message = o365_connection_new_soup_message (SOUP_METHOD_POST, uri, CSM_DEFAULT, error);
+
+ if (!message) {
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+
+ e_o365_connection_set_json_body (message, calendar);
+
+ success = o365_connection_send_request_sync (cnc, message, e_o365_read_json_object_response_cb, NULL,
out_created_calendar, cancellable, error);
+
+ g_clear_object (&message);
+
+ return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/calendar-get?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_get_calendar_folder_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *group_id, /* nullable - then the default group is
used */
+ const gchar *calendar_id, /* nullable - then the default calendar
is used */
+ const gchar *select, /* nullable - properties to select */
+ EO365Calendar **out_calendar,
+ 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_calendar != NULL, FALSE);
+
+ if (group_id && calendar_id) {
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendarGroups",
+ group_id,
+ "calendars",
+ "", calendar_id,
+ "$select", select,
+ NULL);
+ } else if (group_id) {
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, "groups",
+ group_id,
+ "calendar",
+ NULL,
+ "$select", select,
+ NULL);
+ } else if (calendar_id) {
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendars",
+ calendar_id,
+ NULL,
+ "$select", select,
+ NULL);
+ } else {
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendar",
+ NULL,
+ NULL,
+ "$select", select,
+ 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_calendar, cancellable, error);
+
+ g_clear_object (&message);
+
+ return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/calendar-update?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_update_calendar_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *group_id, /* nullable - then the default group is used */
+ const gchar *calendar_id,
+ const gchar *name, /* nullable - to keep the existing name */
+ EO365CalendarColorType color,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupMessage *message;
+ JsonBuilder *builder;
+ gboolean success;
+ gchar *uri;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (calendar_id != NULL, FALSE);
+
+ /* Nothing to change */
+ if (!name && (color == E_O365_CALENDAR_COLOR_NOT_SET || color == E_O365_CALENDAR_COLOR_UNKNOWN))
+ return TRUE;
+
+ if (group_id) {
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendarGroups",
+ group_id,
+ "calendars",
+ "", calendar_id,
+ NULL);
+ } else {
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendars",
+ calendar_id,
+ NULL,
+ NULL);
+ }
+
+ message = o365_connection_new_soup_message ("PATCH", uri, CSM_DISABLE_RESPONSE, error);
+
+ if (!message) {
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+
+ builder = json_builder_new_immutable ();
+
+ e_o365_json_begin_object_member (builder, NULL);
+ e_o365_calendar_add_name (builder, name);
+ e_o365_calendar_add_color (builder, color);
+ e_o365_json_end_object_member (builder);
+
+ e_o365_connection_set_json_body (message, builder);
+
+ g_object_unref (builder);
+
+ success = o365_connection_send_request_sync (cnc, message, NULL, e_o365_read_no_response_cb, NULL,
cancellable, error);
+
+ g_clear_object (&message);
+
+ return success;
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/calendar-delete?view=graph-rest-1.0&tabs=http */
+
+gboolean
+e_o365_connection_delete_calendar_sync (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use the
account user */
+ const gchar *group_id, /* nullable - then the default group is used */
+ const gchar *calendar_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SoupMessage *message;
+ gboolean success;
+ gchar *uri;
+
+ g_return_val_if_fail (E_IS_O365_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (calendar_id != NULL, FALSE);
+
+ if (group_id) {
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendarGroups",
+ group_id,
+ "calendars",
+ "", calendar_id,
+ NULL);
+ } else {
+ uri = e_o365_connection_construct_uri (cnc, TRUE, user_override, E_O365_API_V1_0, NULL,
+ "calendars",
+ calendar_id,
+ NULL,
+ NULL);
+ }
+
+ message = o365_connection_new_soup_message (SOUP_METHOD_DELETE, uri, CSM_DEFAULT, error);
+
+ if (!message) {
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ g_free (uri);
+
+ success = o365_connection_send_request_sync (cnc, message, NULL, e_o365_read_no_response_cb, NULL,
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 433f2828..db41ae97 100644
--- a/src/Office365/common/e-o365-connection.h
+++ b/src/Office365/common/e-o365-connection.h
@@ -131,6 +131,7 @@ ESourceAuthenticationResult
(EO365Connection *cnc,
const gchar *user_override,
EO365FolderKind kind,
+ const gchar *group_id,
const gchar *folder_id,
gchar **out_certificate_pem,
GTlsCertificateFlags *out_certificate_errors,
@@ -177,7 +178,7 @@ 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, /* properties to select, nullable */
+ const gchar *select, /* nullable - properties to select */
GSList **out_folders, /* EO365MailFolder * - the returned
mailFolder objects */
GCancellable *cancellable,
GError **error);
@@ -185,7 +186,7 @@ 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 *select, /* nullable - properties to select */
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 */
@@ -193,6 +194,14 @@ gboolean e_o365_connection_get_folders_delta_sync
gchar **out_delta_link,
GCancellable *cancellable,
GError **error);
+gboolean e_o365_connection_get_mail_folder_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *folder_id, /* nullable - then the 'inbox' is
used */
+ const gchar *select, /* nullable - properties to select */
+ EO365MailFolder **out_folder,
+ GCancellable *cancellable,
+ GError **error);
gboolean e_o365_connection_create_mail_folder_sync
(EO365Connection *cnc,
const gchar *user_override, /* for which user, NULL to use
the account user */
@@ -229,7 +238,7 @@ gboolean e_o365_connection_get_objects_delta_sync
const gchar *user_override, /* for which user, NULL to use
the account user */
EO365FolderKind kind,
const gchar *folder_id, /* folder ID to get delta messages
in */
- const gchar *select, /* properties to select, nullable */
+ const gchar *select, /* nullable - properties to select */
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 */
@@ -306,6 +315,8 @@ gboolean e_o365_connection_send_mail_sync
gboolean e_o365_connection_get_contacts_folder_sync
(EO365Connection *cnc,
const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *folder_id, /* nullable - then the default
'contacts' folder is returned */
+ const gchar *select, /* nullable - properties to select */
EO365Folder **out_folder,
GCancellable *cancellable,
GError **error);
@@ -322,7 +333,7 @@ gboolean e_o365_connection_update_contact_photo_sync
const gchar *user_override, /* for which user, NULL to use
the account user */
const gchar *folder_id,
const gchar *contact_id,
- const GByteArray *jpeg_photo, /* nullable, to remove the
photo */
+ const GByteArray *jpeg_photo, /* nullable - to remove the
photo */
GCancellable *cancellable,
GError **error);
gboolean e_o365_connection_get_contact_sync
@@ -356,6 +367,80 @@ gboolean e_o365_connection_delete_contact_sync
const gchar *contact_id,
GCancellable *cancellable,
GError **error);
+gboolean e_o365_connection_list_calendar_groups_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ GSList **out_groups, /* EO365CalendarGroup * - the returned
calendarGroup objects */
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_o365_connection_create_calendar_group_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *name,
+ EO365CalendarGroup **out_created_group,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_o365_connection_get_calendar_group_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *group_id,
+ EO365CalendarGroup **out_group,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_o365_connection_update_calendar_group_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *group_id,
+ const gchar *name,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_o365_connection_delete_calendar_group_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *group_id,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_o365_connection_list_calendars_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *group_id, /* nullable - calendar group for
group calendars */
+ const gchar *select, /* nullable - properties to select */
+ GSList **out_calendars, /* EO365Calendar * - the returned
calendar objects */
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_o365_connection_create_calendar_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *group_id, /* nullable - then the default group
is used */
+ JsonBuilder *calendar,
+ EO365Calendar **out_created_calendar,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_o365_connection_get_calendar_folder_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *group_id, /* nullable - then the default group
is used */
+ const gchar *calendar_id, /* nullable - then the default
calendar is used */
+ const gchar *select, /* nullable - properties to select */
+ EO365Calendar **out_calendar,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_o365_connection_update_calendar_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *group_id, /* nullable - then the default group
is used */
+ const gchar *calendar_id,
+ const gchar *name, /* nullable - to keep the existing name */
+ EO365CalendarColorType color,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_o365_connection_delete_calendar_sync
+ (EO365Connection *cnc,
+ const gchar *user_override, /* for which user, NULL to use
the account user */
+ const gchar *group_id, /* nullable - then the default group
is used */
+ const gchar *calendar_id,
+ 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 18b95bf2..0ec0e982 100644
--- a/src/Office365/common/e-o365-json-utils.c
+++ b/src/Office365/common/e-o365-json-utils.c
@@ -17,10 +17,84 @@
#include "evolution-ews-config.h"
+#include <stdio.h>
#include <json-glib/json-glib.h>
#include "e-o365-json-utils.h"
+static struct _color_map {
+ const gchar *name;
+ const gchar *rgb;
+ EO365CalendarColorType value;
+} color_map[] = {
+ { "auto", NULL, E_O365_CALENDAR_COLOR_AUTO },
+ { "lightBlue", "#0078d4", E_O365_CALENDAR_COLOR_LIGHT_BLUE },
+ { "lightGreen", "#b67dfa", E_O365_CALENDAR_COLOR_LIGHT_GREEN },
+ { "lightOrange","#25c4fe", E_O365_CALENDAR_COLOR_LIGHT_ORANGE },
+ { "lightGray", "#968681", E_O365_CALENDAR_COLOR_LIGHT_GRAY },
+ { "lightYellow","#ffc699", E_O365_CALENDAR_COLOR_LIGHT_YELLOW }, /* Navy in web UI */
+ { "lightTeal", "#fc7c78", E_O365_CALENDAR_COLOR_LIGHT_TEAL },
+ { "lightPink", "#1cff73", E_O365_CALENDAR_COLOR_LIGHT_PINK },
+ { "lightBrown", "#8bb256", E_O365_CALENDAR_COLOR_LIGHT_BROWN }, /* Purple in web UI */
+ { "lightRed", "#3af0e0", E_O365_CALENDAR_COLOR_LIGHT_RED },
+ { "maxColor", NULL, E_O365_CALENDAR_COLOR_MAX_COLOR }
+};
+
+const gchar *
+e_o365_calendar_color_to_rgb (EO365CalendarColorType color)
+{
+ gint ii;
+
+ for (ii = 0; ii < G_N_ELEMENTS (color_map); ii++) {
+ if (color == color_map[ii].value)
+ return color_map[ii].rgb;
+ }
+
+ return NULL;
+}
+
+EO365CalendarColorType
+e_o365_rgb_to_calendar_color (const gchar *rgb)
+{
+ EO365CalendarColorType res;
+ gint ii, rr, gg, bb;
+ gdouble distance, res_distance = -1.0;
+
+ if (!rgb || !*rgb)
+ return E_O365_CALENDAR_COLOR_NOT_SET;
+
+ for (ii = 0; ii < G_N_ELEMENTS (color_map); ii++) {
+ if (color_map[ii].rgb && g_ascii_strcasecmp (color_map[ii].rgb, rgb) == 0)
+ return color_map[ii].value;
+ }
+
+ /* When exact match did not work, approximate to the closest */
+
+ if (sscanf (rgb, "#%02x%02x%02x", &rr, &gg, &bb) != 3)
+ return E_O365_CALENDAR_COLOR_UNKNOWN;
+
+ distance = (rr * rr) + (gg * gg) + (bb * bb);
+ res = E_O365_CALENDAR_COLOR_UNKNOWN;
+
+ for (ii = 0; ii < G_N_ELEMENTS (color_map); ii++) {
+ if (color_map[ii].rgb && sscanf (color_map[ii].rgb, "#%02x%02x%02x", &rr, &gg, &bb) == 3) {
+ gdouble candidate_distance;
+
+ candidate_distance = (rr * rr) + (gg * gg) + (bb * bb) - distance;
+
+ if (candidate_distance < 0.0)
+ candidate_distance *= -1.0;
+
+ if (!ii || candidate_distance < res_distance) {
+ res_distance = candidate_distance;
+ res = color_map[ii].value;
+ }
+ }
+ }
+
+ return res;
+}
+
JsonArray *
e_o365_json_get_array_member (JsonObject *object,
const gchar *member_name)
@@ -1866,3 +1940,231 @@ e_o365_contact_add_yomi_surname (JsonBuilder *builder,
{
e_o365_json_add_nonempty_or_null_string_member (builder, "yomiSurname", value);
}
+
+/* https://docs.microsoft.com/en-us/graph/api/resources/calendargroup?view=graph-rest-1.0 */
+
+const gchar *
+e_o365_calendar_group_get_id (EO365CalendarGroup *group)
+{
+ return e_o365_json_get_string_member (group, "id", NULL);
+}
+
+const gchar *
+e_o365_calendar_group_get_change_key (EO365CalendarGroup *group)
+{
+ return e_o365_json_get_string_member (group, "changeKey", NULL);
+}
+
+const gchar *
+e_o365_calendar_group_get_class_id (EO365CalendarGroup *group)
+{
+ return e_o365_json_get_string_member (group, "classId", NULL);
+}
+
+const gchar *
+e_o365_calendar_group_get_name (EO365CalendarGroup *group)
+{
+ return e_o365_json_get_string_member (group, "name", NULL);
+}
+
+/* https://docs.microsoft.com/en-us/graph/api/resources/calendar?view=graph-rest-1.0 */
+
+const gchar *
+e_o365_calendar_get_id (EO365Calendar *calendar)
+{
+ return e_o365_json_get_string_member (calendar, "id", NULL);
+}
+
+const gchar *
+e_o365_calendar_get_change_key (EO365Calendar *calendar)
+{
+ return e_o365_json_get_string_member (calendar, "changeKey", NULL);
+}
+
+gboolean
+e_o365_calendar_get_can_edit (EO365Calendar *calendar)
+{
+ return e_o365_json_get_boolean_member (calendar, "canEdit", FALSE);
+}
+
+gboolean
+e_o365_calendar_get_can_share (EO365Calendar *calendar)
+{
+ return e_o365_json_get_boolean_member (calendar, "canShare", FALSE);
+}
+
+gboolean
+e_o365_calendar_get_can_view_private_items (EO365Calendar *calendar)
+{
+ return e_o365_json_get_boolean_member (calendar, "canViewPrivateItems", FALSE);
+}
+
+gboolean
+e_o365_calendar_get_is_removable (EO365Calendar *calendar)
+{
+ return e_o365_json_get_boolean_member (calendar, "isRemovable", FALSE);
+}
+
+gboolean
+e_o365_calendar_get_is_tallying_responses (EO365Calendar *calendar)
+{
+ return e_o365_json_get_boolean_member (calendar, "isTallyingResponses", FALSE);
+}
+
+EO365EmailAddress *
+e_o365_calendar_get_owner (EO365Calendar *calendar)
+{
+ return e_o365_json_get_object_member (calendar, "owner");
+}
+
+const gchar *
+e_o365_calendar_get_name (EO365Calendar *calendar)
+{
+ return e_o365_json_get_string_member (calendar, "name", NULL);
+}
+
+void
+e_o365_calendar_add_name (JsonBuilder *builder,
+ const gchar *name)
+{
+ e_o365_json_add_nonempty_string_member (builder, "name", name);
+}
+
+static struct _meeting_provider_map {
+ const gchar *name;
+ EO365OnlineMeetingProviderType value;
+} meeting_provider_map[] = {
+ { "unknown", E_O365_ONLINE_MEETING_PROVIDER_UNKNOWN },
+ { "skypeForBusiness", E_O365_ONLINE_MEETING_PROVIDER_SKYPE_FOR_BUSINESS },
+ { "skypeForConsumer", E_O365_ONLINE_MEETING_PROVIDER_SKYPE_FOR_CONSUMER },
+ { "teamsForBusiness", E_O365_ONLINE_MEETING_PROVIDER_TEAMS_FOR_BUSINESS }
+};
+
+guint32 /* bit-or of EO365OnlineMeetingProviderType */
+e_o365_calendar_get_allowed_online_meeting_providers (EO365Calendar *calendar)
+{
+ guint32 providers = E_O365_ONLINE_MEETING_PROVIDER_NOT_SET;
+ JsonArray *array;
+
+ array = e_o365_json_get_array_member (calendar, "allowedOnlineMeetingProviders");
+
+ if (array) {
+ guint ii, jj, len;
+
+ providers = E_O365_ONLINE_MEETING_PROVIDER_UNKNOWN;
+
+ len = json_array_get_length (array);
+
+ for (ii = 0; ii < len; ii++) {
+ const gchar *str = json_array_get_string_element (array, ii);
+
+ if (!str)
+ continue;
+
+ for (jj = 0; jj < G_N_ELEMENTS (meeting_provider_map); jj++) {
+ if (g_ascii_strcasecmp (str, meeting_provider_map[jj].name) == 0) {
+ providers |= meeting_provider_map[jj].value;
+ break;
+ }
+ }
+ }
+ }
+
+ return providers;
+}
+
+void
+e_o365_calendar_add_allowed_online_meeting_providers (JsonBuilder *builder,
+ guint providers) /* bit-or of
EO365OnlineMeetingProviderType */
+{
+ gint ii;
+
+ if (providers == E_O365_ONLINE_MEETING_PROVIDER_NOT_SET)
+ return;
+
+ e_o365_json_begin_array_member (builder, "allowedOnlineMeetingProviders");
+
+ if (providers == E_O365_ONLINE_MEETING_PROVIDER_UNKNOWN)
+ json_builder_add_string_value (builder, "unknown");
+
+ for (ii = 0; ii < G_N_ELEMENTS (meeting_provider_map); ii++) {
+ if ((providers & meeting_provider_map[ii].value) != 0)
+ json_builder_add_string_value (builder, meeting_provider_map[ii].name);
+ }
+
+ e_o365_json_end_array_member (builder);
+}
+
+EO365CalendarColorType
+e_o365_calendar_get_color (EO365Calendar *calendar)
+{
+ const gchar *color;
+ gint ii;
+
+ color = e_o365_json_get_string_member (calendar, "color", NULL);
+
+ if (!color)
+ return E_O365_CALENDAR_COLOR_NOT_SET;
+
+ for (ii = 0; ii < G_N_ELEMENTS (color_map); ii++) {
+ if (g_ascii_strcasecmp (color_map[ii].name, color) == 0)
+ return color_map[ii].value;
+ }
+
+ return E_O365_CALENDAR_COLOR_UNKNOWN;
+}
+
+void
+e_o365_calendar_add_color (JsonBuilder *builder,
+ EO365CalendarColorType color)
+{
+ const gchar *name = NULL;
+ gint ii;
+
+ for (ii = 0; ii < G_N_ELEMENTS (color_map); ii++) {
+ if (color_map[ii].value == color) {
+ name = color_map[ii].name;
+ break;
+ }
+ }
+
+ if (name && g_ascii_strcasecmp (name, "maxColor") != 0)
+ e_o365_json_add_string_member (builder, "color", name);
+}
+
+EO365OnlineMeetingProviderType
+e_o365_calendar_get_default_online_meeting_provider (EO365Calendar *calendar)
+{
+ const gchar *name;
+ gint ii;
+
+ name = e_o365_json_get_string_member (calendar, "defaultOnlineMeetingProvider", NULL);
+
+ if (!name)
+ return E_O365_ONLINE_MEETING_PROVIDER_NOT_SET;
+
+ for (ii = 0; ii < G_N_ELEMENTS (meeting_provider_map); ii++) {
+ if (g_ascii_strcasecmp (name, meeting_provider_map[ii].name) == 0)
+ return meeting_provider_map[ii].value;
+ }
+
+ return E_O365_ONLINE_MEETING_PROVIDER_UNKNOWN;
+}
+
+void
+e_o365_calendar_add_default_online_meeting_provider (JsonBuilder *builder,
+ EO365OnlineMeetingProviderType provider)
+{
+ const gchar *name = NULL;
+ gint ii;
+
+ for (ii = 0; ii < G_N_ELEMENTS (meeting_provider_map); ii++) {
+ if (meeting_provider_map[ii].value == provider) {
+ name = meeting_provider_map[ii].name;
+ break;
+ }
+ }
+
+ if (name)
+ e_o365_json_add_string_member (builder, "defaultOnlineMeetingProvider", name);
+}
diff --git a/src/Office365/common/e-o365-json-utils.h b/src/Office365/common/e-o365-json-utils.h
index 2cd13d1c..f5e51ac8 100644
--- a/src/Office365/common/e-o365-json-utils.h
+++ b/src/Office365/common/e-o365-json-utils.h
@@ -25,6 +25,8 @@ G_BEGIN_DECLS
/* Just for better readability */
#define EO365Attachment JsonObject
+#define EO365Calendar JsonObject
+#define EO365CalendarGroup JsonObject
#define EO365Category JsonObject
#define EO365Contact JsonObject
#define EO365DateTimeWithZone JsonObject
@@ -76,6 +78,34 @@ typedef enum _EO365ItemBodyContentTypeType {
E_O365_ITEM_BODY_CONTENT_TYPE_HTML
} EO365ItemBodyContentTypeType;
+typedef enum _EO365OnlineMeetingProviderType {
+ E_O365_ONLINE_MEETING_PROVIDER_NOT_SET = -1,
+ E_O365_ONLINE_MEETING_PROVIDER_UNKNOWN = 0,
+ E_O365_ONLINE_MEETING_PROVIDER_SKYPE_FOR_BUSINESS = 1 << 0,
+ E_O365_ONLINE_MEETING_PROVIDER_SKYPE_FOR_CONSUMER = 1 << 1,
+ E_O365_ONLINE_MEETING_PROVIDER_TEAMS_FOR_BUSINESS = 1 << 2
+} EO365OnlineMeetingProviderType;
+
+typedef enum _EO365CalendarColorType {
+ E_O365_CALENDAR_COLOR_NOT_SET = -3,
+ E_O365_CALENDAR_COLOR_UNKNOWN = -2,
+ E_O365_CALENDAR_COLOR_AUTO = -1,
+ E_O365_CALENDAR_COLOR_LIGHT_BLUE = 0,
+ E_O365_CALENDAR_COLOR_LIGHT_GREEN = 1,
+ E_O365_CALENDAR_COLOR_LIGHT_ORANGE = 2,
+ E_O365_CALENDAR_COLOR_LIGHT_GRAY = 3,
+ E_O365_CALENDAR_COLOR_LIGHT_YELLOW = 4,
+ E_O365_CALENDAR_COLOR_LIGHT_TEAL = 5,
+ E_O365_CALENDAR_COLOR_LIGHT_PINK = 6,
+ E_O365_CALENDAR_COLOR_LIGHT_BROWN = 7,
+ E_O365_CALENDAR_COLOR_LIGHT_RED = 8,
+ E_O365_CALENDAR_COLOR_MAX_COLOR = 9
+} EO365CalendarColorType;
+
+const gchar * e_o365_calendar_color_to_rgb (EO365CalendarColorType color);
+EO365CalendarColorType
+ e_o365_rgb_to_calendar_color (const gchar *rgb);
+
JsonArray * e_o365_json_get_array_member (JsonObject *object,
const gchar *member_name);
void e_o365_json_begin_array_member (JsonBuilder *builder,
@@ -466,6 +496,41 @@ const gchar * e_o365_contact_get_yomi_surname (EO365Contact *contact);
void e_o365_contact_add_yomi_surname (JsonBuilder *builder,
const gchar *value);
+const gchar * e_o365_calendar_group_get_id (EO365CalendarGroup *group);
+const gchar * e_o365_calendar_group_get_change_key (EO365CalendarGroup *group);
+const gchar * e_o365_calendar_group_get_class_id (EO365CalendarGroup *group);
+const gchar * e_o365_calendar_group_get_name (EO365CalendarGroup *group);
+
+const gchar * e_o365_calendar_get_id (EO365Calendar *calendar);
+const gchar * e_o365_calendar_get_change_key (EO365Calendar *calendar);
+gboolean e_o365_calendar_get_can_edit (EO365Calendar *calendar);
+gboolean e_o365_calendar_get_can_share (EO365Calendar *calendar);
+gboolean e_o365_calendar_get_can_view_private_items
+ (EO365Calendar *calendar);
+gboolean e_o365_calendar_get_is_removable (EO365Calendar *calendar);
+gboolean e_o365_calendar_get_is_tallying_responses
+ (EO365Calendar *calendar);
+EO365EmailAddress *
+ e_o365_calendar_get_owner (EO365Calendar *calendar);
+const gchar * e_o365_calendar_get_name (EO365Calendar *calendar);
+void e_o365_calendar_add_name (JsonBuilder *builder,
+ const gchar *name);
+guint32 e_o365_calendar_get_allowed_online_meeting_providers /* bit-or of
EO365OnlineMeetingProviderType */
+ (EO365Calendar *calendar);
+void e_o365_calendar_add_allowed_online_meeting_providers
+ (JsonBuilder *builder,
+ guint providers); /* bit-or of
EO365OnlineMeetingProviderType */
+EO365CalendarColorType
+ e_o365_calendar_get_color (EO365Calendar *calendar);
+void e_o365_calendar_add_color (JsonBuilder *builder,
+ EO365CalendarColorType color);
+EO365OnlineMeetingProviderType
+ e_o365_calendar_get_default_online_meeting_provider
+ (EO365Calendar *calendar);
+void e_o365_calendar_add_default_online_meeting_provider
+ (JsonBuilder *builder,
+ EO365OnlineMeetingProviderType provider);
+
G_END_DECLS
#endif /* E_O365_JSON_UTILS_H */
diff --git a/src/Office365/common/e-source-o365-folder.c b/src/Office365/common/e-source-o365-folder.c
index 8d7ca61e..d8321f5a 100644
--- a/src/Office365/common/e-source-o365-folder.c
+++ b/src/Office365/common/e-source-o365-folder.c
@@ -21,13 +21,15 @@
struct _ESourceO365FolderPrivate {
gchar *id;
+ gchar *group_id;
gboolean is_default;
};
enum {
PROP_0,
PROP_ID,
- PROP_IS_DEFAULT
+ PROP_IS_DEFAULT,
+ PROP_GROUP_ID
};
G_DEFINE_TYPE_WITH_PRIVATE (ESourceO365Folder, e_source_o365_folder, E_TYPE_SOURCE_EXTENSION)
@@ -50,6 +52,12 @@ source_o365_folder_set_property (GObject *object,
E_SOURCE_O365_FOLDER (object),
g_value_get_string (value));
return;
+
+ case PROP_GROUP_ID:
+ e_source_o365_folder_set_group_id (
+ E_SOURCE_O365_FOLDER (object),
+ g_value_get_string (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -75,6 +83,13 @@ source_o365_folder_get_property (GObject *object,
e_source_o365_folder_dup_id (
E_SOURCE_O365_FOLDER (object)));
return;
+
+ case PROP_GROUP_ID:
+ g_value_take_string (
+ value,
+ e_source_o365_folder_dup_group_id (
+ E_SOURCE_O365_FOLDER (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -86,6 +101,7 @@ source_o365_folder_finalize (GObject *object)
ESourceO365Folder *o365_folder = E_SOURCE_O365_FOLDER (object);
g_free (o365_folder->priv->id);
+ g_free (o365_folder->priv->group_id);
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_source_o365_folder_parent_class)->finalize (object);
@@ -130,6 +146,19 @@ e_source_o365_folder_class_init (ESourceO365FolderClass *class)
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS |
E_SOURCE_PARAM_SETTING));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_GROUP_ID,
+ g_param_spec_string (
+ "group-id",
+ "Group ID",
+ "Optional group ID, into which the folder ID belongs",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS |
+ E_SOURCE_PARAM_SETTING));
}
static void
@@ -220,3 +249,50 @@ e_source_o365_folder_set_is_default (ESourceO365Folder *extension,
g_object_notify (G_OBJECT (extension), "is-default");
}
+
+const gchar *
+e_source_o365_folder_get_group_id (ESourceO365Folder *extension)
+{
+ g_return_val_if_fail (E_IS_SOURCE_O365_FOLDER (extension), NULL);
+
+ return extension->priv->group_id;
+}
+
+gchar *
+e_source_o365_folder_dup_group_id (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));
+
+ protected = e_source_o365_folder_get_group_id (extension);
+ duplicate = g_strdup (protected);
+
+ e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+
+ return duplicate;
+}
+
+void
+e_source_o365_folder_set_group_id (ESourceO365Folder *extension,
+ const gchar *group_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->group_id, group_id) == 0) {
+ e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+ return;
+ }
+
+ g_free (extension->priv->group_id);
+ extension->priv->group_id = g_strdup (group_id);
+
+ e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+
+ g_object_notify (G_OBJECT (extension), "group-id");
+}
diff --git a/src/Office365/common/e-source-o365-folder.h b/src/Office365/common/e-source-o365-folder.h
index 4b1ddc63..2a7ca84a 100644
--- a/src/Office365/common/e-source-o365-folder.h
+++ b/src/Office365/common/e-source-o365-folder.h
@@ -68,6 +68,13 @@ gboolean e_source_o365_folder_get_is_default
void e_source_o365_folder_set_is_default
(ESourceO365Folder *extension,
gboolean value);
+const gchar * e_source_o365_folder_get_group_id
+ (ESourceO365Folder *extension);
+gchar * e_source_o365_folder_dup_group_id
+ (ESourceO365Folder *extension);
+void e_source_o365_folder_set_group_id
+ (ESourceO365Folder *extension,
+ const gchar *group_id);
G_END_DECLS
diff --git a/src/Office365/registry/e-o365-backend.c b/src/Office365/registry/e-o365-backend.c
index 20f85b68..a2dc10fb 100644
--- a/src/Office365/registry/e-o365-backend.c
+++ b/src/Office365/registry/e-o365-backend.c
@@ -110,6 +110,7 @@ static void
o365_backend_update_resource (EO365Backend *o365_backend,
const gchar *extension_name,
const gchar *id,
+ const gchar *group_id,
const gchar *display_name,
gboolean is_default,
const gchar *calendar_color)
@@ -171,6 +172,7 @@ o365_backend_update_resource (EO365Backend *o365_backend,
extension = e_source_get_extension (source, E_SOURCE_EXTENSION_O365_FOLDER);
e_source_o365_folder_set_id (extension, id);
+ e_source_o365_folder_set_group_id (extension, group_id);
e_source_o365_folder_set_is_default (extension, is_default);
server = e_collection_backend_ref_server (E_COLLECTION_BACKEND (o365_backend));
@@ -222,34 +224,69 @@ o365_backend_remove_resource (EO365Backend *o365_backend,
g_clear_object (&existing_source);
}
-static void
-o365_backend_forget_folders (EO365Backend *o365_backend,
- const gchar *extension_name)
+static GHashTable * /* gchar *uid ~> NULL */
+o365_backend_get_known_folder_ids (EO365Backend *o365_backend,
+ const gchar *extension_name,
+ gboolean with_the_default)
{
+ GHashTable *ids;
GHashTableIter iter;
- GSList *ids = NULL, *link;
gpointer value;
+ ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
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)));
+ if (source && e_source_has_extension (source, extension_name)) {
+ ESourceO365Folder *o365_folder;
+
+ o365_folder = e_source_get_extension (source, E_SOURCE_EXTENSION_O365_FOLDER);
+
+ if (with_the_default || !e_source_o365_folder_get_is_default (o365_folder))
+ g_hash_table_insert (ids, e_source_o365_folder_dup_id (o365_folder), NULL);
+ }
}
UNLOCK (o365_backend);
- for (link = ids; link; link = g_slist_next (link)) {
- const gchar *id = link->data;
+ return ids;
+}
+
+static void
+o365_backend_forget_folders_hash (EO365Backend *o365_backend,
+ const gchar *extension_name,
+ GHashTable *ids) /* gchar *id ~> NULL */
+{
+ GHashTableIter iter;
+ gpointer key;
+
+ g_hash_table_iter_init (&iter, ids);
+
+ while (g_hash_table_iter_next (&iter, &key, NULL)) {
+ const gchar *id = key;
if (id)
o365_backend_remove_resource (o365_backend, extension_name, id);
}
+}
+
+static void
+o365_backend_forget_folders (EO365Backend *o365_backend,
+ const gchar *extension_name,
+ gboolean with_the_default)
+{
+ GHashTable *ids;
- g_slist_free_full (ids, g_free);
+ ids = o365_backend_get_known_folder_ids (o365_backend, extension_name, with_the_default);
+
+ o365_backend_forget_folders_hash (o365_backend, extension_name, ids);
+
+ g_hash_table_destroy (ids);
}
static gboolean
@@ -275,7 +312,7 @@ o365_backend_got_contact_folders_delta_cb (EO365Connection *cnc,
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),
+ id, NULL, e_o365_folder_get_display_name (object),
FALSE, NULL);
}
}
@@ -284,25 +321,19 @@ o365_backend_got_contact_folders_delta_cb (EO365Connection *cnc,
}
static void
-o365_backend_sync_folders_thread (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
+o365_backend_sync_contact_folders_sync (EO365Backend *o365_backend,
+ EO365Connection *cnc,
+ GCancellable *cancellable)
{
- EO365Backend *o365_backend = source_object;
- EO365Connection *cnc = task_data;
- ESourceO365Deltas *o365_deltas;
EO365Folder *user_contacts = NULL;
+ ESourceO365Deltas *o365_deltas;
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)) {
+ if (e_o365_connection_get_contacts_folder_sync (cnc, NULL, NULL, NULL, &user_contacts, cancellable,
&error)) {
const gchar *id, *display_name;
id = e_o365_folder_get_id (user_contacts);
@@ -313,7 +344,7 @@ o365_backend_sync_folders_thread (GTask *task,
o365_backend_update_resource (o365_backend,
E_SOURCE_EXTENSION_ADDRESS_BOOK,
- id, display_name, TRUE, NULL);
+ id, NULL, display_name, TRUE, NULL);
json_object_unref (user_contacts);
} else if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND) ||
@@ -333,7 +364,7 @@ o365_backend_sync_folders_thread (GTask *task,
g_clear_pointer (&old_delta_link, g_free);
g_clear_error (&error);
- o365_backend_forget_folders (o365_backend, E_SOURCE_EXTENSION_ADDRESS_BOOK);
+ o365_backend_forget_folders (o365_backend, E_SOURCE_EXTENSION_ADDRESS_BOOK, FALSE);
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);
@@ -347,6 +378,88 @@ o365_backend_sync_folders_thread (GTask *task,
g_clear_error (&error);
}
+static void
+o365_backend_sync_calendar_folders_sync (EO365Backend *o365_backend,
+ EO365Connection *cnc,
+ GCancellable *cancellable)
+{
+ const gchar *extension_name = E_SOURCE_EXTENSION_CALENDAR;
+ GHashTable *known_ids; /* gchar *id ~> NULL */
+ gboolean success = FALSE;
+ GSList *groups = NULL, *link;
+ GError *error = NULL;
+
+ known_ids = o365_backend_get_known_folder_ids (o365_backend, extension_name, FALSE);
+
+ if (e_o365_connection_list_calendar_groups_sync (cnc, NULL, &groups, cancellable, &error) && groups) {
+ success = TRUE;
+
+ for (link = groups; link && success; link = g_slist_next (link)) {
+ EO365CalendarGroup *group = link->data;
+ GSList *calendars = NULL;
+
+ if (!group)
+ continue;
+
+ if (e_o365_connection_list_calendars_sync (cnc, NULL, e_o365_calendar_group_get_id
(group), NULL, &calendars, cancellable, &error)) {
+ GSList *clink;
+
+ for (clink = calendars; clink; clink = g_slist_next (clink)) {
+ EO365Calendar *calendar = clink->data;
+
+ if (!calendar || !e_o365_calendar_get_id (calendar))
+ continue;
+
+ o365_backend_update_resource (o365_backend, extension_name,
+ e_o365_calendar_get_id (calendar),
+ e_o365_calendar_group_get_id (group),
+ e_o365_calendar_get_name (calendar),
+ FALSE,
+ e_o365_calendar_color_to_rgb (e_o365_calendar_get_color
(calendar)));
+
+ g_hash_table_remove (known_ids, e_o365_calendar_get_id (calendar));
+ }
+ } else {
+ success = FALSE;
+ }
+ }
+
+ g_slist_free_full (groups, (GDestroyNotify) json_object_unref);
+ }
+
+ if (success)
+ o365_backend_forget_folders_hash (o365_backend, extension_name, known_ids);
+
+ g_hash_table_destroy (known_ids);
+ g_clear_error (&error);
+}
+
+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;
+ ESourceCollection *collection_extension = NULL;
+ ESource *source;
+
+ g_return_if_fail (E_IS_O365_BACKEND (o365_backend));
+ g_return_if_fail (E_IS_O365_CONNECTION (cnc));
+
+ source = e_backend_get_source (E_BACKEND (o365_backend));
+ collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION);
+
+ if (e_source_collection_get_contacts_enabled (collection_extension)) {
+ o365_backend_sync_contact_folders_sync (o365_backend, cnc, cancellable);
+ }
+
+ if (e_source_collection_get_calendar_enabled (collection_extension)) {
+ o365_backend_sync_calendar_folders_sync (o365_backend, cnc, cancellable);
+ }
+}
+
static void
o365_backend_sync_folders (EO365Backend *o365_backend,
EO365Connection *cnc,
@@ -663,7 +776,7 @@ o365_backend_authenticate_sync (EBackend *backend,
cnc = e_o365_connection_new (e_backend_get_source (backend), o365_settings);
- result = e_o365_connection_authenticate_sync (cnc, NULL, E_O365_FOLDER_KIND_UNKNOWN, NULL,
out_certificate_pem, out_certificate_errors, cancellable, error);
+ result = e_o365_connection_authenticate_sync (cnc, NULL, E_O365_FOLDER_KIND_UNKNOWN, NULL, NULL,
out_certificate_pem, out_certificate_errors, cancellable, error);
if (result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
e_collection_backend_authenticate_children (E_COLLECTION_BACKEND (backend), credentials);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]