[evolution-ews/wip/mcrha/office365: 10/50] Add mostly blank stubs into src/Office365/
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews/wip/mcrha/office365: 10/50] Add mostly blank stubs into src/Office365/
- Date: Mon, 3 Aug 2020 15:24:07 +0000 (UTC)
commit aa581272f415d3bb29e16012fa648a235d9a713d
Author: Milan Crha <mcrha redhat com>
Date: Wed Jun 3 15:52:19 2020 +0200
Add mostly blank stubs into src/Office365/
CMakeLists.txt | 2 +-
src/CMakeLists.txt | 1 +
src/Office365/CMakeLists.txt | 64 ++
src/Office365/addressbook/CMakeLists.txt | 65 ++
.../addressbook/e-book-backend-o365-factory.c | 81 ++
src/Office365/addressbook/e-book-backend-o365.c | 482 ++++++++++++
src/Office365/addressbook/e-book-backend-o365.h | 43 ++
src/Office365/calendar/CMakeLists.txt | 61 ++
.../calendar/e-cal-backend-o365-factory.c | 157 ++++
src/Office365/calendar/e-cal-backend-o365.c | 461 ++++++++++++
src/Office365/calendar/e-cal-backend-o365.h | 48 ++
src/Office365/camel/CMakeLists.txt | 65 ++
src/Office365/camel/camel-o365-provider.c | 128 ++++
src/Office365/camel/camel-o365-store.c | 383 ++++++++++
src/Office365/camel/camel-o365-store.h | 67 ++
src/Office365/camel/camel-o365-transport.c | 189 +++++
src/Office365/camel/camel-o365-transport.h | 61 ++
src/Office365/camel/libcameloffice365.urls | 1 +
src/Office365/common/CMakeLists.txt | 53 ++
src/Office365/common/camel-o365-settings.c | 826 +++++++++++++++++++++
src/Office365/common/camel-o365-settings.h | 125 ++++
src/Office365/common/e-source-o365-folder.c | 242 ++++++
src/Office365/common/e-source-o365-folder.h | 76 ++
src/Office365/evolution/CMakeLists.txt | 39 +
src/Office365/evolution/e-book-config-o365.c | 77 ++
src/Office365/evolution/e-book-config-o365.h | 62 ++
src/Office365/evolution/e-cal-config-o365.c | 92 +++
src/Office365/evolution/e-cal-config-o365.h | 62 ++
.../evolution/e-mail-config-o365-backend.c | 461 ++++++++++++
.../evolution/e-mail-config-o365-backend.h | 64 ++
.../evolution/module-o365-configuration.c | 48 ++
src/Office365/registry/CMakeLists.txt | 22 +
src/Office365/registry/e-o365-backend-factory.c | 89 +++
src/Office365/registry/e-o365-backend-factory.h | 63 ++
src/Office365/registry/e-o365-backend.c | 533 +++++++++++++
src/Office365/registry/e-o365-backend.h | 62 ++
src/Office365/registry/module-o365-backend.c | 45 ++
37 files changed, 5399 insertions(+), 1 deletion(-)
---
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fc2571a7..a814d4a9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -188,7 +188,7 @@ endif(WITH_OFFICE365_TENANT STREQUAL "")
add_printable_variable(WITH_OFFICE365_CLIENT_ID "Office365.com OAuth 2.0 client ID" "")
if(WITH_OFFICE365_CLIENT_ID STREQUAL "")
- set(WITH_OFFICE365_CLIENT_ID "")
+ set(WITH_OFFICE365_CLIENT_ID "20460e5d-ce91-49af-a3a5-70b6be7486d1")
endif(WITH_OFFICE365_CLIENT_ID STREQUAL "")
add_printable_variable(WITH_OFFICE365_REDIRECT_URI "Office365.com OAuth 2.0 redirect URI" "")
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5b514ee3..40579bf1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -62,3 +62,4 @@ add_subdirectory(camel)
add_subdirectory(collection)
add_subdirectory(configuration)
add_subdirectory(server)
+add_subdirectory(Office365)
diff --git a/src/Office365/CMakeLists.txt b/src/Office365/CMakeLists.txt
new file mode 100644
index 00000000..76469509
--- /dev/null
+++ b/src/Office365/CMakeLists.txt
@@ -0,0 +1,64 @@
+macro(add_simple_module_o365 _name _sourcesvar _depsvar _defsvar _cflagsvar _incdirsvar _ldflagsvar
_destination)
+ set(DEPENDENCIES
+ evolution-office365
+ )
+
+ set(SOURCES
+ ${${_sourcesvar}}
+ )
+
+ add_library(${_name} MODULE
+ ${SOURCES}
+ )
+
+ set_target_properties(${_name} PROPERTIES
+ PREFIX ""
+ )
+
+ add_dependencies(${_name}
+ ${DEPENDENCIES}
+ ${${_depsvar}}
+ )
+
+ target_compile_definitions(${_name} PRIVATE
+ -DG_LOG_DOMAIN=\"${_name}\"
+ -DO365_LOCALEDIR=\"${LOCALE_INSTALL_DIR}\"
+ ${${_defsvar}}
+ )
+
+ target_compile_options(${_name} PUBLIC
+ ${LIBEBACKEND_CFLAGS}
+ ${LIBEDATASERVER_CFLAGS}
+ ${SOUP_CFLAGS}
+ ${${_cflagsvar}}
+ )
+
+ target_include_directories(${_name} PUBLIC
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}
+ ${LIBEBACKEND_INCLUDE_DIRS}
+ ${LIBEDATASERVER_INCLUDE_DIRS}
+ ${SOUP_INCLUDE_DIRS}
+ ${${_incdirsvar}}
+ )
+
+ target_link_libraries(${_name}
+ ${DEPENDENCIES}
+ ${${_depsvar}}
+ ${LIBEBACKEND_LDFLAGS}
+ ${LIBEDATASERVER_LDFLAGS}
+ ${SOUP_LDFLAGS}
+ ${${_ldflagsvar}}
+ )
+
+ install(TARGETS ${_name}
+ DESTINATION ${_destination}
+ )
+endmacro(add_simple_module_o365)
+
+add_subdirectory(addressbook)
+add_subdirectory(calendar)
+add_subdirectory(camel)
+add_subdirectory(common)
+add_subdirectory(evolution)
+add_subdirectory(registry)
diff --git a/src/Office365/addressbook/CMakeLists.txt b/src/Office365/addressbook/CMakeLists.txt
new file mode 100644
index 00000000..8886cebd
--- /dev/null
+++ b/src/Office365/addressbook/CMakeLists.txt
@@ -0,0 +1,65 @@
+set(DEPENDENCIES
+ evolution-office365
+)
+
+set(SOURCES
+ e-book-backend-o365.c
+ e-book-backend-o365.h
+ e-book-backend-o365-factory.c
+)
+
+add_library(ebookbackendoffice365 MODULE
+ ${SOURCES}
+)
+
+add_dependencies(ebookbackendoffice365
+ ${DEPENDENCIES}
+)
+
+target_compile_definitions(ebookbackendoffice365 PRIVATE
+ -DG_LOG_DOMAIN=\"ebookbackendoffice365\"
+ -DBACKENDDIR=\"${ebook_backenddir}\"
+ -DO365_LOCALEDIR=\"${LOCALE_INSTALL_DIR}\"
+)
+
+target_compile_options(ebookbackendoffice365 PUBLIC
+ ${LIBEBACKEND_CFLAGS}
+ ${LIBEBOOK_CFLAGS}
+ ${LIBEDATABOOK_CFLAGS}
+ ${LIBEDATASERVER_CFLAGS}
+ ${LIBICAL_GLIB_CFLAGS}
+ ${MSPACK_CFLAGS}
+ ${SOUP_CFLAGS}
+)
+
+target_include_directories(ebookbackendoffice365 PUBLIC
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}/src/Office365
+ ${CMAKE_SOURCE_DIR}/src/Office365
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${LIBEBACKEND_INCLUDE_DIRS}
+ ${LIBEBOOK_INCLUDE_DIRS}
+ ${LIBEDATABOOK_INCLUDE_DIRS}
+ ${LIBEDATASERVER_INCLUDE_DIRS}
+ ${LIBICAL_GLIB_INCLUDE_DIRS}
+ ${MSPACK_INCLUDE_DIRS}
+ ${SOUP_INCLUDE_DIRS}
+)
+
+target_link_libraries(ebookbackendoffice365
+ ${DEPENDENCIES}
+ ${LIBEBACKEND_LDFLAGS}
+ ${LIBEBOOK_LDFLAGS}
+ ${LIBEDATABOOK_LDFLAGS}
+ ${LIBEDATASERVER_LDFLAGS}
+ ${LIBICAL_GLIB_LDFLAGS}
+ ${MATH_LDFLAGS}
+ ${MSPACK_LDFLAGS}
+ ${SOUP_LDFLAGS}
+)
+
+install(TARGETS ebookbackendoffice365
+ DESTINATION ${ebook_backenddir}
+)
diff --git a/src/Office365/addressbook/e-book-backend-o365-factory.c
b/src/Office365/addressbook/e-book-backend-o365-factory.c
new file mode 100644
index 00000000..767351ba
--- /dev/null
+++ b/src/Office365/addressbook/e-book-backend-o365-factory.c
@@ -0,0 +1,81 @@
+/* -*- 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 <glib/gi18n-lib.h>
+
+#include <libedata-book/libedata-book.h>
+
+#include "common/e-source-o365-folder.h"
+
+#include "e-book-backend-o365.h"
+
+typedef EBookBackendFactory EBookBackendO365Factory;
+typedef EBookBackendFactoryClass EBookBackendO365FactoryClass;
+
+static EModule *e_module;
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+/* Forward Declarations */
+GType e_book_backend_o365_factory_get_type (void);
+
+G_DEFINE_DYNAMIC_TYPE (EBookBackendO365Factory, e_book_backend_o365_factory, E_TYPE_BOOK_BACKEND_FACTORY)
+
+static void
+e_book_backend_o365_factory_class_init (EBookBackendFactoryClass *class)
+{
+ EBackendFactoryClass *backend_factory_class;
+
+ backend_factory_class = E_BACKEND_FACTORY_CLASS (class);
+ backend_factory_class->e_module = e_module;
+ backend_factory_class->share_subprocess = TRUE;
+
+ class->factory_name = "office365";
+ class->backend_type = E_TYPE_BOOK_BACKEND_O365;
+}
+
+static void
+e_book_backend_o365_factory_class_finalize (EBookBackendFactoryClass *class)
+{
+}
+
+static void
+e_book_backend_o365_factory_init (EBookBackendFactory *factory)
+{
+}
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ bindtextdomain (GETTEXT_PACKAGE, O365_LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ e_module = E_MODULE (type_module);
+
+ e_source_o365_folder_type_register (type_module);
+ e_book_backend_o365_factory_register_type (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+ e_module = NULL;
+}
diff --git a/src/Office365/addressbook/e-book-backend-o365.c b/src/Office365/addressbook/e-book-backend-o365.c
new file mode 100644
index 00000000..d60003ba
--- /dev/null
+++ b/src/Office365/addressbook/e-book-backend-o365.c
@@ -0,0 +1,482 @@
+/* -*- 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 <glib.h>
+#include <glib/gi18n-lib.h>
+
+#define LIBICAL_GLIB_UNSTABLE_API
+#include <libical-glib/libical-glib.h>
+#undef LIBICAL_GLIB_UNSTABLE_API
+
+#include <libedata-book/libedata-book.h>
+
+#include "common/camel-o365-settings.h"
+
+#include "e-book-backend-o365.h"
+
+#ifdef G_OS_WIN32
+#ifdef gmtime_r
+#undef gmtime_r
+#endif
+
+/* The gmtime() in Microsoft's C library is MT-safe */
+#define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
+#endif
+
+#define d(x)
+
+#define EC_ERROR_EX(_code,_msg) e_client_error_create (_code, _msg)
+#define EBC_ERROR_EX(_code,_msg) e_book_client_error_create (_code, _msg)
+
+#define EBB_O365_DATA_VERSION 1
+#define EBB_O365_DATA_VERSION_KEY "o365-data-version"
+
+struct _EBookBackendO365Private {
+ GRecMutex property_lock;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (EBookBackendO365, e_book_backend_o365, E_TYPE_BOOK_META_BACKEND)
+
+static void
+ebb_o365_convert_error_to_client_error (GError **perror)
+{
+ GError *error = NULL;
+
+ if (!perror || !*perror || (*perror)->domain == E_CLIENT_ERROR || (*perror)->domain ==
E_BOOK_CLIENT_ERROR)
+ return;
+
+ /*if ((*perror)->domain == EWS_CONNECTION_ERROR) {
+ switch ((*perror)->code) {
+ case EWS_CONNECTION_ERROR_AUTHENTICATION_FAILED:
+ error = EC_ERROR_EX (E_CLIENT_ERROR_AUTHENTICATION_FAILED, (*perror)->message);
+ break;
+ case EWS_CONNECTION_ERROR_FOLDERNOTFOUND:
+ case EWS_CONNECTION_ERROR_MANAGEDFOLDERNOTFOUND:
+ case EWS_CONNECTION_ERROR_PARENTFOLDERNOTFOUND:
+ case EWS_CONNECTION_ERROR_PUBLICFOLDERSERVERNOTFOUND:
+ error = EBC_ERROR_EX (E_BOOK_CLIENT_ERROR_NO_SUCH_BOOK, (*perror)->message);
+ break;
+ case EWS_CONNECTION_ERROR_EVENTNOTFOUND:
+ case EWS_CONNECTION_ERROR_ITEMNOTFOUND:
+ error = EBC_ERROR_EX (E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND, (*perror)->message);
+ break;
+ case EWS_CONNECTION_ERROR_UNAVAILABLE:
+ g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_HOST_NOT_FOUND,
(*perror)->message);
+ break;
+ }
+
+ if (!error)
+ error = EC_ERROR_EX (E_CLIENT_ERROR_OTHER_ERROR, (*perror)->message);
+ }*/
+
+ if (error) {
+ g_error_free (*perror);
+ *perror = error;
+ }
+}
+
+static void
+ebb_o365_maybe_disconnect_sync (EBookBackendO365 *bbo365,
+ GError **in_perror,
+ GCancellable *cancellable)
+{
+ g_return_if_fail (E_IS_BOOK_BACKEND_O365 (bbo365));
+
+ if (in_perror && g_error_matches (*in_perror, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED)) {
+ e_book_meta_backend_disconnect_sync (E_BOOK_META_BACKEND (bbo365), cancellable, NULL);
+ e_backend_schedule_credentials_required (E_BACKEND (bbo365),
E_SOURCE_CREDENTIALS_REASON_REJECTED, NULL, 0, NULL, NULL, G_STRFUNC);
+ }
+}
+
+static void
+ebb_o365_unset_connection (EBookBackendO365 *bbo365,
+ gboolean is_disconnect)
+{
+ g_return_if_fail (E_IS_BOOK_BACKEND_O365 (bbo365));
+
+ g_rec_mutex_lock (&bbo365->priv->property_lock);
+
+ /*if (bbo365->priv->cnc) {
+ if (is_disconnect)
+ e_o365_connection_set_disconnected_flag (bbo365->priv->cnc, TRUE);
+ }
+
+ g_clear_object (&bbo365->priv->cnc);*/
+
+ g_rec_mutex_unlock (&bbo365->priv->property_lock);
+}
+
+static gboolean
+ebb_o365_connect_sync (EBookMetaBackend *meta_backend,
+ const ENamedParameters *credentials,
+ ESourceAuthenticationResult *out_auth_result,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EBookBackendO365 *bbo365;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_O365 (meta_backend), FALSE);
+ g_return_val_if_fail (out_auth_result != NULL, FALSE);
+
+ bbo365 = E_BOOK_BACKEND_O365 (meta_backend);
+
+ g_rec_mutex_lock (&bbo365->priv->property_lock);
+
+ /*if (bbo365->priv->cnc)*/ {
+ g_rec_mutex_unlock (&bbo365->priv->property_lock);
+
+ *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+
+ return TRUE;
+ }
+
+ g_rec_mutex_unlock (&bbo365->priv->property_lock);
+
+ return success;
+}
+
+static gboolean
+ebb_o365_disconnect_sync (EBookMetaBackend *meta_backend,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_O365 (meta_backend), FALSE);
+
+ ebb_o365_unset_connection (E_BOOK_BACKEND_O365 (meta_backend), TRUE);
+
+ return TRUE;
+}
+
+static gboolean
+ebb_o365_get_changes_sync (EBookMetaBackend *meta_backend,
+ const gchar *last_sync_tag,
+ gboolean is_repeat,
+ gchar **out_new_sync_tag,
+ gboolean *out_repeat,
+ GSList **out_created_objects,
+ GSList **out_modified_objects,
+ GSList **out_removed_objects,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EBookBackendO365 *bbo365;
+ EBookCache *book_cache;
+ gboolean success = TRUE;
+ /*GError *local_error = NULL;*/
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_O365 (meta_backend), FALSE);
+ g_return_val_if_fail (out_new_sync_tag != NULL, FALSE);
+ g_return_val_if_fail (out_repeat != NULL, FALSE);
+ g_return_val_if_fail (out_created_objects != NULL, FALSE);
+ g_return_val_if_fail (out_modified_objects != NULL, FALSE);
+ g_return_val_if_fail (out_removed_objects != NULL, FALSE);
+
+ *out_created_objects = NULL;
+ *out_modified_objects = NULL;
+ *out_removed_objects = NULL;
+
+ bbo365 = E_BOOK_BACKEND_O365 (meta_backend);
+
+ book_cache = e_book_meta_backend_ref_cache (meta_backend);
+ g_return_val_if_fail (E_IS_BOOK_CACHE (book_cache), FALSE);
+
+ g_rec_mutex_lock (&bbo365->priv->property_lock);
+
+ g_rec_mutex_unlock (&bbo365->priv->property_lock);
+
+ ebb_o365_convert_error_to_client_error (error);
+ ebb_o365_maybe_disconnect_sync (bbo365, error, cancellable);
+
+ g_clear_object (&book_cache);
+
+ return success;
+}
+
+static gboolean
+ebb_o365_load_contact_sync (EBookMetaBackend *meta_backend,
+ const gchar *uid,
+ const gchar *extra,
+ EContact **out_contact,
+ gchar **out_extra,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EBookBackendO365 *bbo365;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_O365 (meta_backend), FALSE);
+ g_return_val_if_fail (uid != NULL, FALSE);
+ g_return_val_if_fail (out_contact, FALSE);
+
+ bbo365 = E_BOOK_BACKEND_O365 (meta_backend);
+
+ g_rec_mutex_lock (&bbo365->priv->property_lock);
+
+ g_rec_mutex_unlock (&bbo365->priv->property_lock);
+
+ ebb_o365_convert_error_to_client_error (error);
+ ebb_o365_maybe_disconnect_sync (bbo365, error, cancellable);
+
+ return success;
+}
+
+static gboolean
+ebb_o365_save_contact_sync (EBookMetaBackend *meta_backend,
+ gboolean overwrite_existing,
+ EConflictResolution conflict_resolution,
+ /* const */ EContact *contact,
+ const gchar *extra,
+ guint32 opflags,
+ gchar **out_new_uid,
+ gchar **out_new_extra,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EBookBackendO365 *bbo365;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_O365 (meta_backend), FALSE);
+ g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
+ g_return_val_if_fail (out_new_uid != NULL, FALSE);
+ g_return_val_if_fail (out_new_extra != NULL, FALSE);
+
+ bbo365 = E_BOOK_BACKEND_O365 (meta_backend);
+
+ g_rec_mutex_lock (&bbo365->priv->property_lock);
+
+ g_rec_mutex_unlock (&bbo365->priv->property_lock);
+
+ ebb_o365_convert_error_to_client_error (error);
+ ebb_o365_maybe_disconnect_sync (bbo365, error, cancellable);
+
+ return success;
+}
+
+static gboolean
+ebb_o365_remove_contact_sync (EBookMetaBackend *meta_backend,
+ EConflictResolution conflict_resolution,
+ const gchar *uid,
+ const gchar *extra,
+ const gchar *object,
+ guint32 opflags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EBookBackendO365 *bbo365;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_O365 (meta_backend), FALSE);
+
+ bbo365 = E_BOOK_BACKEND_O365 (meta_backend);
+
+ g_rec_mutex_lock (&bbo365->priv->property_lock);
+
+ g_rec_mutex_unlock (&bbo365->priv->property_lock);
+
+ ebb_o365_convert_error_to_client_error (error);
+ ebb_o365_maybe_disconnect_sync (bbo365, error, cancellable);
+
+ return success;
+}
+
+static gboolean
+ebb_o365_search_sync (EBookMetaBackend *meta_backend,
+ const gchar *expr,
+ gboolean meta_contact,
+ GSList **out_contacts,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_O365 (meta_backend), FALSE);
+
+ /* Ignore errors, just try its best */
+ /*ebb_o365_update_cache_for_expression (E_BOOK_BACKEND_O365 (meta_backend), expr, cancellable,
NULL);*/
+
+ /* Chain up to parent's method */
+ if (!E_BOOK_META_BACKEND_CLASS (e_book_backend_o365_parent_class)->search_sync (meta_backend, expr,
meta_contact,
+ out_contacts, cancellable, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+ebb_o365_search_uids_sync (EBookMetaBackend *meta_backend,
+ const gchar *expr,
+ GSList **out_uids,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_O365 (meta_backend), FALSE);
+
+ /* Ignore errors, just try its best */
+ /*ebb_o365_update_cache_for_expression (E_BOOK_BACKEND_O365 (meta_backend), expr, cancellable,
NULL);*/
+
+ /* Chain up to parent's method */
+ return E_BOOK_META_BACKEND_CLASS (e_book_backend_o365_parent_class)->search_uids_sync (meta_backend,
expr,
+ out_uids, cancellable, error);
+}
+
+static gchar *
+ebb_o365_get_backend_property (EBookBackend *book_backend,
+ const gchar *prop_name)
+{
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_O365 (book_backend), NULL);
+ g_return_val_if_fail (prop_name != NULL, NULL);
+
+ if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+ return g_strjoin (",",
+ "net",
+ "contact-lists",
+ "do-initial-query",
+ e_book_meta_backend_get_capabilities (E_BOOK_META_BACKEND (book_backend)),
+ NULL);
+ } else if (g_str_equal (prop_name, E_BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS)) {
+ return g_strdup (e_contact_field_name (E_CONTACT_FILE_AS));
+ } else if (g_str_equal (prop_name, E_BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS)) {
+ GString *buffer;
+ gchar *fields;
+ /*gint ii;*/
+
+ buffer = g_string_sized_new (1024);
+
+ /*for (ii = 0; ii < G_N_ELEMENTS (mappings); ii++) {
+ if (mappings[ii].element_type != ELEMENT_TYPE_SIMPLE)
+ continue;
+
+ if (buffer->len > 0)
+ g_string_append_c (buffer, ',');
+ g_string_append (buffer, e_contact_field_name (mappings[ii].field_id));
+ }
+
+ for (ii = 0; ii < G_N_ELEMENTS (phone_field_map); ii++) {
+ if (buffer->len > 0)
+ g_string_append_c (buffer, ',');
+ g_string_append (buffer, e_contact_field_name (phone_field_map[ii].field));
+ }*/
+
+ fields = g_strjoin (
+ ",",
+ buffer->str,
+ e_contact_field_name (E_CONTACT_FULL_NAME),
+ e_contact_field_name (E_CONTACT_NICKNAME),
+ e_contact_field_name (E_CONTACT_FAMILY_NAME),
+ e_contact_field_name (E_CONTACT_EMAIL_1),
+ e_contact_field_name (E_CONTACT_EMAIL_2),
+ e_contact_field_name (E_CONTACT_EMAIL_3),
+ e_contact_field_name (E_CONTACT_ADDRESS_WORK),
+ e_contact_field_name (E_CONTACT_ADDRESS_HOME),
+ e_contact_field_name (E_CONTACT_ADDRESS_OTHER),
+ e_contact_field_name (E_CONTACT_ANNIVERSARY),
+ e_contact_field_name (E_CONTACT_BIRTH_DATE),
+ e_contact_field_name (E_CONTACT_NOTE),
+ e_contact_field_name (E_CONTACT_PHOTO),
+ NULL);
+
+ g_string_free (buffer, TRUE);
+
+ return fields;
+ }
+
+ /* Chain up to parent's method. */
+ return E_BOOK_BACKEND_CLASS (e_book_backend_o365_parent_class)->impl_get_backend_property
(book_backend, prop_name);
+}
+
+static gboolean
+ebb_o365_get_destination_address (EBackend *backend,
+ gchar **host,
+ guint16 *port)
+{
+ g_return_val_if_fail (port != NULL, FALSE);
+ g_return_val_if_fail (host != NULL, FALSE);
+
+ /* Sanity checking */
+ if (!e_book_backend_get_registry (E_BOOK_BACKEND (backend)) ||
+ !e_backend_get_source (backend))
+ return FALSE;
+
+ *host = g_strdup ("graph.microsoft.com");
+ *port = 443;
+
+ return TRUE;
+}
+
+static void
+e_book_backend_o365_dispose (GObject *object)
+{
+ EBookBackendO365 *bbo365 = E_BOOK_BACKEND_O365 (object);
+
+ ebb_o365_unset_connection (bbo365, FALSE);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_book_backend_o365_parent_class)->dispose (object);
+}
+
+static void
+e_book_backend_o365_finalize (GObject *object)
+{
+ EBookBackendO365 *bbo365 = E_BOOK_BACKEND_O365 (object);
+
+ g_rec_mutex_clear (&bbo365->priv->property_lock);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_book_backend_o365_parent_class)->finalize (object);
+}
+
+static void
+e_book_backend_o365_init (EBookBackendO365 *bbo365)
+{
+ bbo365->priv = e_book_backend_o365_get_instance_private (bbo365);
+
+ g_rec_mutex_init (&bbo365->priv->property_lock);
+}
+
+static void
+e_book_backend_o365_class_init (EBookBackendO365Class *klass)
+{
+ GObjectClass *object_class;
+ EBackendClass *backend_class;
+ EBookBackendClass *book_backend_class;
+ EBookMetaBackendClass *book_meta_backend_class;
+
+ book_meta_backend_class = E_BOOK_META_BACKEND_CLASS (klass);
+ book_meta_backend_class->backend_module_filename = "libebookbackendoffice365.so";
+ book_meta_backend_class->backend_factory_type_name = "EBookBackendO365Factory";
+ book_meta_backend_class->connect_sync = ebb_o365_connect_sync;
+ book_meta_backend_class->disconnect_sync = ebb_o365_disconnect_sync;
+ book_meta_backend_class->get_changes_sync = ebb_o365_get_changes_sync;
+ book_meta_backend_class->load_contact_sync = ebb_o365_load_contact_sync;
+ book_meta_backend_class->save_contact_sync = ebb_o365_save_contact_sync;
+ book_meta_backend_class->remove_contact_sync = ebb_o365_remove_contact_sync;
+ book_meta_backend_class->search_sync = ebb_o365_search_sync;
+ book_meta_backend_class->search_uids_sync = ebb_o365_search_uids_sync;
+
+ book_backend_class = E_BOOK_BACKEND_CLASS (klass);
+ book_backend_class->impl_get_backend_property = ebb_o365_get_backend_property;
+
+ backend_class = E_BACKEND_CLASS (klass);
+ backend_class->get_destination_address = ebb_o365_get_destination_address;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = e_book_backend_o365_dispose;
+ object_class->finalize = e_book_backend_o365_finalize;
+}
diff --git a/src/Office365/addressbook/e-book-backend-o365.h b/src/Office365/addressbook/e-book-backend-o365.h
new file mode 100644
index 00000000..b91b36a6
--- /dev/null
+++ b/src/Office365/addressbook/e-book-backend-o365.h
@@ -0,0 +1,43 @@
+/* -*- 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_BOOK_BACKEND_O365_H
+#define E_BOOK_BACKEND_O365_H
+
+#include <libedata-book/libedata-book.h>
+
+#define E_TYPE_BOOK_BACKEND_O365 (e_book_backend_o365_get_type ())
+#define E_BOOK_BACKEND_O365(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_O365,
EBookBackendO365))
+#define E_BOOK_BACKEND_O365_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BOOK_BACKEND_O365,
EBookBackendO365Class))
+#define E_IS_BOOK_BACKEND_O365(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_O365))
+#define E_IS_BOOK_BACKEND_O365_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_O365))
+#define E_BOOK_BACKEND_O365_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_BACKEND_O365,
EBookBackenO365Class))
+
+typedef struct _EBookBackendO365Private EBookBackendO365Private;
+
+typedef struct {
+ EBookMetaBackend parent_object;
+ EBookBackendO365Private *priv;
+} EBookBackendO365;
+
+typedef struct {
+ EBookMetaBackendClass parent_class;
+} EBookBackendO365Class;
+
+GType e_book_backend_o365_get_type (void);
+
+#endif /* E_BOOK_BACKEND_O365_H */
diff --git a/src/Office365/calendar/CMakeLists.txt b/src/Office365/calendar/CMakeLists.txt
new file mode 100644
index 00000000..5a5400ff
--- /dev/null
+++ b/src/Office365/calendar/CMakeLists.txt
@@ -0,0 +1,61 @@
+set(DEPENDENCIES
+ evolution-office365
+)
+
+set(SOURCES
+ e-cal-backend-o365.c
+ e-cal-backend-o365.h
+ e-cal-backend-o365-factory.c
+)
+
+add_library(ecalbackendoffice365 MODULE
+ ${SOURCES}
+)
+
+add_dependencies(ecalbackendoffice365
+ ${DEPENDENCIES}
+)
+
+target_compile_definitions(ecalbackendoffice365 PRIVATE
+ -DG_LOG_DOMAIN=\"ecalbackendoffice365\"
+ -DO365_DATADIR=\"${ewsdatadir}\"
+ -DO365_LOCALEDIR=\"${LOCALE_INSTALL_DIR}\"
+ -DO365_SRCDIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"
+)
+
+target_compile_options(ecalbackendoffice365 PUBLIC
+ ${CAMEL_CFLAGS}
+ ${EVOLUTION_CALENDAR_CFLAGS}
+ ${LIBEBACKEND_CFLAGS}
+ ${LIBECAL_CFLAGS}
+ ${LIBEDATACAL_CFLAGS}
+ ${SOUP_CFLAGS}
+)
+
+target_include_directories(ecalbackendoffice365 PUBLIC
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}/src/Office365
+ ${CMAKE_SOURCE_DIR}/src/Office365
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CAMEL_INCLUDE_DIRS}
+ ${EVOLUTION_CALENDAR_INCLUDE_DIRS}
+ ${LIBEBACKEND_INCLUDE_DIRS}
+ ${LIBECAL_INCLUDE_DIRS}
+ ${LIBEDATACAL_INCLUDE_DIRS}
+ ${SOUP_INCLUDE_DIRS}
+)
+
+target_link_libraries(ecalbackendoffice365
+ ${DEPENDENCIES}
+ ${CAMEL_LDFLAGS}
+ ${EVOLUTION_CALENDAR_LDFLAGS}
+ ${LIBEBACKEND_LDFLAGS}
+ ${LIBECAL_LDFLAGS}
+ ${LIBEDATACAL_LDFLAGS}
+ ${SOUP_LDFLAGS}
+)
+
+install(TARGETS ecalbackendoffice365
+ DESTINATION ${ecal_backenddir}
+)
diff --git a/src/Office365/calendar/e-cal-backend-o365-factory.c
b/src/Office365/calendar/e-cal-backend-o365-factory.c
new file mode 100644
index 00000000..83710795
--- /dev/null
+++ b/src/Office365/calendar/e-cal-backend-o365-factory.c
@@ -0,0 +1,157 @@
+/* -*- 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 <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <libedata-cal/libedata-cal.h>
+
+#include "common/e-source-o365-folder.h"
+
+#include "e-cal-backend-o365.h"
+
+#define FACTORY_NAME "office365"
+
+typedef ECalBackendFactory ECalBackendO365EventsFactory;
+typedef ECalBackendFactoryClass ECalBackendO365EventsFactoryClass;
+
+typedef ECalBackendFactory ECalBackendO365JournalFactory;
+typedef ECalBackendFactoryClass ECalBackendO365JournalFactoryClass;
+
+typedef ECalBackendFactory ECalBackendO365TodosFactory;
+typedef ECalBackendFactoryClass ECalBackendO365TodosFactoryClass;
+
+static EModule *e_module;
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+/* Forward Declarations */
+GType e_cal_backend_o365_events_factory_get_type (void);
+GType e_cal_backend_o365_journal_factory_get_type (void);
+GType e_cal_backend_o365_todos_factory_get_type (void);
+
+G_DEFINE_DYNAMIC_TYPE (
+ ECalBackendO365EventsFactory,
+ e_cal_backend_o365_events_factory,
+ E_TYPE_CAL_BACKEND_FACTORY)
+
+G_DEFINE_DYNAMIC_TYPE (
+ ECalBackendO365JournalFactory,
+ e_cal_backend_o365_journal_factory,
+ E_TYPE_CAL_BACKEND_FACTORY)
+
+G_DEFINE_DYNAMIC_TYPE (
+ ECalBackendO365TodosFactory,
+ e_cal_backend_o365_todos_factory,
+ E_TYPE_CAL_BACKEND_FACTORY)
+
+static void
+e_cal_backend_o365_events_factory_class_init (ECalBackendFactoryClass *class)
+{
+ EBackendFactoryClass *backend_factory_class;
+
+ backend_factory_class = E_BACKEND_FACTORY_CLASS (class);
+ backend_factory_class->e_module = e_module;
+ backend_factory_class->share_subprocess = TRUE;
+
+ class->factory_name = FACTORY_NAME;
+ class->component_kind = I_CAL_VEVENT_COMPONENT;
+ class->backend_type = E_TYPE_CAL_BACKEND_O365;
+}
+
+static void
+e_cal_backend_o365_events_factory_class_finalize (ECalBackendFactoryClass *class)
+{
+}
+
+static void
+e_cal_backend_o365_events_factory_init (ECalBackendFactory *factory)
+{
+}
+
+static void
+e_cal_backend_o365_journal_factory_class_init (ECalBackendFactoryClass *class)
+{
+ EBackendFactoryClass *backend_factory_class;
+
+ backend_factory_class = E_BACKEND_FACTORY_CLASS (class);
+ backend_factory_class->e_module = e_module;
+ backend_factory_class->share_subprocess = TRUE;
+
+ class->factory_name = FACTORY_NAME;
+ class->component_kind = I_CAL_VJOURNAL_COMPONENT;
+ class->backend_type = E_TYPE_CAL_BACKEND_O365;
+}
+
+static void
+e_cal_backend_o365_journal_factory_class_finalize (ECalBackendFactoryClass *class)
+{
+}
+
+static void
+e_cal_backend_o365_journal_factory_init (ECalBackendFactory *factory)
+{
+}
+
+static void
+e_cal_backend_o365_todos_factory_class_init (ECalBackendFactoryClass *class)
+{
+ EBackendFactoryClass *backend_factory_class;
+
+ backend_factory_class = E_BACKEND_FACTORY_CLASS (class);
+ backend_factory_class->e_module = e_module;
+ backend_factory_class->share_subprocess = TRUE;
+
+ class->factory_name = FACTORY_NAME;
+ class->component_kind = I_CAL_VTODO_COMPONENT;
+ class->backend_type = E_TYPE_CAL_BACKEND_O365;
+}
+
+static void
+e_cal_backend_o365_todos_factory_class_finalize (ECalBackendFactoryClass *class)
+{
+}
+
+static void
+e_cal_backend_o365_todos_factory_init (ECalBackendFactory *factory)
+{
+}
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ bindtextdomain (GETTEXT_PACKAGE, O365_LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ e_module = E_MODULE (type_module);
+
+ e_source_o365_folder_type_register (type_module);
+
+ e_cal_backend_o365_events_factory_register_type (type_module);
+ e_cal_backend_o365_journal_factory_register_type (type_module);
+ e_cal_backend_o365_todos_factory_register_type (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+ e_module = NULL;
+}
diff --git a/src/Office365/calendar/e-cal-backend-o365.c b/src/Office365/calendar/e-cal-backend-o365.c
new file mode 100644
index 00000000..f130ac37
--- /dev/null
+++ b/src/Office365/calendar/e-cal-backend-o365.c
@@ -0,0 +1,461 @@
+/* -*- 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 <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+
+#include <libedata-cal/libedata-cal.h>
+#include <libecal/libecal.h>
+
+#include "common/camel-o365-settings.h"
+#include "common/e-source-o365-folder.h"
+
+#include "e-cal-backend-o365.h"
+
+#ifdef G_OS_WIN32
+#ifdef gmtime_r
+#undef gmtime_r
+#endif
+
+/* The gmtime() in Microsoft's C library is MT-safe */
+#define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
+#endif
+
+#define EC_ERROR(_code) e_client_error_create (_code, NULL)
+#define EC_ERROR_EX(_code, _msg) e_client_error_create (_code, _msg)
+#define ECC_ERROR(_code) e_cal_client_error_create (_code, NULL)
+#define ECC_ERROR_EX(_code, _msg) e_cal_client_error_create (_code, _msg)
+
+/* Private part of the CalBackendO365 structure */
+struct _ECalBackendO365Private {
+ GRecMutex property_lock;
+
+ gchar *attachments_dir;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (ECalBackendO365, e_cal_backend_o365, E_TYPE_CAL_META_BACKEND)
+
+static void
+ecb_o365_convert_error_to_edc_error (GError **perror)
+{
+ GError *error = NULL;
+
+ if (!perror || !*perror ||
+ (*perror)->domain == E_CLIENT_ERROR ||
+ (*perror)->domain == E_CAL_CLIENT_ERROR)
+ return;
+
+ /*if ((*perror)->domain == O365_CONNECTION_ERROR) {
+ switch ((*perror)->code) {
+ case O365_CONNECTION_ERROR_AUTHENTICATION_FAILED:
+ error = EC_ERROR_EX (E_CLIENT_ERROR_AUTHENTICATION_FAILED, (*perror)->message);
+ break;
+ case O365_CONNECTION_ERROR_FOLDERNOTFOUND:
+ case O365_CONNECTION_ERROR_MANAGEDFOLDERNOTFOUND:
+ case O365_CONNECTION_ERROR_PARENTFOLDERNOTFOUND:
+ case O365_CONNECTION_ERROR_PUBLICFOLDERSERVERNOTFOUND:
+ error = ECC_ERROR_EX (E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR, (*perror)->message);
+ break;
+ case O365_CONNECTION_ERROR_EVENTNOTFOUND:
+ case O365_CONNECTION_ERROR_ITEMNOTFOUND:
+ error = ECC_ERROR_EX (E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND, (*perror)->message);
+ break;
+ case O365_CONNECTION_ERROR_UNAVAILABLE:
+ g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_HOST_NOT_FOUND,
(*perror)->message);
+ break;
+ }
+
+ if (!error)
+ error = EC_ERROR_EX (E_CLIENT_ERROR_OTHER_ERROR, (*perror)->message);
+ }*/
+
+ if (error) {
+ g_error_free (*perror);
+ *perror = error;
+ }
+}
+
+static void
+ecb_o365_maybe_disconnect_sync (ECalBackendO365 *cbo365,
+ GError **in_perror,
+ GCancellable *cancellable)
+{
+ g_return_if_fail (E_IS_CAL_BACKEND_O365 (cbo365));
+
+ if (in_perror && g_error_matches (*in_perror, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED)) {
+ e_cal_meta_backend_disconnect_sync (E_CAL_META_BACKEND (cbo365), cancellable, NULL);
+ e_backend_schedule_credentials_required (E_BACKEND (cbo365),
E_SOURCE_CREDENTIALS_REASON_REJECTED, NULL, 0, NULL, NULL, G_STRFUNC);
+ }
+}
+
+static void
+ecb_o365_unset_connection (ECalBackendO365 *cbo365,
+ gboolean is_disconnect)
+{
+ g_return_if_fail (E_IS_CAL_BACKEND_O365 (cbo365));
+
+ g_rec_mutex_lock (&cbo365->priv->property_lock);
+
+ /*if (cbo365->priv->cnc) {
+ if (is_disconnect)
+ e_o365_connection_set_disconnected_flag (cbo365->priv->cnc, TRUE);
+ }
+
+ g_clear_object (&cbo365->priv->cnc);*/
+
+ g_rec_mutex_unlock (&cbo365->priv->property_lock);
+}
+
+static gboolean
+ecb_o365_connect_sync (ECalMetaBackend *meta_backend,
+ const ENamedParameters *credentials,
+ ESourceAuthenticationResult *out_auth_result,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalBackendO365 *cbo365;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_CAL_BACKEND_O365 (meta_backend), FALSE);
+ g_return_val_if_fail (out_auth_result != NULL, FALSE);
+
+ cbo365 = E_CAL_BACKEND_O365 (meta_backend);
+
+ g_rec_mutex_lock (&cbo365->priv->property_lock);
+
+ /*if (cbo365->priv->cnc)*/ {
+ g_rec_mutex_unlock (&cbo365->priv->property_lock);
+
+ *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+
+ return TRUE;
+ }
+
+ g_rec_mutex_unlock (&cbo365->priv->property_lock);
+
+ return success;
+}
+
+static gboolean
+ecb_o365_disconnect_sync (ECalMetaBackend *meta_backend,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (E_IS_CAL_BACKEND_O365 (meta_backend), FALSE);
+
+ ecb_o365_unset_connection (E_CAL_BACKEND_O365 (meta_backend), TRUE);
+
+ return TRUE;
+}
+
+static gboolean
+ecb_o365_get_changes_sync (ECalMetaBackend *meta_backend,
+ const gchar *last_sync_tag,
+ gboolean is_repeat,
+ gchar **out_new_sync_tag,
+ gboolean *out_repeat,
+ GSList **out_created_objects,
+ GSList **out_modified_objects,
+ GSList **out_removed_objects,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalBackendO365 *cbo365;
+ ECalCache *cal_cache;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_CAL_BACKEND_O365 (meta_backend), FALSE);
+ g_return_val_if_fail (out_new_sync_tag != NULL, FALSE);
+ g_return_val_if_fail (out_repeat != NULL, FALSE);
+ g_return_val_if_fail (out_created_objects != NULL, FALSE);
+ g_return_val_if_fail (out_modified_objects != NULL, FALSE);
+ g_return_val_if_fail (out_removed_objects != NULL, FALSE);
+
+ *out_created_objects = NULL;
+ *out_modified_objects = NULL;
+ *out_removed_objects = NULL;
+
+ cbo365 = E_CAL_BACKEND_O365 (meta_backend);
+
+ cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
+ g_return_val_if_fail (E_IS_CAL_CACHE (cal_cache), FALSE);
+
+ g_rec_mutex_lock (&cbo365->priv->property_lock);
+
+ g_rec_mutex_unlock (&cbo365->priv->property_lock);
+
+ ecb_o365_convert_error_to_edc_error (error);
+ ecb_o365_maybe_disconnect_sync (cbo365, error, cancellable);
+
+ return success;
+}
+
+static gboolean
+ecb_o365_load_component_sync (ECalMetaBackend *meta_backend,
+ const gchar *uid,
+ const gchar *extra,
+ ICalComponent **out_component,
+ gchar **out_extra,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalBackendO365 *cbo365;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_CAL_BACKEND_O365 (meta_backend), FALSE);
+ g_return_val_if_fail (uid != NULL, FALSE);
+ g_return_val_if_fail (out_component != NULL, FALSE);
+ g_return_val_if_fail (out_extra != NULL, FALSE);
+
+ cbo365 = E_CAL_BACKEND_O365 (meta_backend);
+
+ g_rec_mutex_lock (&cbo365->priv->property_lock);
+
+ g_rec_mutex_unlock (&cbo365->priv->property_lock);
+
+ ecb_o365_convert_error_to_edc_error (error);
+ ecb_o365_maybe_disconnect_sync (cbo365, error, cancellable);
+
+ return success;
+}
+
+static gboolean
+ecb_o365_save_component_sync (ECalMetaBackend *meta_backend,
+ gboolean overwrite_existing,
+ EConflictResolution conflict_resolution,
+ const GSList *instances,
+ const gchar *extra,
+ guint32 opflags,
+ gchar **out_new_uid,
+ gchar **out_new_extra,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalBackendO365 *cbo365;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_CAL_BACKEND_O365 (meta_backend), FALSE);
+
+ cbo365 = E_CAL_BACKEND_O365 (meta_backend);
+
+ g_rec_mutex_lock (&cbo365->priv->property_lock);
+
+ g_rec_mutex_unlock (&cbo365->priv->property_lock);
+
+ ecb_o365_convert_error_to_edc_error (error);
+ ecb_o365_maybe_disconnect_sync (cbo365, error, cancellable);
+
+ return success;
+}
+
+static gboolean
+ecb_o365_remove_component_sync (ECalMetaBackend *meta_backend,
+ EConflictResolution conflict_resolution,
+ const gchar *uid,
+ const gchar *extra,
+ const gchar *object,
+ guint32 opflags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalBackendO365 *cbo365;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_CAL_BACKEND_O365 (meta_backend), FALSE);
+ g_return_val_if_fail (object != NULL, FALSE);
+
+ cbo365 = E_CAL_BACKEND_O365 (meta_backend);
+
+ g_rec_mutex_lock (&cbo365->priv->property_lock);
+
+ g_rec_mutex_unlock (&cbo365->priv->property_lock);
+
+ ecb_o365_convert_error_to_edc_error (error);
+ ecb_o365_maybe_disconnect_sync (cbo365, error, cancellable);
+
+ return success;
+}
+
+static gchar *
+ecb_o365_get_backend_property (ECalBackend *cal_backend,
+ const gchar *prop_name)
+{
+ ECalBackendO365 *cbo365;
+
+ g_return_val_if_fail (E_IS_CAL_BACKEND_O365 (cal_backend), NULL);
+ g_return_val_if_fail (prop_name != NULL, NULL);
+
+ cbo365 = E_CAL_BACKEND_O365 (cal_backend);
+
+ if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+ return g_strjoin (
+ ",",
+ E_CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS,
+ E_CAL_STATIC_CAPABILITY_NO_AUDIO_ALARMS,
+ E_CAL_STATIC_CAPABILITY_NO_PROCEDURE_ALARMS,
+ E_CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY,
+ E_CAL_STATIC_CAPABILITY_REMOVE_ALARMS,
+ E_CAL_STATIC_CAPABILITY_NO_THISANDPRIOR,
+ E_CAL_STATIC_CAPABILITY_NO_THISANDFUTURE,
+ E_CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK,
+ E_CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT,
+ E_CAL_STATIC_CAPABILITY_SAVE_SCHEDULES,
+ E_CAL_STATIC_CAPABILITY_NO_ALARM_AFTER_START,
+ E_CAL_STATIC_CAPABILITY_NO_MEMO_START_DATE,
+ E_CAL_STATIC_CAPABILITY_ALL_DAY_EVENT_AS_TIME,
+ E_CAL_STATIC_CAPABILITY_TASK_DATE_ONLY,
+ E_CAL_STATIC_CAPABILITY_TASK_NO_ALARM,
+ E_CAL_STATIC_CAPABILITY_TASK_CAN_RECUR,
+ E_CAL_STATIC_CAPABILITY_TASK_HANDLE_RECUR,
+ e_cal_meta_backend_get_capabilities (E_CAL_META_BACKEND (cbo365)),
+ NULL);
+ } else if (g_str_equal (prop_name, E_CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS)) {
+ /* return email address of the person who opened the calendar */
+ CamelO365Settings *o365_settings;
+
+ o365_settings = camel_o365_settings_get_from_backend (E_BACKEND (cal_backend),
e_cal_backend_get_registry (cal_backend));
+
+ return camel_o365_settings_dup_email (o365_settings);
+ } else if (g_str_equal (prop_name, E_CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
+ /* Office 365 does not support email based alarms */
+ return NULL;
+ }
+
+ /* Chain up to parent's method. */
+ return E_CAL_BACKEND_CLASS (e_cal_backend_o365_parent_class)->impl_get_backend_property (cal_backend,
prop_name);
+}
+
+static gboolean
+ecb_o365_get_destination_address (EBackend *backend,
+ gchar **host,
+ guint16 *port)
+{
+ g_return_val_if_fail (port != NULL, FALSE);
+ g_return_val_if_fail (host != NULL, FALSE);
+
+ /* Sanity checking */
+ if (!e_cal_backend_get_registry (E_CAL_BACKEND (backend)) ||
+ !e_backend_get_source (backend))
+ return FALSE;
+
+ *host = g_strdup ("graph.microsoft.com");
+ *port = 443;
+
+ return TRUE;
+}
+
+static gchar *
+ecb_o365_dup_component_revision (ECalCache *cal_cache,
+ ICalComponent *icomp,
+ gpointer user_data)
+{
+ g_return_val_if_fail (icomp != NULL, NULL);
+
+ return e_cal_util_component_dup_x_property (icomp, "X-EVOLUTION-CHANGEKEY");
+}
+
+static void
+ecb_o365_constructed (GObject *object)
+{
+ ECalBackendO365 *cbo365 = E_CAL_BACKEND_O365 (object);
+ ECalCache *cal_cache;
+ gchar *cache_dirname;
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_cal_backend_o365_parent_class)->constructed (object);
+
+ /* Reset the connectable, it steals data from Authentication extension,
+ where is written incorrect address */
+ e_backend_set_connectable (E_BACKEND (object), NULL);
+
+ cal_cache = e_cal_meta_backend_ref_cache (E_CAL_META_BACKEND (cbo365));
+ g_return_if_fail (cal_cache != NULL);
+
+ cache_dirname = g_path_get_dirname (e_cache_get_filename (E_CACHE (cal_cache)));
+ g_signal_connect (cal_cache, "dup-component-revision", G_CALLBACK (ecb_o365_dup_component_revision),
NULL);
+
+ g_clear_object (&cal_cache);
+
+ cbo365->priv->attachments_dir = g_build_filename (cache_dirname, "attachments", NULL);
+ g_mkdir_with_parents (cbo365->priv->attachments_dir, 0777);
+
+ g_free (cache_dirname);
+}
+
+static void
+ecb_o365_dispose (GObject *object)
+{
+ ECalBackendO365 *cbo365 = E_CAL_BACKEND_O365 (object);
+
+ ecb_o365_unset_connection (cbo365, FALSE);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_cal_backend_o365_parent_class)->dispose (object);
+}
+
+static void
+ecb_o365_finalize (GObject *object)
+{
+ ECalBackendO365 *cbo365 = E_CAL_BACKEND_O365 (object);
+
+ g_free (cbo365->priv->attachments_dir);
+
+ g_rec_mutex_clear (&cbo365->priv->property_lock);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_cal_backend_o365_parent_class)->finalize (object);
+}
+
+static void
+e_cal_backend_o365_init (ECalBackendO365 *cbo365)
+{
+ cbo365->priv = e_cal_backend_o365_get_instance_private (cbo365);
+
+ g_rec_mutex_init (&cbo365->priv->property_lock);
+}
+
+static void
+e_cal_backend_o365_class_init (ECalBackendO365Class *klass)
+{
+ GObjectClass *object_class;
+ EBackendClass *backend_class;
+ ECalBackendClass *cal_backend_class;
+ ECalMetaBackendClass *cal_meta_backend_class;
+
+ cal_meta_backend_class = E_CAL_META_BACKEND_CLASS (klass);
+ cal_meta_backend_class->connect_sync = ecb_o365_connect_sync;
+ cal_meta_backend_class->disconnect_sync = ecb_o365_disconnect_sync;
+ cal_meta_backend_class->get_changes_sync = ecb_o365_get_changes_sync;
+ cal_meta_backend_class->load_component_sync = ecb_o365_load_component_sync;
+ cal_meta_backend_class->save_component_sync = ecb_o365_save_component_sync;
+ cal_meta_backend_class->remove_component_sync = ecb_o365_remove_component_sync;
+
+ cal_backend_class = E_CAL_BACKEND_CLASS (klass);
+ cal_backend_class->impl_get_backend_property = ecb_o365_get_backend_property;
+
+ backend_class = E_BACKEND_CLASS (klass);
+ backend_class->get_destination_address = ecb_o365_get_destination_address;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->constructed = ecb_o365_constructed;
+ object_class->dispose = ecb_o365_dispose;
+ object_class->finalize = ecb_o365_finalize;
+}
diff --git a/src/Office365/calendar/e-cal-backend-o365.h b/src/Office365/calendar/e-cal-backend-o365.h
new file mode 100644
index 00000000..1ffeb8c9
--- /dev/null
+++ b/src/Office365/calendar/e-cal-backend-o365.h
@@ -0,0 +1,48 @@
+/* -*- 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_CAL_BACKEND_O365_H
+#define E_CAL_BACKEND_O365_H
+
+#include <libedata-cal/libedata-cal.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_CAL_BACKEND_O365 (e_cal_backend_o365_get_type ())
+#define E_CAL_BACKEND_O365(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_BACKEND_O365,
ECalBackendO365))
+#define E_CAL_BACKEND_O365_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_BACKEND_O365,
ECalBackendO365Class))
+#define E_IS_CAL_BACKEND_O365(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_BACKEND_O365))
+#define E_IS_CAL_BACKEND_O365_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_BACKEND_O365))
+
+typedef struct _ECalBackendO365 ECalBackendO365;
+typedef struct _ECalBackendO365Class ECalBackendO365Class;
+typedef struct _ECalBackendO365Private ECalBackendO365Private;
+
+struct _ECalBackendO365 {
+ ECalMetaBackend parent_object;
+ ECalBackendO365Private *priv;
+};
+
+struct _ECalBackendO365Class {
+ ECalMetaBackendClass parent_class;
+};
+
+GType e_cal_backend_o365_get_type (void);
+
+G_END_DECLS
+
+#endif /* E_CAL_BACKEND_O365_H */
diff --git a/src/Office365/camel/CMakeLists.txt b/src/Office365/camel/CMakeLists.txt
new file mode 100644
index 00000000..56e506b9
--- /dev/null
+++ b/src/Office365/camel/CMakeLists.txt
@@ -0,0 +1,65 @@
+install(FILES libcameloffice365.urls
+ DESTINATION ${camel_providerdir}
+)
+
+set(DEPENDENCIES
+ evolution-office365
+)
+
+set(SOURCES
+ camel-o365-provider.c
+ camel-o365-store.c
+ camel-o365-store.h
+ camel-o365-transport.c
+ camel-o365-transport.h
+)
+
+add_library(cameloffice365 MODULE
+ ${SOURCES}
+)
+
+add_dependencies(cameloffice365
+ ${DEPENDENCIES}
+)
+
+target_compile_definitions(cameloffice365 PRIVATE
+ -DG_LOG_DOMAIN=\"camel-office365-provider\"
+ -DO365_LOCALEDIR=\"${LOCALE_INSTALL_DIR}\"
+)
+
+target_compile_options(cameloffice365 PUBLIC
+ ${CAMEL_CFLAGS}
+ ${EVOLUTION_SHELL_CFLAGS}
+ ${EVOLUTION_MAIL_CFLAGS}
+ ${LIBEDATASERVER_CFLAGS}
+ ${LIBECAL_CFLAGS}
+ ${SOUP_CFLAGS}
+)
+
+target_include_directories(cameloffice365 PUBLIC
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}/src/Office365
+ ${CMAKE_SOURCE_DIR}/src/Office365
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CAMEL_INCLUDE_DIRS}
+ ${EVOLUTION_SHELL_INCLUDE_DIRS}
+ ${EVOLUTION_MAIL_INCLUDE_DIRS}
+ ${LIBEDATASERVER_INCLUDE_DIRS}
+ ${LIBECAL_INCLUDE_DIRS}
+ ${SOUP_INCLUDE_DIRS}
+)
+
+target_link_libraries(cameloffice365
+ ${DEPENDENCIES}
+ ${CAMEL_LDFLAGS}
+ ${EVOLUTION_SHELL_LDFLAGS}
+ ${EVOLUTION_MAIL_LDFLAGS}
+ ${LIBEDATASERVER_LDFLAGS}
+ ${LIBECAL_LDFLAGS}
+ ${SOUP_LDFLAGS}
+)
+
+install(TARGETS cameloffice365
+ DESTINATION ${camel_providerdir}
+)
diff --git a/src/Office365/camel/camel-o365-provider.c b/src/Office365/camel/camel-o365-provider.c
new file mode 100644
index 00000000..d57614af
--- /dev/null
+++ b/src/Office365/camel/camel-o365-provider.c
@@ -0,0 +1,128 @@
+/* -*- 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 <string.h>
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include "camel-o365-store.h"
+#include "camel-o365-transport.h"
+
+static void add_hash (guint *hash, gchar *s);
+static guint o365_url_hash (gconstpointer key);
+static gint o365_url_equal (gconstpointer a, gconstpointer b);
+
+static CamelProviderConfEntry o365_conf_entries[] = {
+ { CAMEL_PROVIDER_CONF_SECTION_START, "mailcheck", NULL,
+ N_("Checking for new mail") },
+ { CAMEL_PROVIDER_CONF_CHECKBOX, "check-all", NULL,
+ N_("C_heck for new messages in all folders"), "1" },
+ { CAMEL_PROVIDER_CONF_SECTION_END },
+
+ { CAMEL_PROVIDER_CONF_SECTION_START, "general", NULL, N_("Options") },
+ { CAMEL_PROVIDER_CONF_CHECKBOX, "filter-inbox", NULL,
+ N_("_Apply filters to new messages in Inbox on this server"), "0" },
+ { CAMEL_PROVIDER_CONF_CHECKBOX, "filter-junk", NULL,
+ N_("Check new messages for _Junk contents"), "0" },
+ { CAMEL_PROVIDER_CONF_CHECKBOX, "filter-junk-inbox", "filter-junk",
+ N_("Only check for Junk messages in the IN_BOX folder"), "0" },
+ { CAMEL_PROVIDER_CONF_CHECKBOX, "stay-synchronized", NULL,
+ N_("Synchroni_ze remote mail locally in all folders"), "0" },
+ { CAMEL_PROVIDER_CONF_PLACEHOLDER, "o365-limit-by-age-placeholder", NULL },
+ { CAMEL_PROVIDER_CONF_SECTION_END },
+
+ { CAMEL_PROVIDER_CONF_SECTION_START, "connection", NULL, N_("Connection") },
+ { CAMEL_PROVIDER_CONF_CHECKSPIN, "timeout", NULL,
+ /* Translators: '%s' is preplaced with a widget, where "
+ * user can select how long the timeout should be. */
+ N_("Connection _timeout (in seconds) %s"), "0:1:0:32768" },
+ { CAMEL_PROVIDER_CONF_CHECKSPIN, "concurrent-connections", NULL,
+ N_("Numbe_r of concurrent connections to use"), "y:1:1:7" },
+ { CAMEL_PROVIDER_CONF_SECTION_END },
+
+ { CAMEL_PROVIDER_CONF_END }
+};
+
+static CamelProvider o365_provider = {
+ "office365",
+ N_("Office 365"),
+
+ N_("For accessing Microsoft Office 365 server"),
+
+ "mail",
+
+ CAMEL_PROVIDER_IS_REMOTE | CAMEL_PROVIDER_IS_SOURCE |
+ CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_IS_EXTERNAL,
+
+ CAMEL_URL_ALLOW_USER | CAMEL_URL_ALLOW_AUTH | CAMEL_URL_HIDDEN_HOST,
+
+ o365_conf_entries,
+
+ /* ... */
+};
+
+void
+camel_provider_module_init (void)
+{
+ bindtextdomain (GETTEXT_PACKAGE, O365_LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ o365_provider.url_hash = o365_url_hash;
+ o365_provider.url_equal = o365_url_equal;
+ o365_provider.authtypes = NULL;
+ o365_provider.translation_domain = GETTEXT_PACKAGE;
+ o365_provider.object_types[CAMEL_PROVIDER_STORE] = CAMEL_TYPE_O365_STORE;
+ o365_provider.object_types[CAMEL_PROVIDER_TRANSPORT] = CAMEL_TYPE_O365_TRANSPORT;
+
+ camel_provider_register (&o365_provider);
+}
+
+static void
+add_hash (guint *hash,
+ gchar *s)
+{
+ if (s)
+ *hash ^= g_str_hash(s);
+}
+
+static guint
+o365_url_hash (gconstpointer key)
+{
+ const CamelURL *u = (CamelURL *) key;
+ guint hash = 0;
+
+ add_hash (&hash, u->user);
+ add_hash (&hash, u->host);
+ hash ^= u->port;
+
+ return hash;
+}
+
+static gint
+o365_url_equal (gconstpointer a,
+ gconstpointer b)
+{
+ const CamelURL *u1 = a, *u2 = b;
+
+ return ((g_strcmp0 (u1->protocol, u2->protocol) == 0)
+ && (g_strcmp0 (u1->user, u2->user) == 0)
+ && (g_strcmp0 (u1->host, u2->host) == 0)
+ && (u1->port == u2->port));
+}
diff --git a/src/Office365/camel/camel-o365-store.c b/src/Office365/camel/camel-o365-store.c
new file mode 100644
index 00000000..7efb4f1d
--- /dev/null
+++ b/src/Office365/camel/camel-o365-store.c
@@ -0,0 +1,383 @@
+/* -*- 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 <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+
+#include "common/camel-o365-settings.h"
+
+#include "camel-o365-store.h"
+
+struct _CamelO365StorePrivate {
+ GRecMutex property_lock;
+ gchar *storage_path;
+};
+
+static void camel_o365_store_initable_init (GInitableIface *iface);
+static void camel_o365_subscribable_init (CamelSubscribableInterface *iface);
+static GInitableIface *parent_initable_interface;
+
+enum {
+ PROP_0,
+ PROP_CONNECTABLE,
+ PROP_HOST_REACHABLE
+};
+
+G_DEFINE_TYPE_WITH_CODE (CamelO365Store, camel_o365_store, CAMEL_TYPE_OFFLINE_STORE,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, camel_o365_store_initable_init)
+ G_IMPLEMENT_INTERFACE (CAMEL_TYPE_NETWORK_SERVICE, NULL)
+ G_IMPLEMENT_INTERFACE (CAMEL_TYPE_SUBSCRIBABLE, camel_o365_subscribable_init)
+ G_ADD_PRIVATE (CamelO365Store))
+
+static void
+o365_store_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CONNECTABLE:
+ camel_network_service_set_connectable (
+ CAMEL_NETWORK_SERVICE (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+o365_store_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CONNECTABLE:
+ g_value_take_object (
+ value,
+ camel_network_service_ref_connectable (
+ CAMEL_NETWORK_SERVICE (object)));
+ return;
+ case PROP_HOST_REACHABLE:
+ g_value_set_boolean (
+ value,
+ camel_network_service_get_host_reachable (
+ CAMEL_NETWORK_SERVICE (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static gboolean
+o365_store_construct (CamelService *service,
+ CamelSession *session,
+ CamelProvider *provider,
+ GError **error)
+{
+ CamelO365Store *o365_store;
+ gchar /**summary_file,*/ *session_storage_path;
+ guint32 store_flags;
+
+ o365_store = (CamelO365Store *) service;
+
+ store_flags = camel_store_get_flags (CAMEL_STORE (o365_store));
+
+ /* Disable virtual trash and junk folders. Office365 has real
+ * folders for that */
+ store_flags &= ~(CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK);
+ store_flags |= CAMEL_STORE_REAL_JUNK_FOLDER;
+ camel_store_set_flags (CAMEL_STORE (o365_store), store_flags);
+
+ /*storage path*/
+ session_storage_path = g_strdup (camel_service_get_user_cache_dir (service));
+ if (!session_storage_path) {
+ g_set_error (
+ error, CAMEL_STORE_ERROR,
+ CAMEL_STORE_ERROR_INVALID,
+ _("Session has no storage path"));
+ return FALSE;
+ }
+
+ o365_store->priv->storage_path = session_storage_path;
+
+ g_mkdir_with_parents (o365_store->priv->storage_path, 0700);
+ /*summary_file = g_build_filename (o365_store->storage_path, "folder-tree", NULL);
+ o365_store->summary = camel_o365_store_summary_new (summary_file);
+ camel_o365_store_summary_load (o365_store->summary, NULL);
+
+ g_free (summary_file);*/
+
+ return TRUE;
+}
+
+static gboolean
+o365_store_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelService *service;
+ CamelSession *session;
+ CamelStore *store;
+ gboolean ret;
+
+ store = CAMEL_STORE (initable);
+ service = CAMEL_SERVICE (initable);
+
+ camel_store_set_flags (store, camel_store_get_flags (store) |
+ CAMEL_STORE_USE_CACHE_DIR |
+ CAMEL_STORE_SUPPORTS_INITIAL_SETUP |
+ CAMEL_STORE_CAN_DELETE_FOLDERS_AT_ONCE);
+
+ /* Chain up to parent interface's method. */
+ if (!parent_initable_interface->init (initable, cancellable, error))
+ return FALSE;
+
+ session = camel_service_ref_session (service);
+
+ ret = o365_store_construct (service, session, NULL, error);
+
+ g_object_unref (session);
+
+ return ret;
+}
+
+static GList *
+o365_store_query_auth_types_sync (CamelService *service,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (CAMEL_IS_O365_STORE (service), NULL);
+
+ return NULL;
+}
+
+static gchar *
+o365_store_get_name (CamelService *service,
+ gboolean brief)
+{
+ gchar *name;
+
+ if (brief)
+ name = g_strdup (_("Office365 server"));
+ else
+ name = g_strdup (_("Mail receive via Microsoft Office365"));
+
+ return name;
+}
+
+static gboolean
+o365_store_connect_sync (CamelService *service,
+ GCancellable *cancellable,
+ GError **error)
+{
+ /*CamelO365Store *o365_store;*/
+ gboolean success = FALSE;
+
+ /* Chain up to parent's method. */
+ if (!CAMEL_SERVICE_CLASS (camel_o365_store_parent_class)->connect_sync (service, cancellable, error))
+ return FALSE;
+
+ if (camel_service_get_connection_status (service) == CAMEL_SERVICE_DISCONNECTED)
+ return FALSE;
+
+ /*o365_store = CAMEL_O365_STORE (service);
+
+ g_signal_connect_swapped (
+ o365_settings,
+ "notify::listen-notifications",
+ G_CALLBACK (camel_o365_store_listen_notifications_cb),
+ o365_store);
+
+ g_signal_connect_swapped (
+ o365_settings,
+ "notify::check-all",
+ G_CALLBACK (camel_o365_store_check_all_cb),
+ o365_store);*/
+
+ return success;
+}
+
+static gboolean
+o365_store_disconnect_sync (CamelService *service,
+ gboolean clean,
+ GCancellable *cancellable,
+ GError **error)
+{
+ /*CamelO365Store *o365_store = CAMEL_O365_STORE (service);
+
+ g_mutex_lock (&o365_store->priv->connection_lock);
+ o365_store_unset_connection_locked (o365_store, TRUE);
+ g_mutex_unlock (&o365_store->priv->connection_lock);*/
+
+ return CAMEL_SERVICE_CLASS (camel_o365_store_parent_class)->disconnect_sync (service, clean,
cancellable, error);
+}
+
+static CamelAuthenticationResult
+o365_store_authenticate_sync (CamelService *service,
+ const gchar *mechanism,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelAuthenticationResult result;
+ /*CamelO365Store *o365_store;
+
+ o365_store = CAMEL_O365_STORE (service);*/
+
+ result = CAMEL_AUTHENTICATION_ERROR;
+
+ return result;
+}
+
+gboolean
+camel_o365_store_connected (CamelO365Store *o365_store,
+ GCancellable *cancellable,
+ GError **error)
+{
+ if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (o365_store))) {
+ g_set_error (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_UNAVAILABLE,
+ _("You must be working online to complete this operation"));
+ return FALSE;
+ }
+
+ if (!camel_service_connect_sync ((CamelService *) o365_store, cancellable, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+void
+camel_o365_store_maybe_disconnect (CamelO365Store *store,
+ const GError *error)
+{
+ CamelService *service;
+
+ g_return_if_fail (store != NULL);
+
+ if (!error)
+ return;
+
+ service = CAMEL_SERVICE (store);
+
+ if (camel_service_get_connection_status (service) != CAMEL_SERVICE_CONNECTED)
+ return;
+
+#if 0
+ if (g_error_matches (error, O365_CONNECTION_ERROR, O365_CONNECTION_ERROR_NORESPONSE) ||
+ g_error_matches (error, O365_CONNECTION_ERROR, O365_CONNECTION_ERROR_AUTHENTICATION_FAILED))
+ camel_service_disconnect_sync (service, FALSE, NULL, NULL);
+#endif
+}
+
+static void
+o365_store_dispose (GObject *object)
+{
+ /*CamelO365Store *o365_store = CAMEL_O365_STORE (object);*/
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (camel_o365_store_parent_class)->dispose (object);
+}
+
+static void
+o365_store_finalize (GObject *object)
+{
+ CamelO365Store *o365_store;
+
+ o365_store = CAMEL_O365_STORE (object);
+
+ g_rec_mutex_clear (&o365_store->priv->property_lock);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (camel_o365_store_parent_class)->finalize (object);
+}
+
+static void
+camel_o365_store_class_init (CamelO365StoreClass *class)
+{
+ GObjectClass *object_class;
+ CamelServiceClass *service_class;
+ /*CamelStoreClass *store_class;*/
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = o365_store_set_property;
+ object_class->get_property = o365_store_get_property;
+ object_class->dispose = o365_store_dispose;
+ object_class->finalize = o365_store_finalize;
+
+ /* Inherited from CamelNetworkService */
+ g_object_class_override_property (
+ object_class,
+ PROP_CONNECTABLE,
+ "connectable");
+
+ /* Inherited from CamelNetworkService */
+ g_object_class_override_property (
+ object_class,
+ PROP_HOST_REACHABLE,
+ "host-reachable");
+
+ service_class = CAMEL_SERVICE_CLASS (class);
+ service_class->settings_type = CAMEL_TYPE_O365_SETTINGS;
+ service_class->query_auth_types_sync = o365_store_query_auth_types_sync;
+ service_class->get_name = o365_store_get_name;
+ service_class->connect_sync = o365_store_connect_sync;
+ service_class->disconnect_sync = o365_store_disconnect_sync;
+ service_class->authenticate_sync = o365_store_authenticate_sync;
+#if 0
+ store_class = CAMEL_STORE_CLASS (class);
+ store_class->get_folder_sync = o365_get_folder_sync;
+ store_class->create_folder_sync = o365_create_folder_sync;
+ store_class->delete_folder_sync = o365_delete_folder_sync;
+ store_class->rename_folder_sync = o365_rename_folder_sync;
+ store_class->get_folder_info_sync = o365_get_folder_info_sync;
+ store_class->initial_setup_sync = o365_initial_setup_sync;
+ store_class->get_trash_folder_sync = o365_get_trash_folder_sync;
+ store_class->get_junk_folder_sync = o365_get_junk_folder_sync;
+ store_class->can_refresh_folder = o365_can_refresh_folder;
+#endif
+}
+
+static void
+camel_o365_store_initable_init (GInitableIface *iface)
+{
+ parent_initable_interface = g_type_interface_peek_parent (iface);
+
+ iface->init = o365_store_initable_init;
+}
+
+static void
+camel_o365_subscribable_init (CamelSubscribableInterface *iface)
+{
+#if 0
+ iface->folder_is_subscribed = o365_store_folder_is_subscribed;
+ iface->subscribe_folder_sync = o365_store_subscribe_folder_sync;
+ iface->unsubscribe_folder_sync = o365_store_unsubscribe_folder_sync;
+#endif
+}
+
+static void
+camel_o365_store_init (CamelO365Store *o365_store)
+{
+ o365_store->priv = camel_o365_store_get_instance_private (o365_store);
+
+ g_rec_mutex_init (&o365_store->priv->property_lock);
+}
diff --git a/src/Office365/camel/camel-o365-store.h b/src/Office365/camel/camel-o365-store.h
new file mode 100644
index 00000000..1567d012
--- /dev/null
+++ b/src/Office365/camel/camel-o365-store.h
@@ -0,0 +1,67 @@
+/* -*- 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 CAMEL_O365_STORE_H
+#define CAMEL_O365_STORE_H
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_O365_STORE \
+ (camel_o365_store_get_type ())
+#define CAMEL_O365_STORE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), CAMEL_TYPE_O365_STORE, CamelO365Store))
+#define CAMEL_O365_STORE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), CAMEL_TYPE_O365_STORE, CamelO365StoreClass))
+#define CAMEL_IS_O365_STORE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), CAMEL_TYPE_O365_STORE))
+#define CAMEL_IS_O365_STORE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), CAMEL_TYPE_O365_STORE))
+#define CAMEL_O365_STORE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), CAMEL_TYPE_O365_STORE, CamelO365StoreClass))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelO365Store CamelO365Store;
+typedef struct _CamelO365StoreClass CamelO365StoreClass;
+typedef struct _CamelO365StorePrivate CamelO365StorePrivate;
+
+struct _CamelO365Store {
+ CamelOfflineStore parent;
+ CamelO365StorePrivate *priv;
+};
+
+struct _CamelO365StoreClass {
+ CamelOfflineStoreClass parent_class;
+};
+
+GType camel_o365_store_get_type (void);
+gboolean camel_o365_store_connected (CamelO365Store *store,
+ GCancellable *cancellable,
+ GError **error);
+void camel_o365_store_maybe_disconnect
+ (CamelO365Store *store,
+ const GError *error);
+
+G_END_DECLS
+
+#endif /* CAMEL_O365_STORE_H */
diff --git a/src/Office365/camel/camel-o365-transport.c b/src/Office365/camel/camel-o365-transport.c
new file mode 100644
index 00000000..27bbfe91
--- /dev/null
+++ b/src/Office365/camel/camel-o365-transport.c
@@ -0,0 +1,189 @@
+/* -*- 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 <string.h>
+
+#include <glib/gi18n-lib.h>
+
+#include "common/camel-o365-settings.h"
+
+#include "camel-o365-transport.h"
+
+struct _CamelO365TransportPrivate
+{
+ GMutex property_lock;
+ /*EO365Connection *connection;*/
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (CamelO365Transport, camel_o365_transport, CAMEL_TYPE_TRANSPORT)
+
+/*static EO365Connection *
+o365_transport_ref_connection (CamelO365Transport *o365_transport)
+{
+ EO365Connection *connection = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_O365_TRANSPORT (o365_transport), NULL);
+
+ g_mutex_lock (&o365_transport->priv->property_lock);
+
+ if (o365_transport->priv->connection)
+ connection = g_object_ref (o365_transport->priv->connection);
+
+ g_mutex_unlock (&o365_transport->priv->property_lock);
+
+ return connection;
+}*/
+
+static gboolean
+o365_transport_connect_sync (CamelService *service,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelSession *session;
+ gboolean success;
+
+ /* Chain up to parent's method. */
+ if (!CAMEL_SERVICE_CLASS (camel_o365_transport_parent_class)->connect_sync (service, cancellable,
error))
+ return FALSE;
+
+ if (camel_service_get_connection_status (service) == CAMEL_SERVICE_DISCONNECTED)
+ return FALSE;
+
+ /*connection = o365_transport_ref_connection (CAMEL_O365_TRANSPORT (service));
+ if (connection) {
+ g_object_unref (connection);
+ return TRUE;
+ }*/
+
+ session = camel_service_ref_session (service);
+
+ success = camel_session_authenticate_sync (session, service, "Office365", cancellable, error);
+
+ g_object_unref (session);
+
+ return success;
+}
+
+static gboolean
+o365_transport_disconnect_sync (CamelService *service,
+ gboolean clean,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelO365Transport *o365_transport = CAMEL_O365_TRANSPORT (service);
+
+ g_mutex_lock (&o365_transport->priv->property_lock);
+ /*g_clear_object (&o365_transport->priv->connection);*/
+ g_mutex_unlock (&o365_transport->priv->property_lock);
+
+ return CAMEL_SERVICE_CLASS (camel_o365_transport_parent_class)->disconnect_sync (service, clean,
cancellable, error);
+}
+
+static CamelAuthenticationResult
+o365_transport_authenticate_sync (CamelService *service,
+ const gchar *mechanism,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelAuthenticationResult result;
+
+ result = CAMEL_AUTHENTICATION_ERROR;
+
+ return result;
+}
+
+static gchar *
+o365_transport_get_name (CamelService *service,
+ gboolean brief)
+{
+ gchar *name;
+
+ if (brief)
+ name = g_strdup (_("Office365 server"));
+ else
+ name = g_strdup (_("Mail delivery via Microsoft Office365"));
+
+ return name;
+}
+
+static gboolean
+o365_send_to_sync (CamelTransport *transport,
+ CamelMimeMessage *message,
+ CamelAddress *from,
+ CamelAddress *recipients,
+ gboolean *out_sent_message_saved,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return FALSE;
+}
+
+static void
+o365_transport_dispose (GObject *object)
+{
+ CamelO365Transport *o365_transport = CAMEL_O365_TRANSPORT (object);
+
+ g_mutex_lock (&o365_transport->priv->property_lock);
+ /*g_clear_object (&o365_transport->priv->connection);*/
+ g_mutex_unlock (&o365_transport->priv->property_lock);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (camel_o365_transport_parent_class)->dispose (object);
+}
+
+static void
+o365_transport_finalize (GObject *object)
+{
+ CamelO365Transport *o365_transport = CAMEL_O365_TRANSPORT (object);
+
+ g_mutex_clear (&o365_transport->priv->property_lock);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (camel_o365_transport_parent_class)->finalize (object);
+}
+
+static void
+camel_o365_transport_class_init (CamelO365TransportClass *class)
+{
+ GObjectClass *object_class;
+ CamelServiceClass *service_class;
+ CamelTransportClass *transport_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = o365_transport_dispose;
+ object_class->finalize = o365_transport_finalize;
+
+ service_class = CAMEL_SERVICE_CLASS (class);
+ service_class->settings_type = CAMEL_TYPE_O365_SETTINGS;
+ service_class->get_name = o365_transport_get_name;
+ service_class->connect_sync = o365_transport_connect_sync;
+ service_class->disconnect_sync = o365_transport_disconnect_sync;
+ service_class->authenticate_sync = o365_transport_authenticate_sync;
+
+ transport_class = CAMEL_TRANSPORT_CLASS (class);
+ transport_class->send_to_sync = o365_send_to_sync;
+}
+
+static void
+camel_o365_transport_init (CamelO365Transport *o365_transport)
+{
+ o365_transport->priv = camel_o365_transport_get_instance_private (o365_transport);
+
+ g_mutex_init (&o365_transport->priv->property_lock);
+}
diff --git a/src/Office365/camel/camel-o365-transport.h b/src/Office365/camel/camel-o365-transport.h
new file mode 100644
index 00000000..ed679f49
--- /dev/null
+++ b/src/Office365/camel/camel-o365-transport.h
@@ -0,0 +1,61 @@
+/* -*- 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 CAMEL_O365_TRANSPORT_H
+#define CAMEL_O365_TRANSPORT_H
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_O365_TRANSPORT \
+ (camel_o365_transport_get_type ())
+#define CAMEL_O365_TRANSPORT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), CAMEL_TYPE_O365_TRANSPORT, CamelO365Transport))
+#define CAMEL_O365_TRANSPORT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), CAMEL_TYPE_O365_TRANSPORT, CamelO365TransportClass))
+#define CAMEL_IS_O365_TRANSPORT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), CAMEL_TYPE_O365_TRANSPORT))
+#define CAMEL_IS_O365_TRANSPORT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), CAMEL_TYPE_O365_TRANSPORT))
+#define CAMEL_O365_TRANSPORT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), CAMEL_TYPE_O365_TRANSPORT, CamelO365TransportClass))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelO365Transport CamelO365Transport;
+typedef struct _CamelO365TransportClass CamelO365TransportClass;
+typedef struct _CamelO365TransportPrivate CamelO365TransportPrivate;
+
+struct _CamelO365Transport {
+ CamelTransport parent;
+ CamelO365TransportPrivate *priv;
+};
+
+struct _CamelO365TransportClass {
+ CamelTransportClass parent_class;
+};
+
+GType camel_o365_transport_get_type (void);
+
+G_END_DECLS
+
+#endif /* CAMEL_O365_TRANSPORT_H */
diff --git a/src/Office365/camel/libcameloffice365.urls b/src/Office365/camel/libcameloffice365.urls
new file mode 100644
index 00000000..ea5d8c19
--- /dev/null
+++ b/src/Office365/camel/libcameloffice365.urls
@@ -0,0 +1 @@
+office365
diff --git a/src/Office365/common/CMakeLists.txt b/src/Office365/common/CMakeLists.txt
new file mode 100644
index 00000000..ff271000
--- /dev/null
+++ b/src/Office365/common/CMakeLists.txt
@@ -0,0 +1,53 @@
+set(SOURCES
+ camel-o365-settings.c
+ camel-o365-settings.h
+ e-source-o365-folder.c
+ e-source-o365-folder.h
+)
+
+add_library(evolution-office365 SHARED
+ ${SOURCES}
+)
+
+target_compile_definitions(evolution-office365 PRIVATE
+ -DG_LOG_DOMAIN=\"evolution-office365\"
+)
+
+target_compile_options(evolution-office365 PUBLIC
+ ${CAMEL_CFLAGS}
+ ${EVOLUTION_CALENDAR_CFLAGS}
+ ${LIBEBACKEND_CFLAGS}
+ ${LIBECAL_CFLAGS}
+ ${LIBEDATACAL_CFLAGS}
+ ${LIBEDATASERVER_CFLAGS}
+ ${SOUP_CFLAGS}
+)
+
+target_include_directories(evolution-office365 PUBLIC
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}/src/Office365
+ ${CMAKE_SOURCE_DIR}/src/Office365
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CAMEL_INCLUDE_DIRS}
+ ${EVOLUTION_CALENDAR_INCLUDE_DIRS}
+ ${LIBEBACKEND_INCLUDE_DIRS}
+ ${LIBECAL_INCLUDE_DIRS}
+ ${LIBEDATACAL_INCLUDE_DIRS}
+ ${LIBEDATASERVER_INCLUDE_DIRS}
+ ${SOUP_INCLUDE_DIRS}
+)
+
+target_link_libraries(evolution-office365
+ ${CAMEL_LDFLAGS}
+ ${EVOLUTION_CALENDAR_LDFLAGS}
+ ${LIBEBACKEND_LDFLAGS}
+ ${LIBECAL_LDFLAGS}
+ ${LIBEDATACAL_LDFLAGS}
+ ${LIBEDATASERVER_LDFLAGS}
+ ${SOUP_LDFLAGS}
+)
+
+install(TARGETS evolution-office365
+ DESTINATION ${privsolibdir}
+)
diff --git a/src/Office365/common/camel-o365-settings.c b/src/Office365/common/camel-o365-settings.c
new file mode 100644
index 00000000..c103962f
--- /dev/null
+++ b/src/Office365/common/camel-o365-settings.c
@@ -0,0 +1,826 @@
+/* -*- 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 <libebackend/libebackend.h>
+#include <libedataserver/libedataserver.h>
+
+#include "camel-o365-settings.h"
+
+struct _CamelO365SettingsPrivate {
+ GMutex property_lock;
+ gboolean check_all;
+ gboolean filter_junk;
+ gboolean filter_junk_inbox;
+ gboolean override_oauth2;
+ guint timeout;
+ guint concurrent_connections;
+ gchar *email;
+ gchar *oauth2_tenant;
+ gchar *oauth2_client_id;
+ gchar *oauth2_redirect_uri;
+};
+
+enum {
+ PROP_0,
+ PROP_AUTH_MECHANISM,
+ PROP_CHECK_ALL,
+ PROP_EMAIL,
+ PROP_FILTER_JUNK,
+ PROP_FILTER_JUNK_INBOX,
+ PROP_HOST,
+ PROP_PORT,
+ PROP_SECURITY_METHOD,
+ PROP_TIMEOUT,
+ PROP_USER,
+ PROP_OVERRIDE_OAUTH2,
+ PROP_OAUTH2_TENANT,
+ PROP_OAUTH2_CLIENT_ID,
+ PROP_OAUTH2_REDIRECT_URI,
+ PROP_CONCURRENT_CONNECTIONS
+};
+
+G_DEFINE_TYPE_WITH_CODE (CamelO365Settings, camel_o365_settings, CAMEL_TYPE_OFFLINE_SETTINGS,
+ G_IMPLEMENT_INTERFACE (CAMEL_TYPE_NETWORK_SETTINGS, NULL)
+ G_ADD_PRIVATE (CamelO365Settings))
+
+static void
+o365_settings_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_AUTH_MECHANISM:
+ camel_network_settings_set_auth_mechanism (
+ CAMEL_NETWORK_SETTINGS (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_CHECK_ALL:
+ camel_o365_settings_set_check_all (
+ CAMEL_O365_SETTINGS (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_EMAIL:
+ camel_o365_settings_set_email (
+ CAMEL_O365_SETTINGS (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_FILTER_JUNK:
+ camel_o365_settings_set_filter_junk (
+ CAMEL_O365_SETTINGS (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_FILTER_JUNK_INBOX:
+ camel_o365_settings_set_filter_junk_inbox (
+ CAMEL_O365_SETTINGS (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_HOST:
+ camel_network_settings_set_host (
+ CAMEL_NETWORK_SETTINGS (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_PORT:
+ camel_network_settings_set_port (
+ CAMEL_NETWORK_SETTINGS (object),
+ g_value_get_uint (value));
+ return;
+
+ case PROP_SECURITY_METHOD:
+ camel_network_settings_set_security_method (
+ CAMEL_NETWORK_SETTINGS (object),
+ g_value_get_enum (value));
+ return;
+
+ case PROP_TIMEOUT:
+ camel_o365_settings_set_timeout (
+ CAMEL_O365_SETTINGS (object),
+ g_value_get_uint (value));
+ return;
+
+ case PROP_USER:
+ camel_network_settings_set_user (
+ CAMEL_NETWORK_SETTINGS (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_OVERRIDE_OAUTH2:
+ camel_o365_settings_set_override_oauth2 (
+ CAMEL_O365_SETTINGS (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_OAUTH2_TENANT:
+ camel_o365_settings_set_oauth2_tenant (
+ CAMEL_O365_SETTINGS (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_OAUTH2_CLIENT_ID:
+ camel_o365_settings_set_oauth2_client_id (
+ CAMEL_O365_SETTINGS (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_OAUTH2_REDIRECT_URI:
+ camel_o365_settings_set_oauth2_redirect_uri (
+ CAMEL_O365_SETTINGS (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_CONCURRENT_CONNECTIONS:
+ camel_o365_settings_set_concurrent_connections (
+ CAMEL_O365_SETTINGS (object),
+ g_value_get_uint (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+o365_settings_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_AUTH_MECHANISM:
+ g_value_take_string (
+ value,
+ camel_network_settings_dup_auth_mechanism (
+ CAMEL_NETWORK_SETTINGS (object)));
+ return;
+
+ case PROP_CHECK_ALL:
+ g_value_set_boolean (
+ value,
+ camel_o365_settings_get_check_all (
+ CAMEL_O365_SETTINGS (object)));
+ return;
+
+ case PROP_EMAIL:
+ g_value_take_string (
+ value,
+ camel_o365_settings_dup_email (
+ CAMEL_O365_SETTINGS (object)));
+ return;
+
+ case PROP_FILTER_JUNK:
+ g_value_set_boolean (
+ value,
+ camel_o365_settings_get_filter_junk (
+ CAMEL_O365_SETTINGS (object)));
+ return;
+
+ case PROP_FILTER_JUNK_INBOX:
+ g_value_set_boolean (
+ value,
+ camel_o365_settings_get_filter_junk_inbox (
+ CAMEL_O365_SETTINGS (object)));
+ return;
+
+ case PROP_HOST:
+ g_value_take_string (
+ value,
+ camel_network_settings_dup_host (
+ CAMEL_NETWORK_SETTINGS (object)));
+ return;
+
+ case PROP_PORT:
+ g_value_set_uint (
+ value,
+ camel_network_settings_get_port (
+ CAMEL_NETWORK_SETTINGS (object)));
+ return;
+
+ case PROP_SECURITY_METHOD:
+ g_value_set_enum (
+ value,
+ camel_network_settings_get_security_method (
+ CAMEL_NETWORK_SETTINGS (object)));
+ return;
+
+ case PROP_TIMEOUT:
+ g_value_set_uint (
+ value,
+ camel_o365_settings_get_timeout (
+ CAMEL_O365_SETTINGS (object)));
+ return;
+
+ case PROP_USER:
+ g_value_take_string (
+ value,
+ camel_network_settings_dup_user (
+ CAMEL_NETWORK_SETTINGS (object)));
+ return;
+
+ case PROP_OVERRIDE_OAUTH2:
+ g_value_set_boolean (
+ value,
+ camel_o365_settings_get_override_oauth2 (
+ CAMEL_O365_SETTINGS (object)));
+ return;
+
+ case PROP_OAUTH2_TENANT:
+ g_value_take_string (
+ value,
+ camel_o365_settings_dup_oauth2_tenant (
+ CAMEL_O365_SETTINGS (object)));
+ return;
+
+ case PROP_OAUTH2_CLIENT_ID:
+ g_value_take_string (
+ value,
+ camel_o365_settings_dup_oauth2_client_id (
+ CAMEL_O365_SETTINGS (object)));
+ return;
+
+ case PROP_OAUTH2_REDIRECT_URI:
+ g_value_take_string (
+ value,
+ camel_o365_settings_dup_oauth2_redirect_uri (
+ CAMEL_O365_SETTINGS (object)));
+ return;
+
+ case PROP_CONCURRENT_CONNECTIONS:
+ g_value_set_uint (
+ value,
+ camel_o365_settings_get_concurrent_connections (
+ CAMEL_O365_SETTINGS (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+o365_settings_finalize (GObject *object)
+{
+ CamelO365Settings *o365_settings = CAMEL_O365_SETTINGS (object);
+
+ g_mutex_clear (&o365_settings->priv->property_lock);
+
+ g_free (o365_settings->priv->email);
+ g_free (o365_settings->priv->oauth2_tenant);
+ g_free (o365_settings->priv->oauth2_client_id);
+ g_free (o365_settings->priv->oauth2_redirect_uri);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (camel_o365_settings_parent_class)->finalize (object);
+}
+
+static void
+camel_o365_settings_class_init (CamelO365SettingsClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = o365_settings_set_property;
+ object_class->get_property = o365_settings_get_property;
+ object_class->finalize = o365_settings_finalize;
+
+ /* Inherited from CamelNetworkSettings. */
+ g_object_class_override_property (
+ object_class,
+ PROP_AUTH_MECHANISM,
+ "auth-mechanism");
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CHECK_ALL,
+ g_param_spec_boolean (
+ "check-all",
+ "Check All",
+ "Check all folders for new messages",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_EMAIL,
+ g_param_spec_string (
+ "email",
+ "Email",
+ "Email",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILTER_JUNK,
+ g_param_spec_boolean (
+ "filter-junk",
+ "Filter Junk",
+ "Whether to filter junk from all folders",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILTER_JUNK_INBOX,
+ g_param_spec_boolean (
+ "filter-junk-inbox",
+ "Filter Junk Inbox",
+ "Whether to filter junk from Inbox only",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ /* Inherited from CamelNetworkSettings. */
+ g_object_class_override_property (
+ object_class,
+ PROP_HOST,
+ "host");
+
+ /* Inherited from CamelNetworkSettings. */
+ g_object_class_override_property (
+ object_class,
+ PROP_PORT,
+ "port");
+
+ g_object_class_install_property (
+ object_class,
+ PROP_TIMEOUT,
+ g_param_spec_uint (
+ "timeout",
+ "timeout",
+ "Connection timeout in seconds",
+ 0, G_MAXUINT, 120,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ /* Inherited from CamelNetworkSettings. */
+ g_object_class_override_property (
+ object_class,
+ PROP_SECURITY_METHOD,
+ "security-method");
+
+ /* Inherited from CamelNetworkSettings. */
+ g_object_class_override_property (
+ object_class,
+ PROP_USER,
+ "user");
+
+ g_object_class_install_property (
+ object_class,
+ PROP_OVERRIDE_OAUTH2,
+ g_param_spec_boolean (
+ "override-oauth2",
+ "Override OAuth2",
+ "Whether to override OAuth2 values",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_OAUTH2_TENANT,
+ g_param_spec_string (
+ "oauth2-tenant",
+ "OAuth2 Tenant",
+ "OAuth2 Tenant to use, only if override-oauth2 is TRUE, otherwise the compile-time
value is used",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_OAUTH2_CLIENT_ID,
+ g_param_spec_string (
+ "oauth2-client-id",
+ "OAuth2 Client ID",
+ "OAuth2 Client-ID to use, only if override-oauth2 is TRUE, otherwise the compile-time
value is used",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_OAUTH2_REDIRECT_URI,
+ g_param_spec_string (
+ "oauth2-redirect-uri",
+ "OAuth2 Redirect URI",
+ "OAuth2 Redirect URI to use, only if override-oauth2 is TRUE, otherwise the
compile-time value is used",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CONCURRENT_CONNECTIONS,
+ g_param_spec_uint (
+ "concurrent-connections",
+ "Concurrent Connections",
+ "Number of concurrent connections to use",
+ MIN_CONCURRENT_CONNECTIONS,
+ MAX_CONCURRENT_CONNECTIONS,
+ 1,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_EXPLICIT_NOTIFY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+camel_o365_settings_init (CamelO365Settings *settings)
+{
+ settings->priv = camel_o365_settings_get_instance_private (settings);
+
+ g_mutex_init (&settings->priv->property_lock);
+}
+
+/* transfer none. Checks the settings from the ESource extension related to backend. */
+CamelO365Settings *
+camel_o365_settings_get_from_backend (struct _EBackend *backend,
+ struct _ESourceRegistry *registry)
+{
+ ESource *source;
+ ESource *collection;
+ ESourceCamel *extension;
+ CamelSettings *settings;
+ const gchar *extension_name;
+
+ g_return_val_if_fail (E_IS_BACKEND (backend), NULL);
+ if (registry)
+ g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+ source = e_backend_get_source (backend);
+ extension_name = e_source_camel_get_extension_name ("office365");
+ e_source_camel_generate_subtype ("office365", CAMEL_TYPE_O365_SETTINGS);
+
+ if (registry) {
+ /* It's either in the 'source' or in the collection parent. */
+ collection = e_source_registry_find_extension (registry, source, extension_name);
+
+ g_return_val_if_fail (collection != NULL, NULL);
+ } else {
+ collection = g_object_ref (source);
+ }
+
+ extension = e_source_get_extension (collection, extension_name);
+ settings = e_source_camel_get_settings (extension);
+
+ g_object_unref (collection);
+
+ return CAMEL_O365_SETTINGS (settings);
+}
+
+gboolean
+camel_o365_settings_get_check_all (CamelO365Settings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), FALSE);
+
+ return settings->priv->check_all;
+}
+
+void
+camel_o365_settings_set_check_all (CamelO365Settings *settings,
+ gboolean check_all)
+{
+ g_return_if_fail (CAMEL_IS_O365_SETTINGS (settings));
+
+ if ((settings->priv->check_all ? 1 : 0) == (check_all ? 1 : 0))
+ return;
+
+ settings->priv->check_all = check_all;
+
+ g_object_notify (G_OBJECT (settings), "check-all");
+}
+
+const gchar *
+camel_o365_settings_get_email (CamelO365Settings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), NULL);
+
+ return settings->priv->email;
+}
+
+gchar *
+camel_o365_settings_dup_email (CamelO365Settings *settings)
+{
+ const gchar *protected;
+ gchar *duplicate;
+
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), NULL);
+
+ g_mutex_lock (&settings->priv->property_lock);
+
+ protected = camel_o365_settings_get_email (settings);
+ duplicate = g_strdup (protected);
+
+ g_mutex_unlock (&settings->priv->property_lock);
+
+ return duplicate;
+}
+
+void
+camel_o365_settings_set_email (CamelO365Settings *settings,
+ const gchar *email)
+{
+ g_return_if_fail (CAMEL_IS_O365_SETTINGS (settings));
+
+ g_mutex_lock (&settings->priv->property_lock);
+
+ if (g_strcmp0 (settings->priv->email, email) == 0) {
+ g_mutex_unlock (&settings->priv->property_lock);
+ return;
+ }
+
+ g_free (settings->priv->email);
+ settings->priv->email = e_util_strdup_strip (email);
+
+ g_mutex_unlock (&settings->priv->property_lock);
+
+ g_object_notify (G_OBJECT (settings), "email");
+}
+
+gboolean
+camel_o365_settings_get_filter_junk (CamelO365Settings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), FALSE);
+
+ return settings->priv->filter_junk;
+}
+
+void
+camel_o365_settings_set_filter_junk (CamelO365Settings *settings,
+ gboolean filter_junk)
+{
+ g_return_if_fail (CAMEL_IS_O365_SETTINGS (settings));
+
+ if ((settings->priv->filter_junk ? 1 : 0) == (filter_junk ? 1 : 0))
+ return;
+
+ settings->priv->filter_junk = filter_junk;
+
+ g_object_notify (G_OBJECT (settings), "filter-junk");
+}
+
+gboolean
+camel_o365_settings_get_filter_junk_inbox (CamelO365Settings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), FALSE);
+
+ return settings->priv->filter_junk_inbox;
+}
+
+void
+camel_o365_settings_set_filter_junk_inbox (CamelO365Settings *settings,
+ gboolean filter_junk_inbox)
+{
+ g_return_if_fail (CAMEL_IS_O365_SETTINGS (settings));
+
+ if ((settings->priv->filter_junk_inbox ? 1 : 0) == (filter_junk_inbox ? 1 : 0))
+ return;
+
+ settings->priv->filter_junk_inbox = filter_junk_inbox;
+
+ g_object_notify (G_OBJECT (settings), "filter-junk-inbox");
+}
+
+guint
+camel_o365_settings_get_timeout (CamelO365Settings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), 0);
+
+ return settings->priv->timeout;
+}
+
+void
+camel_o365_settings_set_timeout (CamelO365Settings *settings,
+ guint timeout)
+{
+ g_return_if_fail (CAMEL_IS_O365_SETTINGS (settings));
+
+ if (settings->priv->timeout == timeout)
+ return;
+
+ settings->priv->timeout = timeout;
+
+ g_object_notify (G_OBJECT (settings), "timeout");
+}
+
+gboolean
+camel_o365_settings_get_override_oauth2 (CamelO365Settings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), FALSE);
+
+ return settings->priv->override_oauth2;
+}
+
+void
+camel_o365_settings_set_override_oauth2 (CamelO365Settings *settings,
+ gboolean override_oauth2)
+{
+ g_return_if_fail (CAMEL_IS_O365_SETTINGS (settings));
+
+ if ((settings->priv->override_oauth2 ? 1 : 0) == (override_oauth2 ? 1 : 0))
+ return;
+
+ settings->priv->override_oauth2 = override_oauth2;
+
+ g_object_notify (G_OBJECT (settings), "override-oauth2");
+}
+
+const gchar *
+camel_o365_settings_get_oauth2_tenant (CamelO365Settings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), NULL);
+
+ return settings->priv->oauth2_tenant;
+}
+
+gchar *
+camel_o365_settings_dup_oauth2_tenant (CamelO365Settings *settings)
+{
+ const gchar *protected;
+ gchar *duplicate;
+
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), NULL);
+
+ g_mutex_lock (&settings->priv->property_lock);
+
+ protected = camel_o365_settings_get_oauth2_tenant (settings);
+ duplicate = g_strdup (protected);
+
+ g_mutex_unlock (&settings->priv->property_lock);
+
+ return duplicate;
+}
+
+void
+camel_o365_settings_set_oauth2_tenant (CamelO365Settings *settings,
+ const gchar *tenant)
+{
+ g_return_if_fail (CAMEL_IS_O365_SETTINGS (settings));
+
+ g_mutex_lock (&settings->priv->property_lock);
+
+ if (g_strcmp0 (settings->priv->oauth2_tenant, tenant) == 0) {
+ g_mutex_unlock (&settings->priv->property_lock);
+ return;
+ }
+
+ g_free (settings->priv->oauth2_tenant);
+ settings->priv->oauth2_tenant = e_util_strdup_strip (tenant);
+
+ g_mutex_unlock (&settings->priv->property_lock);
+
+ g_object_notify (G_OBJECT (settings), "oauth2-tenant");
+}
+
+const gchar *
+camel_o365_settings_get_oauth2_client_id (CamelO365Settings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), NULL);
+
+ return settings->priv->oauth2_client_id;
+}
+
+gchar *
+camel_o365_settings_dup_oauth2_client_id (CamelO365Settings *settings)
+{
+ const gchar *protected;
+ gchar *duplicate;
+
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), NULL);
+
+ g_mutex_lock (&settings->priv->property_lock);
+
+ protected = camel_o365_settings_get_oauth2_client_id (settings);
+ duplicate = g_strdup (protected);
+
+ g_mutex_unlock (&settings->priv->property_lock);
+
+ return duplicate;
+}
+
+void
+camel_o365_settings_set_oauth2_client_id (CamelO365Settings *settings,
+ const gchar *client_id)
+{
+ g_return_if_fail (CAMEL_IS_O365_SETTINGS (settings));
+
+ g_mutex_lock (&settings->priv->property_lock);
+
+ if (g_strcmp0 (settings->priv->oauth2_client_id, client_id) == 0) {
+ g_mutex_unlock (&settings->priv->property_lock);
+ return;
+ }
+
+ g_free (settings->priv->oauth2_client_id);
+ settings->priv->oauth2_client_id = e_util_strdup_strip (client_id);
+
+ g_mutex_unlock (&settings->priv->property_lock);
+
+ g_object_notify (G_OBJECT (settings), "oauth2-client-id");
+}
+
+const gchar *
+camel_o365_settings_get_oauth2_redirect_uri (CamelO365Settings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), NULL);
+
+ return settings->priv->oauth2_redirect_uri;
+}
+
+gchar *
+camel_o365_settings_dup_oauth2_redirect_uri (CamelO365Settings *settings)
+{
+ const gchar *protected;
+ gchar *duplicate;
+
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), NULL);
+
+ g_mutex_lock (&settings->priv->property_lock);
+
+ protected = camel_o365_settings_get_oauth2_redirect_uri (settings);
+ duplicate = g_strdup (protected);
+
+ g_mutex_unlock (&settings->priv->property_lock);
+
+ return duplicate;
+}
+
+void
+camel_o365_settings_set_oauth2_redirect_uri (CamelO365Settings *settings,
+ const gchar *redirect_uri)
+{
+ g_return_if_fail (CAMEL_IS_O365_SETTINGS (settings));
+
+ g_mutex_lock (&settings->priv->property_lock);
+
+ if (g_strcmp0 (settings->priv->oauth2_redirect_uri, redirect_uri) == 0) {
+ g_mutex_unlock (&settings->priv->property_lock);
+ return;
+ }
+
+ g_free (settings->priv->oauth2_redirect_uri);
+ settings->priv->oauth2_redirect_uri = e_util_strdup_strip (redirect_uri);
+
+ g_mutex_unlock (&settings->priv->property_lock);
+
+ g_object_notify (G_OBJECT (settings), "oauth2-redirect-uri");
+}
+
+guint
+camel_o365_settings_get_concurrent_connections (CamelO365Settings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_O365_SETTINGS (settings), 1);
+
+ return settings->priv->concurrent_connections;
+}
+
+void
+camel_o365_settings_set_concurrent_connections (CamelO365Settings *settings,
+ guint concurrent_connections)
+{
+ g_return_if_fail (CAMEL_IS_O365_SETTINGS (settings));
+
+ concurrent_connections = CLAMP (
+ concurrent_connections,
+ MIN_CONCURRENT_CONNECTIONS,
+ MAX_CONCURRENT_CONNECTIONS);
+
+ if (settings->priv->concurrent_connections == concurrent_connections)
+ return;
+
+ settings->priv->concurrent_connections = concurrent_connections;
+
+ g_object_notify (G_OBJECT (settings), "concurrent-connections");
+}
diff --git a/src/Office365/common/camel-o365-settings.h b/src/Office365/common/camel-o365-settings.h
new file mode 100644
index 00000000..3f05b178
--- /dev/null
+++ b/src/Office365/common/camel-o365-settings.h
@@ -0,0 +1,125 @@
+/* -*- 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 CAMEL_O365_SETTINGS_H
+#define CAMEL_O365_SETTINGS_H
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_O365_SETTINGS \
+ (camel_o365_settings_get_type ())
+#define CAMEL_O365_SETTINGS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), CAMEL_TYPE_O365_SETTINGS, CamelO365Settings))
+#define CAMEL_O365_SETTINGS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), CAMEL_TYPE_O365_SETTINGS, CamelO365SettingsClass))
+#define CAMEL_IS_O365_SETTINGS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), CAMEL_TYPE_O365_SETTINGS))
+#define CAMEL_IS_O365_SETTINGS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), CAMEL_TYPE_O365_SETTINGS))
+#define CAMEL_O365_SETTINGS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), CAMEL_TYPE_O365_SETTINGS))
+
+#define MIN_CONCURRENT_CONNECTIONS 1
+#define MAX_CONCURRENT_CONNECTIONS 7
+
+G_BEGIN_DECLS
+
+/* Forward declaration, to not include libedataserver.h/libebackend.h here */
+struct _EBackend;
+struct _ESourceRegistry;
+
+typedef struct _CamelO365Settings CamelO365Settings;
+typedef struct _CamelO365SettingsClass CamelO365SettingsClass;
+typedef struct _CamelO365SettingsPrivate CamelO365SettingsPrivate;
+
+struct _CamelO365Settings {
+ CamelOfflineSettings parent;
+ CamelO365SettingsPrivate *priv;
+};
+
+struct _CamelO365SettingsClass {
+ CamelOfflineSettingsClass parent_class;
+};
+
+GType camel_o365_settings_get_type (void) G_GNUC_CONST;
+CamelO365Settings *
+ camel_o365_settings_get_from_backend
+ (struct _EBackend *backend,
+ struct _ESourceRegistry *registry);
+gboolean camel_o365_settings_get_check_all
+ (CamelO365Settings *settings);
+void camel_o365_settings_set_check_all
+ (CamelO365Settings *settings,
+ gboolean check_all);
+const gchar * camel_o365_settings_get_email (CamelO365Settings *settings);
+gchar * camel_o365_settings_dup_email (CamelO365Settings *settings);
+void camel_o365_settings_set_email (CamelO365Settings *settings,
+ const gchar *email);
+gboolean camel_o365_settings_get_filter_junk
+ (CamelO365Settings *settings);
+void camel_o365_settings_set_filter_junk
+ (CamelO365Settings *settings,
+ gboolean filter_junk);
+gboolean camel_o365_settings_get_filter_junk_inbox
+ (CamelO365Settings *settings);
+void camel_o365_settings_set_filter_junk_inbox
+ (CamelO365Settings *settings,
+ gboolean filter_junk_inbox);
+guint camel_o365_settings_get_timeout (CamelO365Settings *settings);
+void camel_o365_settings_set_timeout (CamelO365Settings *settings,
+ guint timeout);
+gboolean camel_o365_settings_get_override_oauth2
+ (CamelO365Settings *settings);
+void camel_o365_settings_set_override_oauth2
+ (CamelO365Settings *settings,
+ gboolean override_oauth2);
+const gchar * camel_o365_settings_get_oauth2_tenant
+ (CamelO365Settings *settings);
+gchar * camel_o365_settings_dup_oauth2_tenant
+ (CamelO365Settings *settings);
+void camel_o365_settings_set_oauth2_tenant
+ (CamelO365Settings *settings,
+ const gchar *tenant);
+const gchar * camel_o365_settings_get_oauth2_client_id
+ (CamelO365Settings *settings);
+gchar * camel_o365_settings_dup_oauth2_client_id
+ (CamelO365Settings *settings);
+void camel_o365_settings_set_oauth2_client_id
+ (CamelO365Settings *settings,
+ const gchar *client_id);
+const gchar * camel_o365_settings_get_oauth2_redirect_uri
+ (CamelO365Settings *settings);
+gchar * camel_o365_settings_dup_oauth2_redirect_uri
+ (CamelO365Settings *settings);
+void camel_o365_settings_set_oauth2_redirect_uri
+ (CamelO365Settings *settings,
+ const gchar *redirect_uri);
+guint camel_o365_settings_get_concurrent_connections
+ (CamelO365Settings *settings);
+void camel_o365_settings_set_concurrent_connections
+ (CamelO365Settings *settings,
+ guint concurrent_connections);
+
+G_END_DECLS
+
+#endif /* CAMEL_O365_SETTINGS_H */
diff --git a/src/Office365/common/e-source-o365-folder.c b/src/Office365/common/e-source-o365-folder.c
new file mode 100644
index 00000000..2d1b7a70
--- /dev/null
+++ b/src/Office365/common/e-source-o365-folder.c
@@ -0,0 +1,242 @@
+/* -*- 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-folder.h"
+
+struct _ESourceO365FolderPrivate {
+ gchar *change_key;
+ gchar *id;
+};
+
+enum {
+ PROP_0,
+ PROP_CHANGE_KEY,
+ PROP_ID
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (ESourceO365Folder, e_source_o365_folder, E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_o365_folder_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CHANGE_KEY:
+ e_source_o365_folder_set_change_key (
+ E_SOURCE_O365_FOLDER (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_ID:
+ e_source_o365_folder_set_id (
+ E_SOURCE_O365_FOLDER (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_o365_folder_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CHANGE_KEY:
+ g_value_take_string (
+ value,
+ e_source_o365_folder_dup_change_key (
+ E_SOURCE_O365_FOLDER (object)));
+ return;
+
+ case PROP_ID:
+ g_value_take_string (
+ value,
+ e_source_o365_folder_dup_id (
+ E_SOURCE_O365_FOLDER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+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. */
+ G_OBJECT_CLASS (e_source_o365_folder_parent_class)->finalize (object);
+}
+
+static void
+e_source_o365_folder_class_init (ESourceO365FolderClass *class)
+{
+ GObjectClass *object_class;
+ ESourceExtensionClass *extension_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = source_o365_folder_set_property;
+ object_class->get_property = source_o365_folder_get_property;
+ object_class->finalize = source_o365_folder_finalize;
+
+ extension_class = E_SOURCE_EXTENSION_CLASS (class);
+ extension_class->name = E_SOURCE_EXTENSION_O365_FOLDER;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CHANGE_KEY,
+ g_param_spec_string (
+ "change-key",
+ "Change Key",
+ "Essentially an entity tag, used when submitting changes",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS |
+ E_SOURCE_PARAM_SETTING));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ID,
+ g_param_spec_string (
+ "id",
+ "ID",
+ "The server-assigned folder ID",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS |
+ E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_o365_folder_init (ESourceO365Folder *extension)
+{
+ extension->priv = e_source_o365_folder_get_instance_private (extension);
+}
+
+void
+e_source_o365_folder_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_FOLDER);
+}
+
+const gchar *
+e_source_o365_folder_get_change_key (ESourceO365Folder *extension)
+{
+ g_return_val_if_fail (E_IS_SOURCE_O365_FOLDER (extension), NULL);
+
+ return extension->priv->change_key;
+}
+
+gchar *
+e_source_o365_folder_dup_change_key (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_change_key (extension);
+ duplicate = g_strdup (protected);
+
+ e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+
+ return duplicate;
+}
+
+void
+e_source_o365_folder_set_change_key (ESourceO365Folder *extension,
+ const gchar *change_key)
+{
+ 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) {
+ e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+ return;
+ }
+
+ g_free (extension->priv->change_key);
+ extension->priv->change_key = g_strdup (change_key);
+
+ 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;
+}
+
+gchar *
+e_source_o365_folder_dup_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_id (extension);
+ duplicate = g_strdup (protected);
+
+ e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+
+ return duplicate;
+}
+
+void
+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->id, id) == 0) {
+ e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
+ return;
+ }
+
+ 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), "id");
+}
diff --git a/src/Office365/common/e-source-o365-folder.h b/src/Office365/common/e-source-o365-folder.h
new file mode 100644
index 00000000..775dfbf0
--- /dev/null
+++ b/src/Office365/common/e-source-o365-folder.h
@@ -0,0 +1,76 @@
+/* -*- 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_FOLDER_H
+#define E_SOURCE_O365_FOLDER_H
+
+#include <libedataserver/libedataserver.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_O365_FOLDER \
+ (e_source_o365_folder_get_type ())
+#define E_SOURCE_O365_FOLDER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SOURCE_O365_FOLDER, ESourceO365Folder))
+#define E_SOURCE_O365_FOLDER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SOURCE_O365_FOLDER, ESourceO365FolderClass))
+#define E_IS_SOURCE_O365_FOLDER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SOURCE_O365_FOLDER))
+#define E_IS_SOURCE_O365_FOLDER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SOURCE_O365_FOLDER))
+#define E_SOURCE_O365_FOLDER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SOURCE_O365_FOLDER, ESourceO365FolderClass))
+
+#define E_SOURCE_EXTENSION_O365_FOLDER "Exchange Web Services Folder"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceO365Folder ESourceO365Folder;
+typedef struct _ESourceO365FolderClass ESourceO365FolderClass;
+typedef struct _ESourceO365FolderPrivate ESourceO365FolderPrivate;
+
+struct _ESourceO365Folder {
+ ESourceExtension parent;
+ ESourceO365FolderPrivate *priv;
+};
+
+struct _ESourceO365FolderClass {
+ ESourceExtensionClass parent_class;
+};
+
+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);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_O365_FOLDER_H */
diff --git a/src/Office365/evolution/CMakeLists.txt b/src/Office365/evolution/CMakeLists.txt
new file mode 100644
index 00000000..eb4db02d
--- /dev/null
+++ b/src/Office365/evolution/CMakeLists.txt
@@ -0,0 +1,39 @@
+set(sources
+ e-cal-config-o365.c
+ e-cal-config-o365.h
+ e-book-config-o365.c
+ e-book-config-o365.h
+ e-mail-config-o365-backend.c
+ e-mail-config-o365-backend.h
+ module-o365-configuration.c
+)
+set(extra_deps)
+set(extra_defines)
+set(extra_cflags
+ ${EVOLUTION_MAIL_CFLAGS}
+ ${EVOLUTION_SHELL_CFLAGS}
+ ${LIBECAL_CFLAGS}
+ ${LIBEBOOK_CFLAGS}
+)
+set(extra_incdirs
+ ${EVOLUTION_MAIL_INCLUDE_DIRS}
+ ${EVOLUTION_SHELL_INCLUDE_DIRS}
+ ${LIBECAL_INCLUDE_DIRS}
+ ${LIBEBOOK_INCLUDE_DIRS}
+)
+set(extra_ldflags
+ ${EVOLUTION_MAIL_LDFLAGS}
+ ${EVOLUTION_SHELL_LDFLAGS}
+ ${LIBECAL_LDFLAGS}
+ ${LIBEBOOK_LDFLAGS}
+)
+
+add_simple_module_o365(module-office365-configuration
+ sources
+ extra_deps
+ extra_defines
+ extra_cflags
+ extra_incdirs
+ extra_ldflags
+ "${evo_moduledir}"
+)
diff --git a/src/Office365/evolution/e-book-config-o365.c b/src/Office365/evolution/e-book-config-o365.c
new file mode 100644
index 00000000..b769d29d
--- /dev/null
+++ b/src/Office365/evolution/e-book-config-o365.c
@@ -0,0 +1,77 @@
+/* -*- 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 <glib/gi18n-lib.h>
+
+#include "common/camel-o365-settings.h"
+#include "common/e-source-o365-folder.h"
+
+#include "e-book-config-o365.h"
+
+G_DEFINE_DYNAMIC_TYPE (EBookConfigO365, e_book_config_o365, E_TYPE_SOURCE_CONFIG_BACKEND)
+
+static gboolean
+book_config_o365_allow_creation (ESourceConfigBackend *backend)
+{
+ return TRUE;
+}
+
+static void
+book_config_o365_insert_widgets (ESourceConfigBackend *backend,
+ ESource *scratch_source)
+{
+ if (!scratch_source)
+ return;
+
+ e_source_config_add_refresh_interval (e_source_config_backend_get_config (backend), scratch_source);
+}
+
+static void
+e_book_config_o365_class_init (EBookConfigO365Class *class)
+{
+ EExtensionClass *extension_class;
+ ESourceConfigBackendClass *backend_class;
+
+ extension_class = E_EXTENSION_CLASS (class);
+ extension_class->extensible_type = E_TYPE_BOOK_SOURCE_CONFIG;
+
+ backend_class = E_SOURCE_CONFIG_BACKEND_CLASS (class);
+ backend_class->backend_name = "office365";
+ backend_class->allow_creation = book_config_o365_allow_creation;
+ backend_class->insert_widgets = book_config_o365_insert_widgets;
+}
+
+static void
+e_book_config_o365_class_finalize (EBookConfigO365Class *class)
+{
+}
+
+static void
+e_book_config_o365_init (EBookConfigO365 *backend)
+{
+}
+
+void
+e_book_config_o365_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_book_config_o365_register_type (type_module);
+}
diff --git a/src/Office365/evolution/e-book-config-o365.h b/src/Office365/evolution/e-book-config-o365.h
new file mode 100644
index 00000000..5a9eb765
--- /dev/null
+++ b/src/Office365/evolution/e-book-config-o365.h
@@ -0,0 +1,62 @@
+/* -*- 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_BOOK_CONFIG_O365_H
+#define E_BOOK_CONFIG_O365_H
+
+#include <e-util/e-util.h>
+
+/* Standard GObject macros */
+#define E_TYPE_BOOK_CONFIG_O365 \
+ (e_book_config_o365_get_type ())
+#define E_BOOK_CONFIG_O365(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_BOOK_CONFIG_O365, EBookConfigO365))
+#define E_BOOK_CONFIG_O365_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_BOOK_CONFIG_O365, EBookConfigO365Class))
+#define E_IS_BOOK_CONFIG_O365(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_BOOK_CONFIG_O365))
+#define E_IS_BOOK_CONFIG_O365_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_BOOK_CONFIG_O365))
+#define E_BOOK_CONFIG_O365_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_BOOK_CONFIG_O365, EBookConfigO365Class))
+
+G_BEGIN_DECLS
+
+typedef struct _EBookConfigO365 EBookConfigO365;
+typedef struct _EBookConfigO365Class EBookConfigO365Class;
+typedef struct _EBookConfigO365Private EBookConfigO365Private;
+
+struct _EBookConfigO365 {
+ ESourceConfigBackend parent;
+ EBookConfigO365Private *priv;
+};
+
+struct _EBookConfigO365Class {
+ ESourceConfigBackendClass parent_class;
+};
+
+GType e_book_config_o365_get_type (void) G_GNUC_CONST;
+void e_book_config_o365_type_register(GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_BOOK_CONFIG_O365_H */
diff --git a/src/Office365/evolution/e-cal-config-o365.c b/src/Office365/evolution/e-cal-config-o365.c
new file mode 100644
index 00000000..663da38e
--- /dev/null
+++ b/src/Office365/evolution/e-cal-config-o365.c
@@ -0,0 +1,92 @@
+/* -*- 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-cal-config-o365.h"
+
+G_DEFINE_DYNAMIC_TYPE (ECalConfigO365, e_cal_config_o365, E_TYPE_SOURCE_CONFIG_BACKEND)
+
+static gboolean
+cal_config_o365_allow_creation (ESourceConfigBackend *backend)
+{
+ ESourceConfig *config;
+ ECalSourceConfig *cal_config;
+ ECalClientSourceType source_type;
+ gboolean allow_creation = FALSE;
+
+ config = e_source_config_backend_get_config (backend);
+
+ cal_config = E_CAL_SOURCE_CONFIG (config);
+ source_type = e_cal_source_config_get_source_type (cal_config);
+
+ switch (source_type) {
+ case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+ case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+ allow_creation = TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ return allow_creation;
+}
+
+static void
+cal_config_o365_insert_widgets (ESourceConfigBackend *backend,
+ ESource *scratch_source)
+{
+ if (!scratch_source)
+ return;
+
+ e_source_config_add_refresh_interval (e_source_config_backend_get_config (backend), scratch_source);
+}
+
+static void
+e_cal_config_o365_class_init (ECalConfigO365Class *class)
+{
+ EExtensionClass *extension_class;
+ ESourceConfigBackendClass *backend_class;
+
+ extension_class = E_EXTENSION_CLASS (class);
+ extension_class->extensible_type = E_TYPE_CAL_SOURCE_CONFIG;
+
+ backend_class = E_SOURCE_CONFIG_BACKEND_CLASS (class);
+ backend_class->backend_name = "office365";
+ backend_class->allow_creation = cal_config_o365_allow_creation;
+ backend_class->insert_widgets = cal_config_o365_insert_widgets;
+}
+
+static void
+e_cal_config_o365_class_finalize (ECalConfigO365Class *class)
+{
+}
+
+static void
+e_cal_config_o365_init (ECalConfigO365 *backend)
+{
+}
+
+void
+e_cal_config_o365_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_cal_config_o365_register_type (type_module);
+}
diff --git a/src/Office365/evolution/e-cal-config-o365.h b/src/Office365/evolution/e-cal-config-o365.h
new file mode 100644
index 00000000..a0295c8c
--- /dev/null
+++ b/src/Office365/evolution/e-cal-config-o365.h
@@ -0,0 +1,62 @@
+/* -*- 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_CAL_CONFIG_O365_H
+#define E_CAL_CONFIG_O365_H
+
+#include <e-util/e-util.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_CONFIG_O365 \
+ (e_cal_config_o365_get_type ())
+#define E_CAL_CONFIG_O365(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_CONFIG_O365, ECalConfigO365))
+#define E_CAL_CONFIG_O365_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_CONFIG_O365, ECalConfigO365Class))
+#define E_IS_CAL_CONFIG_O365(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_CONFIG_O365))
+#define E_IS_CAL_CONFIG_O365_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_CONFIG_O365))
+#define E_CAL_CONFIG_O365_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_CONFIG_O365, ECalConfigO365Class))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalConfigO365 ECalConfigO365;
+typedef struct _ECalConfigO365Class ECalConfigO365Class;
+typedef struct _ECalConfigO365Private ECalConfigO365Private;
+
+struct _ECalConfigO365 {
+ ESourceConfigBackend parent;
+ ECalConfigO365Private *priv;
+};
+
+struct _ECalConfigO365Class {
+ ESourceConfigBackendClass parent_class;
+};
+
+GType e_cal_config_o365_get_type (void) G_GNUC_CONST;
+void e_cal_config_o365_type_register (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_CAL_CONFIG_O365_H */
diff --git a/src/Office365/evolution/e-mail-config-o365-backend.c
b/src/Office365/evolution/e-mail-config-o365-backend.c
new file mode 100644
index 00000000..d7bcc1a6
--- /dev/null
+++ b/src/Office365/evolution/e-mail-config-o365-backend.c
@@ -0,0 +1,461 @@
+/* -*- 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 <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+#include <libebackend/libebackend.h>
+
+#include <mail/e-mail-config-auth-check.h>
+#include <mail/e-mail-config-receiving-page.h>
+
+#include "common/camel-o365-settings.h"
+
+#include "e-mail-config-o365-backend.h"
+
+struct _EMailConfigO365BackendPrivate {
+ GtkWidget *user_entry;
+ GtkGrid *oauth2_settings_grid;
+ GtkWidget *oauth2_override_check;
+ GtkWidget *oauth2_tenant_entry;
+ GtkWidget *oauth2_client_id_entry;
+ GtkWidget *oauth2_redirect_uri_entry;
+};
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (EMailConfigO365Backend, e_mail_config_o365_backend,
E_TYPE_MAIL_CONFIG_SERVICE_BACKEND, 0,
+ G_ADD_PRIVATE_DYNAMIC (EMailConfigO365Backend))
+
+static ESource *
+mail_config_o365_backend_new_collection (EMailConfigServiceBackend *backend)
+{
+ EMailConfigServiceBackendClass *class;
+ ESourceBackend *extension;
+ ESource *source;
+ const gchar *extension_name;
+
+ /* This backend serves double duty. One instance holds the
+ * mail account source, another holds the mail transport source.
+ * We can differentiate by examining the EMailConfigServicePage
+ * the backend is associated with. We return a new collection
+ * for both the Receiving Page and Sending Page. Although the
+ * Sending Page instance ultimately gets discarded, it's still
+ * needed to avoid creating an [Office365 Backend] extension
+ * in the mail transport source. */
+
+ class = E_MAIL_CONFIG_SERVICE_BACKEND_GET_CLASS (backend);
+
+ source = e_source_new (NULL, NULL, NULL);
+ extension_name = E_SOURCE_EXTENSION_COLLECTION;
+ extension = e_source_get_extension (source, extension_name);
+ e_source_backend_set_backend_name (extension, class->backend_name);
+
+ return source;
+}
+
+static void
+mail_config_o365_backend_set_oauth2_tooltip (GtkWidget *widget,
+ const gchar *value,
+ const gchar *when_value_empty,
+ gchar *when_value_filled) /* takes ownership */
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ gtk_widget_set_tooltip_text (widget, value && *value ? when_value_filled : when_value_empty);
+
+ g_free (when_value_filled);
+}
+
+static void
+mail_config_o365_backend_insert_widgets (EMailConfigServiceBackend *backend,
+ GtkBox *parent)
+{
+ EMailConfigO365Backend *o365_backend;
+ EMailConfigServicePage *page;
+ ESource *source;
+ ESourceExtension *extension;
+ CamelSettings *settings;
+ GtkLabel *label;
+ GtkWidget *widget;
+ GtkWidget *container;
+ const gchar *extension_name;
+ const gchar *text;
+ gchar *markup;
+
+ o365_backend = E_MAIL_CONFIG_O365_BACKEND (backend);
+ page = e_mail_config_service_backend_get_page (backend);
+
+ /* This backend serves double duty. One instance holds the
+ * mail account source, another holds the mail transport source.
+ * We can differentiate by examining the EMailConfigServicePage
+ * the backend is associated with. This method only applies to
+ * the Receiving Page. */
+ if (!E_IS_MAIL_CONFIG_RECEIVING_PAGE (page))
+ return;
+
+ /* This needs to come _after_ the page type check so we don't
+ * introduce a backend extension in the mail transport source. */
+ settings = e_mail_config_service_backend_get_settings (backend);
+
+ text = _("Configuration");
+ markup = g_markup_printf_escaped ("<b>%s</b>", text);
+ widget = gtk_label_new (markup);
+ gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (parent), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+ g_free (markup);
+
+ widget = gtk_grid_new ();
+ gtk_widget_set_margin_left (widget, 12);
+ gtk_grid_set_row_spacing (GTK_GRID (widget), 6);
+ gtk_grid_set_column_spacing (GTK_GRID (widget), 6);
+ gtk_box_pack_start (GTK_BOX (parent), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_label_new_with_mnemonic (_("User_name:"));
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 1, 1);
+ gtk_widget_show (widget);
+
+ label = GTK_LABEL (widget);
+
+ widget = gtk_entry_new ();
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_label_set_mnemonic_widget (label, widget);
+ gtk_grid_attach (GTK_GRID (container), widget, 1, 0, 2, 1);
+ o365_backend->priv->user_entry = widget; /* do not reference */
+ gtk_widget_show (widget);
+
+ text = _("Authentication");
+ markup = g_markup_printf_escaped ("<b>%s</b>", text);
+ widget = gtk_label_new (markup);
+ gtk_widget_set_margin_top (widget, 6);
+ gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (parent), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+ g_free (markup);
+
+ widget = gtk_grid_new ();
+ gtk_widget_set_margin_left (widget, 12);
+ gtk_box_pack_start (GTK_BOX (parent), widget, FALSE, FALSE, 0);
+ o365_backend->priv->oauth2_settings_grid = GTK_GRID (widget);
+
+ gtk_grid_set_column_spacing (o365_backend->priv->oauth2_settings_grid, 4);
+ gtk_grid_set_row_spacing (o365_backend->priv->oauth2_settings_grid, 4);
+
+ container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_grid_attach (o365_backend->priv->oauth2_settings_grid, container, 0, 0, 2, 1);
+
+ widget = gtk_check_button_new_with_mnemonic (_("_Override Office365 OAuth2 settings"));
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ o365_backend->priv->oauth2_override_check = widget;
+
+ markup = g_markup_printf_escaped ("(<a
href=\"https://wiki.gnome.org/Apps/Evolution/EWS/OAuth2\">%s</a>)", _("Help…"));
+ widget = gtk_label_new (markup);
+ gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ g_free (markup);
+
+ /* Translators: 'Tenant' here means a term used by Microsoft to identify a company or organization in
an Office 365 world.
+ You probably do not want to translate it. More for example here:
https://powerbi.microsoft.com/en-us/blog/what-is-a-tenant/ */
+ widget = gtk_label_new_with_mnemonic (_("_Tenant:"));
+ gtk_widget_set_margin_left (widget, 12);
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_grid_attach (o365_backend->priv->oauth2_settings_grid, widget, 0, 1, 1, 1);
+ label = GTK_LABEL (widget);
+
+ e_binding_bind_property (
+ o365_backend->priv->oauth2_override_check, "active",
+ widget, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ widget = gtk_entry_new ();
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_label_set_mnemonic_widget (label, widget);
+ gtk_grid_attach (o365_backend->priv->oauth2_settings_grid, widget, 1, 1, 1, 1);
+ o365_backend->priv->oauth2_tenant_entry = widget;
+
+ e_binding_bind_property (
+ o365_backend->priv->oauth2_override_check, "active",
+ widget, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ mail_config_o365_backend_set_oauth2_tooltip (widget, OFFICE365_TENANT,
+ /* Translators: 'Tenant' here means a term used by Microsoft to identify a company or
organization in an Office 365 world. Same for 'common', it's a default URL path.
+ You probably do not want to translate it. More for example here:
https://powerbi.microsoft.com/en-us/blog/what-is-a-tenant/ */
+ _("Default tenant is “common“"),
+ /* Translators: 'Tenant' here means a term used by Microsoft to identify a company or
organization in an Office 365 world.
+ You probably do not want to translate it. More for example here:
https://powerbi.microsoft.com/en-us/blog/what-is-a-tenant/ */
+ g_strdup_printf (_("Default tenant is “%s”"), OFFICE365_TENANT));
+
+ widget = gtk_label_new_with_mnemonic (_("Application I_D:"));
+ gtk_widget_set_margin_left (widget, 12);
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_grid_attach (o365_backend->priv->oauth2_settings_grid, widget, 0, 2, 1, 1);
+ label = GTK_LABEL (widget);
+
+ e_binding_bind_property (
+ o365_backend->priv->oauth2_override_check, "active",
+ widget, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ widget = gtk_entry_new ();
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_label_set_mnemonic_widget (label, widget);
+ gtk_grid_attach (o365_backend->priv->oauth2_settings_grid, widget, 1, 2, 1, 1);
+ o365_backend->priv->oauth2_client_id_entry = widget;
+
+ e_binding_bind_property (
+ o365_backend->priv->oauth2_override_check, "active",
+ widget, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ mail_config_o365_backend_set_oauth2_tooltip (widget, OFFICE365_CLIENT_ID,
+ _("There is not set any default application ID"),
+ g_strdup_printf (_("Default application ID is “%s”"), OFFICE365_CLIENT_ID));
+
+ widget = gtk_label_new_with_mnemonic (_("_Redirect URI:"));
+ gtk_widget_set_margin_left (widget, 12);
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_grid_attach (o365_backend->priv->oauth2_settings_grid, widget, 0, 3, 1, 1);
+ label = GTK_LABEL (widget);
+
+ e_binding_bind_property (
+ o365_backend->priv->oauth2_override_check, "active",
+ widget, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ widget = gtk_entry_new ();
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_label_set_mnemonic_widget (label, widget);
+ gtk_grid_attach (o365_backend->priv->oauth2_settings_grid, widget, 1, 3, 1, 1);
+ o365_backend->priv->oauth2_redirect_uri_entry = widget;
+
+ e_binding_bind_property (
+ o365_backend->priv->oauth2_override_check, "active",
+ widget, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ markup = g_strdup_printf (_("Default redirect URI is “%s”"),
"https://login.microsoftonline.com/common/oauth2/nativeclient");
+ mail_config_o365_backend_set_oauth2_tooltip (widget, OFFICE365_REDIRECT_URI,
+ markup,
+ g_strdup_printf (_("Default redirect URI is “%s”"), OFFICE365_REDIRECT_URI));
+ g_free (markup);
+
+ gtk_widget_show_all (GTK_WIDGET (o365_backend->priv->oauth2_settings_grid));
+
+ e_binding_bind_object_text_property (
+ settings, "user",
+ o365_backend->priv->user_entry, "text",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ e_binding_bind_property (
+ settings, "override-oauth2",
+ o365_backend->priv->oauth2_override_check, "active",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ e_binding_bind_object_text_property (
+ settings, "oauth2-tenant",
+ o365_backend->priv->oauth2_tenant_entry, "text",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ e_binding_bind_object_text_property (
+ settings, "oauth2-client-id",
+ o365_backend->priv->oauth2_client_id_entry, "text",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ e_binding_bind_object_text_property (
+ settings, "oauth2-redirect_uri",
+ o365_backend->priv->oauth2_redirect_uri_entry, "text",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ extension_name = E_SOURCE_EXTENSION_COLLECTION;
+ source = e_mail_config_service_backend_get_collection (backend);
+ extension = e_source_get_extension (source, extension_name);
+
+ /* The collection identity is the user name. */
+ e_binding_bind_property (
+ settings, "user",
+ extension, "identity",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+}
+
+static void
+mail_config_o365_backend_setup_defaults (EMailConfigServiceBackend *backend)
+{
+ CamelSettings *settings;
+ EMailConfigServicePage *page;
+ const gchar *email_address;
+
+ page = e_mail_config_service_backend_get_page (backend);
+
+ /* This backend serves double duty. One instance holds the
+ * mail account source, another holds the mail transport source.
+ * We can differentiate by examining the EMailConfigServicePage
+ * the backend is associated with. This method only applies to
+ * the Receiving Page. */
+ if (!E_IS_MAIL_CONFIG_RECEIVING_PAGE (page))
+ return;
+
+ /* This needs to come _after_ the page type check so we don't
+ * introduce a backend extension in the mail transport source. */
+ email_address = e_mail_config_service_page_get_email_address (page);
+ settings = e_mail_config_service_backend_get_settings (backend);
+
+ camel_o365_settings_set_email (CAMEL_O365_SETTINGS (settings), email_address);
+ camel_network_settings_set_user (CAMEL_NETWORK_SETTINGS (settings), email_address);
+}
+
+static gboolean
+mail_config_o365_backend_auto_configure (EMailConfigServiceBackend *backend,
+ EConfigLookup *config_lookup,
+ gint *out_priority,
+ gboolean *out_is_complete)
+{
+ return e_mail_config_service_backend_auto_configure_for_kind (backend, config_lookup,
+ E_CONFIG_LOOKUP_RESULT_COLLECTION, NULL,
+ e_mail_config_service_backend_get_collection (backend),
+ out_priority, out_is_complete);
+}
+
+static gboolean
+mail_config_o365_backend_check_complete (EMailConfigServiceBackend *backend)
+{
+ EMailConfigServicePage *page;
+ EMailConfigO365Backend *o365_backend;
+ CamelSettings *settings;
+ CamelNetworkSettings *network_settings;
+ const gchar *user;
+ gboolean correct, complete = TRUE;
+
+ o365_backend = E_MAIL_CONFIG_O365_BACKEND (backend);
+ page = e_mail_config_service_backend_get_page (backend);
+
+ /* This backend serves double duty. One instance holds the
+ * mail account source, another holds the mail transport source.
+ * We can differentiate by examining the EMailConfigServicePage
+ * the backend is associated with. This method only applies to
+ * the Receiving Page. */
+ if (!E_IS_MAIL_CONFIG_RECEIVING_PAGE (page))
+ return TRUE;
+
+ /* This needs to come _after_ the page type check so we don't
+ * introduce a backend extension in the mail transport source. */
+ settings = e_mail_config_service_backend_get_settings (backend);
+
+ network_settings = CAMEL_NETWORK_SETTINGS (settings);
+ user = camel_network_settings_get_user (network_settings);
+
+ correct = user != NULL && *user != '\0';
+ complete = complete && correct;
+
+ e_util_set_entry_issue_hint (o365_backend->priv->user_entry, correct ? NULL : _("User name cannot be
empty"));
+
+ if (correct) {
+ CamelO365Settings *o365_settings = CAMEL_O365_SETTINGS (settings);
+ const gchar *client_id;
+
+ if (camel_o365_settings_get_override_oauth2 (o365_settings)) {
+ client_id = camel_o365_settings_get_oauth2_client_id (o365_settings);
+ } else {
+ client_id = OFFICE365_CLIENT_ID;
+ }
+
+ correct = client_id && *client_id;
+ complete = complete && correct;
+
+ e_util_set_entry_issue_hint (o365_backend->priv->oauth2_client_id_entry, correct ? NULL :
_("Application ID cannot be empty"));
+ }
+
+ return complete;
+}
+
+static void
+mail_config_o365_backend_commit_changes (EMailConfigServiceBackend *backend)
+{
+ CamelSettings *settings;
+ CamelO365Settings *o365_settings;
+ EMailConfigServicePage *page;
+ const gchar *email_address;
+
+ page = e_mail_config_service_backend_get_page (backend);
+
+ /* This backend serves double duty. One instance holds the
+ * mail account source, another holds the mail transport source.
+ * We can differentiate by examining the EMailConfigServicePage
+ * the backend is associated with. This method only applies to
+ * the Receiving Page. */
+ if (!E_IS_MAIL_CONFIG_RECEIVING_PAGE (page))
+ return;
+
+ /* This needs to come _after_ the page type check so we don't
+ * introduce a backend extension in the mail transport source. */
+ settings = e_mail_config_service_backend_get_settings (backend);
+
+ email_address = e_mail_config_service_page_get_email_address (page);
+ if (email_address != NULL) {
+ o365_settings = CAMEL_O365_SETTINGS (settings);
+ camel_o365_settings_set_email (o365_settings, email_address);
+ }
+}
+
+static void
+e_mail_config_o365_backend_class_init (EMailConfigO365BackendClass *class)
+{
+ EMailConfigServiceBackendClass *backend_class;
+
+ backend_class = E_MAIL_CONFIG_SERVICE_BACKEND_CLASS (class);
+ backend_class->backend_name = "office365";
+ backend_class->new_collection = mail_config_o365_backend_new_collection;
+ backend_class->insert_widgets = mail_config_o365_backend_insert_widgets;
+ backend_class->setup_defaults = mail_config_o365_backend_setup_defaults;
+ backend_class->auto_configure = mail_config_o365_backend_auto_configure;
+ backend_class->check_complete = mail_config_o365_backend_check_complete;
+ backend_class->commit_changes = mail_config_o365_backend_commit_changes;
+}
+
+static void
+e_mail_config_o365_backend_class_finalize (EMailConfigO365BackendClass *class)
+{
+}
+
+static void
+e_mail_config_o365_backend_init (EMailConfigO365Backend *backend)
+{
+ backend->priv = e_mail_config_o365_backend_get_instance_private (backend);
+}
+
+void
+e_mail_config_o365_backend_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_mail_config_o365_backend_register_type (type_module);
+}
diff --git a/src/Office365/evolution/e-mail-config-o365-backend.h
b/src/Office365/evolution/e-mail-config-o365-backend.h
new file mode 100644
index 00000000..52b4d1f4
--- /dev/null
+++ b/src/Office365/evolution/e-mail-config-o365-backend.h
@@ -0,0 +1,64 @@
+/* -*- 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_MAIL_CONFIG_O365_BACKEND_H
+#define E_MAIL_CONFIG_O365_BACKEND_H
+
+#include <mail/e-mail-config-service-backend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_CONFIG_O365_BACKEND \
+ (e_mail_config_o365_backend_get_type ())
+#define E_MAIL_CONFIG_O365_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_CONFIG_O365_BACKEND, EMailConfigO365Backend))
+#define E_MAIL_CONFIG_O365_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_CONFIG_O365_BACKEND, EMailConfigO365BackendClass))
+#define E_IS_MAIL_CONFIG_O365_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_CONFIG_O365_BACKEND))
+#define E_IS_MAIL_CONFIG_O365_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_CONFIG_O365_BACKEND))
+#define E_MAIL_CONFIG_O365_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_CONFIG_O365_BACKEND, EMailConfigO365BackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailConfigO365Backend EMailConfigO365Backend;
+typedef struct _EMailConfigO365BackendClass EMailConfigO365BackendClass;
+typedef struct _EMailConfigO365BackendPrivate EMailConfigO365BackendPrivate;
+
+struct _EMailConfigO365Backend {
+ EMailConfigServiceBackend parent;
+ EMailConfigO365BackendPrivate *priv;
+};
+
+struct _EMailConfigO365BackendClass {
+ EMailConfigServiceBackendClass parent_class;
+};
+
+GType e_mail_config_o365_backend_get_type
+ (void) G_GNUC_CONST;
+void e_mail_config_o365_backend_type_register
+ (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_MAIL_CONFIG_O365_BACKEND_H */
diff --git a/src/Office365/evolution/module-o365-configuration.c
b/src/Office365/evolution/module-o365-configuration.c
new file mode 100644
index 00000000..37dff72c
--- /dev/null
+++ b/src/Office365/evolution/module-o365-configuration.c
@@ -0,0 +1,48 @@
+/* -*- 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 <glib/gi18n-lib.h>
+
+#include "e-cal-config-o365.h"
+#include "e-book-config-o365.h"
+#include "e-mail-config-o365-backend.h"
+
+#include "common/e-source-o365-folder.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ bindtextdomain (GETTEXT_PACKAGE, O365_LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ e_source_o365_folder_type_register (type_module);
+
+ e_cal_config_o365_type_register (type_module);
+ e_book_config_o365_type_register (type_module);
+ e_mail_config_o365_backend_type_register (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
diff --git a/src/Office365/registry/CMakeLists.txt b/src/Office365/registry/CMakeLists.txt
new file mode 100644
index 00000000..dd8b7be3
--- /dev/null
+++ b/src/Office365/registry/CMakeLists.txt
@@ -0,0 +1,22 @@
+set(extra_deps)
+set(sources
+ module-o365-backend.c
+ e-o365-backend.c
+ e-o365-backend.h
+ e-o365-backend-factory.c
+ e-o365-backend-factory.h
+)
+set(extra_defines)
+set(extra_cflags)
+set(extra_incdirs)
+set(extra_ldflags)
+
+add_simple_module_o365(module-office365-backend
+ sources
+ extra_deps
+ extra_defines
+ extra_cflags
+ extra_incdirs
+ extra_ldflags
+ "${eds_moduledir}"
+)
diff --git a/src/Office365/registry/e-o365-backend-factory.c b/src/Office365/registry/e-o365-backend-factory.c
new file mode 100644
index 00000000..a50d9f61
--- /dev/null
+++ b/src/Office365/registry/e-o365-backend-factory.c
@@ -0,0 +1,89 @@
+/* -*- 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-o365-backend.h"
+
+#include "e-o365-backend-factory.h"
+
+G_DEFINE_DYNAMIC_TYPE (EO365BackendFactory, e_o365_backend_factory, E_TYPE_COLLECTION_BACKEND_FACTORY)
+
+static void
+o365_backend_prepare_mail_account_source (ESource *source)
+{
+ ESourceBackend *extension;
+ const gchar *extension_name;
+
+ extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
+ extension = e_source_get_extension (source, extension_name);
+ e_source_backend_set_backend_name (extension, "office365");
+}
+
+static void
+o365_backend_prepare_mail_transport_source (ESource *source)
+{
+ ESourceBackend *extension;
+ const gchar *extension_name;
+
+ extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
+ extension = e_source_get_extension (source, extension_name);
+ e_source_backend_set_backend_name (extension, "office365");
+}
+
+static void
+o365_backend_factory_prepare_mail (ECollectionBackendFactory *factory,
+ ESource *mail_account_source,
+ ESource *mail_identity_source,
+ ESource *mail_transport_source)
+{
+ /* Chain up to parent's method. */
+ E_COLLECTION_BACKEND_FACTORY_CLASS (e_o365_backend_factory_parent_class)->prepare_mail (factory,
mail_account_source, mail_identity_source, mail_transport_source);
+
+ o365_backend_prepare_mail_account_source (mail_account_source);
+ o365_backend_prepare_mail_transport_source (mail_transport_source);
+}
+
+static void
+e_o365_backend_factory_class_init (EO365BackendFactoryClass *class)
+{
+ ECollectionBackendFactoryClass *factory_class;
+
+ factory_class = E_COLLECTION_BACKEND_FACTORY_CLASS (class);
+ factory_class->factory_name = "office365";
+ factory_class->backend_type = E_TYPE_O365_BACKEND;
+ factory_class->prepare_mail = o365_backend_factory_prepare_mail;
+}
+
+static void
+e_o365_backend_factory_class_finalize (EO365BackendFactoryClass *class)
+{
+}
+
+static void
+e_o365_backend_factory_init (EO365BackendFactory *factory)
+{
+}
+
+void
+e_o365_backend_factory_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_o365_backend_factory_register_type (type_module);
+}
diff --git a/src/Office365/registry/e-o365-backend-factory.h b/src/Office365/registry/e-o365-backend-factory.h
new file mode 100644
index 00000000..85080d32
--- /dev/null
+++ b/src/Office365/registry/e-o365-backend-factory.h
@@ -0,0 +1,63 @@
+/* -*- 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_O365_BACKEND_FACTORY_H
+#define E_O365_BACKEND_FACTORY_H
+
+#include <libebackend/libebackend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_O365_BACKEND_FACTORY \
+ (e_o365_backend_factory_get_type ())
+#define E_O365_BACKEND_FACTORY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_O365_BACKEND_FACTORY, EO365BackendFactory))
+#define E_O365_BACKEND_FACTORY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_O365_BACKEND_FACTORY, EO365BackendFactoryClass))
+#define E_IS_O365_BACKEND_FACTORY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_O365_BACKEND_FACTORY))
+#define E_IS_O365_BACKEND_FACTORY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_O365_BACKEND_FACTORY))
+#define E_O365_BACKEND_FACTORY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_O365_BACKEND_FACTORY, EO365BackendFactoryClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EO365BackendFactory EO365BackendFactory;
+typedef struct _EO365BackendFactoryClass EO365BackendFactoryClass;
+typedef struct _EO365BackendFactoryPrivate EO365BackendFactoryPrivate;
+
+struct _EO365BackendFactory {
+ ECollectionBackendFactory parent;
+ EO365BackendFactoryPrivate *priv;
+};
+
+struct _EO365BackendFactoryClass {
+ ECollectionBackendFactoryClass parent_class;
+};
+
+GType e_o365_backend_factory_get_type (void) G_GNUC_CONST;
+void e_o365_backend_factory_type_register
+ (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_O365_BACKEND_FACTORY_H */
diff --git a/src/Office365/registry/e-o365-backend.c b/src/Office365/registry/e-o365-backend.c
new file mode 100644
index 00000000..08fc6af8
--- /dev/null
+++ b/src/Office365/registry/e-o365-backend.c
@@ -0,0 +1,533 @@
+/* -*- 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 <glib/gi18n-lib.h>
+
+#include "common/e-source-o365-folder.h"
+#include "common/camel-o365-settings.h"
+
+#include "e-o365-backend.h"
+
+struct _EO365BackendPrivate {
+ GMutex property_lock;
+
+ gboolean need_update_folders;
+
+ gulong source_changed_id;
+};
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (EO365Backend, e_o365_backend, E_TYPE_COLLECTION_BACKEND, 0,
+ G_ADD_PRIVATE_DYNAMIC (EO365Backend))
+
+static void o365_backend_populate (ECollectionBackend *backend);
+
+#if 0
+static void
+o365_backend_source_changed_cb (ESource *source,
+ EO365Backend *backend)
+{
+ if (!e_source_get_enabled (source)) {
+ backend->priv->need_update_folders = TRUE;
+ return;
+ }
+
+ if (!backend->priv->need_update_folders)
+ return;
+
+ o365_backend_populate (E_COLLECTION_BACKEND (backend));
+}
+#endif
+
+static void
+o365_backend_populate (ECollectionBackend *backend)
+{
+#if 0
+ ESource *source;
+ EO365Backend *o365_backend = E_O365_BACKEND (backend);
+
+ source = e_backend_get_source (E_BACKEND (backend));
+
+ o365_backend->priv->need_update_folders = TRUE;
+
+ if (!o365_backend->priv->source_changed_id) {
+ o365_backend->priv->source_changed_id = g_signal_connect (source, "changed",
+ G_CALLBACK (o365_backend_source_changed_cb), o365_backend);
+ }
+
+ /* do not do anything, if account is disabled */
+ if (!e_source_get_enabled (source))
+ return;
+
+ o365_backend_add_gal_source (o365_backend);
+ o365_backend_claim_old_resources (backend);
+
+ if (e_backend_get_online (E_BACKEND (backend))) {
+ CamelO365Settings *o365_settings;
+
+ o365_settings = camel_o365_settings_get_from_backend (o365_backend, NULL);
+
+ if (e_o365_connection_utils_get_without_password (o365_settings)) {
+ e_backend_schedule_authenticate (E_BACKEND (backend), NULL);
+ } else {
+ e_backend_credentials_required_sync (E_BACKEND (backend),
+ E_SOURCE_CREDENTIALS_REASON_REQUIRED, NULL, 0, NULL,
+ NULL, NULL);
+ }
+ }
+#endif
+}
+
+static gchar *
+o365_backend_dup_resource_id (ECollectionBackend *backend,
+ ESource *child_source)
+{
+ ESourceO365Folder *extension;
+ const gchar *extension_name;
+
+ extension_name = E_SOURCE_EXTENSION_O365_FOLDER;
+ extension = e_source_get_extension (child_source, extension_name);
+
+ return e_source_o365_folder_dup_id (extension);
+}
+
+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)) {
+ 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);
+
+ e_binding_bind_property (
+ collection_extension, "identity",
+ auth_child_extension, "user",
+ G_BINDING_SYNC_CREATE);
+ }
+
+ /* 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)) {
+ ESourceO365Folder *extension;
+ gchar *folder_id;
+
+ extension = e_source_get_extension (
+ child_source, extension_name);
+ 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);
+ }
+ }
+#endif
+ /* Chain up to parent's method. */
+ E_COLLECTION_BACKEND_CLASS (e_o365_backend_parent_class)->child_added (backend, child_source);
+}
+
+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)) {
+ ESourceO365Folder *extension;
+ const gchar *folder_id;
+
+ extension = e_source_get_extension (
+ child_source, extension_name);
+ folder_id = e_source_o365_folder_get_id (extension);
+ if (folder_id != NULL)
+ o365_backend_folders_remove (
+ E_O365_BACKEND (backend), folder_id);
+ }
+#endif
+
+ /* Chain up to parent's method. */
+ E_COLLECTION_BACKEND_CLASS (e_o365_backend_parent_class)->child_removed (backend, child_source);
+}
+
+static gboolean
+o365_backend_create_resource_sync (ECollectionBackend *backend,
+ ESource *source,
+ GCancellable *cancellable,
+ GError **error)
+{
+#if 0
+ EO365Connection *connection = NULL;
+ O365FolderId *out_folder_id = NULL;
+ EO365FolderType folder_type = E_O365_FOLDER_TYPE_UNKNOWN;
+ const gchar *extension_name;
+ const gchar *parent_folder_id = NULL;
+ gchar *folder_name;
+ gboolean success = FALSE;
+
+ extension_name = E_SOURCE_EXTENSION_O365_FOLDER;
+ if (e_source_has_extension (source, extension_name)) {
+ ESourceO365Folder *extension;
+
+ /* foreign and public folders are just added */
+ extension = e_source_get_extension (source, extension_name);
+ if (e_source_o365_folder_get_foreign (extension) ||
+ e_source_o365_folder_get_public (extension))
+ success = TRUE;
+ }
+
+ if (!success) {
+ connection = e_o365_backend_ref_connection_sync (E_O365_BACKEND (backend), NULL, NULL, NULL,
cancellable, error);
+ if (connection == NULL)
+ return FALSE;
+
+ extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+ if (e_source_has_extension (source, extension_name)) {
+ folder_type = E_O365_FOLDER_TYPE_CONTACTS;
+ parent_folder_id = "contacts";
+ }
+
+ extension_name = E_SOURCE_EXTENSION_CALENDAR;
+ if (e_source_has_extension (source, extension_name)) {
+ folder_type = E_O365_FOLDER_TYPE_CALENDAR;
+ parent_folder_id = "calendar";
+ }
+
+ extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+ if (e_source_has_extension (source, extension_name)) {
+ folder_type = E_O365_FOLDER_TYPE_TASKS;
+ parent_folder_id = "tasks";
+ }
+
+ /* FIXME No support for memo lists. */
+
+ if (parent_folder_id == NULL) {
+ g_set_error (
+ error, G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Could not determine a suitable folder "
+ "class for a new folder named “%s”"),
+ e_source_get_display_name (source));
+ goto exit;
+ }
+
+ folder_name = e_source_dup_display_name (source);
+
+ success = e_o365_connection_create_folder_sync (
+ connection, O365_PRIORITY_MEDIUM,
+ parent_folder_id, TRUE,
+ folder_name, folder_type,
+ &out_folder_id, cancellable, error);
+
+ g_free (folder_name);
+
+ /* Sanity check */
+ g_warn_if_fail (
+ (success && out_folder_id != NULL) ||
+ (!success && out_folder_id == NULL));
+
+ if (out_folder_id != NULL) {
+ ESourceO365Folder *extension;
+ const gchar *extension_name;
+
+ extension_name = E_SOURCE_EXTENSION_O365_FOLDER;
+ extension = e_source_get_extension (source, extension_name);
+ e_source_o365_folder_set_id (
+ extension, out_folder_id->id);
+ e_source_o365_folder_set_change_key (
+ extension, out_folder_id->change_key);
+
+ e_o365_folder_id_free (out_folder_id);
+ }
+ }
+
+ if (success) {
+ ESourceRegistryServer *server;
+ ESource *parent_source;
+ const gchar *cache_dir;
+ const gchar *parent_uid;
+
+ /* Configure the source as a collection member. */
+ parent_source = e_backend_get_source (E_BACKEND (backend));
+ parent_uid = e_source_get_uid (parent_source);
+ e_source_set_parent (source, parent_uid);
+
+ /* Changes should be written back to the cache directory. */
+ cache_dir = e_collection_backend_get_cache_dir (backend);
+ e_server_side_source_set_write_directory (
+ E_SERVER_SIDE_SOURCE (source), cache_dir);
+
+ /* Set permissions for clients. */
+ e_server_side_source_set_writable (E_SERVER_SIDE_SOURCE (source), TRUE);
+ e_server_side_source_set_remote_deletable (E_SERVER_SIDE_SOURCE (source), TRUE);
+
+ server = e_collection_backend_ref_server (backend);
+ e_source_registry_server_add_source (server, source);
+ g_object_unref (server);
+ }
+
+ exit:
+ if (connection)
+ g_object_unref (connection);
+
+ return success;
+#endif
+ return FALSE;
+}
+
+static gboolean
+o365_backend_delete_resource_sync (ECollectionBackend *backend,
+ ESource *source,
+ GCancellable *cancellable,
+ GError **error)
+{
+#if 0
+ EO365Connection *connection;
+ ESourceO365Folder *extension;
+ const gchar *extension_name;
+ gboolean success = FALSE;
+
+ connection = e_o365_backend_ref_connection_sync (E_O365_BACKEND (backend), NULL, NULL, NULL,
cancellable, error);
+ if (connection == NULL)
+ return FALSE;
+
+ extension_name = E_SOURCE_EXTENSION_O365_FOLDER;
+ if (!e_source_has_extension (source, extension_name)) {
+ g_set_error (
+ error, G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Data source “%s” does not represent an Office365 folder"),
+ e_source_get_display_name (source));
+ goto exit;
+ }
+ extension = e_source_get_extension (source, extension_name);
+
+ if (e_source_o365_folder_get_foreign (extension) ||
+ e_source_o365_folder_get_public (extension)) {
+ /* do not delete foreign or public folders,
+ * just remove them from local store */
+ success = TRUE;
+ } else {
+ gchar *folder_id;
+
+ folder_id = e_source_o365_folder_dup_id (extension);
+
+ success = e_o365_connection_delete_folder_sync (
+ connection, O365_PRIORITY_MEDIUM, folder_id,
+ FALSE, "HardDelete", cancellable, error);
+
+ g_free (folder_id);
+ }
+
+ if (success)
+ success = e_source_remove_sync (source, cancellable, error);
+
+ exit:
+ g_object_unref (connection);
+
+ return success;
+#endif
+ return FALSE;
+}
+
+static gboolean
+o365_backend_get_destination_address (EBackend *backend,
+ gchar **host,
+ guint16 *port)
+{
+ g_return_val_if_fail (port != NULL, FALSE);
+ g_return_val_if_fail (host != NULL, FALSE);
+
+ *host = g_strdup ("graph.microsoft.com");
+ *port = 443;
+
+ return TRUE;
+}
+
+static ESourceAuthenticationResult
+o365_backend_authenticate_sync (EBackend *backend,
+ const ENamedParameters *credentials,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors,
+ GCancellable *cancellable,
+ GError **error)
+{
+ /*EO365Backend *o365_backend;
+ EO365Connection *connection;*/
+ CamelO365Settings *o365_settings;
+ ESourceAuthenticationResult result = E_SOURCE_AUTHENTICATION_ERROR;
+
+ g_return_val_if_fail (E_IS_O365_BACKEND (backend), E_SOURCE_AUTHENTICATION_ERROR);
+
+ o365_settings = camel_o365_settings_get_from_backend (backend, NULL);
+ g_return_val_if_fail (o365_settings != NULL, E_SOURCE_AUTHENTICATION_ERROR);
+
+ /*o365_backend = E_O365_BACKEND (backend);
+ g_mutex_lock (&o365_backend->priv->connection_lock);
+ g_clear_object (&o365_backend->priv->connection);
+ e_named_parameters_free (o365_backend->priv->credentials);
+ o365_backend->priv->credentials = e_named_parameters_new_clone (credentials);
+ g_mutex_unlock (&o365_backend->priv->connection_lock);
+
+ connection = e_o365_backend_ref_connection_sync (o365_backend, &result, out_certificate_pem,
out_certificate_errors, cancellable, error);
+ g_clear_object (&connection);
+
+ 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);
+ } else if (e_o365_connection_utils_get_without_password (o365_settings) &&
+ result == E_SOURCE_AUTHENTICATION_REJECTED &&
+ !e_named_parameters_exists (credentials, E_SOURCE_CREDENTIAL_PASSWORD)) {
+ e_o365_connection_utils_force_off_ntlm_auth_check ();
+ result = E_SOURCE_AUTHENTICATION_REQUIRED;
+ }*/
+
+ return result;
+}
+
+static void
+o365_backend_constructed (GObject *object)
+{
+ EBackend *backend;
+ ESource *source;
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_o365_backend_parent_class)->constructed (object);
+
+ backend = E_BACKEND (object);
+ source = e_backend_get_source (backend);
+
+ e_server_side_source_set_remote_creatable (E_SERVER_SIDE_SOURCE (source), TRUE);
+
+ /* Reset the connectable, it steals data from Authentication extension,
+ where is written incorrect address */
+ e_backend_set_connectable (backend, NULL);
+
+ if (e_source_has_extension (source, E_SOURCE_EXTENSION_COLLECTION)) {
+ ESourceCollection *collection_extension;
+
+ collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION);
+ e_source_collection_set_allow_sources_rename (collection_extension, TRUE);
+ }
+}
+
+static void
+o365_backend_dispose (GObject *object)
+{
+ EO365Backend *o365_backend = E_O365_BACKEND (object);
+ ESource *source;
+
+ source = e_backend_get_source (E_BACKEND (object));
+ if (source && o365_backend->priv->source_changed_id) {
+ g_signal_handler_disconnect (source, o365_backend->priv->source_changed_id);
+ o365_backend->priv->source_changed_id = 0;
+ }
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_o365_backend_parent_class)->dispose (object);
+}
+
+static void
+o365_backend_finalize (GObject *object)
+{
+ EO365Backend *o365_backend = E_O365_BACKEND (object);
+
+ g_mutex_clear (&o365_backend->priv->property_lock);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_o365_backend_parent_class)->finalize (object);
+}
+
+static void
+e_o365_backend_class_init (EO365BackendClass *class)
+{
+ GObjectClass *object_class;
+ EBackendClass *backend_class;
+ ECollectionBackendClass *collection_backend_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = o365_backend_dispose;
+ object_class->finalize = o365_backend_finalize;
+ object_class->constructed = o365_backend_constructed;
+
+ collection_backend_class = E_COLLECTION_BACKEND_CLASS (class);
+ collection_backend_class->populate = o365_backend_populate;
+ collection_backend_class->dup_resource_id = o365_backend_dup_resource_id;
+ collection_backend_class->child_added = o365_backend_child_added;
+ collection_backend_class->child_removed = o365_backend_child_removed;
+ collection_backend_class->create_resource_sync = o365_backend_create_resource_sync;
+ collection_backend_class->delete_resource_sync = o365_backend_delete_resource_sync;
+
+ backend_class = E_BACKEND_CLASS (class);
+ backend_class->get_destination_address = o365_backend_get_destination_address;
+ backend_class->authenticate_sync = o365_backend_authenticate_sync;
+
+ /* This generates an ESourceCamel subtype for CamelO365Settings. */
+ e_source_camel_generate_subtype ("office365", CAMEL_TYPE_O365_SETTINGS);
+}
+
+static void
+e_o365_backend_class_finalize (EO365BackendClass *class)
+{
+}
+
+static void
+e_o365_backend_init (EO365Backend *backend)
+{
+ backend->priv = e_o365_backend_get_instance_private (backend);
+
+ g_mutex_init (&backend->priv->property_lock);
+}
+
+void
+e_o365_backend_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_o365_backend_register_type (type_module);
+}
diff --git a/src/Office365/registry/e-o365-backend.h b/src/Office365/registry/e-o365-backend.h
new file mode 100644
index 00000000..dba02943
--- /dev/null
+++ b/src/Office365/registry/e-o365-backend.h
@@ -0,0 +1,62 @@
+/* -*- 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_O365_BACKEND_H
+#define E_O365_BACKEND_H
+
+#include <libebackend/libebackend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_O365_BACKEND \
+ (e_o365_backend_get_type ())
+#define E_O365_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_O365_BACKEND, EO365Backend))
+#define E_O365_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_O365_BACKEND, EO365BackendClass))
+#define E_IS_O365_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_O365_BACKEND))
+#define E_IS_O365_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_O365_BACKEND))
+#define E_O365_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_O365_BACKEND, EO365BackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EO365Backend EO365Backend;
+typedef struct _EO365BackendClass EO365BackendClass;
+typedef struct _EO365BackendPrivate EO365BackendPrivate;
+
+struct _EO365Backend {
+ ECollectionBackend parent;
+ EO365BackendPrivate *priv;
+};
+
+struct _EO365BackendClass {
+ ECollectionBackendClass parent_class;
+};
+
+GType e_o365_backend_get_type (void) G_GNUC_CONST;
+void e_o365_backend_type_register (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_O365_BACKEND_H */
diff --git a/src/Office365/registry/module-o365-backend.c b/src/Office365/registry/module-o365-backend.c
new file mode 100644
index 00000000..5f79c6c6
--- /dev/null
+++ b/src/Office365/registry/module-o365-backend.c
@@ -0,0 +1,45 @@
+/* -*- 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 <glib/gi18n-lib.h>
+
+#include "common/e-source-o365-folder.h"
+
+#include "e-o365-backend.h"
+#include "e-o365-backend-factory.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ bindtextdomain (GETTEXT_PACKAGE, O365_LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ e_o365_backend_type_register (type_module);
+ e_o365_backend_factory_type_register (type_module);
+ e_source_o365_folder_type_register (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]