[evolution-ews/account-mgmt] Adapt to the new ESource API.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews/account-mgmt] Adapt to the new ESource API.
- Date: Wed, 30 May 2012 10:52:32 +0000 (UTC)
commit 162336f6b11c04bfe438f613df1300ee0310b6e1
Author: Matthew Barnes <mbarnes redhat com>
Date: Fri May 4 18:22:13 2012 -0400
Adapt to the new ESource API.
configure.ac | 16 +-
src/Makefile.am | 4 +-
.../exchange-ews-account-listener.c | 2 +
.../exchange-ews-account-listener.h | 2 -
.../exchange-ews-account-setup.c | 348 --------
src/addressbook/e-book-backend-ews-factory.c | 5 +
src/addressbook/e-book-backend-ews.c | 402 ++++++----
src/addressbook/ews-oab-decoder.h | 2 -
src/calendar/e-cal-backend-ews-factory.c | 5 +
src/calendar/e-cal-backend-ews-utils.c | 1 -
src/calendar/e-cal-backend-ews.c | 613 ++++++++------
src/camel/camel-ews-folder.c | 2 +-
src/camel/camel-ews-store.c | 6 +-
src/camel/camel-ews-transport.c | 3 +-
src/camel/camel-ews-utils.c | 119 +---
src/modules/Makefile.am | 76 ++
src/modules/e-mail-config-ews-autodiscover.c | 345 +++++++
src/modules/e-mail-config-ews-autodiscover.h | 71 ++
src/modules/e-mail-config-ews-backend.c | 352 ++++++++
src/modules/e-mail-config-ews-backend.h | 66 ++
src/modules/e-mail-config-ews-gal.c | 389 ++++++++
src/modules/e-mail-config-ews-gal.h | 65 ++
src/modules/e-mail-config-ews-oal-combo-box.c | 365 ++++++++
src/modules/e-mail-config-ews-oal-combo-box.h | 82 ++
src/modules/e-mail-config-ews-ooo-page.c | 937 ++++++++++++++++++++
src/modules/e-mail-config-ews-ooo-page.h | 80 ++
src/modules/module-ews-backend.c | 822 +++++++++++++++++
src/modules/module-ews-mail-config.c | 43 +
src/modules/module-ews-mail-config.error.xml | 14 +
src/server/Makefile.am | 4 +
src/{utils => server}/camel-ews-settings.c | 80 ++-
src/{utils => server}/camel-ews-settings.h | 4 +
src/server/e-ews-connection.c | 894 ++++++++++++--------
src/server/e-ews-connection.h | 59 +-
src/server/e-source-ews-folder.c | 254 ++++++
src/server/e-source-ews-folder.h | 78 ++
src/utils/Makefile.am | 4 -
src/utils/ews-esource-utils.c | 306 -------
src/utils/ews-esource-utils.h | 65 --
39 files changed, 5355 insertions(+), 1630 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 80f4fc3..5832644 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,7 +74,6 @@ AS_COMPILER_FLAGS(WARNING_FLAGS,
-Wno-unused-parameter
-Wno-deprecated-declarations
-Wdeclaration-after-statement
- -Wno-unused-but-set-variable
-Werror-implicit-function-declaration
-Wformat-nonliteral -Wformat-security -Winit-self
-Wmissing-declarations -Wmissing-include-dirs
@@ -157,6 +156,11 @@ dnl ****************************
PKG_CHECK_MODULES(EVOLUTION_SHELL, evolution-shell-3.0 >= evo_minimum_version)
dnl ****************************
+dnl Check for evolution mail
+dnl ****************************
+PKG_CHECK_MODULES(EVOLUTION_MAIL, evolution-mail-3.0 >= evo_minimum_version)
+
+dnl ****************************
dnl Check for sqlite3
dnl ****************************
PKG_CHECK_MODULES(SQLITE3, sqlite3)
@@ -192,6 +196,9 @@ AC_SUBST_FILE(EVO_PLUGIN_RULE)
dnl *******************
dnl Special directories
dnl *******************
+errordir=`$PKG_CONFIG --variable=errordir evolution-plugin-3.0`
+AC_SUBST(errordir)
+
plugindir=`$PKG_CONFIG --variable=plugindir evolution-plugin-3.0`
AC_SUBST(plugindir)
@@ -213,6 +220,11 @@ AC_SUBST(ecal_backenddir)
ebook_backenddir=`$PKG_CONFIG --variable=backenddir libedata-book-1.2`
AC_SUBST(ebook_backenddir)
+eds_moduledir=`$PKG_CONFIG --variable=moduledir libebackend-1.2`
+AC_SUBST(eds_moduledir)
+
+evo_moduledir=`$PKG_CONFIG --variable=moduledir evolution-shell-3.0`
+AC_SUBST(evo_moduledir)
dnl *************
dnl Gtk Doc stuff
@@ -229,11 +241,11 @@ src/server/Makefile
src/server/tests/Makefile
src/server/libeews.pc
src/utils/Makefile
-src/account-setup-eplugin/Makefile
src/addressbook/Makefile
src/addressbook/lzx/Makefile
src/calendar/Makefile
src/camel/Makefile
+src/modules/Makefile
po/Makefile.in
])
AC_OUTPUT
diff --git a/src/Makefile.am b/src/Makefile.am
index 5e406f0..d761b74 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = server server/tests utils camel account-setup-eplugin calendar addressbook
-DIST_SUBDIRS = server utils camel account-setup-eplugin calendar addressbook
+SUBDIRS = server server/tests utils camel calendar addressbook modules
+DIST_SUBDIRS = server utils camel calendar addressbook modules
-include $(top_srcdir)/git.mk
diff --git a/src/account-setup-eplugin/exchange-ews-account-listener.c b/src/account-setup-eplugin/exchange-ews-account-listener.c
index 10e1516..0022ae9 100644
--- a/src/account-setup-eplugin/exchange-ews-account-listener.c
+++ b/src/account-setup-eplugin/exchange-ews-account-listener.c
@@ -28,8 +28,10 @@
#include <mail/e-mail-backend.h>
#include <camel/camel.h>
+#if 0 /* ACCOUNT_MGMT */
#include <libedataserver/e-account.h>
#include <libedataserver/e-account-list.h>
+#endif /* ACCOUNT_MGMT */
#include <libebook/e-book.h>
#include "camel/camel-ews-store-summary.h"
diff --git a/src/account-setup-eplugin/exchange-ews-account-listener.h b/src/account-setup-eplugin/exchange-ews-account-listener.h
index 399b5af..f7ccfee 100644
--- a/src/account-setup-eplugin/exchange-ews-account-listener.h
+++ b/src/account-setup-eplugin/exchange-ews-account-listener.h
@@ -44,8 +44,6 @@ struct _ExchangeEWSAccountListenerClass {
GObjectClass parent_class;
};
-void exchange_ews_add_esource (CamelURL *url, const gchar *folder_name, const gchar *fid, gint folder_type);
-void exchange_ews_remove_esource (CamelURL *url, const gchar *folder_name, const gchar *fid, gint folder_type);
GType exchange_ews_account_listener_get_type (void);
ExchangeEWSAccountListener * exchange_ews_account_listener_new (void);
diff --git a/src/account-setup-eplugin/exchange-ews-account-setup.c b/src/account-setup-eplugin/exchange-ews-account-setup.c
index eadc36f..ba5e6ac 100644
--- a/src/account-setup-eplugin/exchange-ews-account-setup.c
+++ b/src/account-setup-eplugin/exchange-ews-account-setup.c
@@ -30,7 +30,6 @@
#include <libedataserver/e-xml-hash-utils.h>
#include <libedataserverui/e-passwords.h>
-#include <libedataserver/e-account.h>
#include <libedataserver/eds-version.h>
#include <e-util/e-dialog-utils.h>
@@ -103,36 +102,6 @@ exchange_ews_accounts_peek_config_listener ()
return config_listener;
}
-struct _AutoDiscCallBackData {
- EConfig *config;
- GtkWidget *host_entry;
- GtkWidget *oab_entry;
-};
-
-static void autodiscover_callback (EwsUrls *urls, gpointer user_data, GError *error)
-{
- struct _AutoDiscCallBackData *cbdata = (struct _AutoDiscCallBackData *) user_data;
-
- if (error) {
- g_warning ("Autodiscover failed: %s", error->message);
- e_notice (NULL, GTK_MESSAGE_ERROR, _("Autodiscover failed: %s"), error->message);
- g_clear_error (&error);
- }
- if (urls) {
- gchar *oab_url;
-
- gtk_entry_set_text (GTK_ENTRY (cbdata->host_entry), urls->as_url);
-
- oab_url = g_strconcat (urls->oab_url, "oab.xml", NULL);
- gtk_entry_set_text (GTK_ENTRY (cbdata->oab_entry), oab_url);
- g_free (oab_url);
-
- g_free (urls->as_url);
- g_free (urls->oab_url);
- g_free (urls);
- }
-}
-
static gchar *
get_password (EMConfigTargetSettings *target_account)
{
@@ -175,171 +144,6 @@ get_password (EMConfigTargetSettings *target_account)
return password;
}
-static void
-validate_credentials (GtkWidget *widget,
- struct _AutoDiscCallBackData *cbdata)
-{
- EConfig *config = cbdata->config;
- EMConfigTargetSettings *target_account = (EMConfigTargetSettings *)(config->target);
- gchar *password = NULL;
- CamelEwsSettings *ews_settings;
-
- ews_settings = CAMEL_EWS_SETTINGS (target_account->storage_settings);
-
- password = get_password (target_account);
- /*Can there be a account without password ?*/
- if (password && *password) {
- e_ews_autodiscover_ws_url (
- autodiscover_callback, cbdata,
- target_account->email_address,
- password,
- camel_ews_settings_get_hosturl (ews_settings),
- camel_network_settings_get_user (CAMEL_NETWORK_SETTINGS (ews_settings)));
- }
- g_free (password);
-}
-
-static void
-oab_url_changed (GtkWidget *entry,
- EConfig *config)
-{
- EMConfigTargetSettings *target = (EMConfigTargetSettings *)(config->target);
- CamelEwsSettings *ews_settings;
- const gchar *oaburl;
-
- ews_settings = CAMEL_EWS_SETTINGS (target->storage_settings);
- oaburl = gtk_entry_get_text (GTK_ENTRY (entry));
- camel_ews_settings_set_oaburl (ews_settings, oaburl);
-}
-
-static void
-host_url_changed (GtkWidget *entry,
- EConfig *config)
-{
- EMConfigTargetSettings *target = (EMConfigTargetSettings *)(config->target);
- CamelEwsSettings *ews_settings;
- const gchar *hosturl;
-
- ews_settings = CAMEL_EWS_SETTINGS (target->storage_settings);
- hosturl = gtk_entry_get_text (GTK_ENTRY (entry));
- camel_ews_settings_set_hosturl (ews_settings, hosturl);
-}
-
-GtkWidget *
-org_gnome_exchange_ews_account_setup (EPlugin *epl,
- EConfigHookItemFactoryData *data)
-{
- EMConfigTargetSettings *target_account;
- EShell *shell;
- CamelSettings *settings;
- CamelEwsSettings *ews_settings;
- CamelNetworkSettings *network_settings;
- GtkWidget *hbox = NULL;
- gint row;
- GtkWidget *label, *oab_label;
- GtkWidget *host_url, *oab_url;
- GtkWidget *auto_discover;
- const gchar *host;
- const gchar *host_url_val;
- const gchar *oab_url_val;
- const gchar *temp, *email_id;
- struct _AutoDiscCallBackData *cbdata;
-
- target_account = (EMConfigTargetSettings *) data->config->target;
- settings = target_account->storage_settings;
-
- if (!CAMEL_IS_EWS_SETTINGS (settings))
- return NULL;
-
- /* Verify the storage and transport settings are shared. */
- g_warn_if_fail (
- target_account->storage_settings ==
- target_account->transport_settings);
-
- ews_settings = CAMEL_EWS_SETTINGS (settings);
- network_settings = CAMEL_NETWORK_SETTINGS (settings);
-
- host = camel_network_settings_get_host (network_settings);
-
- host_url_val = camel_ews_settings_get_hosturl (ews_settings);
- oab_url_val = camel_ews_settings_get_oaburl (ews_settings);
- cbdata = g_new0 (struct _AutoDiscCallBackData, 1);
- /* FIXME free cbdata */
-
- g_object_get (data->parent, "n-rows", &row, NULL);
-
- /* Set email_id */
- email_id = target_account->email_address;
- camel_ews_settings_set_email (ews_settings, email_id);
- temp = g_strstr_len (email_id, -1, "@");
-
- /* Don't overwrite the host if it's already been set */
- if (temp != NULL && (host == NULL || *host == '\0')) {
- camel_network_settings_set_host (network_settings, temp + 1);
- host = camel_network_settings_get_host (network_settings);
- }
-
- if (temp != NULL && (host_url_val == NULL || *host_url_val == '\0')) {
- gchar *temp_host_url;
-
- temp_host_url = g_strdup_printf (
- "https://exchange.%s/EWS/Exchange.asmx", temp + 1);
- camel_ews_settings_set_hosturl (ews_settings, temp_host_url);
- host_url_val = camel_ews_settings_get_hosturl (ews_settings);
- g_free (temp_host_url);
- }
-
- /* OAB url entry */
- oab_label = gtk_label_new_with_mnemonic (_("OAB U_RL:"));
- gtk_widget_show (oab_label);
-
- oab_url = gtk_entry_new ();
- gtk_label_set_mnemonic_widget (GTK_LABEL (oab_label), oab_url);
- if (oab_url_val && *oab_url_val)
- gtk_entry_set_text (GTK_ENTRY (oab_url), oab_url_val);
- g_signal_connect (oab_url, "changed", G_CALLBACK (oab_url_changed), data->config);
- gtk_widget_show (oab_url);
-
- /* Host url and Autodiscover button */
- hbox = gtk_hbox_new (FALSE, 6);
- label = gtk_label_new_with_mnemonic (_("_Host URL:"));
- gtk_widget_show (label);
-
- host_url = gtk_entry_new ();
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), host_url);
- if (host_url_val && *host_url_val)
- gtk_entry_set_text (GTK_ENTRY (host_url), host_url_val);
- else
- gtk_entry_set_text (GTK_ENTRY (host_url), "https://exchange.server.com/EWS/Exchange.asmx");
- g_signal_connect (host_url, "changed", G_CALLBACK (host_url_changed), data->config);
- gtk_box_pack_start (GTK_BOX (hbox), host_url, TRUE, TRUE, 0);
-
- cbdata->config = data->config;
- cbdata->host_entry = host_url;
- cbdata->oab_entry = oab_url;
- auto_discover = gtk_button_new_with_mnemonic (_("Fetch _URL"));
- gtk_box_pack_start (GTK_BOX (hbox), auto_discover, FALSE, FALSE, 0);
- g_signal_connect (G_OBJECT(auto_discover), "clicked", G_CALLBACK(validate_credentials), cbdata);
-
- /* Add Host entry */
- gtk_table_attach (GTK_TABLE (data->parent), label, 0, 1, row, row + 1, 0, 0, 0, 0);
- gtk_widget_show_all (GTK_WIDGET (hbox));
- gtk_table_attach (GTK_TABLE (data->parent), GTK_WIDGET (hbox), 1, 2, row, row + 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
- row++;
-
- /* Add OAB entry */
- gtk_table_attach (GTK_TABLE (data->parent), oab_label, 0, 1, row, row + 1, 0, 0, 0, 0);
- gtk_table_attach (GTK_TABLE (data->parent), oab_url, 1, 2, row, row + 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
- row++;
-
- /* If evolution is offline, dsensitize fetch button and oab entry */
- shell = e_shell_get_default ();
- if (!e_shell_get_online (shell))
- gtk_widget_set_sensitive (auto_discover, FALSE);
-
- return hbox;
-}
-
gboolean
org_gnome_exchange_ews_check_options (EPlugin *epl,
EConfigHookPageCheckData *data)
@@ -397,69 +201,6 @@ struct _oab_setting_data {
};
static void
-clear_combo (GtkComboBoxText *combo_box)
-{
- GtkListStore *store;
-
- g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (combo_box));
-
- store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)));
- gtk_list_store_clear (store);
-}
-
-static void
-update_camel_url (struct _oab_setting_data *cbdata)
-{
- EMConfigTargetSettings *target = (EMConfigTargetSettings *) cbdata->config->target;
- CamelEwsSettings *ews_settings;
-
- ews_settings = CAMEL_EWS_SETTINGS (target->storage_settings);
-
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cbdata->check))) {
- gint num;
-
- gtk_widget_set_sensitive (cbdata->hbox, TRUE);
- camel_ews_settings_set_oab_offline (ews_settings, TRUE);
- num = gtk_combo_box_get_active (GTK_COMBO_BOX (cbdata->combo_text));
-
- /* Set the active oal */
- if (cbdata->oals && num != -1) {
- gchar *mangled_oal;
- EwsOAL *oal = g_slist_nth_data (cbdata->oals, num);
-
- mangled_oal = g_strconcat (oal->id, ":", oal->name, NULL);
- camel_ews_settings_set_oal_selected (ews_settings, mangled_oal);
- g_free (mangled_oal);
- }
- } else {
- gtk_widget_set_sensitive (cbdata->hbox, FALSE);
- camel_ews_settings_set_oab_offline (ews_settings, FALSE);
- camel_ews_settings_set_oal_selected (ews_settings, NULL);
-
- if (cbdata->oals == NULL)
- clear_combo (GTK_COMBO_BOX_TEXT (cbdata->combo_text));
- }
-}
-
-static void
-cache_setting_toggled (GtkToggleButton *check,
- gpointer user_data)
-{
- struct _oab_setting_data *cbdata = (struct _oab_setting_data *) user_data;
-
- update_camel_url (cbdata);
-}
-
-static void
-combo_selection_changed (GtkComboBox *combo,
- gpointer user_data)
-{
- struct _oab_setting_data *cbdata = (struct _oab_setting_data *) user_data;
-
- update_camel_url (cbdata);
-}
-
-static void
ews_oal_list_ready (GObject *obj,
GAsyncResult *res,
gpointer user_data)
@@ -490,9 +231,7 @@ ews_oal_list_ready (GObject *obj,
}
cbdata->oals = oals;
- g_signal_handlers_block_by_func (cbdata->combo_text, combo_selection_changed, cbdata);
clear_combo (GTK_COMBO_BOX_TEXT (cbdata->combo_text));
- g_signal_handlers_unblock_by_func (cbdata->combo_text, combo_selection_changed, cbdata);
for (l = oals; l != NULL; l = g_slist_next (l)) {
EwsOAL *oal = l->data;
@@ -525,15 +264,12 @@ fetch_button_clicked_cb (GtkButton *button,
network_settings = CAMEL_NETWORK_SETTINGS (target->storage_settings);
/* De-sensitize fetch_button and get the list from the server */
- g_signal_handlers_block_by_func (cbdata->combo_text, combo_selection_changed, cbdata);
clear_combo (GTK_COMBO_BOX_TEXT (cbdata->combo_text));
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cbdata->combo_text), _("Fetching..."));
gtk_combo_box_set_active (GTK_COMBO_BOX (cbdata->combo_text), 0);
gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
- g_signal_handlers_unblock_by_func (cbdata->combo_text, combo_selection_changed, cbdata);
-
/* Fetch the oab lists from server */
oab_url = camel_ews_settings_get_oaburl (ews_settings);
user = camel_network_settings_get_user (network_settings);
@@ -548,18 +284,6 @@ fetch_button_clicked_cb (GtkButton *button,
g_free (password);
}
-static void
-ews_oal_free (gpointer data,
- gpointer user_data)
-{
- EwsOAL *oal = (EwsOAL *) data;
-
- g_free (oal->id);
- g_free (oal->dn);
- g_free (oal->name);
- g_free (oal);
-}
-
static gboolean
table_deleted_cb (GtkWidget *widget,
gpointer user_data)
@@ -578,76 +302,6 @@ table_deleted_cb (GtkWidget *widget,
return FALSE;
}
-static void
-init_widgets (struct _oab_setting_data *cbdata)
-{
- EMConfigTargetSettings *target_account;
- CamelEwsSettings *ews_settings;
- const gchar *selected_list;
- const gchar *oab_url;
-
- target_account = (EMConfigTargetSettings *) cbdata->config->target;
-
- ews_settings = CAMEL_EWS_SETTINGS (target_account->storage_settings);
- selected_list = camel_ews_settings_get_oal_selected (ews_settings);
- oab_url = camel_ews_settings_get_oaburl (ews_settings);
-
- if (camel_ews_settings_get_oab_offline (ews_settings)) {
- g_signal_handlers_block_by_func (cbdata->check, cache_setting_toggled, cbdata);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cbdata->check), TRUE);
- g_signal_handlers_unblock_by_func (cbdata->check, cache_setting_toggled, cbdata);
-
- /* selected list will be of form "id:name" */
- if (selected_list && gtk_combo_box_get_active (GTK_COMBO_BOX (cbdata->combo_text)) == -1) {
- const gchar *tmp;
-
- tmp = strrchr (selected_list, ':');
- gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cbdata->combo_text), tmp + 1);
-
- g_signal_handlers_block_by_func (cbdata->combo_text, combo_selection_changed, cbdata);
- gtk_combo_box_set_active (GTK_COMBO_BOX (cbdata->combo_text), 0);
- g_signal_handlers_unblock_by_func (cbdata->combo_text, combo_selection_changed, cbdata);
- }
- } else
- gtk_widget_set_sensitive (cbdata->hbox, FALSE);
-
- /* If oab url is not set, dsensitize*/
- if (!oab_url) {
- gtk_widget_set_sensitive (cbdata->check, FALSE);
- gtk_widget_set_sensitive (cbdata->hbox, FALSE);
- } else
- gtk_widget_set_sensitive (cbdata->check, TRUE);
-}
-
-static void
-ews_prepare_receive_options_page (GtkWidget *page,
- gpointer user_data)
-{
- struct _oab_setting_data *cbdata = (struct _oab_setting_data *) user_data;
- GtkWidget *receive_options;
-
- receive_options = e_config_page_get (cbdata->config, "20.receive_options");
- if (receive_options == page)
- init_widgets (cbdata);
-}
-
-static void
-ews_assistant_page_changed_cb (GtkAssistant *assistant,
- GtkWidget *page,
- gpointer user_data)
-{
- ews_prepare_receive_options_page (page, user_data);
-}
-
-static void
-ews_page_switched_cb (GtkNotebook *notebook,
- GtkWidget *page,
- guint page_num,
- gpointer user_data)
-{
- ews_prepare_receive_options_page (page, user_data);
-}
-
GtkWidget *
org_gnome_ews_oab_settings (EPlugin *epl,
EConfigHookItemFactoryData *data)
@@ -706,9 +360,7 @@ org_gnome_ews_oab_settings (EPlugin *epl,
cbdata->config = data->config;
/* Connect the signals */
- g_signal_connect (check, "toggled", G_CALLBACK (cache_setting_toggled), cbdata);
g_signal_connect (G_OBJECT (fetch_button), "clicked", G_CALLBACK (fetch_button_clicked_cb), cbdata);
- g_signal_connect (GTK_COMBO_BOX (oal_combo), "changed", G_CALLBACK (combo_selection_changed), cbdata);
/* Init widgets when the page is changed to receiving options page */
if (GTK_IS_ASSISTANT (data->config->widget))
diff --git a/src/addressbook/e-book-backend-ews-factory.c b/src/addressbook/e-book-backend-ews-factory.c
index 8f736fb..c928d4c 100644
--- a/src/addressbook/e-book-backend-ews-factory.c
+++ b/src/addressbook/e-book-backend-ews-factory.c
@@ -26,6 +26,9 @@
#endif
#include <libedata-book/e-book-backend-factory.h>
+
+#include "server/e-source-ews-folder.h"
+
#include "e-book-backend-ews.h"
typedef EBookBackendFactory EBookBackendEwsFactory;
@@ -63,6 +66,8 @@ e_book_backend_ews_factory_init (EBookBackendFactory *factory)
G_MODULE_EXPORT void
e_module_load (GTypeModule *type_module)
{
+ e_source_ews_folder_type_register (type_module);
+
e_book_backend_ews_factory_register_type (type_module);
}
diff --git a/src/addressbook/e-book-backend-ews.c b/src/addressbook/e-book-backend-ews.c
index 7773f1d..40605d8 100644
--- a/src/addressbook/e-book-backend-ews.c
+++ b/src/addressbook/e-book-backend-ews.c
@@ -35,34 +35,39 @@
#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>
-#include "libedataserver/e-sexp.h"
-#include "libedataserver/e-data-server-util.h"
-#include "libedataserver/e-flag.h"
-#include "libedataserver/e-url.h"
-#include "libebook/e-contact.h"
-#include "libebook/e-destination.h"
-#include "libedata-book/e-book-backend-sexp.h"
-#include "libedata-book/e-data-book.h"
-#include "libedata-book/e-data-book-view.h"
-#include "e-book-backend-ews.h"
-#include "e-book-backend-sqlitedb.h"
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-flag.h>
+#include <libedataserver/e-sexp.h>
+#include <libedataserver/e-source-camel.h>
+#include <libedataserver/e-source-offline.h>
+#include <libedataserver/e-url.h>
+
+#include <libebook/e-contact.h>
+#include <libebook/e-destination.h>
+
+#include <libedata-book/e-book-backend-sexp.h>
+#include <libedata-book/e-data-book.h>
+#include <libedata-book/e-data-book-view.h>
+
#include "lzx/ews-oal-decompress.h"
-#include "ews-oab-decoder.h"
#include "server/e-ews-item-change.h"
#include "server/e-ews-message.h"
#include "server/e-ews-connection.h"
#include "server/e-ews-item.h"
+#include "server/e-source-ews-folder.h"
#include "utils/e-ews-query-to-restriction.h"
+#include "e-book-backend-ews.h"
+#include "e-book-backend-sqlitedb.h"
+#include "ews-oab-decoder.h"
+
#define d(x) x
#define EDB_ERROR(_code) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, NULL)
#define EDB_ERROR_EX(_code,_msg) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, _msg)
-G_DEFINE_TYPE (EBookBackendEws, e_book_backend_ews, E_TYPE_BOOK_BACKEND)
-
static gboolean ebews_fetch_items (EBookBackendEws *ebews, GSList *items, gboolean store_to_cache, GSList **vcards, GCancellable *cancellable, GError **error);
typedef struct {
@@ -97,7 +102,6 @@ struct _EBookBackendEwsPrivate {
GThread *dthread;
SyncDelta *dlock;
- ECredentials *credentials;
GCancellable *cancellable;
};
@@ -121,6 +125,47 @@ enum {
#define PRIV_LOCK(p) (g_static_rec_mutex_lock (&(p)->rec_mutex))
#define PRIV_UNLOCK(p) (g_static_rec_mutex_unlock (&(p)->rec_mutex))
+/* Forward Declarations */
+static void e_book_backend_ews_authenticator_init
+ (ESourceAuthenticatorInterface *interface);
+
+G_DEFINE_TYPE_WITH_CODE (
+ EBookBackendEws,
+ e_book_backend_ews,
+ E_TYPE_BOOK_BACKEND,
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_SOURCE_AUTHENTICATOR,
+ e_book_backend_ews_authenticator_init))
+
+static CamelEwsSettings *
+book_backend_ews_get_collection_settings (EBookBackendEws *backend)
+{
+ ESource *source;
+ ESource *collection;
+ ESourceCamel *extension;
+ ESourceRegistry *registry;
+ CamelSettings *settings;
+ const gchar *extension_name;
+
+ source = e_backend_get_source (E_BACKEND (backend));
+ registry = e_book_backend_get_registry (E_BOOK_BACKEND (backend));
+
+ extension_name = e_source_camel_get_extension_name ("ews");
+ e_source_camel_generate_subtype ("ews", CAMEL_TYPE_EWS_SETTINGS);
+
+ /* The collection settings live in our parent data source. */
+ collection = e_source_registry_find_extension (
+ registry, source, extension_name);
+ g_return_val_if_fail (collection != NULL, NULL);
+
+ extension = e_source_get_extension (collection, extension_name);
+ settings = e_source_camel_get_settings (extension);
+
+ g_object_unref (collection);
+
+ return CAMEL_EWS_SETTINGS (settings);
+}
+
static void
convert_error_to_edb_error (GError **perror)
{
@@ -158,12 +203,6 @@ convert_error_to_edb_error (GError **perror)
*perror = error;
}
-static void
-ews_auth_required (EBookBackend *backend)
-{
- e_book_backend_notify_auth_required (backend, TRUE, NULL);
-}
-
static gboolean
ews_remove_attachments (const gchar *attachment_dir)
{
@@ -2358,7 +2397,7 @@ ebews_start_refreshing (EBookBackendEws *ebews)
PRIV_LOCK (priv);
if (e_backend_get_online (E_BACKEND (ebews)) &&
- priv->cnc != NULL&& priv->marked_for_offline)
+ priv->cnc != NULL && priv->marked_for_offline)
fetch_deltas (ebews);
PRIV_UNLOCK (priv);
@@ -2410,14 +2449,20 @@ e_book_backend_ews_start_book_view (EBookBackend *backend,
GCancellable *cancellable;
GSList *ids = NULL, *mailboxes = NULL, *l, *contacts = NULL, *c;
EwsFolderId *fid;
+ ESource *source;
+ ESourceRegistry *registry;
+ ESourceEwsFolder *extension;
+ const gchar *extension_name;
GError *error = NULL;
gboolean includes_last_item;
- ESource *source;
ebews = E_BOOK_BACKEND_EWS (backend);
priv = ebews->priv;
query = e_data_book_view_get_card_query (book_view);
+ registry = e_book_backend_get_registry (backend);
+ source = e_backend_get_source (E_BACKEND (backend));
+
e_data_book_view_ref (book_view);
e_data_book_view_notify_progress (book_view, -1, _("Searching..."));
@@ -2434,15 +2479,23 @@ e_book_backend_ews_start_book_view (EBookBackend *backend,
return;
}
- if (!priv->cnc) {
- error = EDB_ERROR (AUTHENTICATION_REQUIRED);
- ews_auth_required (backend);
- e_data_book_view_notify_complete (book_view, error);
- e_data_book_view_unref (book_view);
- g_error_free (error);
- return;
+ if (priv->cnc == NULL) {
+ /* XXX Why doesn't start_book_view()
+ * get passed a GCancellable? */
+ e_source_registry_authenticate_sync (
+ registry, source,
+ E_SOURCE_AUTHENTICATOR (backend),
+ NULL, &error);
+ if (error != NULL) {
+ e_data_book_view_notify_complete (book_view, error);
+ e_data_book_view_unref (book_view);
+ g_error_free (error);
+ return;
+ }
}
+ g_return_if_fail (priv->cnc != NULL);
+
ebews_start_refreshing (ebews);
if (priv->ebsdb &&
@@ -2459,7 +2512,9 @@ e_book_backend_ews_start_book_view (EBookBackend *backend,
return;
}
- source = e_backend_get_source (E_BACKEND (backend));
+ extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
+ extension = e_source_get_extension (source, extension_name);
+
cancellable = g_cancellable_new ();
/* FIXME Need to convert the Ids from EwsLegacyId format to EwsId format using
@@ -2467,7 +2522,7 @@ e_book_backend_ews_start_book_view (EBookBackend *backend,
* 2007 and 2007_SP1 */
fid = g_new0 (EwsFolderId, 1);
fid->id = g_strdup (priv->folder_id);
- fid->change_key = e_source_get_duped_property (source, "change-key");
+ fid->change_key = e_source_ews_folder_dup_change_key (extension);
ids = g_slist_append (ids, fid);
/* We do not scan until we reach the last_item as it might be good enough to show first 100
@@ -2560,58 +2615,62 @@ e_book_backend_ews_load_source (EBookBackend *backend,
{
EBookBackendEws *cbews;
EBookBackendEwsPrivate *priv;
+ CamelEwsSettings *settings;
+ ESourceExtension *extension;
const gchar *cache_dir, *email;
- const gchar *folder_name;
- const gchar *offline, *is_gal;
- GError *err = NULL;
+ const gchar *display_name;
+ const gchar *extension_name;
+ const gchar *gal_uid;
+ const gchar *uid;
cbews = E_BOOK_BACKEND_EWS (backend);
priv = cbews->priv;
cache_dir = e_book_backend_get_cache_dir (backend);
- email = e_source_get_property (source, "email");
- is_gal = e_source_get_property (source, "gal");
+ settings = book_backend_ews_get_collection_settings (cbews);
+ email = camel_ews_settings_get_email (settings);
- if (is_gal && !strcmp (is_gal, "1"))
- priv->is_gal = TRUE;
+ uid = e_source_get_uid (source);
+ gal_uid = camel_ews_settings_get_gal_uid (settings);
+ priv->is_gal = (g_strcmp0 (uid, gal_uid) == 0);
- if (!priv->is_gal) {
- priv->folder_id = e_source_get_duped_property (source, "folder-id");
- folder_name = e_source_peek_name (source);
+ display_name = e_source_get_display_name (source);
- priv->ebsdb = e_book_backend_sqlitedb_new (cache_dir, email, priv->folder_id, folder_name, TRUE, &err);
- if (err) {
- g_propagate_error (perror, err);
- return;
- }
+ extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
+ extension = e_source_get_extension (source, extension_name);
- offline = e_source_get_property (source, "offline_sync");
- if (offline && g_str_equal (offline, "1"))
- priv->marked_for_offline = TRUE;
- } else {
- priv->folder_id = e_source_get_duped_property (source, "oal_id");
+ priv->folder_id = e_source_ews_folder_dup_id (
+ E_SOURCE_EWS_FOLDER (extension));
- /* If folder_id is present it means the GAL is marked for offline usage, we do not check for offline_sync property */
- if (priv->folder_id) {
- priv->folder_name = g_strdup (e_source_peek_name (source));
- priv->oab_url = e_source_get_duped_property (source, "oab_url");
+ priv->ebsdb = e_book_backend_sqlitedb_new (
+ cache_dir, email, priv->folder_id,
+ display_name, TRUE, perror);
- /* setup stagging dir, remove any old files from there */
- priv->attachment_dir = g_build_filename (cache_dir, "attachments", NULL);
- g_mkdir_with_parents (priv->attachment_dir, 0777);
+ if (priv->ebsdb == NULL)
+ return;
- priv->ebsdb = e_book_backend_sqlitedb_new (cache_dir, email, priv->folder_id, priv->folder_name, TRUE, &err);
- if (err) {
- g_propagate_error (perror, err);
- return;
- }
- priv->marked_for_offline = TRUE;
- priv->is_writable = FALSE;
- }
- }
+ if (!priv->is_gal) {
+ extension_name = E_SOURCE_EXTENSION_OFFLINE;
+ extension = e_source_get_extension (source, extension_name);
- if (e_backend_get_online (E_BACKEND (backend)))
- e_book_backend_notify_auth_required (backend, TRUE, NULL);
+ priv->marked_for_offline =
+ e_source_offline_get_stay_synchronized (
+ E_SOURCE_OFFLINE (extension));
+
+ /* If folder_id is present it means the GAL is marked for
+ * offline usage, we do not check for offline_sync property */
+ } else if (priv->folder_id != NULL) {
+ priv->folder_name = g_strdup (display_name);
+ priv->oab_url = camel_ews_settings_dup_oaburl (settings);
+
+ /* setup stagging dir, remove any old files from there */
+ priv->attachment_dir = g_build_filename (
+ cache_dir, "attachments", NULL);
+ g_mkdir_with_parents (priv->attachment_dir, 0777);
+
+ priv->marked_for_offline = TRUE;
+ priv->is_writable = FALSE;
+ }
}
static void
@@ -2624,80 +2683,6 @@ e_book_backend_ews_remove (EBookBackend *backend,
}
static void
-e_book_backend_ews_authenticate_user (EBookBackend *backend,
- GCancellable *cancellable,
- ECredentials *credentials)
-{
- EBookBackendEws *ebews;
- EBookBackendEwsPrivate *priv;
- EEwsConnection *cnc = NULL;
- ESource *esource;
- GError *error = NULL;
- GSList *folders = NULL, *ids = NULL;
- EwsFolderId *fid = NULL;
-
- const gchar *host_url;
- const gchar *read_only;
-
- ebews = E_BOOK_BACKEND_EWS (backend);
- priv = ebews->priv;
-
- if (!e_backend_get_online (E_BACKEND (backend))) {
- e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
- return;
- }
-
- if (priv->cnc) {
- e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
- return;
- }
-
- esource = e_backend_get_source (E_BACKEND (backend));
- host_url = e_source_get_property (esource, "hosturl");
- read_only = e_source_get_property (esource, "read_only");
-
- cnc = e_ews_connection_new (host_url, e_credentials_peek (credentials, E_CREDENTIALS_KEY_USERNAME),
- e_credentials_peek (credentials, E_CREDENTIALS_KEY_PASSWORD),
- NULL, NULL, &error);
-
- if ((read_only && !strcmp (read_only, "true")) || priv->is_gal) {
- priv->is_writable = FALSE;
- } else
- priv->is_writable = TRUE;
-
- if (!error && cnc) {
- /* a dummy request to make sure we have a authenticated connection */
- fid = g_new0 (EwsFolderId, 1);
- fid->id = g_strdup ("contacts");
- fid->is_distinguished_id = TRUE;
- ids = g_slist_append (ids, fid);
- e_ews_connection_get_folder_sync (
- cnc, EWS_PRIORITY_MEDIUM, "Default",
- NULL, ids, &folders, cancellable, &error);
-
- e_ews_folder_free_fid (fid);
- g_slist_free (ids);
- ids = NULL;
- }
-
- if (error) {
- convert_error_to_edb_error (&error);
-
- e_book_backend_notify_auth_required (backend, TRUE, priv->credentials);
- e_book_backend_notify_opened (backend, error);
- g_object_unref (cnc);
- return;
- }
-
- priv->cnc = cnc;
- priv->username = e_source_get_duped_property (esource, "username");
- priv->password = g_strdup (e_credentials_peek (credentials, E_CREDENTIALS_KEY_PASSWORD));
-
- e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
- e_book_backend_notify_readonly (backend, !priv->is_writable);
-}
-
-static void
e_book_backend_ews_notify_online_cb (EBookBackend *backend,
GParamSpec *spec)
{
@@ -2724,7 +2709,6 @@ e_book_backend_ews_notify_online_cb (EBookBackend *backend,
e_book_backend_notify_readonly (backend, !ebews->priv->is_writable);
e_book_backend_notify_online (backend, TRUE);
- e_book_backend_notify_auth_required (backend, TRUE, NULL);
}
}
}
@@ -2798,13 +2782,35 @@ e_book_backend_ews_open (EBookBackend *backend,
GCancellable *cancellable,
gboolean only_if_exists)
{
- GError *error = NULL;
+ EBookBackendEws *cbews;
+ ESourceRegistry *registry;
ESource *source;
+ GError *error = NULL;
+ cbews = E_BOOK_BACKEND_EWS (backend);
+
+ registry = e_book_backend_get_registry (backend);
source = e_backend_get_source (E_BACKEND (backend));
e_book_backend_ews_load_source (backend, source, only_if_exists, &error);
+
+ if (error == NULL) {
+ gboolean need_to_authenticate;
+
+ PRIV_LOCK (cbews->priv);
+ need_to_authenticate =
+ (cbews->priv->cnc == NULL) &&
+ (e_backend_get_online (E_BACKEND (backend)));
+ PRIV_UNLOCK (cbews->priv);
+
+ if (need_to_authenticate)
+ e_source_registry_authenticate_sync (
+ registry, source,
+ E_SOURCE_AUTHENTICATOR (backend),
+ cancellable, &error);
+ }
+
convert_error_to_edb_error (&error);
- e_data_book_respond_open (book, opid, error);
+ e_book_backend_respond_opened (backend, book, opid, error);
}
/**
@@ -2891,9 +2897,6 @@ e_book_backend_ews_dispose (GObject *object)
priv->ebsdb = NULL;
}
- e_credentials_free (priv->credentials);
- priv->credentials = NULL;
-
g_static_rec_mutex_free (&priv->rec_mutex);
g_free (priv);
@@ -2902,6 +2905,98 @@ e_book_backend_ews_dispose (GObject *object)
G_OBJECT_CLASS (e_book_backend_ews_parent_class)->dispose (object);
}
+static ESourceAuthenticationResult
+book_backend_ews_try_password_sync (ESourceAuthenticator *authenticator,
+ const GString *password,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EBookBackendEws *backend;
+ EEwsConnection *connection;
+ ESourceAuthenticationResult result;
+ CamelEwsSettings *ews_settings;
+ CamelNetworkSettings *network_settings;
+ EwsFolderId *fid = NULL;
+ GSList *folders = NULL;
+ GSList *ids = NULL;
+ gchar *hosturl;
+ gchar *user;
+ GError *local_error = NULL;
+
+ /* This tests the password by fetching the contacts folder. */
+
+ backend = E_BOOK_BACKEND_EWS (authenticator);
+ ews_settings = book_backend_ews_get_collection_settings (backend);
+ hosturl = camel_ews_settings_dup_hosturl (ews_settings);
+
+ network_settings = CAMEL_NETWORK_SETTINGS (ews_settings);
+ user = camel_network_settings_dup_user (network_settings);
+
+ connection = e_ews_connection_new (
+ hosturl, user, password->str, NULL, NULL, error);
+
+ if (connection == NULL) {
+ result = E_SOURCE_AUTHENTICATION_ERROR;
+ goto exit;
+ }
+
+ fid = g_new0 (EwsFolderId, 1);
+ fid->id = g_strdup ("contacts");
+ fid->is_distinguished_id = TRUE;
+ ids = g_slist_append (ids, fid);
+
+ e_ews_connection_get_folder_sync (
+ connection, EWS_PRIORITY_MEDIUM, "Default",
+ NULL, ids, &folders, cancellable, &local_error);
+
+ e_ews_folder_free_fid (fid);
+ g_slist_free (ids);
+ ids = NULL;
+
+ if (local_error == NULL) {
+
+ PRIV_LOCK (backend->priv);
+
+ if (backend->priv->cnc != NULL)
+ g_object_unref (backend->priv->cnc);
+ backend->priv->cnc = g_object_ref (connection);
+
+ /* Stash the username and password for later
+ * reuse in Offline Address Book connections. */
+ g_free (backend->priv->username);
+ g_free (backend->priv->password);
+ backend->priv->username = g_strdup (user);
+ backend->priv->password = g_strdup (password->str);
+
+ PRIV_UNLOCK (backend->priv);
+
+ result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+
+ } else {
+ gboolean auth_failed;
+
+ auth_failed = g_error_matches (
+ local_error, EWS_CONNECTION_ERROR,
+ EWS_CONNECTION_ERROR_AUTHENTICATION_FAILED);
+
+ if (auth_failed) {
+ g_clear_error (&local_error);
+ result = E_SOURCE_AUTHENTICATION_REJECTED;
+ } else {
+ g_propagate_error (error, local_error);
+ result = E_SOURCE_AUTHENTICATION_ERROR;
+ }
+ }
+
+ g_object_unref (connection);
+
+exit:
+ g_free (hosturl);
+ g_free (user);
+
+ return result;
+}
+
static void
e_book_backend_ews_class_init (EBookBackendEwsClass *klass)
{
@@ -2921,7 +3016,6 @@ e_book_backend_ews_class_init (EBookBackendEwsClass *klass)
parent_class->get_contact = e_book_backend_ews_get_contact;
parent_class->get_contact_list = e_book_backend_ews_get_contact_list;
parent_class->remove = e_book_backend_ews_remove;
- parent_class->authenticate_user = e_book_backend_ews_authenticate_user;
parent_class->start_book_view = e_book_backend_ews_start_book_view;
parent_class->stop_book_view = e_book_backend_ews_stop_book_view;
@@ -2929,6 +3023,12 @@ e_book_backend_ews_class_init (EBookBackendEwsClass *klass)
}
static void
+e_book_backend_ews_authenticator_init (ESourceAuthenticatorInterface *interface)
+{
+ interface->try_password_sync = book_backend_ews_try_password_sync;
+}
+
+static void
e_book_backend_ews_init (EBookBackendEws *backend)
{
EBookBackendEws *bews;
diff --git a/src/addressbook/ews-oab-decoder.h b/src/addressbook/ews-oab-decoder.h
index d948966..cfc6551 100644
--- a/src/addressbook/ews-oab-decoder.h
+++ b/src/addressbook/ews-oab-decoder.h
@@ -22,8 +22,6 @@
#ifndef _EWS_OAB_DECODER
#define _EWS_OAB_DECODER
-#include <glib.h>
-#include <glib-object.h>
#include <gio/gio.h>
#include <libebook/e-contact.h>
diff --git a/src/calendar/e-cal-backend-ews-factory.c b/src/calendar/e-cal-backend-ews-factory.c
index 8647402..e9996d3 100644
--- a/src/calendar/e-cal-backend-ews-factory.c
+++ b/src/calendar/e-cal-backend-ews-factory.c
@@ -12,6 +12,9 @@
#include <string.h>
#include <libedata-cal/e-cal-backend-factory.h>
+
+#include "server/e-source-ews-folder.h"
+
#include "e-cal-backend-ews.h"
#define FACTORY_NAME "ews"
@@ -106,6 +109,8 @@ e_cal_backend_ews_todos_factory_init (ECalBackendFactory *factory)
G_MODULE_EXPORT void
e_module_load (GTypeModule *type_module)
{
+ e_source_ews_folder_type_register (type_module);
+
e_cal_backend_ews_events_factory_register_type (type_module);
e_cal_backend_ews_journal_factory_register_type (type_module);
e_cal_backend_ews_todos_factory_register_type (type_module);
diff --git a/src/calendar/e-cal-backend-ews-utils.c b/src/calendar/e-cal-backend-ews-utils.c
index edfd485..7177908 100644
--- a/src/calendar/e-cal-backend-ews-utils.c
+++ b/src/calendar/e-cal-backend-ews-utils.c
@@ -35,7 +35,6 @@
#include <libecal/e-cal-recur.h>
#include <libecal/e-cal-time-util.h>
#include <libsoup/soup-misc.h>
-#include <libedataserver/e-source-list.h>
#include "server/e-ews-connection.h"
#include "server/e-ews-message.h"
diff --git a/src/calendar/e-cal-backend-ews.c b/src/calendar/e-cal-backend-ews.c
index c9d70a5..40c2e2e 100644
--- a/src/calendar/e-cal-backend-ews.c
+++ b/src/calendar/e-cal-backend-ews.c
@@ -27,25 +27,33 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+
#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>
-#include "libedataserver/e-xml-hash-utils.h"
-#include "libedataserver/e-url.h"
+
+#include <camel/camel.h>
+
+#include <libedataserver/eds-version.h>
+#include <libedataserver/e-source-camel.h>
+#include <libedataserver/e-xml-hash-utils.h>
+#include <libedataserver/e-url.h>
+
#include <libedata-cal/e-cal-backend-cache.h>
#include <libedata-cal/e-cal-backend-file-store.h>
#include <libedata-cal/e-cal-backend-util.h>
+
#include <libecal/e-cal-component.h>
#include <libecal/e-cal-time-util.h>
+
#include <libical/icaltz-util.h>
#include <libical/icalcomponent.h>
#include <libical/icalproperty.h>
#include <libical/icalparameter.h>
-#include <camel/camel.h>
-#include <libedataserver/eds-version.h>
#include "server/e-ews-item-change.h"
#include "server/e-ews-message.h"
#include "server/e-soap-response.h"
+#include "server/e-source-ews-folder.h"
#include "utils/ews-camel-common.h"
@@ -65,7 +73,7 @@
#define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
#endif
-G_DEFINE_TYPE (ECalBackendEws, e_cal_backend_ews, E_TYPE_CAL_BACKEND)
+typedef struct _SyncItemsClosure SyncItemsClosure;
/* Private part of the CalBackendEws structure */
struct _ECalBackendEwsPrivate {
@@ -88,10 +96,19 @@ struct _ECalBackendEwsPrivate {
gboolean refreshing;
GHashTable *item_id_hash;
- ECredentials *credentials;
GCancellable *cancellable;
};
+struct _SyncItemsClosure {
+ ECalBackendEws *backend;
+ EEwsConnection *connection;
+ gchar *sync_state;
+ gboolean includes_last_item;
+ GSList *items_created;
+ GSList *items_deleted;
+ GSList *items_updated;
+};
+
#define PRIV_LOCK(p) (g_static_rec_mutex_lock (&(p)->rec_mutex))
#define PRIV_UNLOCK(p) (g_static_rec_mutex_unlock (&(p)->rec_mutex))
@@ -117,13 +134,74 @@ struct _ECalBackendEwsPrivate {
} \
} G_STMT_END
-#define PARENT_TYPE E_TYPE_CAL_BACKEND
-static ECalBackendClass *parent_class = NULL;
static void ews_cal_sync_items_ready_cb (GObject *obj, GAsyncResult *res, gpointer user_data);
static void ews_cal_component_get_item_id (ECalComponent *comp, gchar **itemid, gchar **changekey);
static gboolean ews_start_sync (gpointer data);
static icaltimezone * e_cal_get_timezone_from_ical_component (ECalBackend *backend, icalcomponent *comp);
+/* Forward Declarations */
+static void e_cal_backend_ews_authenticator_init
+ (ESourceAuthenticatorInterface *interface);
+
+G_DEFINE_TYPE_WITH_CODE (
+ ECalBackendEws,
+ e_cal_backend_ews,
+ E_TYPE_CAL_BACKEND,
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_SOURCE_AUTHENTICATOR,
+ e_cal_backend_ews_authenticator_init))
+
+static void
+sync_items_closure_free (SyncItemsClosure *closure)
+{
+ g_object_unref (closure->backend);
+ g_object_unref (closure->connection);
+ g_free (closure->sync_state);
+
+ g_slist_free_full (
+ closure->items_created,
+ (GDestroyNotify) g_object_unref);
+
+ g_slist_free_full (
+ closure->items_updated,
+ (GDestroyNotify) g_object_unref);
+
+ g_slist_free_full (
+ closure->items_deleted,
+ (GDestroyNotify) g_free);
+
+ g_slice_free (SyncItemsClosure, closure);
+}
+
+static CamelEwsSettings *
+cal_backend_ews_get_collection_settings (ECalBackendEws *backend)
+{
+ ESource *source;
+ ESource *collection;
+ ESourceCamel *extension;
+ ESourceRegistry *registry;
+ CamelSettings *settings;
+ const gchar *extension_name;
+
+ source = e_backend_get_source (E_BACKEND (backend));
+ registry = e_cal_backend_get_registry (E_CAL_BACKEND (backend));
+
+ extension_name = e_source_camel_get_extension_name ("ews");
+ e_source_camel_generate_subtype ("ews", CAMEL_TYPE_EWS_SETTINGS);
+
+ /* The collection settings live in our parent data source. */
+ collection = e_source_registry_find_extension (
+ registry, source, extension_name);
+ g_return_val_if_fail (collection != NULL, NULL);
+
+ extension = e_source_get_extension (collection, extension_name);
+ settings = e_source_camel_get_settings (extension);
+
+ g_object_unref (collection);
+
+ return CAMEL_EWS_SETTINGS (settings);
+}
+
static void
convert_error_to_edc_error (GError **perror)
{
@@ -201,8 +279,8 @@ e_cal_backend_ews_internal_get_timezone (ECalBackend *backend,
if (cbews->priv->store)
zone = (icaltimezone *) e_cal_backend_store_get_timezone (cbews->priv->store, tzid);
- if (!zone && E_CAL_BACKEND_CLASS (parent_class)->internal_get_timezone)
- zone = E_CAL_BACKEND_CLASS (parent_class)->internal_get_timezone (backend, tzid);
+ if (!zone && E_CAL_BACKEND_CLASS (e_cal_backend_ews_parent_class)->internal_get_timezone)
+ zone = E_CAL_BACKEND_CLASS (e_cal_backend_ews_parent_class)->internal_get_timezone (backend, tzid);
return zone;
}
@@ -537,99 +615,38 @@ add_comps_to_item_id_hash (ECalBackendEws *cbews)
g_slist_free (comps);
}
-static gboolean
-connect_to_server (ECalBackendEws *cbews,
- const gchar *username,
- const gchar *password,
- GError **error)
-{
- ECalBackendEwsPrivate *priv;
- ESource *esource;
-
- priv = cbews->priv;
- esource = e_backend_get_source (E_BACKEND (cbews));
-
- PRIV_LOCK (priv);
-
- if (e_backend_get_online (E_BACKEND (cbews)) &&
- priv->cnc == NULL && password != NULL) {
- const gchar *host_url;
- GSList *folders = NULL, *ids = NULL;
- EwsFolderId *fid = NULL;
- EEwsConnection *cnc = NULL;
- GError *err = NULL;
-
- /* If we can be called a second time while the first is still
- * "outstanding", we need a bit of a rethink... */
- g_assert (!priv->opening_ctx && !priv->opening_cal);
-
- priv->user_email = e_source_get_duped_property (esource, "email");
-
- host_url = e_source_get_property (esource, "hosturl");
- cnc = e_ews_connection_new (host_url, username, password,
- NULL, NULL, error);
-
- fid = g_new0 (EwsFolderId, 1);
- fid->id = g_strdup (priv->folder_id);
- ids = g_slist_append (ids, fid);
- e_ews_connection_get_folder_sync (
- cnc, EWS_PRIORITY_MEDIUM, "Default", NULL,
- ids, &folders, priv->cancellable, &err);
-
- e_ews_folder_free_fid (fid);
- g_slist_free (ids);
- ids = NULL;
-
- if (err) {
- g_object_unref (cnc);
- g_propagate_error (error, err);
- PRIV_UNLOCK (priv);
-
- e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbews), TRUE, priv->credentials);
-
- return FALSE;
- }
-
- g_object_unref ((EEwsFolder *) folders->data);
- g_slist_free (folders);
- folders = NULL;
-
- priv->cnc = cnc;
-
- /* Trigger an update request, which will test our authentication */
- ews_start_sync (cbews);
- PRIV_UNLOCK (priv);
- return TRUE;
- }
-
- PRIV_UNLOCK (priv);
- return FALSE;
-}
-
-static gboolean
+static void
e_cal_backend_ews_open (ECalBackend *backend,
EDataCal *cal,
- guint32 context,
+ guint32 opid,
GCancellable *cancellable,
- gboolean only_if_exists,
- const gchar *username,
- const gchar *password,
- GError **error)
+ gboolean only_if_exists)
{
ECalBackendEws *cbews;
ECalBackendEwsPrivate *priv;
- ESource *esource;
+ ESourceRegistry *registry;
+ ESource *source;
const gchar *cache_dir;
+ gboolean need_to_authenticate;
+ GError *error = NULL;
cbews = (ECalBackendEws *) backend;
priv = cbews->priv;
+ registry = e_cal_backend_get_registry (backend);
cache_dir = e_cal_backend_get_cache_dir (backend);
- esource = e_backend_get_source (E_BACKEND (cbews));
+ source = e_backend_get_source (E_BACKEND (cbews));
PRIV_LOCK (priv);
+
if (!priv->store) {
- priv->folder_id = e_source_get_duped_property (esource, "folder-id");
+ ESourceEwsFolder *extension;
+ const gchar *extension_name;
+
+ extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
+ extension = e_source_get_extension (source, extension_name);
+ priv->folder_id = e_source_ews_folder_dup_id (extension);
+
priv->storage_path = g_build_filename (cache_dir, priv->folder_id, NULL);
priv->store = e_cal_backend_file_store_new (priv->storage_path);
@@ -637,82 +654,24 @@ e_cal_backend_ews_open (ECalBackend *backend,
add_comps_to_item_id_hash (cbews);
if (priv->default_zone)
- e_cal_backend_store_set_default_timezone (priv->store, priv->default_zone);
- }
- PRIV_UNLOCK (priv);
-
- if (connect_to_server (cbews, username, password, error)) {
- priv->opening_cal = cal;
- priv->opening_ctx = context;
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-e_cal_backend_ews_open_compat (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- gboolean only_if_exists)
-{
- GError *error = NULL;
- ECalBackendEws *cbews = E_CAL_BACKEND_EWS (backend);
- ECalBackendEwsPrivate *priv = cbews->priv;
- const gchar *user_name = NULL, *password = NULL;
- gboolean ret;
-
- if (priv->credentials) {
- user_name = e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_USERNAME);
- password = e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_PASSWORD);
- }
-
- ret = e_cal_backend_ews_open (backend, cal, opid, cancellable, only_if_exists, user_name,
- password, &error);
-
- if (!priv->credentials)
- e_cal_backend_notify_auth_required (backend, TRUE, priv->credentials);
-
- e_cal_backend_notify_opened (backend, NULL);
- convert_error_to_edc_error (&error);
- e_data_cal_respond_open (cal, opid, error);
-}
-
-static void
-e_cal_backend_ews_authenticate_user (ECalBackend *backend,
- GCancellable *cancellable,
- ECredentials *credentials)
-{
- ECalBackendEws *cbews;
- ECalBackendEwsPrivate *priv;
- GError *error = NULL;
-
- cbews = E_CAL_BACKEND_EWS (backend);
- priv = cbews->priv;
-
- PRIV_LOCK (priv);
-
- e_credentials_free (priv->credentials);
- priv->credentials = NULL;
-
- if (!credentials || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME)) {
- PRIV_UNLOCK (priv);
- g_propagate_error (&error, EDC_ERROR (AuthenticationFailed));
- e_cal_backend_notify_opened (backend, error);
- return;
+ e_cal_backend_store_set_default_timezone (
+ priv->store, priv->default_zone);
}
- priv->credentials = e_credentials_new_clone (credentials);
-
- connect_to_server (cbews, e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_USERNAME),
- e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_PASSWORD), &error);
+ need_to_authenticate =
+ (priv->cnc == NULL) &&
+ (e_backend_get_online (E_BACKEND (backend)));
PRIV_UNLOCK (priv);
+ if (need_to_authenticate)
+ e_source_registry_authenticate_sync (
+ registry, source,
+ E_SOURCE_AUTHENTICATOR (backend),
+ cancellable, &error);
+
convert_error_to_edc_error (&error);
- e_cal_backend_notify_opened (backend, error);
+ e_cal_backend_respond_opened (backend, cal, opid, error);
}
static void
@@ -1486,7 +1445,6 @@ ews_create_object_cb (GObject *object,
icalproperty *icalprop;
icalcomponent *icalcomp;
guint n_attach;
- gboolean result;
EEwsItem *item;
/* get a list of ids from server (single item) */
@@ -1508,7 +1466,7 @@ ews_create_object_cb (GObject *object,
items = g_slist_append (items, item_id->id);
/* get calender uid from server*/
- result = e_ews_connection_get_items_sync (
+ e_ews_connection_get_items_sync (
cnc, EWS_PRIORITY_MEDIUM,
items,
"IdOnly",
@@ -3414,55 +3372,23 @@ exit:
g_free (sync_data->master_uid);
g_free (sync_data->sync_state);
g_free (sync_data);
- g_object_unref (cbews);
}
static void
-ews_cal_sync_items_ready_cb (GObject *obj,
- GAsyncResult *res,
- gpointer user_data)
+cal_backend_ews_process_folder_items (ECalBackendEws *backend,
+ EEwsConnection *connection,
+ const gchar *sync_state,
+ gboolean includes_last_item,
+ GSList *items_created,
+ GSList *items_updated,
+ GSList *items_deleted)
{
- EEwsConnection *cnc;
- ECalBackendEws *cbews;
ECalBackendEwsPrivate *priv;
- GSList *items_created = NULL, *items_updated = NULL;
- GSList *items_deleted = NULL, *l[2], *m, *cal_item_ids = NULL, *task_item_ids = NULL;
- gchar *sync_state = NULL;
- gboolean includes_last_item;
- GError *error = NULL;
+ GSList *l[2], *m, *cal_item_ids = NULL, *task_item_ids = NULL;
struct _ews_sync_data *sync_data = NULL;
gint i;
- cnc = (EEwsConnection *) obj;
- cbews = (ECalBackendEws *) user_data;
- priv = cbews->priv;
-
- e_ews_connection_sync_folder_items_finish (cnc, res, &sync_state, &includes_last_item,
- &items_created, &items_updated,
- &items_deleted, &error);
-
- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
- g_error_matches (error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_CANCELLED)) {
- g_clear_error (&error);
- g_object_unref (cbews);
- return;
- }
-
- /*FIXME invoke a dummy request in authenticate user to ensure we have a valid connection to avoid this mess */
- if (!g_error_matches (error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_AUTHENTICATION_FAILED))
- e_cal_backend_notify_readonly (E_CAL_BACKEND (cbews), FALSE);
-
- if (error != NULL) {
- g_warning ("Unable to Sync changes %s \n", error->message);
-
- PRIV_LOCK (priv);
- priv->refreshing = FALSE;
- PRIV_UNLOCK (priv);
-
- g_clear_error (&error);
- g_object_unref (cbews);
- return;
- }
+ priv = backend->priv;
l[0] = items_created;
l[1] = items_updated;
@@ -3478,7 +3404,6 @@ ews_cal_sync_items_ready_cb (GObject *obj,
cal_item_ids = g_slist_append (cal_item_ids, g_strdup (id->id));
else if (type == E_EWS_ITEM_TYPE_TASK)
task_item_ids = g_slist_append (task_item_ids, g_strdup (id->id));
- g_object_unref (item);
}
}
@@ -3492,36 +3417,34 @@ ews_cal_sync_items_ready_cb (GObject *obj,
PRIV_UNLOCK (priv);
if (comp)
- ews_cal_delete_comp (cbews, comp, item_id);
-
- g_free (m->data);
+ ews_cal_delete_comp (backend, comp, item_id);
}
e_cal_backend_store_thaw_changes (priv->store);
if (!cal_item_ids && !task_item_ids && !includes_last_item) {
e_cal_backend_store_put_key_value (priv->store, SYNC_KEY, sync_state);
e_ews_connection_sync_folder_items (
- g_object_ref (priv->cnc), EWS_PRIORITY_MEDIUM,
+ connection,
+ EWS_PRIORITY_MEDIUM,
sync_state, priv->folder_id,
"IdOnly", NULL,
EWS_MAX_FETCH_COUNT,
priv->cancellable,
ews_cal_sync_items_ready_cb,
- g_object_ref (cbews));
- g_free (sync_state);
+ g_object_ref (backend));
goto exit;
}
if (cal_item_ids || task_item_ids) {
sync_data = g_new0 (struct _ews_sync_data, 1);
- sync_data->cbews = g_object_ref (cbews);
- sync_data->sync_state = sync_state;
+ sync_data->cbews = g_object_ref (backend);
+ sync_data->sync_state = g_strdup (sync_state);
sync_data->sync_pending = !includes_last_item;
}
if (cal_item_ids)
e_ews_connection_get_items (
- cnc,
+ connection,
EWS_PRIORITY_MEDIUM,
cal_item_ids,
"IdOnly",
@@ -3533,7 +3456,8 @@ ews_cal_sync_items_ready_cb (GObject *obj,
if (task_item_ids)
e_ews_connection_get_items (
- cnc, EWS_PRIORITY_MEDIUM,
+ connection,
+ EWS_PRIORITY_MEDIUM,
task_item_ids,
"AllProperties",
NULL,
@@ -3552,15 +3476,92 @@ exit:
g_slist_foreach (task_item_ids, (GFunc) g_free, NULL);
g_slist_free (task_item_ids);
}
+}
+
+static gboolean
+cal_backend_ews_sync_items_idle_cb (gpointer user_data)
+{
+ SyncItemsClosure *closure = user_data;
- if (items_created)
- g_slist_free (items_created);
- if (items_updated)
- g_slist_free (items_updated);
- if (items_deleted)
- g_slist_free (items_deleted);
+ cal_backend_ews_process_folder_items (
+ closure->backend,
+ closure->connection,
+ closure->sync_state,
+ closure->includes_last_item,
+ closure->items_created,
+ closure->items_updated,
+ closure->items_deleted);
- g_object_unref (cbews);
+ return FALSE;
+}
+
+static void
+ews_cal_sync_items_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ECalBackendEws *backend;
+ EEwsConnection *connection;
+ GSList *items_created = NULL;
+ GSList *items_updated = NULL;
+ GSList *items_deleted = NULL;
+ gboolean includes_last_item;
+ gchar *sync_state = NULL;
+ GError *error = NULL;
+
+ connection = E_EWS_CONNECTION (source_object);
+ backend = E_CAL_BACKEND_EWS (user_data);
+
+ e_ews_connection_sync_folder_items_finish (
+ connection, result,
+ &sync_state,
+ &includes_last_item,
+ &items_created,
+ &items_updated,
+ &items_deleted,
+ &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_error_free (error);
+ g_object_unref (backend);
+ return;
+ }
+
+ /* XXX Why are there two different error codes for cancellation? */
+ if (g_error_matches (error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_CANCELLED)) {
+ g_error_free (error);
+ g_object_unref (backend);
+ return;
+ }
+
+ if (!g_error_matches (error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_AUTHENTICATION_FAILED))
+ e_cal_backend_notify_readonly (E_CAL_BACKEND (backend), FALSE);
+
+ if (error == NULL) {
+ cal_backend_ews_process_folder_items (
+ backend, connection,
+ sync_state, includes_last_item,
+ items_created, items_updated, items_deleted);
+ } else {
+ g_warn_if_fail (items_created == NULL);
+ g_warn_if_fail (items_updated == NULL);
+ g_warn_if_fail (items_deleted == NULL);
+
+ PRIV_LOCK (backend->priv);
+ backend->priv->refreshing = FALSE;
+ PRIV_UNLOCK (backend->priv);
+
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+
+ g_slist_free_full (items_created, (GDestroyNotify) g_object_unref);
+ g_slist_free_full (items_updated, (GDestroyNotify) g_object_unref);
+ g_slist_free_full (items_deleted, (GDestroyNotify) g_free);
+
+ g_free (sync_state);
+
+ g_object_unref (backend);
}
static gboolean
@@ -3897,7 +3898,7 @@ e_cal_backend_ews_get_backend_property (ECalBackend *backend,
prop_value = e_cal_component_get_as_string (comp);
g_object_unref (comp);
} else {
- E_CAL_BACKEND_CLASS (parent_class)->get_backend_property (backend, cal, opid, cancellable, prop_name);
+ E_CAL_BACKEND_CLASS (e_cal_backend_ews_parent_class)->get_backend_property (backend, cal, opid, cancellable, prop_name);
return;
}
@@ -3929,8 +3930,6 @@ e_cal_backend_ews_notify_online_cb (ECalBackend *backend,
priv->read_only = FALSE;
e_cal_backend_notify_online (backend, TRUE);
e_cal_backend_notify_readonly (backend, priv->read_only);
- if (e_cal_backend_is_opened (backend))
- e_cal_backend_notify_auth_required (backend, TRUE, priv->credentials);
} else {
switch_offline (E_CAL_BACKEND_EWS (backend));
e_cal_backend_notify_readonly (backend, priv->read_only);
@@ -3963,8 +3962,7 @@ e_cal_backend_ews_dispose (GObject *object)
priv->cnc = NULL;
}
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
+ G_OBJECT_CLASS (e_cal_backend_ews_parent_class)->dispose (object);
}
/* Finalize handler for the file backend */
@@ -4015,41 +4013,127 @@ e_cal_backend_ews_finalize (GObject *object)
g_hash_table_destroy (priv->item_id_hash);
- e_credentials_free (priv->credentials);
- priv->credentials = NULL;
-
g_free (priv);
cbews->priv = NULL;
- if (G_OBJECT_CLASS (parent_class)->finalize)
- (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+ G_OBJECT_CLASS (e_cal_backend_ews_parent_class)->finalize (object);
}
-/* Object initialization function for the file backend */
-static void
-e_cal_backend_ews_init (ECalBackendEws *cbews)
+static ESourceAuthenticationResult
+cal_backend_ews_try_password_sync (ESourceAuthenticator *authenticator,
+ const GString *password,
+ GCancellable *cancellable,
+ GError **error)
{
- ECalBackendEwsPrivate *priv;
+ ECalBackendEws *backend;
+ ECalBackendStore *store;
+ EEwsConnection *connection;
+ ESourceAuthenticationResult result;
+ CamelEwsSettings *ews_settings;
+ CamelNetworkSettings *network_settings;
+ GSList *items_created = NULL;
+ GSList *items_updated = NULL;
+ GSList *items_deleted = NULL;
+ gboolean includes_last_item = FALSE;
+ const gchar *sync_state;
+ gchar *sync_state_inout;
+ gchar *hosturl;
+ gchar *user;
+ GError *local_error = NULL;
- priv = g_new0 (ECalBackendEwsPrivate, 1);
+ /* This tests the password by synchronizing the folder. */
- /* create the mutex for thread safety */
- g_static_rec_mutex_init (&priv->rec_mutex);
- priv->item_id_hash = g_hash_table_new_full
- (g_str_hash, g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) g_object_unref);
- priv->default_zone = icaltimezone_get_utc_timezone ();
- priv->cancellable = g_cancellable_new ();
+ backend = E_CAL_BACKEND_EWS (authenticator);
+ ews_settings = cal_backend_ews_get_collection_settings (backend);
+ hosturl = camel_ews_settings_dup_hosturl (ews_settings);
- cbews->priv = priv;
+ network_settings = CAMEL_NETWORK_SETTINGS (ews_settings);
+ user = camel_network_settings_dup_user (network_settings);
- g_signal_connect (
- cbews, "notify::online",
- G_CALLBACK (e_cal_backend_ews_notify_online_cb), NULL);
+ connection = e_ews_connection_new (
+ hosturl, user, password->str, NULL, NULL, error);
+
+ g_free (hosturl);
+ g_free (user);
+
+ if (connection == NULL)
+ return E_SOURCE_AUTHENTICATION_ERROR;
+
+ store = backend->priv->store;
+ sync_state = e_cal_backend_store_get_key_value (store, SYNC_KEY);
+ sync_state_inout = g_strdup (sync_state);
+
+ e_ews_connection_sync_folder_items_sync (
+ connection,
+ EWS_PRIORITY_MEDIUM,
+ &sync_state_inout,
+ backend->priv->folder_id,
+ "IdOnly", NULL,
+ EWS_MAX_FETCH_COUNT,
+ &includes_last_item,
+ &items_created,
+ &items_updated,
+ &items_deleted,
+ cancellable, &local_error);
+
+ if (local_error == NULL) {
+ SyncItemsClosure *closure;
+
+ /* We can now report the password was accepted.
+ * Because a password dialog may be stuck in a busy
+ * state, process the synchronization results from an
+ * idle callback so we don't delay the authentication
+ * session any longer than neccessary. */
+
+ /* This takes ownership of the item lists. */
+ closure = g_slice_new0 (SyncItemsClosure);
+ closure->backend = g_object_ref (backend);
+ closure->connection = g_object_ref (connection);
+ closure->includes_last_item = includes_last_item;
+ closure->items_created = items_created;
+ closure->items_deleted = items_deleted;
+ closure->items_updated = items_updated;
+
+ g_idle_add_full (
+ G_PRIORITY_DEFAULT_IDLE,
+ cal_backend_ews_sync_items_idle_cb, closure,
+ (GDestroyNotify) sync_items_closure_free);
+
+ PRIV_LOCK (backend->priv);
+ if (backend->priv->cnc != NULL)
+ g_object_unref (backend->priv->cnc);
+ backend->priv->cnc = g_object_ref (connection);
+ PRIV_UNLOCK (backend->priv);
+
+ result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+
+ } else {
+ gboolean auth_failed;
+
+ /* Make sure we're not leaking anything. */
+ g_warn_if_fail (items_created == NULL);
+ g_warn_if_fail (items_updated == NULL);
+ g_warn_if_fail (items_deleted == NULL);
+
+ auth_failed = g_error_matches (
+ local_error, EWS_CONNECTION_ERROR,
+ EWS_CONNECTION_ERROR_AUTHENTICATION_FAILED);
+
+ if (auth_failed) {
+ g_clear_error (&local_error);
+ result = E_SOURCE_AUTHENTICATION_REJECTED;
+ } else {
+ g_propagate_error (error, local_error);
+ result = E_SOURCE_AUTHENTICATION_ERROR;
+ }
+ }
+
+ g_free (sync_state_inout);
+ g_object_unref (connection);
+
+ return result;
}
-/* Class initialization function for the ews backend */
static void
e_cal_backend_ews_class_init (ECalBackendEwsClass *class)
{
@@ -4059,8 +4143,6 @@ e_cal_backend_ews_class_init (ECalBackendEwsClass *class)
object_class = (GObjectClass *) class;
backend_class = (ECalBackendClass *) class;
- parent_class = g_type_class_peek_parent (class);
-
object_class->dispose = e_cal_backend_ews_dispose;
object_class->finalize = e_cal_backend_ews_finalize;
@@ -4073,8 +4155,7 @@ e_cal_backend_ews_class_init (ECalBackendEwsClass *class)
backend_class->add_timezone = e_cal_backend_ews_add_timezone;
backend_class->get_timezone = e_cal_backend_ews_get_timezone;
- backend_class->open = e_cal_backend_ews_open_compat;
- backend_class->authenticate_user = e_cal_backend_ews_authenticate_user;
+ backend_class->open = e_cal_backend_ews_open;
backend_class->refresh = e_cal_backend_ews_refresh;
backend_class->get_object = e_cal_backend_ews_get_object;
backend_class->get_object_list = e_cal_backend_ews_get_object_list;
@@ -4093,3 +4174,33 @@ e_cal_backend_ews_class_init (ECalBackendEwsClass *class)
/* backend_class->get_changes = e_cal_backend_ews_get_changes; */
backend_class->internal_get_timezone = e_cal_backend_ews_internal_get_timezone;
}
+
+static void
+e_cal_backend_ews_authenticator_init (ESourceAuthenticatorInterface *interface)
+{
+ interface->try_password_sync = cal_backend_ews_try_password_sync;
+}
+
+static void
+e_cal_backend_ews_init (ECalBackendEws *cbews)
+{
+ ECalBackendEwsPrivate *priv;
+
+ priv = g_new0 (ECalBackendEwsPrivate, 1);
+
+ /* create the mutex for thread safety */
+ g_static_rec_mutex_init (&priv->rec_mutex);
+ priv->item_id_hash = g_hash_table_new_full
+ (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+ priv->default_zone = icaltimezone_get_utc_timezone ();
+ priv->cancellable = g_cancellable_new ();
+
+ cbews->priv = priv;
+
+ g_signal_connect (
+ cbews, "notify::online",
+ G_CALLBACK (e_cal_backend_ews_notify_online_cb), NULL);
+}
+
diff --git a/src/camel/camel-ews-folder.c b/src/camel/camel-ews-folder.c
index 36ae586..f50c061 100644
--- a/src/camel/camel-ews-folder.c
+++ b/src/camel/camel-ews-folder.c
@@ -45,12 +45,12 @@ which needs to be better organized via functions */
#include <libical/icalcomponent.h>
#include <libical/icalparser.h>
+#include "server/camel-ews-settings.h"
#include "server/e-ews-connection.h"
#include "server/e-ews-item-change.h"
#include "server/e-ews-message.h"
#include "utils/ews-camel-common.h"
-#include "utils/camel-ews-settings.h"
#include "camel-ews-folder.h"
#include "camel-ews-private.h"
diff --git a/src/camel/camel-ews-store.c b/src/camel/camel-ews-store.c
index be33b7b..f7881e3 100644
--- a/src/camel/camel-ews-store.c
+++ b/src/camel/camel-ews-store.c
@@ -38,12 +38,10 @@
#include <libedataserver/e-flag.h>
+#include "server/camel-ews-settings.h"
#include "server/e-ews-item-change.h"
#include "server/e-ews-message.h"
-#include "utils/camel-ews-settings.h"
-#include "utils/ews-esource-utils.h"
-
#include "camel-ews-folder.h"
#include "camel-ews-store.h"
#include "camel-ews-summary.h"
@@ -167,11 +165,9 @@ ews_store_construct (CamelService *service,
GError **error)
{
CamelEwsStore *ews_store;
- CamelEwsStorePrivate *priv;
gchar *summary_file, *session_storage_path;
ews_store = (CamelEwsStore *) service;
- priv = ews_store->priv;
/* Disable virtual trash and junk folders. Exchange has real
* folders for that */
diff --git a/src/camel/camel-ews-transport.c b/src/camel/camel-ews-transport.c
index 6cc575b..32f85ee 100644
--- a/src/camel/camel-ews-transport.c
+++ b/src/camel/camel-ews-transport.c
@@ -30,7 +30,8 @@
#include <glib/gi18n-lib.h>
-#include "utils/camel-ews-settings.h"
+#include "server/camel-ews-settings.h"
+
#include "utils/ews-camel-common.h"
#include "camel-ews-store.h"
diff --git a/src/camel/camel-ews-utils.c b/src/camel/camel-ews-utils.c
index 701e81b..cf5f29f 100644
--- a/src/camel/camel-ews-utils.c
+++ b/src/camel/camel-ews-utils.c
@@ -30,11 +30,9 @@
#include <glib/gi18n-lib.h>
#include <glib/gstdio.h>
+#include "server/camel-ews-settings.h"
#include "server/e-ews-message.h"
-#include "utils/camel-ews-settings.h"
-#include "utils/ews-esource-utils.h"
-
#include "camel-ews-utils.h"
#define SUBFOLDER_DIR_NAME "subfolders"
@@ -320,44 +318,13 @@ camel_ews_utils_build_folder_info (CamelEwsStore *store,
return fi;
}
-struct remove_esrc_data {
- gchar *fid;
- CamelURL *account_url;
- EwsFolderType ftype;
-};
-
-static gboolean ews_do_remove_esource (gpointer user_data)
-{
- struct remove_esrc_data *remove_data = user_data;
-
- ews_esource_utils_remove_esource (remove_data->fid,
- remove_data->account_url,
- remove_data->ftype);
-
- camel_url_free (remove_data->account_url);
- g_free (remove_data->fid);
- g_free (remove_data);
-
- return FALSE;
-}
-
static void
sync_deleted_folders (CamelEwsStore *store,
GSList *deleted_folders)
{
CamelEwsStoreSummary *ews_summary = store->summary;
- CamelEwsSettings *ews_settings;
- CamelSettings *settings;
- CamelService *service;
- const gchar *email;
GSList *l;
- service = CAMEL_SERVICE (store);
- settings = camel_service_get_settings (service);
-
- ews_settings = CAMEL_EWS_SETTINGS (settings);
- email = camel_ews_settings_get_email (ews_settings);
-
for (l = deleted_folders; l != NULL; l = g_slist_next (l)) {
const gchar *fid = l->data;
EwsFolderType ftype;
@@ -375,15 +342,6 @@ sync_deleted_folders (CamelEwsStore *store,
camel_store_folder_deleted ((CamelStore *) store, fi);
g_clear_error (&error);
- } else {
- struct remove_esrc_data *remove_data = g_new0 (struct remove_esrc_data, 1);
-
- remove_data->fid = g_strdup (fid);
- remove_data->account_url = camel_service_new_camel_url (service);
- remove_data->ftype = ftype;
-
- /* This uses GConf so has to be done in the main thread */
- g_idle_add_full (G_PRIORITY_DEFAULT, ews_do_remove_esource, remove_data, NULL);
}
}
}
@@ -425,11 +383,7 @@ sync_updated_folders (CamelEwsStore *store,
const EwsFolderId *fid, *pfid;
ftype = e_ews_folder_get_folder_type (ews_folder);
- if (ftype == EWS_FOLDER_TYPE_CALENDAR ||
- ftype == EWS_FOLDER_TYPE_TASKS ||
- ftype == EWS_FOLDER_TYPE_CONTACTS) {
- /* TODO Update esource */
- } else if (ftype != EWS_FOLDER_TYPE_MAILBOX)
+ if (ftype != EWS_FOLDER_TYPE_MAILBOX)
continue;
fid = e_ews_folder_get_id (ews_folder);
@@ -516,58 +470,11 @@ add_folder_to_summary (CamelEwsStore *store,
camel_ews_store_summary_set_folder_unread (ews_summary, fid->id, unread);
}
-struct add_esrc_data {
- EEwsFolder *folder;
- gchar *account_uri;
- gchar *account_name;
- gchar *username;
- gchar *email_id;
- gchar *hosturl;
- gint refresh_timeout;
-};
-
-static gboolean ews_do_add_esource (gpointer user_data)
-{
- struct add_esrc_data *add_data = user_data;
-
- ews_esource_utils_add_esource (add_data->folder, add_data->account_uri,
- add_data->account_name,
- add_data->username, add_data->email_id,
- add_data->hosturl, add_data->refresh_timeout);
-
- g_object_unref (add_data->folder);
- g_free (add_data->account_uri);
- g_free (add_data->account_name);
- g_free (add_data->username);
- g_free (add_data->email_id);
- g_free (add_data->hosturl);
- g_free (add_data);
-
- return FALSE;
-}
-
static void
sync_created_folders (CamelEwsStore *ews_store,
GSList *created_folders)
{
- CamelNetworkSettings *network_settings;
- CamelEwsSettings *ews_settings;
- CamelSettings *settings;
- CamelService *service;
GSList *l;
- const gchar *email;
- const gchar *hosturl;
- const gchar *user;
-
- service = CAMEL_SERVICE (ews_store);
- settings = camel_service_get_settings (service);
-
- ews_settings = CAMEL_EWS_SETTINGS (settings);
- email = camel_ews_settings_get_email (ews_settings);
- hosturl = camel_ews_settings_get_hosturl (ews_settings);
-
- network_settings = CAMEL_NETWORK_SETTINGS (settings);
- user = camel_network_settings_get_user (network_settings);
for (l = created_folders; l != NULL; l = g_slist_next (l)) {
EEwsFolder *folder = (EEwsFolder *) l->data;
@@ -576,27 +483,7 @@ sync_created_folders (CamelEwsStore *ews_store,
const EwsFolderId *fid;
ftype = e_ews_folder_get_folder_type (folder);
- if (ftype == EWS_FOLDER_TYPE_CALENDAR ||
- ftype == EWS_FOLDER_TYPE_TASKS ||
- ftype == EWS_FOLDER_TYPE_CONTACTS) {
- struct add_esrc_data *add_data = g_new0 (struct add_esrc_data, 1);
- CamelURL *url = camel_service_new_camel_url (service);
-
- add_data->folder = g_object_ref (folder);
- add_data->account_uri = camel_url_to_string (url, CAMEL_URL_HIDE_PARAMS);
- add_data->account_name = g_strdup (email);
- add_data->username = g_strdup (user);
- /* Duplicate... for now */
- add_data->email_id = g_strdup (email);
- add_data->hosturl = g_strdup (hosturl);
- /* FIXME pass right refresh timeout */
-
- camel_url_free (url);
-
- /* This uses GConf so has to be done in the main thread */
- g_idle_add_full (G_PRIORITY_DEFAULT, ews_do_add_esource, add_data, NULL);
-
- } else if (ftype != EWS_FOLDER_TYPE_MAILBOX)
+ if (ftype != EWS_FOLDER_TYPE_MAILBOX)
continue;
fid = e_ews_folder_get_id (folder);
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
new file mode 100644
index 0000000..2659d42
--- /dev/null
+++ b/src/modules/Makefile.am
@@ -0,0 +1,76 @@
+NULL =
+
+# module-ews-backend is for evolution-data-server
+
+eds_module_LTLIBRARIES = module-ews-backend.la
+
+module_ews_backend_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src \
+ $(LIBEDATASERVER_CFLAGS) \
+ $(LIBEBACKEND_CFLAGS) \
+ $(SOUP_CFLAGS) \
+ $(NULL)
+
+module_ews_backend_la_SOURCES = \
+ module-ews-backend.c
+
+module_ews_backend_la_LIBADD = \
+ $(top_builddir)/src/server/libeews-1.2.la \
+ $(top_builddir)/src/utils/libewsutils.la \
+ $(LIBEDATASERVER_LIBS) \
+ $(LIBEBACKEND_LIBS) \
+ $(SOUP_LIBS) \
+ $(NULL)
+
+module_ews_backend_la_LDFLAGS = \
+ -module -avoid-version $(NO_UNDEFINED) \
+ $(NULL)
+
+# module-ews-mail-config is for evolution
+
+evo_module_LTLIBRARIES = module-ews-mail-config.la
+
+module_ews_mail_config_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src \
+ $(EVOLUTION_MAIL_CFLAGS) \
+ $(NULL)
+
+module_ews_mail_config_la_SOURCES = \
+ module-ews-mail-config.c \
+ e-mail-config-ews-autodiscover.c \
+ e-mail-config-ews-autodiscover.h \
+ e-mail-config-ews-backend.c \
+ e-mail-config-ews-backend.h \
+ e-mail-config-ews-gal.c \
+ e-mail-config-ews-gal.h \
+ e-mail-config-ews-oal-combo-box.c \
+ e-mail-config-ews-oal-combo-box.h \
+ e-mail-config-ews-ooo-page.c \
+ e-mail-config-ews-ooo-page.h \
+ $(NULL)
+
+module_ews_mail_config_la_LIBADD = \
+ $(top_builddir)/src/server/libeews-1.2.la \
+ $(top_builddir)/src/utils/libewsutils.la \
+ $(EVOLUTION_MAIL_LIBS) \
+ $(NULL)
+
+module_ews_mail_config_la_LDFLAGS = \
+ -module -avoid-version $(NO_UNDEFINED)
+
+error_DATA = module-ews-mail-config.error
+
+%.error: %.error.xml
+ $(AM_V_GEN) LC_ALL=C $(INTLTOOL_MERGE) -x -u /tmp/notthere $< $@
+
+EXTRA_DIST = module-ews-mail-config.error.xml
+
+BUILT_SOURCES = $(error_DATA)
+
+CLEANFILES = $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/src/modules/e-mail-config-ews-autodiscover.c b/src/modules/e-mail-config-ews-autodiscover.c
new file mode 100644
index 0000000..f301008
--- /dev/null
+++ b/src/modules/e-mail-config-ews-autodiscover.c
@@ -0,0 +1,345 @@
+/*
+ * e-mail-config-ews-autodiscover.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-config-ews-autodiscover.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <mail/e-mail-config-service-page.h>
+
+#include "server/e-ews-connection.h"
+
+#define E_MAIL_CONFIG_EWS_AUTODISCOVER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_AUTODISCOVER, EMailConfigEwsAutodiscoverPrivate))
+
+typedef struct _AsyncContext AsyncContext;
+
+struct _EMailConfigEwsAutodiscoverPrivate {
+ EMailConfigServiceBackend *backend;
+};
+
+struct _AsyncContext {
+ EMailConfigEwsAutodiscover *autodiscover;
+ EActivity *activity;
+};
+
+enum {
+ PROP_0,
+ PROP_BACKEND
+};
+
+/* Forward Declarations */
+static void e_mail_config_ews_autodiscover_authenticator_init
+ (ESourceAuthenticatorInterface *interface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (
+ EMailConfigEwsAutodiscover,
+ e_mail_config_ews_autodiscover,
+ GTK_TYPE_BUTTON,
+ 0,
+ G_IMPLEMENT_INTERFACE_DYNAMIC (
+ E_TYPE_SOURCE_AUTHENTICATOR,
+ e_mail_config_ews_autodiscover_authenticator_init))
+
+static void
+async_context_free (AsyncContext *async_context)
+{
+ if (async_context->autodiscover != NULL)
+ g_object_unref (async_context->autodiscover);
+
+ if (async_context->activity != NULL)
+ g_object_unref (async_context->activity);
+
+ g_slice_free (AsyncContext, async_context);
+}
+
+static void
+mail_config_ews_autodiscover_run_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ EMailConfigEwsAutodiscover *autodiscover;
+ EAlertSink *alert_sink;
+ GError *error = NULL;
+
+ autodiscover = async_context->autodiscover;
+ alert_sink = e_activity_get_alert_sink (async_context->activity);
+
+ e_source_registry_authenticate_finish (
+ E_SOURCE_REGISTRY (source_object), result, &error);
+
+ if (e_activity_handle_cancellation (async_context->activity, error)) {
+ g_error_free (error);
+
+ } else if (error != NULL) {
+ e_alert_submit (
+ alert_sink,
+ "ews:autodiscovery-error",
+ error->message, NULL);
+ g_error_free (error);
+ }
+
+ gtk_widget_set_sensitive (GTK_WIDGET (autodiscover), TRUE);
+
+ async_context_free (async_context);
+}
+
+static void
+mail_config_ews_autodiscover_run (EMailConfigEwsAutodiscover *autodiscover)
+{
+ EActivity *activity;
+ EMailConfigServicePage *page;
+ EMailConfigServiceBackend *backend;
+ ESourceRegistry *registry;
+ ESource *source;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ backend = e_mail_config_ews_autodiscover_get_backend (autodiscover);
+ page = e_mail_config_service_backend_get_page (backend);
+ source = e_mail_config_service_backend_get_source (backend);
+
+ registry = e_mail_config_service_page_get_registry (page);
+
+ activity = e_mail_config_service_page_new_activity (page);
+ cancellable = e_activity_get_cancellable (activity);
+
+ e_activity_set_text (activity, _("Querying Autodiscover service"));
+
+ gtk_widget_set_sensitive (GTK_WIDGET (autodiscover), FALSE);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->autodiscover = g_object_ref (autodiscover);
+ async_context->activity = activity; /* takes ownership */
+
+ e_source_registry_authenticate (
+ registry, source,
+ E_SOURCE_AUTHENTICATOR (autodiscover),
+ cancellable, mail_config_ews_autodiscover_run_cb,
+ async_context);
+}
+
+static void
+mail_config_ews_autodiscover_set_backend (EMailConfigEwsAutodiscover *autodiscover,
+ EMailConfigServiceBackend *backend)
+{
+ g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend));
+ g_return_if_fail (autodiscover->priv->backend == NULL);
+
+ autodiscover->priv->backend = g_object_ref (backend);
+}
+
+static void
+mail_config_ews_autodiscover_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BACKEND:
+ mail_config_ews_autodiscover_set_backend (
+ E_MAIL_CONFIG_EWS_AUTODISCOVER (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_config_ews_autodiscover_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BACKEND:
+ g_value_set_object (
+ value,
+ e_mail_config_ews_autodiscover_get_backend (
+ E_MAIL_CONFIG_EWS_AUTODISCOVER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_config_ews_autodiscover_dispose (GObject *object)
+{
+ EMailConfigEwsAutodiscoverPrivate *priv;
+
+ priv = E_MAIL_CONFIG_EWS_AUTODISCOVER_GET_PRIVATE (object);
+
+ if (priv->backend != NULL) {
+ g_object_unref (priv->backend);
+ priv->backend = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_config_ews_autodiscover_parent_class)->
+ dispose (object);
+}
+
+static void
+mail_config_ews_autodiscover_constructed (GObject *object)
+{
+ GtkButton *button;
+
+ button = GTK_BUTTON (object);
+ gtk_button_set_label (button, _("Fetch _URL"));
+ gtk_button_set_use_underline (button, TRUE);
+
+ /* Chain up tp parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_config_ews_autodiscover_parent_class)->
+ constructed (object);
+}
+
+static void
+mail_config_ews_autodiscover_clicked (GtkButton *button)
+{
+ EMailConfigEwsAutodiscover *autodiscover;
+
+ autodiscover = E_MAIL_CONFIG_EWS_AUTODISCOVER (button);
+
+ mail_config_ews_autodiscover_run (autodiscover);
+}
+
+static ESourceAuthenticationResult
+mail_config_ews_autodiscover_try_password_sync (ESourceAuthenticator *auth,
+ const GString *password,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EMailConfigEwsAutodiscover *autodiscover;
+ EMailConfigServiceBackend *backend;
+ EMailConfigServicePage *page;
+ CamelSettings *settings;
+ CamelEwsSettings *ews_settings;
+ ESourceAuthenticationResult result;
+ const gchar *email_address;
+ GError *local_error = NULL;
+
+ autodiscover = E_MAIL_CONFIG_EWS_AUTODISCOVER (auth);
+ backend = e_mail_config_ews_autodiscover_get_backend (autodiscover);
+ page = e_mail_config_service_backend_get_page (backend);
+ settings = e_mail_config_service_backend_get_settings (backend);
+
+ email_address = e_mail_config_service_page_get_email_address (page);
+
+ ews_settings = CAMEL_EWS_SETTINGS (settings);
+
+ e_ews_autodiscover_ws_url_sync (
+ ews_settings, email_address, password->str,
+ cancellable, &local_error);
+
+ if (local_error == NULL) {
+ result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+
+ } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+ result = E_SOURCE_AUTHENTICATION_REJECTED;
+ g_error_free (local_error);
+
+ } else {
+ result = E_SOURCE_AUTHENTICATION_ERROR;
+ g_propagate_error (error, local_error);
+ }
+
+ return result;
+}
+
+static void
+e_mail_config_ews_autodiscover_class_init (EMailConfigEwsAutodiscoverClass *class)
+{
+ GObjectClass *object_class;
+ GtkButtonClass *button_class;
+
+ g_type_class_add_private (
+ class, sizeof (EMailConfigEwsAutodiscoverPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_config_ews_autodiscover_set_property;
+ object_class->get_property = mail_config_ews_autodiscover_get_property;
+ object_class->dispose = mail_config_ews_autodiscover_dispose;
+ object_class->constructed = mail_config_ews_autodiscover_constructed;
+
+ button_class = GTK_BUTTON_CLASS (class);
+ button_class->clicked = mail_config_ews_autodiscover_clicked;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_BACKEND,
+ g_param_spec_object (
+ "backend",
+ "Backend",
+ "Mail configuration backend",
+ E_TYPE_MAIL_CONFIG_SERVICE_BACKEND,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+e_mail_config_ews_autodiscover_authenticator_init (ESourceAuthenticatorInterface *interface)
+{
+ interface->try_password_sync =
+ mail_config_ews_autodiscover_try_password_sync;
+}
+
+static void
+e_mail_config_ews_autodiscover_class_finalize (EMailConfigEwsAutodiscoverClass *class)
+{
+}
+
+static void
+e_mail_config_ews_autodiscover_init (EMailConfigEwsAutodiscover *autodiscover)
+{
+ autodiscover->priv =
+ E_MAIL_CONFIG_EWS_AUTODISCOVER_GET_PRIVATE (autodiscover);
+}
+
+void
+e_mail_config_ews_autodiscover_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_ews_autodiscover_register_type (type_module);
+}
+
+GtkWidget *
+e_mail_config_ews_autodiscover_new (EMailConfigServiceBackend *backend)
+{
+ g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_CONFIG_EWS_AUTODISCOVER,
+ "backend", backend, NULL);
+}
+
+EMailConfigServiceBackend *
+e_mail_config_ews_autodiscover_get_backend (EMailConfigEwsAutodiscover *autodiscover)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_CONFIG_EWS_AUTODISCOVER (autodiscover), NULL);
+
+ return autodiscover->priv->backend;
+}
+
diff --git a/src/modules/e-mail-config-ews-autodiscover.h b/src/modules/e-mail-config-ews-autodiscover.h
new file mode 100644
index 0000000..a6dd371
--- /dev/null
+++ b/src/modules/e-mail-config-ews-autodiscover.h
@@ -0,0 +1,71 @@
+/*
+ * e-mail-config-ews-autodiscover.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_CONFIG_EWS_AUTODISCOVER_H
+#define E_MAIL_CONFIG_EWS_AUTODISCOVER_H
+
+#include <mail/e-mail-config-service-backend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_CONFIG_EWS_AUTODISCOVER \
+ (e_mail_config_ews_autodiscover_get_type ())
+#define E_MAIL_CONFIG_EWS_AUTODISCOVER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_AUTODISCOVER, EMailConfigEwsAutodiscover))
+#define E_MAIL_CONFIG_EWS_AUTODISCOVER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_CONFIG_EWS_AUTODISCOVER, EMailConfigEwsAutodiscoverClass))
+#define E_IS_MAIL_CONFIG_EWS_AUTODISCOVER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_AUTODISCOVER))
+#define E_IS_MAIL_CONFIG_EWS_AUTODISCOVER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_CONFIG_EWS_AUTODISCOVER))
+#define E_MAIL_CONFIG_EWS_AUTODISCOVER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_AUTODISCOVER, EMailConfigEwsAutodiscoverClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailConfigEwsAutodiscover EMailConfigEwsAutodiscover;
+typedef struct _EMailConfigEwsAutodiscoverClass EMailConfigEwsAutodiscoverClass;
+typedef struct _EMailConfigEwsAutodiscoverPrivate EMailConfigEwsAutodiscoverPrivate;
+
+struct _EMailConfigEwsAutodiscover {
+ GtkButton parent;
+ EMailConfigEwsAutodiscoverPrivate *priv;
+};
+
+struct _EMailConfigEwsAutodiscoverClass {
+ GtkButtonClass parent_class;
+};
+
+GType e_mail_config_ews_autodiscover_get_type
+ (void) G_GNUC_CONST;
+void e_mail_config_ews_autodiscover_type_register
+ (GTypeModule *type_module);
+GtkWidget * e_mail_config_ews_autodiscover_new
+ (EMailConfigServiceBackend *backend);
+EMailConfigServiceBackend *
+ e_mail_config_ews_autodiscover_get_backend
+ (EMailConfigEwsAutodiscover *autodiscover);
+
+G_END_DECLS
+
+#endif /* E_MAIL_CONFIG_EWS_AUTODISCOVER_H */
+
diff --git a/src/modules/e-mail-config-ews-backend.c b/src/modules/e-mail-config-ews-backend.c
new file mode 100644
index 0000000..7352269
--- /dev/null
+++ b/src/modules/e-mail-config-ews-backend.c
@@ -0,0 +1,352 @@
+/*
+ * e-mail-config-ews-backend.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-config-ews-backend.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+#include <libebackend/e-extension.h>
+#include <libedataserver/e-source-collection.h>
+
+#include <mail/e-mail-config-auth-check.h>
+#include <mail/e-mail-config-receiving-page.h>
+
+#include "server/camel-ews-settings.h"
+
+#include "e-mail-config-ews-autodiscover.h"
+
+#define E_MAIL_CONFIG_EWS_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_BACKEND, EMailConfigEwsBackendPrivate))
+
+struct _EMailConfigEwsBackendPrivate {
+ GtkWidget *user_entry; /* not referenced */
+ GtkWidget *host_entry; /* not referenced */
+ GtkWidget *url_button; /* not referenced */
+ GtkWidget *oab_entry; /* not referenced */
+ GtkWidget *auth_check; /* not referenced */
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+ EMailConfigEwsBackend,
+ e_mail_config_ews_backend,
+ E_TYPE_MAIL_CONFIG_SERVICE_BACKEND)
+
+static ESource *
+mail_config_ews_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 [Ews 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_ews_backend_insert_widgets (EMailConfigServiceBackend *backend,
+ GtkBox *parent)
+{
+ EMailConfigEwsBackendPrivate *priv;
+ EMailConfigServicePage *page;
+ ESource *source;
+ ESourceExtension *extension;
+ CamelSettings *settings;
+ GtkLabel *label;
+ GtkWidget *widget;
+ GtkWidget *container;
+ const gchar *extension_name;
+ const gchar *text;
+ gchar *markup;
+
+ priv = E_MAIL_CONFIG_EWS_BACKEND_GET_PRIVATE (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);
+ priv->user_entry = widget; /* do not reference */
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new_with_mnemonic (_("_Host URL:"));
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_grid_attach (GTK_GRID (container), widget, 0, 1, 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, 1, 1, 1);
+ priv->host_entry = widget; /* do not reference */
+ gtk_widget_show (widget);
+
+ widget = e_mail_config_ews_autodiscover_new (backend);
+ gtk_grid_attach (GTK_GRID (container), widget, 2, 1, 1, 1);
+ priv->url_button = widget; /* do not reference */
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new_with_mnemonic (_("OAB U_RL:"));
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_grid_attach (GTK_GRID (container), widget, 0, 2, 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, 2, 2, 1);
+ priv->oab_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 = e_mail_config_auth_check_new (backend);
+ gtk_widget_set_margin_left (widget, 12);
+ gtk_box_pack_start (GTK_BOX (parent), widget, FALSE, FALSE, 0);
+ priv->auth_check = widget; /* do not reference */
+ gtk_widget_show (widget);
+
+ g_object_bind_property (
+ settings, "user",
+ priv->user_entry, "text",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ g_object_bind_property (
+ settings, "hosturl",
+ priv->host_entry, "text",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ g_object_bind_property (
+ settings, "oaburl",
+ priv->oab_entry, "text",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ /* Don't use G_BINDING_SYNC_CREATE here since the widget
+ * chooses its initial mechanism more intelligently than
+ * a simple property binding would. */
+ g_object_bind_property (
+ settings, "auth-mechanism",
+ priv->auth_check, "active-mechanism",
+ G_BINDING_BIDIRECTIONAL);
+
+ 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. */
+ g_object_bind_property (
+ settings, "user",
+ extension, "identity",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+}
+
+static void
+mail_config_ews_backend_setup_defaults (EMailConfigServiceBackend *backend)
+{
+ CamelSettings *settings;
+ EMailConfigServicePage *page;
+ const gchar *email_address;
+ gchar **parts = NULL;
+
+ 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)
+ parts = g_strsplit (email_address, "@", 2);
+
+ if (parts != NULL && g_strv_length (parts) >= 2) {
+ CamelEwsSettings *ews_settings;
+ CamelNetworkSettings *network_settings;
+ gchar *hosturl;
+
+ g_strstrip (parts[0]); /* user name */
+ g_strstrip (parts[1]); /* domain name */
+
+ hosturl = g_strdup_printf (
+ "https://exchange.%s/EWS/Exchange.asmx", parts[1]);
+
+ ews_settings = CAMEL_EWS_SETTINGS (settings);
+ camel_ews_settings_set_hosturl (ews_settings, hosturl);
+
+ network_settings = CAMEL_NETWORK_SETTINGS (settings);
+ camel_network_settings_set_user (network_settings, parts[0]);
+
+ g_free (hosturl);
+ }
+
+ g_strfreev (parts);
+}
+
+static gboolean
+mail_config_ews_backend_check_complete (EMailConfigServiceBackend *backend)
+{
+ EMailConfigServicePage *page;
+ CamelSettings *settings;
+ CamelEwsSettings *ews_settings;
+ CamelNetworkSettings *network_settings;
+ const gchar *hosturl;
+ const gchar *user;
+
+ 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);
+
+ ews_settings = CAMEL_EWS_SETTINGS (settings);
+ hosturl = camel_ews_settings_get_hosturl (ews_settings);
+
+ network_settings = CAMEL_NETWORK_SETTINGS (settings);
+ user = camel_network_settings_get_user (network_settings);
+
+ if (hosturl == NULL || *hosturl == '\0')
+ return FALSE;
+
+ if (user == NULL || *user == '\0')
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+e_mail_config_ews_backend_class_init (EMailConfigEwsBackendClass *class)
+{
+ EMailConfigServiceBackendClass *backend_class;
+
+ g_type_class_add_private (
+ class, sizeof (EMailConfigEwsBackendPrivate));
+
+ backend_class = E_MAIL_CONFIG_SERVICE_BACKEND_CLASS (class);
+ backend_class->backend_name = "ews";
+ backend_class->new_collection = mail_config_ews_backend_new_collection;
+ backend_class->insert_widgets = mail_config_ews_backend_insert_widgets;
+ backend_class->setup_defaults = mail_config_ews_backend_setup_defaults;
+ backend_class->check_complete = mail_config_ews_backend_check_complete;
+}
+
+static void
+e_mail_config_ews_backend_class_finalize (EMailConfigEwsBackendClass *class)
+{
+}
+
+static void
+e_mail_config_ews_backend_init (EMailConfigEwsBackend *backend)
+{
+ backend->priv = E_MAIL_CONFIG_EWS_BACKEND_GET_PRIVATE (backend);
+}
+
+void
+e_mail_config_ews_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_ews_backend_register_type (type_module);
+}
+
diff --git a/src/modules/e-mail-config-ews-backend.h b/src/modules/e-mail-config-ews-backend.h
new file mode 100644
index 0000000..7d5de45
--- /dev/null
+++ b/src/modules/e-mail-config-ews-backend.h
@@ -0,0 +1,66 @@
+/*
+ * e-mail-config-ews-backend.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_CONFIG_EWS_BACKEND_H
+#define E_MAIL_CONFIG_EWS_BACKEND_H
+
+#include <mail/e-mail-config-service-backend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_CONFIG_EWS_BACKEND \
+ (e_mail_config_ews_backend_get_type ())
+#define E_MAIL_CONFIG_EWS_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_BACKEND, EMailConfigEwsBackend))
+#define E_MAIL_CONFIG_EWS_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_CONFIG_EWS_BACKEND, EMailConfigEwsBackendClass))
+#define E_IS_MAIL_CONFIG_EWS_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_BACKEND))
+#define E_IS_MAIL_CONFIG_EWS_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_CONFIG_EWS_BACKEND))
+#define E_MAIL_CONFIG_EWS_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_BACKEND, EMailConfigEwsBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailConfigEwsBackend EMailConfigEwsBackend;
+typedef struct _EMailConfigEwsBackendClass EMailConfigEwsBackendClass;
+typedef struct _EMailConfigEwsBackendPrivate EMailConfigEwsBackendPrivate;
+
+struct _EMailConfigEwsBackend {
+ EMailConfigServiceBackend parent;
+ EMailConfigEwsBackendPrivate *priv;
+};
+
+struct _EMailConfigEwsBackendClass {
+ EMailConfigServiceBackendClass parent_class;
+};
+
+GType e_mail_config_ews_backend_get_type
+ (void) G_GNUC_CONST;
+void e_mail_config_ews_backend_type_register
+ (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_MAIL_CONFIG_EWS_BACKEND_H */
+
diff --git a/src/modules/e-mail-config-ews-gal.c b/src/modules/e-mail-config-ews-gal.c
new file mode 100644
index 0000000..3a6c263
--- /dev/null
+++ b/src/modules/e-mail-config-ews-gal.c
@@ -0,0 +1,389 @@
+/*
+ * e-mail-config-ews-gal.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-config-ews-gal.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <mail/e-mail-config-provider-page.h>
+
+#include "server/camel-ews-settings.h"
+
+#include "e-mail-config-ews-oal-combo-box.h"
+
+#define E_MAIL_CONFIG_EWS_GAL_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_GAL, EMailConfigEwsGalPrivate))
+
+typedef struct _AsyncContext AsyncContext;
+
+struct _EMailConfigEwsGalPrivate {
+ GtkWidget *toggle_button; /* not referenced */
+ GtkWidget *combo_box; /* not referenced */
+ GtkWidget *fetch_button; /* not referenced */
+};
+
+struct _AsyncContext {
+ EMailConfigEwsGal *extension;
+ EActivity *activity;
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+ EMailConfigEwsGal,
+ e_mail_config_ews_gal,
+ E_TYPE_EXTENSION)
+
+static void
+async_context_free (AsyncContext *async_context)
+{
+ if (async_context->extension != NULL)
+ g_object_unref (async_context->extension);
+
+ if (async_context->activity != NULL)
+ g_object_unref (async_context->activity);
+
+ g_slice_free (AsyncContext, async_context);
+}
+
+static EMailConfigProviderPage *
+mail_config_ews_gal_get_provider_page (EMailConfigEwsGal *extension)
+{
+ EExtensible *extensible;
+
+ extensible = e_extension_get_extensible (E_EXTENSION (extension));
+
+ return E_MAIL_CONFIG_PROVIDER_PAGE (extensible);
+}
+
+static gboolean
+mail_config_ews_gal_string_to_boolean (GBinding *binding,
+ const GValue *source_value,
+ GValue *target_value,
+ gpointer unused)
+{
+ const gchar *v_string;
+ gboolean v_boolean;
+
+ v_string = g_value_get_string (source_value);
+ v_boolean = (v_string != NULL && *v_string != '\0');
+ g_value_set_boolean (target_value, v_boolean);
+
+ return TRUE;
+}
+
+static gboolean
+mail_config_ews_gal_oal_selected_to_active_id (GBinding *binding,
+ const GValue *source_value,
+ GValue *target_value,
+ gpointer unused)
+{
+ GObject *target_object;
+ GtkComboBox *combo_box;
+ const gchar *selected;
+ gchar *active_id;
+ gchar *active_text;
+
+ selected = g_value_get_string (source_value);
+
+ if (selected == NULL)
+ return FALSE;
+
+ /* Selected value is of the form "id:name". */
+ active_id = g_strdup (selected);
+ active_text = strrchr (active_id, ':');
+
+ if (active_text != NULL) {
+ *active_text++ = '\0';
+ } else {
+ g_free (active_id);
+ return FALSE;
+ }
+
+ target_object = g_binding_get_target (binding);
+ combo_box = GTK_COMBO_BOX (target_object);
+
+ /* The combo box might already have the OAL ID, in which case
+ * we simply make it the active combo box row. Otherwise we
+ * have to add a new row and make it the active row. */
+ if (!gtk_combo_box_set_active_id (combo_box, active_id)) {
+ gtk_combo_box_text_append (
+ GTK_COMBO_BOX_TEXT (combo_box),
+ active_id, active_text);
+ gtk_combo_box_set_active_id (combo_box, active_id);
+ }
+
+ g_free (active_id);
+
+ return TRUE;
+}
+
+static gboolean
+mail_config_ews_gal_active_id_to_oal_selected (GBinding *binding,
+ const GValue *source_value,
+ GValue *target_value,
+ gpointer unused)
+{
+ GObject *source_object;
+ GtkComboBoxText *combo_box;
+ const gchar *active_id;
+ const gchar *active_text;
+ gchar *selected = NULL;
+
+ source_object = g_binding_get_source (binding);
+ combo_box = GTK_COMBO_BOX_TEXT (source_object);
+
+ active_id = g_value_get_string (source_value);
+ active_text = gtk_combo_box_text_get_active_text (combo_box);
+
+ if (active_id != NULL && active_text != NULL)
+ selected = g_strdup_printf ("%s:%s", active_id, active_text);
+
+ g_value_set_string (target_value, selected);
+
+ g_free (selected);
+
+ return TRUE;
+}
+
+static void
+mail_config_ews_gal_fetch_list_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ EMailConfigEwsGal *extension;
+ EAlertSink *alert_sink;
+ GError *error = NULL;
+
+ extension = async_context->extension;
+ alert_sink = e_activity_get_alert_sink (async_context->activity);
+
+ e_mail_config_ews_oal_combo_box_update_finish (
+ E_MAIL_CONFIG_EWS_OAL_COMBO_BOX (source_object),
+ result, &error);
+
+ if (e_activity_handle_cancellation (async_context->activity, error)) {
+ g_error_free (error);
+
+ } else if (error != NULL) {
+ e_alert_submit (
+ alert_sink,
+ "ews:query-oal-error",
+ error->message, NULL);
+ g_error_free (error);
+ }
+
+ gtk_widget_set_sensitive (extension->priv->combo_box, TRUE);
+ gtk_widget_set_sensitive (extension->priv->fetch_button, TRUE);
+
+ async_context_free (async_context);
+}
+
+static void
+mail_config_ews_gal_fetch_list (EMailConfigEwsGal *extension)
+{
+ EActivity *activity;
+ EMailConfigProviderPage *page;
+ GtkWidget *combo_box;
+ GCancellable *cancellable;
+ AsyncContext *async_context;
+
+ combo_box = extension->priv->combo_box;
+
+ page = mail_config_ews_gal_get_provider_page (extension);
+
+ activity = e_mail_config_provider_page_new_activity (page);
+ cancellable = e_activity_get_cancellable (activity);
+
+ e_activity_set_text (activity, _("Locating offline address books"));
+
+ gtk_widget_set_sensitive (extension->priv->combo_box, FALSE);
+ gtk_widget_set_sensitive (extension->priv->fetch_button, FALSE);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->extension = g_object_ref (extension);
+ async_context->activity = activity; /* takes ownership */
+
+ e_mail_config_ews_oal_combo_box_update (
+ E_MAIL_CONFIG_EWS_OAL_COMBO_BOX (combo_box),
+ cancellable, mail_config_ews_gal_fetch_list_cb,
+ async_context);
+}
+
+static void
+mail_config_ews_gal_fetch_button_clicked_cb (GtkButton *button,
+ EMailConfigEwsGal *extension)
+{
+ mail_config_ews_gal_fetch_list (extension);
+}
+
+static void
+mail_config_ews_gal_constructed (GObject *object)
+{
+ EMailConfigEwsGal *extension;
+ EMailConfigProviderPage *page;
+ EMailConfigServiceBackend *backend;
+ CamelSettings *settings;
+ GtkWidget *container;
+ GtkWidget *widget;
+ GtkLabel *label;
+ const gchar *text;
+ gchar *markup;
+
+ extension = E_MAIL_CONFIG_EWS_GAL (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_config_ews_gal_parent_class)->
+ constructed (object);
+
+ page = mail_config_ews_gal_get_provider_page (extension);
+ backend = e_mail_config_provider_page_get_backend (page);
+ settings = e_mail_config_service_backend_get_settings (backend);
+
+ /* A provider page is created for every available CamelStore
+ * class. We're only interested in the one for CamelEwsStore.
+ * We determine this by the CamelSettings type returned. */
+ if (!CAMEL_IS_EWS_SETTINGS (settings))
+ return;
+
+ container = GTK_WIDGET (page);
+
+ text = _("Global Address List");
+ 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 (container), 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 (page), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ g_object_bind_property_full (
+ settings, "oaburl",
+ widget, "sensitive",
+ G_BINDING_SYNC_CREATE,
+ mail_config_ews_gal_string_to_boolean,
+ NULL,
+ NULL, (GDestroyNotify) NULL);
+
+ container = widget;
+
+ text = _("Cache o_ffline address book");
+ widget = gtk_check_button_new_with_mnemonic (text);
+ gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 1, 1);
+ extension->priv->toggle_button = widget; /* do not reference */
+ gtk_widget_show (widget);
+
+ g_object_bind_property (
+ settings, "oab-offline",
+ widget, "active",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE);
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_widget_set_margin_left (widget, 12);
+ gtk_box_set_spacing (GTK_BOX (widget), 6);
+ gtk_grid_attach (GTK_GRID (container), widget, 0, 1, 1, 1);
+ gtk_widget_show (widget);
+
+ g_object_bind_property (
+ settings, "oab-offline",
+ widget, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ container = widget;
+
+ text = _("Select ad_dress list:");
+ widget = gtk_label_new_with_mnemonic (text);
+ gtk_widget_set_margin_left (widget, 12);
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ label = GTK_LABEL (widget);
+
+ widget = e_mail_config_ews_oal_combo_box_new (backend);
+ gtk_label_set_mnemonic_widget (label, widget);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ extension->priv->combo_box = widget; /* do not reference */
+ gtk_widget_show (widget);
+
+ g_object_bind_property_full (
+ settings, "oal-selected",
+ widget, "active-id",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE,
+ mail_config_ews_gal_oal_selected_to_active_id,
+ mail_config_ews_gal_active_id_to_oal_selected,
+ NULL, (GDestroyNotify) NULL);
+
+ widget = gtk_button_new_with_label (_("Fetch List"));
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ extension->priv->fetch_button = widget; /* do not reference */
+ gtk_widget_show (widget);
+
+ g_signal_connect (
+ widget, "clicked",
+ G_CALLBACK (mail_config_ews_gal_fetch_button_clicked_cb),
+ extension);
+}
+
+static void
+e_mail_config_ews_gal_class_init (EMailConfigEwsGalClass *class)
+{
+ GObjectClass *object_class;
+ EExtensionClass *extension_class;
+
+ g_type_class_add_private (class, sizeof (EMailConfigEwsGalPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = mail_config_ews_gal_constructed;
+
+ extension_class = E_EXTENSION_CLASS (class);
+ extension_class->extensible_type = E_TYPE_MAIL_CONFIG_PROVIDER_PAGE;
+}
+
+static void
+e_mail_config_ews_gal_class_finalize (EMailConfigEwsGalClass *class)
+{
+}
+
+static void
+e_mail_config_ews_gal_init (EMailConfigEwsGal *extension)
+{
+ extension->priv = E_MAIL_CONFIG_EWS_GAL_GET_PRIVATE (extension);
+}
+
+void
+e_mail_config_ews_gal_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_ews_gal_register_type (type_module);
+}
+
diff --git a/src/modules/e-mail-config-ews-gal.h b/src/modules/e-mail-config-ews-gal.h
new file mode 100644
index 0000000..2ab1db7
--- /dev/null
+++ b/src/modules/e-mail-config-ews-gal.h
@@ -0,0 +1,65 @@
+/*
+ * e-mail-config-ews-gal.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_CONFIG_EWS_GAL_H
+#define E_MAIL_CONFIG_EWS_GAL_H
+
+#include <libebackend/e-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_CONFIG_EWS_GAL \
+ (e_mail_config_ews_gal_get_type ())
+#define E_MAIL_CONFIG_EWS_GAL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_GAL, EMailConfigEwsGal))
+#define E_MAIL_CONFIG_EWS_GAL_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_CONFIG_EWS_GAL, EMailConfigEwsGalClass))
+#define E_IS_MAIL_CONFIG_EWS_GAL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_GAL))
+#define E_IS_MAIL_CONFIG_EWS_GAL_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_CONFIG_EWS_GAL))
+#define E_MAIL_CONFIG_EWS_GAL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_GAL, EMailConfigEwsGalClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailConfigEwsGal EMailConfigEwsGal;
+typedef struct _EMailConfigEwsGalClass EMailConfigEwsGalClass;
+typedef struct _EMailConfigEwsGalPrivate EMailConfigEwsGalPrivate;
+
+struct _EMailConfigEwsGal {
+ EExtension parent;
+ EMailConfigEwsGalPrivate *priv;
+};
+
+struct _EMailConfigEwsGalClass {
+ EExtensionClass parent_class;
+};
+
+GType e_mail_config_ews_gal_get_type (void) G_GNUC_CONST;
+void e_mail_config_ews_gal_type_register
+ (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_MAIL_CONFIG_EWS_GAL_H */
+
diff --git a/src/modules/e-mail-config-ews-oal-combo-box.c b/src/modules/e-mail-config-ews-oal-combo-box.c
new file mode 100644
index 0000000..5aa08a5
--- /dev/null
+++ b/src/modules/e-mail-config-ews-oal-combo-box.c
@@ -0,0 +1,365 @@
+/*
+ * e-mail-config-ews-oal-combo-box.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-config-ews-oal-combo-box.h"
+
+#include <mail/e-mail-config-service-page.h>
+
+#include "server/e-ews-connection.h"
+
+#define E_MAIL_CONFIG_EWS_OAL_COMBO_BOX_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_OAL_COMBO_BOX, EMailConfigEwsOalComboBoxPrivate))
+
+struct _EMailConfigEwsOalComboBoxPrivate {
+ EMailConfigServiceBackend *backend;
+
+ /* The try_password() method deposits results here, and the
+ * update_finish() function uses the results to re-populate
+ * the combo box. This avoids calling GTK+ functions from
+ * multiple threads. */
+ GSList *oal_items;
+ GMutex *oal_items_lock;
+};
+
+enum {
+ PROP_0,
+ PROP_BACKEND
+};
+
+/* Forward Declarations */
+static void e_mail_config_ews_oal_combo_box_authenticator_init
+ (ESourceAuthenticatorInterface *interface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (
+ EMailConfigEwsOalComboBox,
+ e_mail_config_ews_oal_combo_box,
+ GTK_TYPE_COMBO_BOX_TEXT,
+ 0,
+ G_IMPLEMENT_INTERFACE_DYNAMIC (
+ E_TYPE_SOURCE_AUTHENTICATOR,
+ e_mail_config_ews_oal_combo_box_authenticator_init))
+
+static void
+mail_config_ews_oal_combo_box_set_backend (EMailConfigEwsOalComboBox *combo_box,
+ EMailConfigServiceBackend *backend)
+{
+ g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend));
+ g_return_if_fail (combo_box->priv->backend == NULL);
+
+ combo_box->priv->backend = g_object_ref (backend);
+}
+
+static void
+mail_config_ews_oal_combo_box_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BACKEND:
+ mail_config_ews_oal_combo_box_set_backend (
+ E_MAIL_CONFIG_EWS_OAL_COMBO_BOX (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_config_ews_oal_combo_box_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BACKEND:
+ g_value_set_object (
+ value,
+ e_mail_config_ews_oal_combo_box_get_backend (
+ E_MAIL_CONFIG_EWS_OAL_COMBO_BOX (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_config_ews_oal_combo_box_dispose (GObject *object)
+{
+ EMailConfigEwsOalComboBoxPrivate *priv;
+
+ priv = E_MAIL_CONFIG_EWS_OAL_COMBO_BOX_GET_PRIVATE (object);
+
+ if (priv->backend != NULL) {
+ g_object_ref (priv->backend);
+ priv->backend = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_config_ews_oal_combo_box_parent_class)->
+ dispose (object);
+}
+
+static void
+mail_config_ews_oal_combo_box_finalize (GObject *object)
+{
+ EMailConfigEwsOalComboBoxPrivate *priv;
+
+ priv = E_MAIL_CONFIG_EWS_OAL_COMBO_BOX_GET_PRIVATE (object);
+
+ g_mutex_free (priv->oal_items_lock);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_mail_config_ews_oal_combo_box_parent_class)->
+ finalize (object);
+}
+
+static ESourceAuthenticationResult
+mail_config_ews_oal_combo_box_try_password_sync (ESourceAuthenticator *auth,
+ const GString *password,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EMailConfigEwsOalComboBox *combo_box;
+ EMailConfigServiceBackend *backend;
+ CamelSettings *settings;
+ CamelEwsSettings *ews_settings;
+ CamelNetworkSettings *network_settings;
+ ESourceAuthenticationResult result;
+ EEwsConnection *cnc;
+ GSList *oal_items = NULL;
+ const gchar *oab_url;
+ const gchar *user;
+ GError *local_error = NULL;
+
+ combo_box = E_MAIL_CONFIG_EWS_OAL_COMBO_BOX (auth);
+ backend = e_mail_config_ews_oal_combo_box_get_backend (combo_box);
+ settings = e_mail_config_service_backend_get_settings (backend);
+
+ ews_settings = CAMEL_EWS_SETTINGS (settings);
+ oab_url = camel_ews_settings_get_oaburl (ews_settings);
+
+ network_settings = CAMEL_NETWORK_SETTINGS (settings);
+ user = camel_network_settings_get_user (network_settings);
+
+ /* XXX This takes a GError but never fails, so skip it. */
+ cnc = e_ews_connection_new (
+ oab_url, user, password->str, NULL, NULL, NULL);
+
+ e_ews_connection_get_oal_list_sync (
+ cnc, &oal_items, cancellable, &local_error);
+
+ g_object_unref (cnc);
+
+ if (local_error == NULL) {
+ result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+
+ /* Deposit results in the private struct for
+ * the update_finish() function to pick up. */
+ g_mutex_lock (combo_box->priv->oal_items_lock);
+ g_slist_free_full (
+ combo_box->priv->oal_items,
+ (GDestroyNotify) ews_oal_free);
+ combo_box->priv->oal_items = oal_items;
+ g_mutex_unlock (combo_box->priv->oal_items_lock);
+
+ } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+ result = E_SOURCE_AUTHENTICATION_REJECTED;
+ g_error_free (local_error);
+
+ } else {
+ result = E_SOURCE_AUTHENTICATION_ERROR;
+ g_propagate_error (error, local_error);
+ }
+
+ return result;
+}
+
+static void
+e_mail_config_ews_oal_combo_box_class_init (EMailConfigEwsOalComboBoxClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (
+ class, sizeof (EMailConfigEwsOalComboBoxPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_config_ews_oal_combo_box_set_property;
+ object_class->get_property = mail_config_ews_oal_combo_box_get_property;
+ object_class->dispose = mail_config_ews_oal_combo_box_dispose;
+ object_class->finalize = mail_config_ews_oal_combo_box_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_BACKEND,
+ g_param_spec_object (
+ "backend",
+ "Backend",
+ "Service backend",
+ E_TYPE_MAIL_CONFIG_SERVICE_BACKEND,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+e_mail_config_ews_oal_combo_box_authenticator_init (ESourceAuthenticatorInterface *interface)
+{
+ interface->try_password_sync =
+ mail_config_ews_oal_combo_box_try_password_sync;
+}
+
+static void
+e_mail_config_ews_oal_combo_box_class_finalize (EMailConfigEwsOalComboBoxClass *class)
+{
+}
+
+static void
+e_mail_config_ews_oal_combo_box_init (EMailConfigEwsOalComboBox *combo_box)
+{
+ combo_box->priv =
+ E_MAIL_CONFIG_EWS_OAL_COMBO_BOX_GET_PRIVATE (combo_box);
+
+ combo_box->priv->oal_items_lock = g_mutex_new ();
+}
+
+void
+e_mail_config_ews_oal_combo_box_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_ews_oal_combo_box_register_type (type_module);
+}
+
+GtkWidget *
+e_mail_config_ews_oal_combo_box_new (EMailConfigServiceBackend *backend)
+{
+ g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_CONFIG_EWS_OAL_COMBO_BOX,
+ "backend", backend, NULL);
+}
+
+EMailConfigServiceBackend *
+e_mail_config_ews_oal_combo_box_get_backend (EMailConfigEwsOalComboBox *combo_box)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_CONFIG_EWS_OAL_COMBO_BOX (combo_box), NULL);
+
+ return combo_box->priv->backend;
+}
+
+/* Helper for e_mail_config_ews_oal_combo_box_update() */
+static void
+mail_config_ews_oal_combo_box_update_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ GError *error = NULL;
+
+ simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ e_source_registry_authenticate_finish (
+ E_SOURCE_REGISTRY (source_object), result, &error);
+
+ if (error != NULL)
+ g_simple_async_result_take_error (simple, error);
+
+ g_simple_async_result_complete (simple);
+
+ g_object_unref (simple);
+}
+
+void
+e_mail_config_ews_oal_combo_box_update (EMailConfigEwsOalComboBox *combo_box,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ EMailConfigServicePage *page;
+ EMailConfigServiceBackend *backend;
+ ESourceAuthenticator *authenticator;
+ ESourceRegistry *registry;
+ ESource *source;
+
+ g_return_if_fail (E_IS_MAIL_CONFIG_EWS_OAL_COMBO_BOX (combo_box));
+
+ backend = e_mail_config_ews_oal_combo_box_get_backend (combo_box);
+ page = e_mail_config_service_backend_get_page (backend);
+ source = e_mail_config_service_backend_get_source (backend);
+ registry = e_mail_config_service_page_get_registry (page);
+
+ authenticator = E_SOURCE_AUTHENTICATOR (combo_box);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (combo_box), callback, user_data,
+ e_mail_config_ews_oal_combo_box_update);
+
+ e_source_registry_authenticate (
+ registry, source, authenticator, cancellable,
+ mail_config_ews_oal_combo_box_update_cb, simple);
+}
+
+gboolean
+e_mail_config_ews_oal_combo_box_update_finish (EMailConfigEwsOalComboBox *combo_box,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ GtkComboBoxText *combo_box_text;
+ GSList *list, *link;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (combo_box),
+ e_mail_config_ews_oal_combo_box_update), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ /* Re-populate the combo box using the cached results. */
+
+ g_mutex_lock (combo_box->priv->oal_items_lock);
+ list = combo_box->priv->oal_items;
+ combo_box->priv->oal_items = NULL;
+ g_mutex_unlock (combo_box->priv->oal_items_lock);
+
+ combo_box_text = GTK_COMBO_BOX_TEXT (combo_box);
+ gtk_combo_box_text_remove_all (combo_box_text);
+
+ for (link = list; link != NULL; link = g_slist_next (link)) {
+ EwsOAL *oal = link->data;
+
+ gtk_combo_box_text_append (
+ combo_box_text, oal->id, oal->name);
+ }
+
+ g_slist_free_full (list, (GDestroyNotify) ews_oal_free);
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
+
+ return TRUE;
+}
+
diff --git a/src/modules/e-mail-config-ews-oal-combo-box.h b/src/modules/e-mail-config-ews-oal-combo-box.h
new file mode 100644
index 0000000..8510044
--- /dev/null
+++ b/src/modules/e-mail-config-ews-oal-combo-box.h
@@ -0,0 +1,82 @@
+/*
+ * e-mail-config-ews-oal-combo-box.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_CONFIG_EWS_OAL_COMBO_BOX_H
+#define E_MAIL_CONFIG_EWS_OAL_COMBO_BOX_H
+
+#include <gtk/gtk.h>
+#include <mail/e-mail-config-service-backend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_CONFIG_EWS_OAL_COMBO_BOX \
+ (e_mail_config_ews_oal_combo_box_get_type ())
+#define E_MAIL_CONFIG_EWS_OAL_COMBO_BOX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_OAL_COMBO_BOX, EMailConfigEwsOalComboBox))
+#define E_MAIL_CONFIG_EWS_OAL_COMBO_BOX_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_CONFIG_EWS_OAL_COMBO_BOX, EMailConfigEwsOalComboBoxClass))
+#define E_IS_MAIL_CONFIG_EWS_OAL_COMBO_BOX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_OAL_COMBO_BOX))
+#define E_IS_MAIL_CONFIG_EWS_OAL_COMBO_BOX_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_CONFIG_EWS_OAL_COMBO_BOX))
+#define E_MAIL_CONFIG_EWS_OAL_COMBO_BOX_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_OAL_COMBO_BOX, EMailConfigEwsOalComboBoxClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailConfigEwsOalComboBox EMailConfigEwsOalComboBox;
+typedef struct _EMailConfigEwsOalComboBoxClass EMailConfigEwsOalComboBoxClass;
+typedef struct _EMailConfigEwsOalComboBoxPrivate EMailConfigEwsOalComboBoxPrivate;
+
+struct _EMailConfigEwsOalComboBox {
+ GtkComboBoxText parent;
+ EMailConfigEwsOalComboBoxPrivate *priv;
+};
+
+struct _EMailConfigEwsOalComboBoxClass {
+ GtkComboBoxTextClass parent_class;
+};
+
+GType e_mail_config_ews_oal_combo_box_get_type
+ (void) G_GNUC_CONST;
+void e_mail_config_ews_oal_combo_box_type_register
+ (GTypeModule *type_module);
+GtkWidget * e_mail_config_ews_oal_combo_box_new
+ (EMailConfigServiceBackend *backend);
+EMailConfigServiceBackend *
+ e_mail_config_ews_oal_combo_box_get_backend
+ (EMailConfigEwsOalComboBox *combo_box);
+void e_mail_config_ews_oal_combo_box_update
+ (EMailConfigEwsOalComboBox *combo_box,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_mail_config_ews_oal_combo_box_update_finish
+ (EMailConfigEwsOalComboBox *combo_box,
+ GAsyncResult *result,
+ GError **error);
+
+
+G_END_DECLS
+
+#endif /* E_MAIL_CONFIG_EWS_OAL_COMBO_BOX_H */
+
diff --git a/src/modules/e-mail-config-ews-ooo-page.c b/src/modules/e-mail-config-ews-ooo-page.c
new file mode 100644
index 0000000..2cafd0a
--- /dev/null
+++ b/src/modules/e-mail-config-ews-ooo-page.c
@@ -0,0 +1,937 @@
+/*
+ * e-mail-config-ews-ooo-page.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-config-ews-ooo-page.h"
+
+#include <config.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+
+#include <misc/e-dateedit.h>
+#include <e-util/e-dialog-utils.h>
+
+#include "server/camel-ews-settings.h"
+#include "server/e-ews-connection.h"
+
+#define E_MAIL_CONFIG_EWS_OOO_PAGE_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_OOO_PAGE, EMailConfigEwsOooPagePrivate))
+
+typedef enum {
+ EXTERNAL_AUDIENCE_NONE,
+ EXTERNAL_AUDIENCE_KNOWN,
+ EXTERNAL_AUDIENCE_ALL
+} ExternalAudience;
+
+struct _EMailConfigEwsOooPagePrivate {
+ ESource *account_source;
+ ESource *identity_source;
+
+ gboolean state;
+
+ /*to set duration or not*/
+ gboolean set_range;
+ GtkWidget *range_wt;
+
+ /*duration for out of office*/
+ time_t from_time;
+ time_t to_time;
+ EDateEdit *from_date;
+ EDateEdit *to_date;
+
+ /*External Audience type*/
+ gchar *audience;
+ gint audience_type;
+ GtkWidget *aud_box;
+
+ /*Internal and External messages*/
+ gchar *external_message;
+ gchar *internal_message;
+ GtkWidget *external_view;
+ GtkWidget *internal_view;
+
+ /*Update box*/
+ GtkWidget *stat_box;
+};
+
+enum {
+ PROP_0,
+ PROP_ACCOUNT_SOURCE,
+ PROP_IDENTITY_SOURCE
+};
+
+/* Forward Declarations */
+static void e_mail_config_ews_ooo_page_interface_init
+ (EMailConfigPageInterface *interface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (
+ EMailConfigEwsOooPage,
+ e_mail_config_ews_ooo_page,
+ GTK_TYPE_BOX,
+ 0,
+ G_IMPLEMENT_INTERFACE_DYNAMIC (
+ E_TYPE_MAIL_CONFIG_PAGE,
+ e_mail_config_ews_ooo_page_interface_init))
+
+static void
+update_audience_type (void)
+{
+#if 0 /* ACCOUNT_MGMT */
+ if (!g_ascii_strcasecmp (oof_data->audience, "None"))
+ oof_data->audience_type = EXTERNAL_AUDIENCE_NONE;
+ else if (!g_ascii_strcasecmp (oof_data->audience, "Known"))
+ oof_data->audience_type = EXTERNAL_AUDIENCE_KNOWN;
+ else
+ oof_data->audience_type = EXTERNAL_AUDIENCE_ALL;
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+update_audience (void)
+{
+#if 0 /* ACCOUNT_MGMT */
+ g_free (oof_data->audience);
+ oof_data->audience = NULL;
+
+ if (oof_data->audience_type == EXTERNAL_AUDIENCE_NONE)
+ oof_data->audience = g_strdup ("None");
+ else if (oof_data->audience_type == EXTERNAL_AUDIENCE_KNOWN)
+ oof_data->audience = g_strdup ("Known");
+ else
+ oof_data->audience = g_strdup ("All");
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+update_audience_cb (GtkComboBoxText *combo,
+ gpointer data)
+{
+#if 0 /* ACCOUNT_MGMT */
+ gint active;
+
+ active = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
+ if (active == oof_data->audience_type)
+ return;
+ else
+ oof_data->audience_type = active;
+
+ update_audience ();
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+update_int_msg_cb (GtkTextBuffer *buffer,
+ gpointer data)
+{
+#if 0 /* ACCOUNT_MGMT */
+ if (gtk_text_buffer_get_modified (buffer)) {
+ GtkTextIter start, end;
+ if (oof_data->internal_message)
+ g_free (oof_data->internal_message);
+ gtk_text_buffer_get_bounds (buffer, &start, &end);
+ oof_data->internal_message = gtk_text_buffer_get_text (buffer, &start,
+ &end, FALSE);
+ gtk_text_buffer_set_modified (buffer, FALSE);
+ }
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+update_ext_msg_cb (GtkTextBuffer *buffer,
+ gpointer data)
+{
+#if 0 /* ACCOUNT_MGMT */
+ if (gtk_text_buffer_get_modified (buffer)) {
+ GtkTextIter start, end;
+ if (oof_data->external_message)
+ g_free (oof_data->external_message);
+ gtk_text_buffer_get_bounds (buffer, &start, &end);
+ oof_data->external_message = gtk_text_buffer_get_text (buffer, &start,
+ &end, FALSE);
+ gtk_text_buffer_set_modified (buffer, FALSE);
+ }
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+toggled_state_cb (GtkToggleButton *button,
+ gpointer data)
+{
+#if 0 /* ACCOUNT_MGMT */
+ gboolean current_oof_state;
+
+ current_oof_state = gtk_toggle_button_get_active (button);
+ if (current_oof_state == oof_data->state)
+ return;
+ oof_data->state = current_oof_state;
+ gtk_widget_set_sensitive (oof_data->range_wt, current_oof_state);
+ gtk_widget_set_sensitive (oof_data->internal_view, current_oof_state);
+ gtk_widget_set_sensitive (oof_data->external_view, current_oof_state);
+ gtk_widget_set_sensitive ((GtkWidget *) oof_data->from_date, current_oof_state && oof_data->set_range);
+ gtk_widget_set_sensitive ((GtkWidget *) oof_data->to_date, current_oof_state && oof_data->set_range);
+ gtk_widget_set_sensitive (oof_data->aud_box, current_oof_state);
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+toggled_set_date_cb (GtkToggleButton *button,
+ gpointer data)
+{
+#if 0 /* ACCOUNT_MGMT */
+ gboolean current_state;
+
+ current_state = gtk_toggle_button_get_active (button);
+ if (current_state == oof_data->set_range)
+ return;
+
+ oof_data->set_range = current_state;
+ gtk_widget_set_sensitive ((GtkWidget *) oof_data->from_date, current_state);
+ gtk_widget_set_sensitive ((GtkWidget *) oof_data->to_date, current_state);
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+from_time_changed_cb (EDateEdit *date_tm,
+ gpointer data)
+{
+#if 0 /* ACCOUNT_MGMT */
+ if (e_date_edit_get_time (date_tm) < time (NULL)) {
+ e_notice (NULL, GTK_MESSAGE_WARNING, _("Cannot set Date-Time in Past"));
+ e_date_edit_set_time (date_tm, time (NULL) + 60);
+ } else if (e_date_edit_date_is_valid (date_tm) && e_date_edit_time_is_valid (date_tm)) {
+ oof_data->from_time = e_date_edit_get_time (date_tm);
+ }
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+to_time_changed_cb (EDateEdit *date_tm,
+ gpointer data)
+{
+#if 0 /* ACCOUNT_MGMT */
+ if (e_date_edit_get_time (date_tm) < time (NULL)) {
+ e_notice (NULL, GTK_MESSAGE_WARNING, _("Cannot set Date-Time in Past"));
+ e_date_edit_set_time (date_tm, time (NULL) + 60);
+ return;
+ } else if (e_date_edit_date_is_valid (date_tm) && e_date_edit_time_is_valid (date_tm)) {
+ oof_data->to_time = e_date_edit_get_time (date_tm);
+ }
+ if (oof_data->from_time > oof_data->to_time)
+ e_notice (NULL, GTK_MESSAGE_WARNING, _("Select a valid time range"));
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+oof_data_new (void)
+{
+#if 0 /* ACCOUNT_MGMT */
+ oof_data = g_new0 (OOFData, 1);
+ oof_data->state = FALSE;
+ oof_data->set_range = FALSE;
+ oof_data->range_wt = NULL;
+ oof_data->audience_type = EXTERNAL_AUDIENCE_ALL;
+ oof_data->audience = NULL;
+ oof_data->external_message = NULL;
+ oof_data->internal_message = NULL;
+ oof_data->internal_view = NULL;
+ oof_data->external_view = NULL;
+ oof_data->from_time = 0;
+ oof_data->to_time = 0;
+ oof_data->from_date = NULL;
+ oof_data->to_date = NULL;
+ oof_data->stat_box = NULL;
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+destroy_oof_data (void)
+{
+#if 0 /* ACCOUNT_MGMT */
+ if (oof_data->audience) {
+ g_free (oof_data->audience);
+ oof_data->audience = NULL;
+ }
+
+ if (oof_data->external_message) {
+ g_free (oof_data->external_message);
+ oof_data->external_message = NULL;
+ }
+
+ if (oof_data->internal_message) {
+ g_free (oof_data->internal_message);
+ oof_data->internal_message = NULL;
+ }
+
+ if (oof_data) {
+ g_free (oof_data);
+ oof_data = NULL;
+ }
+#endif /* ACCOUNT_MGMT */
+}
+
+#if 0 /* ACCOUNT_MGMT */
+static gchar *
+get_password (CamelSettings *settings)
+{
+ gchar *key, *password = NULL;
+ CamelURL *url;
+
+ url = g_new0 (CamelURL, 1);
+ camel_settings_save_to_url (settings, url);
+ key = camel_url_to_string (url, CAMEL_URL_HIDE_PARAMS);
+ camel_url_free (url);
+
+ password = e_passwords_get_password ("Exchange Web Services", key);
+
+ g_free (key);
+ return password;
+}
+#endif /* ACCOUNT_MGMT */
+
+#if 0 /* ACCOUNT_MGMT */
+static EEwsConnection *
+get_connection (EMConfigTargetSettings *target)
+{
+ CamelEwsSettings *ews_settings;
+ CamelNetworkSettings *network_settings;
+ EEwsConnection *cnc;
+ const gchar *host_url;
+ const gchar *user;
+ gchar *email, *password;
+ GError *error = NULL;
+
+ ews_settings = CAMEL_EWS_SETTINGS (target->storage_settings);
+ network_settings = CAMEL_NETWORK_SETTINGS (target->storage_settings);
+
+ /* Create a new connection */
+ host_url = camel_ews_settings_get_hosturl (ews_settings);
+ user = camel_network_settings_get_user (network_settings);
+ password = get_password (target->storage_settings);
+ email = target->email_address;
+
+ cnc = e_ews_connection_new (host_url, user, password, NULL, NULL, &error);
+
+ if (!cnc) {
+ g_warning ("Error in connection: %s\n", error->message);
+ g_clear_error (&error);
+ return NULL;
+ }
+
+ e_ews_connection_set_mailbox (cnc, email);
+
+ g_free (password);
+ return cnc;
+}
+#endif /* ACCOUNT_MGMT */
+
+static void
+set_oof_error_to_frame (GtkWidget *oof_frame,
+ GError *error)
+{
+#if 0 /* ACCOUNT_MGMT */
+ GtkHBox *error_box;
+ GtkLabel *error_msg;
+ GtkWidget *error_img;
+ gchar *message;
+
+ gtk_widget_destroy (oof_data->stat_box);
+
+ error_box = (GtkHBox*) g_object_new (GTK_TYPE_HBOX, NULL, "homogeneous", FALSE, "spacing", 6, NULL);
+ error_img = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ message = g_strdup_printf (_("Unable to fetch out of office settings: \n%s"), error->message);
+ error_msg = (GtkLabel *) gtk_label_new (message);
+ gtk_label_set_use_markup (error_msg, TRUE);
+ gtk_box_pack_start (GTK_BOX (error_box), GTK_WIDGET (error_img), FALSE, FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (error_box), GTK_WIDGET (error_msg), FALSE, FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (oof_frame), GTK_WIDGET (error_box));
+ gtk_widget_show_all (GTK_WIDGET (error_box));
+
+ g_free (message);
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+set_oof_settings_to_frame (GtkWidget *oof_frame)
+{
+#if 0 /* ACCOUNT_MGMT */
+ gtk_widget_destroy (oof_data->stat_box);
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+get_oof_settings_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EEwsConnection *cnc = E_EWS_CONNECTION (object);
+ GtkWidget *oof_frame = GTK_WIDGET (user_data);
+ OOFSettings *oof_settings = NULL;
+ GError *error = NULL;
+
+ e_ews_connection_get_oof_settings_finish (cnc, res, &oof_settings, &error);
+
+ if (error) {
+ g_warning ("Error Unable to get out of office settings: %s\n", error->message);
+ set_oof_error_to_frame (oof_frame, error);
+ g_object_unref (cnc);
+ g_clear_error (&error);
+ return;
+ }
+
+#if 0 /* ACCOUNT_MGMT */
+ if (!g_ascii_strcasecmp (oof_settings->state, "Disabled"))
+ oof_data->state = FALSE;
+ else
+ oof_data->state = TRUE;
+
+ oof_data->audience = g_strdup (oof_settings->ext_aud);
+ update_audience_type ();
+ if (!g_ascii_strcasecmp (oof_settings->state, "Scheduled")) {
+ oof_data->from_time = oof_settings->start_tm;
+ oof_data->to_time = oof_settings->end_tm;
+ oof_data->set_range = TRUE;
+ }
+ oof_data->internal_message = g_strdup (oof_settings->int_reply);
+ oof_data->external_message = g_strdup (oof_settings->ext_reply);
+#endif /* ACCOUNT_MGMT */
+
+ set_oof_settings_to_frame (oof_frame);
+ e_ews_connection_free_oof_settings (oof_settings);
+ g_object_unref (cnc);
+}
+
+#if 0 /* ACCOUNT_MGMT */
+static void
+set_oof_data_from_settings (EMConfigTargetSettings *target,
+ GtkWidget *oof_frame)
+{
+ GCancellable *cancellable = NULL;
+ EEwsConnection *cnc = NULL;
+
+ cnc = get_connection (target);
+ if (!cnc)
+ return;
+
+ cancellable = g_cancellable_new ();
+
+ e_ews_connection_get_oof_settings (
+ cnc, EWS_PRIORITY_MEDIUM, cancellable,
+ get_oof_settings_cb, oof_frame);
+}
+#endif /* ACCOUNT_MGMT */
+
+static OOFSettings *
+get_settings_from_data (void)
+{
+ OOFSettings *oof_settings = NULL;
+
+ oof_settings = g_new0 (OOFSettings, 1);
+
+#if 0 /* ACCOUNT_MGMT */
+ if (oof_data->from_time >= oof_data->to_time || !oof_data->set_range) {
+ d (printf ("not a valid time range or set duration is not available"));
+ oof_data->from_time = 0;
+ oof_data->to_time = 0;
+ }
+
+ if (oof_data->state) {
+ if (oof_data->from_time && oof_data->to_time)
+ oof_settings->state = g_strdup ("Scheduled");
+ else
+ oof_settings->state = g_strdup ("Enabled");
+ } else
+ oof_settings->state = g_strdup ("Disabled");
+
+ oof_settings->ext_aud = g_strdup (oof_data->audience);
+ oof_settings->start_tm = oof_data->from_time;
+ oof_settings->end_tm = oof_data->to_time;
+ oof_settings->int_reply = g_strdup (oof_data->internal_message);
+ oof_settings->ext_reply = g_strdup (oof_data->external_message);
+#endif /* ACCOUNT_MGMT */
+
+ return oof_settings;
+}
+
+#if 0 /* ACCOUNT_MGMT */
+gboolean
+ews_set_oof_settings (EMConfigTargetSettings *target)
+{
+ GCancellable *cancellable = NULL;
+ OOFSettings *oof_settings = NULL;
+ EEwsConnection *cnc = NULL;
+ GError *error = NULL;
+ gboolean ret_val;
+
+ cnc = get_connection (target);
+ if (!cnc) {
+ destroy_oof_data ();
+ return FALSE;
+ }
+
+ cancellable = g_cancellable_new ();
+
+ oof_settings = get_settings_from_data ();
+
+ e_ews_connection_set_oof_settings_sync (
+ cnc, EWS_PRIORITY_MEDIUM,
+ oof_settings, cancellable, &error);
+
+ if (error) {
+ g_warning ("Error While setting out of office: %s\n", error->message);
+ g_clear_error (&error);
+ ret_val = FALSE;
+ } else
+ ret_val = TRUE;
+
+ destroy_oof_data ();
+ e_ews_connection_free_oof_settings (oof_settings);
+ g_object_unref (cnc);
+
+ return ret_val;
+}
+#endif /* ACCOUNT_MGMT */
+
+#if 0 /* ACCOUNT_MGMT */
+GtkWidget *
+ews_get_outo_office_widget (EMConfigTargetSettings *target_account)
+{
+ GtkFrame *frm_oof;
+ GtkHBox *stat_box;
+ GtkLabel *stat_msg;
+ GtkWidget *spinner, *label;
+ gchar *txt;
+
+ txt = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>", _("Out of Office"));
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup ((GtkLabel *) label, txt);
+ g_free (txt);
+ frm_oof = (GtkFrame*) g_object_new (GTK_TYPE_FRAME, "label-widget", label, NULL);
+
+ oof_data_new ();
+
+ stat_box = (GtkHBox*) g_object_new (GTK_TYPE_HBOX, NULL, "homogeneous", FALSE, "spacing", 6, NULL);
+ spinner = gtk_spinner_new ();
+ stat_msg = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", _("Fetching out of office settings..."), "use-markup", TRUE, NULL);
+
+ oof_data->stat_box = GTK_WIDGET (stat_box);
+
+ gtk_box_pack_start (GTK_BOX (stat_box), GTK_WIDGET (spinner), FALSE, FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (stat_box), GTK_WIDGET (stat_msg), FALSE, FALSE, 0);
+ gtk_spinner_start ((GtkSpinner *) spinner);
+ gtk_container_add (GTK_CONTAINER (frm_oof), GTK_WIDGET (stat_box));
+
+ set_oof_data_from_settings (target_account, (GtkWidget *) frm_oof);
+
+ return (GtkWidget *) frm_oof;
+}
+#endif /* ACCOUNT_MGMT */
+
+static void
+mail_config_ews_ooo_page_set_account_source (EMailConfigEwsOooPage *page,
+ ESource *account_source)
+{
+ g_return_if_fail (E_IS_SOURCE (account_source));
+ g_return_if_fail (page->priv->account_source == NULL);
+
+ page->priv->account_source = g_object_ref (account_source);
+}
+
+static void
+mail_config_ews_ooo_page_set_identity_source (EMailConfigEwsOooPage *page,
+ ESource *identity_source)
+{
+ g_return_if_fail (E_IS_SOURCE (identity_source));
+ g_return_if_fail (page->priv->identity_source == NULL);
+
+ page->priv->identity_source = g_object_ref (identity_source);
+}
+
+static void
+mail_config_ews_ooo_page_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACCOUNT_SOURCE:
+ mail_config_ews_ooo_page_set_account_source (
+ E_MAIL_CONFIG_EWS_OOO_PAGE (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_IDENTITY_SOURCE:
+ mail_config_ews_ooo_page_set_identity_source (
+ E_MAIL_CONFIG_EWS_OOO_PAGE (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_config_ews_ooo_page_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACCOUNT_SOURCE:
+ g_value_set_object (
+ value,
+ e_mail_config_ews_ooo_page_get_account_source (
+ E_MAIL_CONFIG_EWS_OOO_PAGE (object)));
+ return;
+
+ case PROP_IDENTITY_SOURCE:
+ g_value_set_object (
+ value,
+ e_mail_config_ews_ooo_page_get_identity_source (
+ E_MAIL_CONFIG_EWS_OOO_PAGE (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_config_ews_ooo_page_dispose (GObject *object)
+{
+ EMailConfigEwsOooPagePrivate *priv;
+
+ priv = E_MAIL_CONFIG_EWS_OOO_PAGE_GET_PRIVATE (object);
+
+ if (priv->account_source != NULL) {
+ g_object_unref (priv->account_source);
+ priv->account_source = NULL;
+ }
+
+ if (priv->identity_source != NULL) {
+ g_object_unref (priv->identity_source);
+ priv->identity_source = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_config_ews_ooo_page_parent_class)->
+ dispose (object);
+}
+
+static void
+mail_config_ews_ooo_page_constructed (GObject *object)
+{
+ EMailConfigEwsOooPage *page;
+ GtkWidget *widget;
+ GtkWidget *container;
+ const gchar *text;
+ gchar *markup;
+
+ GtkHBox *hbox_ext, *hbox_state;
+ GtkLabel *lbl_oof_desc, *from_label, *to_label;
+ GtkTable *tbl_oof_status;
+ GtkLabel *lbl_status, *lbl_external, *lbl_internal;
+ GtkRadioButton *radio_iof, *radio_oof;
+ GtkScrolledWindow *scrwnd_oof_int, *scrwnd_oof_ext;
+ GtkTextView *txtview_oof_int, *txtview_oof_ext;
+ GtkTextBuffer *buffer_int, *buffer_ext;
+ GtkWidget *from_date, *to_date, *aud_box, *set_range;
+
+ page = E_MAIL_CONFIG_EWS_OOO_PAGE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_config_ews_ooo_page_parent_class)->
+ constructed (object);
+
+ text = _("Out of Office");
+ 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 (page), 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 (page), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ text = _("The messages specified below will be automatically sent "
+ "to each internal and external personal who sends a mail "
+ "to you.");
+ widget = gtk_label_new (text);
+ gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 1, 1);
+ gtk_widget_show (widget);
+
+ /* XXX Crap starts here */
+
+ tbl_oof_status = (GtkTable*) g_object_new (GTK_TYPE_TABLE, "n-rows", 7, "n-columns", 2, "homogeneous", FALSE, "row-spacing", 6, "column-spacing", 6, NULL);
+ gtk_grid_attach (GTK_GRID (container), GTK_WIDGET (tbl_oof_status), 0, 1, 1, 1);
+ gtk_widget_show (GTK_WIDGET (tbl_oof_status));
+
+ lbl_status = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", _("Status:"), "use-markup", TRUE, NULL);
+ gtk_misc_set_alignment (GTK_MISC (lbl_status), 0, 0.5);
+ gtk_misc_set_padding (GTK_MISC (lbl_status), 0, 0);
+
+#if 0 /* ACCOUNT_MGMT */
+ if (oof_data->state) {
+#endif /* ACCOUNT_MGMT */
+ radio_oof = (GtkRadioButton*) g_object_new (GTK_TYPE_RADIO_BUTTON, "label", _("I am _out of the office"), "use-underline", TRUE, NULL);
+ radio_iof = (GtkRadioButton*) g_object_new (GTK_TYPE_RADIO_BUTTON, "label", _("I am _in the office"), "use-underline", TRUE, "group", radio_oof, NULL);
+#if 0 /* ACCOUNT_MGMT */
+ } else {
+ radio_iof = (GtkRadioButton*) g_object_new (GTK_TYPE_RADIO_BUTTON, "label", _("I am _in the office"), "use-underline", TRUE, NULL);
+ radio_oof = (GtkRadioButton*) g_object_new (GTK_TYPE_RADIO_BUTTON, "label", _("I am _out of the office"), "use-underline", TRUE, "group", radio_iof, NULL);
+ }
+#endif /* ACCOUNT_MGMT */
+ g_signal_connect (radio_oof, "toggled", G_CALLBACK (toggled_state_cb), NULL);
+
+ hbox_state = g_object_new (GTK_TYPE_HBOX, NULL, "homogeneous", FALSE, "spacing", 6, NULL);
+ gtk_box_pack_start (GTK_BOX (hbox_state), GTK_WIDGET (radio_iof), FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox_state), GTK_WIDGET (radio_oof), FALSE, FALSE, 12);
+
+ /*Check box for setting date*/
+ set_range = gtk_check_button_new_with_mnemonic (_("_Send only during this time period"));
+#if 0 /* ACCOUNT_MGMT */
+ oof_data->range_wt = set_range;
+ gtk_toggle_button_set_active ((GtkToggleButton*) set_range, oof_data->set_range);
+#endif /* ACCOUNT_MGMT */
+ g_signal_connect ((GtkToggleButton*) set_range, "toggled", G_CALLBACK (toggled_set_date_cb), NULL);
+
+
+ /*Selectable Dates*/
+ from_date = e_date_edit_new ();
+ to_date = e_date_edit_new ();
+
+#if 0 /* ACCOUNT_MGMT */
+ e_date_edit_set_time ((EDateEdit *) from_date, oof_data->from_time);
+ e_date_edit_set_time ((EDateEdit *) to_date, oof_data->to_time);
+
+ oof_data->from_date = (EDateEdit *) from_date;
+ oof_data->to_date = (EDateEdit *) to_date;
+#endif /* ACCOUNT_MGMT */
+
+ g_signal_connect (from_date, "changed", G_CALLBACK (from_time_changed_cb), NULL);
+ g_signal_connect (to_date, "changed", G_CALLBACK (to_time_changed_cb), NULL);
+
+ from_label = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", _("_From:"), "use-underline", TRUE, "use-markup", TRUE, NULL);
+ gtk_label_set_mnemonic_widget (from_label, GTK_WIDGET (from_date));
+ gtk_misc_set_alignment (GTK_MISC (from_label), 0, 0.5);
+ gtk_misc_set_padding (GTK_MISC (from_label), 0, 0);
+
+ to_label = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", _("_To:"), "use-markup", TRUE, "use-underline", TRUE, NULL);
+ gtk_label_set_mnemonic_widget (to_label, GTK_WIDGET (to_date));
+ gtk_misc_set_alignment (GTK_MISC (to_label), 0, 0.5);
+ gtk_misc_set_padding (GTK_MISC (to_label), 0, 0);
+
+ scrwnd_oof_int = (GtkScrolledWindow*) g_object_new (GTK_TYPE_SCROLLED_WINDOW, "hscrollbar-policy", GTK_POLICY_AUTOMATIC, "vscrollbar-policy", GTK_POLICY_AUTOMATIC, "shadow-type", GTK_SHADOW_IN, NULL);
+ txtview_oof_int = (GtkTextView*) g_object_new (GTK_TYPE_TEXT_VIEW, "justification", GTK_JUSTIFY_LEFT, "wrap-mode", GTK_WRAP_WORD, "editable", TRUE, NULL);
+
+ buffer_int = gtk_text_view_get_buffer (txtview_oof_int);
+#if 0 /* ACCOUNT_MGMT */
+ if (oof_data->internal_message) {
+ /* previuosly set message */
+ gtk_text_buffer_set_text (buffer_int, oof_data->internal_message, -1);
+ gtk_text_view_set_buffer (txtview_oof_int, buffer_int);
+ }
+#endif /* ACCOUNT_MGMT */
+ gtk_text_buffer_set_modified (buffer_int, FALSE);
+ gtk_container_add (GTK_CONTAINER (scrwnd_oof_int), GTK_WIDGET (txtview_oof_int));
+
+ lbl_internal = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", _("I_nternal:"), "use-underline", TRUE, "use-markup", TRUE, NULL);
+ gtk_label_set_mnemonic_widget (lbl_internal, GTK_WIDGET (txtview_oof_int));
+ gtk_widget_set_tooltip_text (GTK_WIDGET (lbl_internal), _("Message to be sent inside organization"));
+ gtk_misc_set_alignment (GTK_MISC (lbl_internal), 0, 0.5);
+ gtk_misc_set_padding (GTK_MISC (lbl_internal), 0, 0);
+
+ /*Select External Audience*/
+ hbox_ext = g_object_new (GTK_TYPE_HBOX, NULL, "homogeneous", FALSE, "spacing", 6, NULL);
+ aud_box = gtk_combo_box_text_new ();
+ gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (aud_box), EXTERNAL_AUDIENCE_NONE, _("None"));
+ gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (aud_box), EXTERNAL_AUDIENCE_KNOWN, _("Known"));
+ gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (aud_box), EXTERNAL_AUDIENCE_ALL, _("All"));
+#if 0 /* ACCOUNT_MGMT */
+ gtk_combo_box_set_active (GTK_COMBO_BOX (aud_box), oof_data->audience_type);
+#endif /* ACCOUNT_MGMT */
+ gtk_widget_set_tooltip_text (GTK_WIDGET (aud_box), _("Send Message to"));
+
+#if 0 /* ACCOUNT_MGMT */
+ oof_data->aud_box = aud_box;
+#endif /* ACCOUNT_MGMT */
+ gtk_box_pack_start (GTK_BOX (hbox_ext), GTK_WIDGET (aud_box), FALSE, FALSE, 0);
+ g_signal_connect (GTK_COMBO_BOX (aud_box), "changed", G_CALLBACK (update_audience_cb), NULL);
+
+ scrwnd_oof_ext = (GtkScrolledWindow*) g_object_new (GTK_TYPE_SCROLLED_WINDOW, "hscrollbar-policy", GTK_POLICY_AUTOMATIC, "vscrollbar-policy", GTK_POLICY_AUTOMATIC, "shadow-type", GTK_SHADOW_IN, NULL);
+ gtk_box_pack_start (GTK_BOX (hbox_ext), GTK_WIDGET (scrwnd_oof_ext), TRUE, TRUE, 0);
+ txtview_oof_ext = (GtkTextView*) g_object_new (GTK_TYPE_TEXT_VIEW, "justification", GTK_JUSTIFY_LEFT, "wrap-mode", GTK_WRAP_WORD, "editable", TRUE, NULL);
+
+ buffer_ext = gtk_text_view_get_buffer (txtview_oof_ext);
+#if 0 /* ACCOUNT_MGMT */
+ if (oof_data->external_message) {
+ /* previuosly set message */
+ gtk_text_buffer_set_text (buffer_ext, oof_data->external_message, -1);
+ gtk_text_view_set_buffer (txtview_oof_ext, buffer_ext);
+
+ }
+#endif /* ACCOUNT_MGMT */
+ gtk_text_buffer_set_modified (buffer_ext, FALSE);
+ gtk_container_add (GTK_CONTAINER (scrwnd_oof_ext), GTK_WIDGET (txtview_oof_ext));
+
+ lbl_external = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", _("E_xternal:"), "use-underline", TRUE, "use-markup", TRUE, NULL);
+ gtk_label_set_mnemonic_widget (lbl_external, GTK_WIDGET (txtview_oof_ext));
+ gtk_widget_set_tooltip_text (GTK_WIDGET (lbl_external), _("Message to be sent outside organization"));
+ gtk_misc_set_alignment (GTK_MISC (lbl_external), 0, 0.5);
+ gtk_misc_set_padding (GTK_MISC (lbl_external), 0, 0);
+
+ g_signal_connect (buffer_int, "changed", G_CALLBACK (update_int_msg_cb), NULL);
+ g_signal_connect (buffer_ext, "changed", G_CALLBACK (update_ext_msg_cb), NULL);
+
+ gtk_table_attach (tbl_oof_status, GTK_WIDGET (lbl_status), 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_table_attach (tbl_oof_status, GTK_WIDGET (hbox_state), 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_table_attach (tbl_oof_status, GTK_WIDGET (set_range), 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_table_attach (tbl_oof_status, GTK_WIDGET (from_label), 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_table_attach (tbl_oof_status, GTK_WIDGET (from_date), 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_table_attach (tbl_oof_status, GTK_WIDGET (to_label), 0, 1, 3, 4, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_table_attach (tbl_oof_status, GTK_WIDGET (to_date), 1, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_table_attach (tbl_oof_status, GTK_WIDGET (lbl_internal), 0, 1, 4, 5, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_table_attach (tbl_oof_status, GTK_WIDGET (scrwnd_oof_int), 1, 2, 4, 5, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_table_attach (tbl_oof_status, GTK_WIDGET (lbl_external), 0, 1, 5, 6, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_table_attach (tbl_oof_status, GTK_WIDGET (hbox_ext), 1, 2, 5, 6, GTK_FILL, GTK_FILL, 0, 0);
+
+#if 0 /* ACCOUNT_MGMT */
+ if (!oof_data->state) {
+ gtk_widget_set_sensitive ((GtkWidget *) set_range, FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (txtview_oof_int), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (txtview_oof_ext), FALSE);
+ gtk_widget_set_sensitive ((GtkWidget *) from_date, FALSE);
+ gtk_widget_set_sensitive ((GtkWidget *) to_date, FALSE);
+ gtk_widget_set_sensitive (aud_box, FALSE);
+ }
+ if (!oof_data->set_range) {
+ gtk_widget_set_sensitive ((GtkWidget *) from_date, FALSE);
+ gtk_widget_set_sensitive ((GtkWidget *) to_date, FALSE);
+ }
+
+ oof_data->internal_view = GTK_WIDGET (txtview_oof_int);
+ oof_data->external_view = GTK_WIDGET (txtview_oof_ext);
+#endif /* ACCOUNT_MGMT */
+}
+
+static void
+e_mail_config_ews_ooo_page_class_init (EMailConfigEwsOooPageClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (
+ class, sizeof (EMailConfigEwsOooPagePrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_config_ews_ooo_page_set_property;
+ object_class->get_property = mail_config_ews_ooo_page_get_property;
+ object_class->dispose = mail_config_ews_ooo_page_dispose;
+ object_class->constructed = mail_config_ews_ooo_page_constructed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ACCOUNT_SOURCE,
+ g_param_spec_object (
+ "account-source",
+ "Account Source",
+ "Mail account source being edited",
+ E_TYPE_SOURCE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_IDENTITY_SOURCE,
+ g_param_spec_object (
+ "identity-source",
+ "Identity Source",
+ "Mail identity source being edited",
+ E_TYPE_SOURCE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_mail_config_ews_ooo_page_interface_init (EMailConfigPageInterface *interface)
+{
+ interface->title = _("EWS Settings");
+ interface->sort_order = E_MAIL_CONFIG_EWS_OOO_PAGE_SORT_ORDER;
+}
+
+static void
+e_mail_config_ews_ooo_page_class_finalize (EMailConfigEwsOooPageClass *class)
+{
+}
+
+static void
+e_mail_config_ews_ooo_page_init (EMailConfigEwsOooPage *page)
+{
+ page->priv = E_MAIL_CONFIG_EWS_OOO_PAGE_GET_PRIVATE (page);
+}
+
+void
+e_mail_config_ews_ooo_page_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_ews_ooo_page_register_type (type_module);
+}
+
+EMailConfigPage *
+e_mail_config_ews_ooo_page_new (ESource *account_source,
+ ESource *identity_source)
+{
+ g_return_val_if_fail (E_IS_SOURCE (account_source), NULL);
+ g_return_val_if_fail (E_IS_SOURCE (identity_source), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_CONFIG_EWS_OOO_PAGE,
+ "account-source", account_source,
+ "identity-source", identity_source, NULL);
+}
+
+ESource *
+e_mail_config_ews_ooo_page_get_account_source (EMailConfigEwsOooPage *page)
+{
+ g_return_val_if_fail (E_IS_MAIL_CONFIG_EWS_OOO_PAGE (page), NULL);
+
+ return page->priv->account_source;
+}
+
+ESource *
+e_mail_config_ews_ooo_page_get_identity_source (EMailConfigEwsOooPage *page)
+{
+ g_return_val_if_fail (E_IS_MAIL_CONFIG_EWS_OOO_PAGE (page), NULL);
+
+ return page->priv->identity_source;
+}
+
diff --git a/src/modules/e-mail-config-ews-ooo-page.h b/src/modules/e-mail-config-ews-ooo-page.h
new file mode 100644
index 0000000..86e5cf9
--- /dev/null
+++ b/src/modules/e-mail-config-ews-ooo-page.h
@@ -0,0 +1,80 @@
+/*
+ * e-mail-config-ews-ooo-page.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* "OOO" = "Out of Office" */
+
+#ifndef E_MAIL_CONFIG_EWS_OOO_PAGE_H
+#define E_MAIL_CONFIG_EWS_OOO_PAGE_H
+
+#include <gtk/gtk.h>
+#include <libedataserver/e-source.h>
+
+#include <mail/e-mail-config-page.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_CONFIG_EWS_OOO_PAGE \
+ (e_mail_config_ews_ooo_page_get_type ())
+#define E_MAIL_CONFIG_EWS_OOO_PAGE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_OOO_PAGE, EMailConfigEwsOooPage))
+#define E_MAIL_CONFIG_EWS_OOO_PAGE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_CONFIG_EWS_OOO_PAGE, EMailConfigEwsOooPageClass))
+#define E_IS_MAIL_CONFIG_EWS_OOO_PAGE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_OOO_PAGE))
+#define E_IS_MAIL_CONFIG_EWS_OOO_PAGE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_CONFIG_EWS_OOO_PAGE))
+#define E_MAIL_CONFIG_EWS_OOO_PAGE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_CONFIG_EWS_OOO_PAGE, EMailConfigEwsOooPageClass))
+
+#define E_MAIL_CONFIG_EWS_OOO_PAGE_SORT_ORDER (550)
+
+G_BEGIN_DECLS
+
+typedef struct _EMailConfigEwsOooPage EMailConfigEwsOooPage;
+typedef struct _EMailConfigEwsOooPageClass EMailConfigEwsOooPageClass;
+typedef struct _EMailConfigEwsOooPagePrivate EMailConfigEwsOooPagePrivate;
+
+struct _EMailConfigEwsOooPage {
+ GtkBox parent;
+ EMailConfigEwsOooPagePrivate *priv;
+};
+
+struct _EMailConfigEwsOooPageClass {
+ GtkBoxClass parent_class;
+};
+
+GType e_mail_config_ews_ooo_page_get_type
+ (void) G_GNUC_CONST;
+void e_mail_config_ews_ooo_page_type_register
+ (GTypeModule *type_module);
+EMailConfigPage *
+ e_mail_config_ews_ooo_page_new (ESource *account_source,
+ ESource *identity_source);
+ESource * e_mail_config_ews_ooo_page_get_account_source
+ (EMailConfigEwsOooPage *page);
+ESource * e_mail_config_ews_ooo_page_get_identity_source
+ (EMailConfigEwsOooPage *page);
+
+G_END_DECLS
+
+#endif /* E_MAIL_CONFIG_EWS_OOO_PAGE_H */
+
diff --git a/src/modules/module-ews-backend.c b/src/modules/module-ews-backend.c
new file mode 100644
index 0000000..6fdb342
--- /dev/null
+++ b/src/modules/module-ews-backend.c
@@ -0,0 +1,822 @@
+/*
+ * module-ews-backend.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <libedataserver/e-source-address-book.h>
+#include <libedataserver/e-source-authentication.h>
+#include <libedataserver/e-source-autocomplete.h>
+#include <libedataserver/e-source-calendar.h>
+#include <libedataserver/e-source-camel.h>
+#include <libedataserver/e-source-collection.h>
+#include <libedataserver/e-source-mail-account.h>
+#include <libedataserver/e-source-mail-identity.h>
+#include <libedataserver/e-source-mail-transport.h>
+#include <libedataserver/e-source-offline.h>
+
+#include <libebackend/e-collection-backend.h>
+#include <libebackend/e-collection-backend-factory.h>
+#include <libebackend/e-source-registry-server.h>
+
+#include "server/e-ews-connection.h"
+#include "server/e-source-ews-folder.h"
+
+/* Standard GObject macros */
+#define E_TYPE_EWS_BACKEND \
+ (e_ews_backend_get_type ())
+#define E_EWS_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_EWS_BACKEND, EEwsBackend))
+
+typedef struct _EEwsBackend EEwsBackend;
+typedef struct _EEwsBackendClass EEwsBackendClass;
+
+typedef struct _EEwsBackendFactory EEwsBackendFactory;
+typedef struct _EEwsBackendFactoryClass EEwsBackendFactoryClass;
+
+typedef struct _SyncFoldersClosure SyncFoldersClosure;
+
+struct _SyncFoldersClosure {
+ EEwsBackend *backend;
+ GSList *folders_created;
+ GSList *folders_deleted;
+ GSList *folders_updated;
+};
+
+struct _EEwsBackend {
+ ECollectionBackend parent;
+
+ /* Folder ID -> ESource */
+ GHashTable *folders;
+
+ ESource *gal_source;
+ gchar *oal_selected;
+
+ gchar *sync_state;
+ GMutex *sync_state_lock;
+};
+
+struct _EEwsBackendClass {
+ ECollectionBackendClass parent_class;
+};
+
+struct _EEwsBackendFactory {
+ ECollectionBackendFactory parent;
+};
+
+struct _EEwsBackendFactoryClass {
+ ECollectionBackendFactoryClass parent_class;
+};
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+/* Forward Declarations */
+GType e_ews_backend_get_type (void);
+GType e_ews_backend_factory_get_type (void);
+
+static void e_ews_backend_authenticator_init
+ (ESourceAuthenticatorInterface *interface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (
+ EEwsBackend,
+ e_ews_backend,
+ E_TYPE_COLLECTION_BACKEND,
+ 0,
+ G_IMPLEMENT_INTERFACE_DYNAMIC (
+ E_TYPE_SOURCE_AUTHENTICATOR,
+ e_ews_backend_authenticator_init))
+
+G_DEFINE_DYNAMIC_TYPE (
+ EEwsBackendFactory,
+ e_ews_backend_factory,
+ E_TYPE_COLLECTION_BACKEND_FACTORY)
+
+static void
+sync_folders_closure_free (SyncFoldersClosure *closure)
+{
+ g_object_unref (closure->backend);
+
+ /* List of EEwsFolder instances. */
+ g_slist_free_full (
+ closure->folders_created,
+ (GDestroyNotify) g_object_unref);
+
+ /* List of folder ID strings. */
+ g_slist_free_full (
+ closure->folders_deleted,
+ (GDestroyNotify) g_free);
+
+ /* List of EEwsFolder instances. */
+ g_slist_free_full (
+ closure->folders_updated,
+ (GDestroyNotify) g_object_unref);
+
+ g_slice_free (SyncFoldersClosure, closure);
+}
+
+static CamelEwsSettings *
+ews_backend_get_settings (EEwsBackend *backend)
+{
+ ESource *source;
+ ESourceCamel *extension;
+ CamelSettings *settings;
+ const gchar *extension_name;
+
+ source = e_backend_get_source (E_BACKEND (backend));
+ extension_name = e_source_camel_get_extension_name ("ews");
+ extension = e_source_get_extension (source, extension_name);
+ settings = e_source_camel_get_settings (extension);
+
+ return CAMEL_EWS_SETTINGS (settings);
+}
+
+static void
+ews_backend_queue_auth_session (ECollectionBackend *backend)
+{
+ ESourceRegistryServer *server;
+ EAuthenticationSession *session;
+ ESource *source;
+
+ server = e_collection_backend_ref_server (backend);
+ source = e_backend_get_source (E_BACKEND (backend));
+
+ session = e_authentication_session_new (
+ server, E_SOURCE_AUTHENTICATOR (backend),
+ e_source_get_uid (source));
+
+ e_source_registry_server_queue_auth_session (server, session);
+
+ g_object_unref (session);
+ g_object_unref (server);
+}
+
+static ESource *
+ews_backend_new_child (EEwsBackend *backend,
+ EEwsFolder *folder)
+{
+ ECollectionBackend *collection_backend;
+ ESourceExtension *extension;
+ ESource *source;
+ const EwsFolderId *fid;
+ const gchar *display_name;
+ const gchar *extension_name;
+
+ fid = e_ews_folder_get_id (folder);
+
+ collection_backend = E_COLLECTION_BACKEND (backend);
+ source = e_collection_backend_new_child (collection_backend, fid->id);
+
+ display_name = e_ews_folder_get_name (folder);
+ e_source_set_display_name (source, display_name);
+
+ switch (e_ews_folder_get_folder_type (folder)) {
+ case EWS_FOLDER_TYPE_CALENDAR:
+ extension_name = E_SOURCE_EXTENSION_CALENDAR;
+ break;
+ case EWS_FOLDER_TYPE_TASKS:
+ extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+ break;
+ case EWS_FOLDER_TYPE_CONTACTS:
+ extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+ break;
+ default:
+ g_object_unref (source);
+ g_return_val_if_reached (NULL);
+ }
+ extension = e_source_get_extension (source, extension_name);
+ e_source_backend_set_backend_name (
+ E_SOURCE_BACKEND (extension), "ews");
+
+ extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
+ extension = e_source_get_extension (source, extension_name);
+ e_source_ews_folder_set_id (
+ E_SOURCE_EWS_FOLDER (extension), fid->id);
+ e_source_ews_folder_set_change_key (
+ E_SOURCE_EWS_FOLDER (extension), fid->change_key);
+
+ extension_name = E_SOURCE_EXTENSION_OFFLINE;
+ extension = e_source_get_extension (source, extension_name);
+ e_source_offline_set_stay_synchronized (
+ E_SOURCE_OFFLINE (extension), TRUE);
+
+ return source;
+}
+
+static ESource *
+ews_backend_new_calendar (EEwsBackend *backend,
+ EEwsFolder *folder)
+{
+ ESourceExtension *extension;
+ ESource *source;
+ const gchar *extension_name;
+
+ source = ews_backend_new_child (backend, folder);
+
+ /* XXX The Exchange server does not provide a color? */
+ extension_name = E_SOURCE_EXTENSION_CALENDAR;
+ extension = e_source_get_extension (source, extension_name);
+ e_source_selectable_set_color (
+ E_SOURCE_SELECTABLE (extension), "#EEBC60");
+
+ return source;
+}
+
+static ESource *
+ews_backend_new_task_list (EEwsBackend *backend,
+ EEwsFolder *folder)
+{
+ ESourceExtension *extension;
+ ESource *source;
+ const gchar *extension_name;
+
+ source = ews_backend_new_child (backend, folder);
+
+ /* XXX The Exchange server does not provide a color? */
+ extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+ extension = e_source_get_extension (source, extension_name);
+ e_source_selectable_set_color (
+ E_SOURCE_SELECTABLE (extension), "#EEBC60");
+
+ return source;
+}
+
+static ESource *
+ews_backend_new_address_book (EEwsBackend *backend,
+ EEwsFolder *folder)
+{
+ /* No extra configuration to do. */
+ return ews_backend_new_child (backend, folder);
+}
+
+static void
+ews_backend_sync_created_folders (EEwsBackend *backend,
+ GSList *list)
+{
+ ECollectionBackend *collection_backend;
+ ESourceRegistryServer *server;
+ GSList *link;
+
+ collection_backend = E_COLLECTION_BACKEND (backend);
+ server = e_collection_backend_ref_server (collection_backend);
+
+ for (link = list; link != NULL; link = g_slist_next (link)) {
+ EEwsFolder *folder = E_EWS_FOLDER (link->data);
+ const EwsFolderId *fid;
+ ESource *source = NULL;
+
+ /* If we already know about this folder, skip it. */
+ fid = e_ews_folder_get_id (folder);
+ if (fid->id == NULL)
+ continue; /* not a valid ID anyway */
+ if (g_hash_table_contains (backend->folders, fid->id))
+ continue;
+
+ switch (e_ews_folder_get_folder_type (folder)) {
+ case EWS_FOLDER_TYPE_CALENDAR:
+ source = ews_backend_new_calendar (
+ backend, folder);
+ break;
+ case EWS_FOLDER_TYPE_TASKS:
+ source = ews_backend_new_task_list (
+ backend, folder);
+ break;
+ case EWS_FOLDER_TYPE_CONTACTS:
+ source = ews_backend_new_address_book (
+ backend, folder);
+ break;
+ default:
+ break;
+ }
+
+ if (source != NULL) {
+ e_source_registry_server_add_source (server, source);
+ g_object_unref (source);
+ }
+ }
+
+ g_object_unref (server);
+}
+
+static void
+ews_backend_sync_deleted_folders (EEwsBackend *backend,
+ GSList *list)
+{
+ ECollectionBackend *collection_backend;
+ ESourceRegistryServer *server;
+ GSList *link;
+
+ collection_backend = E_COLLECTION_BACKEND (backend);
+ server = e_collection_backend_ref_server (collection_backend);
+
+ for (link = list; link != NULL; link = g_slist_next (link)) {
+ const gchar *folder_id = link->data;
+ ESource *source = NULL;
+
+ if (folder_id != NULL)
+ source = g_hash_table_lookup (
+ backend->folders, folder_id);
+
+ if (source == NULL)
+ continue;
+
+ /* This will trigger a "child-removed" signal and
+ * our handler will remove the hash table entry. */
+ e_source_registry_server_remove_source (server, source);
+ }
+
+ g_object_unref (server);
+}
+
+static void
+ews_backend_add_gal_source (EEwsBackend *backend)
+{
+ ECollectionBackend *collection_backend;
+ ESourceAutocomplete *autocomplete_extension;
+ ESourceBackend *backend_extension;
+ ESourceEwsFolder *folder_extension;
+ ESourceOffline *offline_extension;
+ ESourceRegistryServer *server;
+ ESource *source = NULL;
+ CamelEwsSettings *settings;
+ const gchar *display_name;
+ const gchar *extension_name;
+ const gchar *gal_uid;
+ const gchar *oal_id;
+ const gchar *uid;
+ gchar *oal_selected;
+
+ settings = ews_backend_get_settings (backend);
+ collection_backend = E_COLLECTION_BACKEND (backend);
+
+ gal_uid = camel_ews_settings_get_gal_uid (settings);
+
+ if (gal_uid != NULL) {
+ server = e_collection_backend_ref_server (collection_backend);
+ source = e_source_registry_server_ref_source (server, gal_uid);
+ g_object_unref (server);
+
+ if (source != NULL) {
+ g_object_unref (source);
+ return;
+ }
+ }
+
+ oal_selected = camel_ews_settings_dup_oal_selected (settings);
+
+ /* This is supposed to be in the form: ID ':' NAME */
+ if (oal_selected != NULL) {
+ gchar *cp = strrchr (oal_selected, ':');
+ if (cp != NULL) {
+ *cp++ = '\0';
+ display_name = cp;
+ oal_id = oal_selected;
+ } else {
+ g_free (oal_selected);
+ oal_selected = NULL;
+ }
+ }
+
+ if (oal_selected == NULL) {
+ display_name = _("Global Address List");
+ oal_id = NULL;
+ }
+
+ g_free (backend->oal_selected);
+ backend->oal_selected = oal_selected; /* takes ownership */
+
+ if (oal_id != NULL)
+ source = e_collection_backend_new_child (
+ collection_backend, oal_id);
+ else
+ source = e_collection_backend_new_child (
+ collection_backend, "Global Address List");
+
+ e_source_set_display_name (source, display_name);
+
+ extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+ backend_extension = e_source_get_extension (source, extension_name);
+ e_source_backend_set_backend_name (backend_extension, "ews");
+
+ extension_name = E_SOURCE_EXTENSION_AUTOCOMPLETE;
+ autocomplete_extension = e_source_get_extension (source, extension_name);
+ e_source_autocomplete_set_include_me (autocomplete_extension, TRUE);
+
+ extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
+ folder_extension = e_source_get_extension (source, extension_name);
+ e_source_ews_folder_set_id (folder_extension, oal_id);
+
+ extension_name = E_SOURCE_EXTENSION_OFFLINE;
+ offline_extension = e_source_get_extension (source, extension_name);
+ e_source_offline_set_stay_synchronized (offline_extension, TRUE);
+
+ server = e_collection_backend_ref_server (collection_backend);
+ e_source_registry_server_add_source (server, source);
+ g_object_unref (server);
+
+ uid = e_source_get_uid (source);
+ camel_ews_settings_set_gal_uid (settings, uid);
+
+ g_object_unref (source);
+}
+
+static void
+ews_backend_source_changed_cb (ESource *source,
+ EEwsBackend *backend)
+{
+ CamelEwsSettings *settings;
+ const gchar *oal_selected;
+ const gchar *gal_uid;
+
+ settings = ews_backend_get_settings (backend);
+ gal_uid = camel_ews_settings_get_gal_uid (settings);
+ oal_selected = camel_ews_settings_get_oal_selected (settings);
+
+ g_print ("OAL: '%s' vs '%s'\n", oal_selected, backend->oal_selected);
+
+ if (g_strcmp0 (oal_selected, backend->oal_selected) == 0)
+ return;
+
+ /* Remove the old Global Address List source if present. */
+ if (gal_uid != NULL) {
+ ECollectionBackend *collection_backend;
+ ESourceRegistryServer *server;
+
+ collection_backend = E_COLLECTION_BACKEND (backend);
+ server = e_collection_backend_ref_server (collection_backend);
+ source = e_source_registry_server_ref_source (server, gal_uid);
+
+ if (source != NULL) {
+ e_source_registry_server_remove_source (server, source);
+ g_object_unref (source);
+ }
+
+ camel_ews_settings_set_gal_uid (settings, NULL);
+ }
+
+ ews_backend_add_gal_source (backend);
+}
+
+static gboolean
+ews_backend_sync_folders_idle_cb (gpointer user_data)
+{
+ SyncFoldersClosure *closure = user_data;
+
+ /* FIXME Handle updated folders. */
+
+ ews_backend_sync_deleted_folders (
+ closure->backend, closure->folders_deleted);
+ ews_backend_sync_created_folders (
+ closure->backend, closure->folders_created);
+
+ return FALSE;
+}
+
+static void
+ews_backend_dispose (GObject *object)
+{
+ EEwsBackend *backend = E_EWS_BACKEND (object);
+
+ g_hash_table_remove_all (backend->folders);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_ews_backend_parent_class)->dispose (object);
+}
+
+static void
+ews_backend_finalize (GObject *object)
+{
+ EEwsBackend *backend = E_EWS_BACKEND (object);
+
+ g_hash_table_destroy (backend->folders);
+
+ g_free (backend->oal_selected);
+
+ g_free (backend->sync_state);
+ g_mutex_free (backend->sync_state_lock);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_ews_backend_parent_class)->finalize (object);
+}
+
+static void
+ews_backend_populate (ECollectionBackend *backend)
+{
+ ESource *source;
+
+ /* We test authentication passwords by attempting to synchronize
+ * the folder hierarchy. Since we want to synchronize the folder
+ * hierarchy immediately on startup, schedule an authentication
+ * session first thing. */
+ ews_backend_queue_auth_session (backend);
+
+ ews_backend_add_gal_source (E_EWS_BACKEND (backend));
+
+ source = e_backend_get_source (E_BACKEND (backend));
+
+ g_signal_connect (
+ source, "changed",
+ G_CALLBACK (ews_backend_source_changed_cb), backend);
+}
+
+static void
+ews_backend_child_added (ECollectionBackend *backend,
+ ESource *child_source)
+{
+ EEwsBackend *ews_backend;
+ ESource *collection_source;
+ const gchar *extension_name;
+ gboolean is_mail = FALSE;
+
+ ews_backend = E_EWS_BACKEND (backend);
+
+ 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 display names with the collection. */
+ if (is_mail)
+ g_object_bind_property (
+ collection_source, "display-name",
+ child_source, "display-name",
+ G_BINDING_SYNC_CREATE);
+
+ /* 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);
+
+ g_object_bind_property (
+ collection_extension, "identity",
+ auth_child_extension, "user",
+ G_BINDING_SYNC_CREATE);
+ }
+
+ /* We track EWS folders in a hash table by folder ID. */
+ extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
+ if (e_source_has_extension (child_source, extension_name)) {
+ ESourceEwsFolder *extension;
+ gchar *folder_id;
+
+ extension = e_source_get_extension (
+ child_source, extension_name);
+ folder_id = e_source_ews_folder_dup_id (extension);
+ if (folder_id != NULL)
+ g_hash_table_insert (
+ ews_backend->folders, folder_id,
+ g_object_ref (child_source));
+ }
+
+ /* Chain up to parent's child_added() method. */
+ E_COLLECTION_BACKEND_CLASS (e_ews_backend_parent_class)->
+ child_added (backend, child_source);
+}
+
+static void
+ews_backend_child_removed (ECollectionBackend *backend,
+ ESource *child_source)
+{
+ EEwsBackend *ews_backend;
+ const gchar *extension_name;
+
+ ews_backend = E_EWS_BACKEND (backend);
+
+ /* We track EWS folders in a hash table by folder ID. */
+ extension_name = E_SOURCE_EXTENSION_EWS_FOLDER;
+ if (e_source_has_extension (child_source, extension_name)) {
+ ESourceEwsFolder *extension;
+ const gchar *folder_id;
+
+ extension = e_source_get_extension (
+ child_source, extension_name);
+ folder_id = e_source_ews_folder_get_id (extension);
+ if (folder_id != NULL)
+ g_hash_table_remove (
+ ews_backend->folders, folder_id);
+ }
+
+ /* Chain up to parent's child_removed() method. */
+ E_COLLECTION_BACKEND_CLASS (e_ews_backend_parent_class)->
+ child_removed (backend, child_source);
+}
+
+static ESourceAuthenticationResult
+ews_backend_try_password_sync (ESourceAuthenticator *authenticator,
+ const GString *password,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EEwsBackend *backend;
+ EEwsConnection *connection;
+ ESource *source;
+ ESourceCollection *collection_extension;
+ ESourceAuthenticationResult result;
+ CamelEwsSettings *settings;
+ GSList *folders_created = NULL;
+ GSList *folders_updated = NULL;
+ GSList *folders_deleted = NULL;
+ gboolean includes_last_folder = FALSE;
+ const gchar *extension_name;
+ gchar *sync_state;
+ gchar *hosturl;
+ gchar *user;
+ GError *local_error = NULL;
+
+ /* This tests the password by updating the folder hierarchy. */
+
+ backend = E_EWS_BACKEND (authenticator);
+ source = e_backend_get_source (E_BACKEND (backend));
+
+ settings = ews_backend_get_settings (backend);
+ hosturl = camel_ews_settings_dup_hosturl (settings);
+
+ extension_name = E_SOURCE_EXTENSION_COLLECTION;
+ collection_extension = e_source_get_extension (source, extension_name);
+ user = e_source_collection_dup_identity (collection_extension);
+
+ connection = e_ews_connection_new (
+ hosturl, user, password->str, NULL, NULL, error);
+
+ g_free (hosturl);
+ g_free (user);
+
+ if (connection == NULL)
+ return E_SOURCE_AUTHENTICATION_ERROR;
+
+ g_mutex_lock (backend->sync_state_lock);
+ sync_state = g_strdup (backend->sync_state);
+ g_mutex_unlock (backend->sync_state_lock);
+
+ /* XXX I think this leaks the old sync_state value when
+ * it replaces it with the new sync_state value. */
+ e_ews_connection_sync_folder_hierarchy_sync (
+ connection, EWS_PRIORITY_MEDIUM,
+ &sync_state, &includes_last_folder,
+ &folders_created, &folders_updated, &folders_deleted,
+ cancellable, &local_error);
+
+ g_object_unref (connection);
+
+ if (local_error == NULL) {
+ SyncFoldersClosure *closure;
+
+ /* We can now report the password was accepted.
+ * Because a password dialog may be stuck in a busy
+ * state, process the synchronization results from an
+ * idle callback so we don't delay the authentication
+ * session any longer than necessary. */
+
+ /* This takes ownership of the folder lists. */
+ closure = g_slice_new0 (SyncFoldersClosure);
+ closure->backend = g_object_ref (backend);
+ closure->folders_created = folders_created;
+ closure->folders_deleted = folders_deleted;
+ closure->folders_updated = folders_updated;
+
+ g_idle_add_full (
+ G_PRIORITY_DEFAULT_IDLE,
+ ews_backend_sync_folders_idle_cb, closure,
+ (GDestroyNotify) sync_folders_closure_free);
+
+ g_mutex_lock (backend->sync_state_lock);
+ g_free (backend->sync_state);
+ backend->sync_state = sync_state;
+ g_mutex_unlock (backend->sync_state_lock);
+
+ result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+
+ } else {
+ gboolean auth_failed;
+
+ /* Make sure we're not leaking anything. */
+ g_warn_if_fail (folders_created == NULL);
+ g_warn_if_fail (folders_updated == NULL);
+ g_warn_if_fail (folders_deleted == NULL);
+
+ auth_failed = g_error_matches (
+ local_error, EWS_CONNECTION_ERROR,
+ EWS_CONNECTION_ERROR_AUTHENTICATION_FAILED);
+
+ if (auth_failed) {
+ g_clear_error (&local_error);
+ result = E_SOURCE_AUTHENTICATION_REJECTED;
+ } else {
+ g_propagate_error (error, local_error);
+ result = E_SOURCE_AUTHENTICATION_ERROR;
+ }
+
+ g_free (sync_state);
+ }
+
+ return result;
+}
+
+static void
+e_ews_backend_class_init (EEwsBackendClass *class)
+{
+ GObjectClass *object_class;
+ ECollectionBackendClass *backend_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = ews_backend_dispose;
+ object_class->finalize = ews_backend_finalize;
+
+ backend_class = E_COLLECTION_BACKEND_CLASS (class);
+ backend_class->populate = ews_backend_populate;
+ backend_class->child_added = ews_backend_child_added;
+ backend_class->child_removed = ews_backend_child_removed;
+}
+
+static void
+e_ews_backend_class_finalize (EEwsBackendClass *class)
+{
+}
+
+static void
+e_ews_backend_authenticator_init (ESourceAuthenticatorInterface *interface)
+{
+ interface->try_password_sync = ews_backend_try_password_sync;
+}
+
+static void
+e_ews_backend_init (EEwsBackend *backend)
+{
+ backend->folders = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+
+ backend->sync_state_lock = g_mutex_new ();
+
+ /* This generates an ESourceCamel subtype for CamelEwsSettings. */
+ e_source_camel_generate_subtype ("ews", CAMEL_TYPE_EWS_SETTINGS);
+}
+
+static void
+e_ews_backend_factory_class_init (EEwsBackendFactoryClass *class)
+{
+ ECollectionBackendFactoryClass *factory_class;
+
+ factory_class = E_COLLECTION_BACKEND_FACTORY_CLASS (class);
+ factory_class->factory_name = "ews";
+ factory_class->backend_type = E_TYPE_EWS_BACKEND;
+}
+
+static void
+e_ews_backend_factory_class_finalize (EEwsBackendFactoryClass *class)
+{
+}
+
+static void
+e_ews_backend_factory_init (EEwsBackendFactory *factory)
+{
+}
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ e_ews_backend_register_type (type_module);
+ e_ews_backend_factory_register_type (type_module);
+
+ e_source_ews_folder_type_register (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
+
diff --git a/src/modules/module-ews-mail-config.c b/src/modules/module-ews-mail-config.c
new file mode 100644
index 0000000..5748f77
--- /dev/null
+++ b/src/modules/module-ews-mail-config.c
@@ -0,0 +1,43 @@
+/*
+ * module-ews-mail-config.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-config-ews-autodiscover.h"
+#include "e-mail-config-ews-backend.h"
+#include "e-mail-config-ews-gal.h"
+#include "e-mail-config-ews-oal-combo-box.h"
+#include "e-mail-config-ews-ooo-page.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)
+{
+ e_mail_config_ews_autodiscover_type_register (type_module);
+ e_mail_config_ews_backend_type_register (type_module);
+ e_mail_config_ews_gal_type_register (type_module);
+ e_mail_config_ews_oal_combo_box_type_register (type_module);
+ e_mail_config_ews_ooo_page_type_register (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
+
diff --git a/src/modules/module-ews-mail-config.error.xml b/src/modules/module-ews-mail-config.error.xml
new file mode 100644
index 0000000..3ac5023
--- /dev/null
+++ b/src/modules/module-ews-mail-config.error.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<error-list domain="ews">
+
+ <error type="warning" id="autodiscovery-error">
+ <primary>Autodiscovery query failed.</primary>
+ <secondary>The reported error was "{0}".</secondary>
+ </error>
+
+ <error type="warning" id="query-oal-error">
+ <primary>Failed to locate offline address books.</primary>
+ <secondary>The reported error was "{0}".</secondary>
+ </error>
+
+</error-list>
\ No newline at end of file
diff --git a/src/server/Makefile.am b/src/server/Makefile.am
index 580967e..fc84f82 100644
--- a/src/server/Makefile.am
+++ b/src/server/Makefile.am
@@ -42,6 +42,8 @@ libeews_1_2_la_CPPFLAGS = \
$(NULL)
libeews_1_2_la_SOURCES = \
+ camel-ews-settings.h \
+ camel-ews-settings.c \
ews-errors.h \
ews-errors.c \
ews-marshal.h \
@@ -57,6 +59,8 @@ libeews_1_2_la_SOURCES = \
e-soap-message.h \
e-soap-response.c \
e-soap-response.h \
+ e-source-ews-folder.c \
+ e-source-ews-folder.h \
$(NULL)
libeews_1_2_la_LIBADD = \
diff --git a/src/utils/camel-ews-settings.c b/src/server/camel-ews-settings.c
similarity index 89%
rename from src/utils/camel-ews-settings.c
rename to src/server/camel-ews-settings.c
index ff9e81d..6ac8645 100644
--- a/src/utils/camel-ews-settings.c
+++ b/src/server/camel-ews-settings.c
@@ -18,6 +18,8 @@
#include "camel-ews-settings.h"
+#include <libedataserver/e-data-server-util.h>
+
#define CAMEL_EWS_SETTINGS_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), CAMEL_TYPE_EWS_SETTINGS, CamelEwsSettingsPrivate))
@@ -29,6 +31,7 @@ struct _CamelEwsSettingsPrivate {
gboolean filter_junk_inbox;
gboolean oab_offline;
gchar *email;
+ gchar *gal_uid;
gchar *hosturl;
gchar *oaburl;
gchar *oal_selected;
@@ -41,6 +44,7 @@ enum {
PROP_EMAIL,
PROP_FILTER_JUNK,
PROP_FILTER_JUNK_INBOX,
+ PROP_GAL_UID,
PROP_HOST,
PROP_HOSTURL,
PROP_OABURL,
@@ -95,6 +99,12 @@ ews_settings_set_property (GObject *object,
g_value_get_boolean (value));
return;
+ case PROP_GAL_UID:
+ camel_ews_settings_set_gal_uid (
+ CAMEL_EWS_SETTINGS (object),
+ g_value_get_string (value));
+ return;
+
case PROP_HOST:
camel_network_settings_set_host (
CAMEL_NETWORK_SETTINGS (object),
@@ -189,6 +199,13 @@ ews_settings_get_property (GObject *object,
CAMEL_EWS_SETTINGS (object)));
return;
+ case PROP_GAL_UID:
+ g_value_take_string (
+ value,
+ camel_ews_settings_dup_gal_uid (
+ CAMEL_EWS_SETTINGS (object)));
+ return;
+
case PROP_HOST:
g_value_take_string (
value,
@@ -259,6 +276,7 @@ ews_settings_finalize (GObject *object)
g_mutex_free (priv->property_lock);
g_free (priv->email);
+ g_free (priv->gal_uid);
g_free (priv->hosturl);
g_free (priv->oaburl);
g_free (priv->oal_selected);
@@ -333,6 +351,18 @@ camel_ews_settings_class_init (CamelEwsSettingsClass *class)
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (
+ object_class,
+ PROP_GAL_UID,
+ g_param_spec_string (
+ "gal-uid",
+ "GAL UID",
+ "Global Address List data source UID",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
/* Inherited from CamelNetworkSettings. */
g_object_class_override_property (
object_class,
@@ -486,7 +516,7 @@ camel_ews_settings_set_email (CamelEwsSettings *settings,
g_mutex_lock (settings->priv->property_lock);
g_free (settings->priv->email);
- settings->priv->email = g_strdup (email);
+ settings->priv->email = e_util_strdup_strip (email);
g_mutex_unlock (settings->priv->property_lock);
@@ -574,6 +604,48 @@ camel_ews_settings_set_filter_junk_inbox (CamelEwsSettings *settings,
}
const gchar *
+camel_ews_settings_get_gal_uid (CamelEwsSettings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_EWS_SETTINGS (settings), NULL);
+
+ return settings->priv->gal_uid;
+}
+
+gchar *
+camel_ews_settings_dup_gal_uid (CamelEwsSettings *settings)
+{
+ const gchar *protected;
+ gchar *duplicate;
+
+ g_return_val_if_fail (CAMEL_IS_EWS_SETTINGS (settings), NULL);
+
+ g_mutex_lock (settings->priv->property_lock);
+
+ protected = camel_ews_settings_get_gal_uid (settings);
+ duplicate = g_strdup (protected);
+
+ g_mutex_unlock (settings->priv->property_lock);
+
+ return duplicate;
+}
+
+void
+camel_ews_settings_set_gal_uid (CamelEwsSettings *settings,
+ const gchar *gal_uid)
+{
+ g_return_if_fail (CAMEL_IS_EWS_SETTINGS (settings));
+
+ g_mutex_lock (settings->priv->property_lock);
+
+ g_free (settings->priv->gal_uid);
+ settings->priv->gal_uid = e_util_strdup_strip (gal_uid);
+
+ g_mutex_unlock (settings->priv->property_lock);
+
+ g_object_notify (G_OBJECT (settings), "gal-uid");
+}
+
+const gchar *
camel_ews_settings_get_hosturl (CamelEwsSettings *settings)
{
g_return_val_if_fail (CAMEL_IS_EWS_SETTINGS (settings), NULL);
@@ -608,7 +680,7 @@ camel_ews_settings_set_hosturl (CamelEwsSettings *settings,
g_mutex_lock (settings->priv->property_lock);
g_free (settings->priv->hosturl);
- settings->priv->hosturl = g_strdup (hosturl);
+ settings->priv->hosturl = e_util_strdup_strip (hosturl);
g_mutex_unlock (settings->priv->property_lock);
@@ -650,7 +722,7 @@ camel_ews_settings_set_oaburl (CamelEwsSettings *settings,
g_mutex_lock (settings->priv->property_lock);
g_free (settings->priv->oaburl);
- settings->priv->oaburl = g_strdup (oaburl);
+ settings->priv->oaburl = e_util_strdup_strip (oaburl);
g_mutex_unlock (settings->priv->property_lock);
@@ -711,7 +783,7 @@ camel_ews_settings_set_oal_selected (CamelEwsSettings *settings,
g_mutex_lock (settings->priv->property_lock);
g_free (settings->priv->oal_selected);
- settings->priv->oal_selected = g_strdup (oal_selected);
+ settings->priv->oal_selected = e_util_strdup_strip (oal_selected);
g_mutex_unlock (settings->priv->property_lock);
diff --git a/src/utils/camel-ews-settings.h b/src/server/camel-ews-settings.h
similarity index 93%
rename from src/utils/camel-ews-settings.h
rename to src/server/camel-ews-settings.h
index d976fbc..55a5700 100644
--- a/src/utils/camel-ews-settings.h
+++ b/src/server/camel-ews-settings.h
@@ -75,6 +75,10 @@ gboolean camel_ews_settings_get_filter_junk_inbox
void camel_ews_settings_set_filter_junk_inbox
(CamelEwsSettings *settings,
gboolean filter_junk_inbox);
+const gchar * camel_ews_settings_get_gal_uid (CamelEwsSettings *settings);
+gchar * camel_ews_settings_dup_gal_uid (CamelEwsSettings *settings);
+void camel_ews_settings_set_gal_uid (CamelEwsSettings *settings,
+ const gchar *gal_uid);
const gchar * camel_ews_settings_get_hosturl (CamelEwsSettings *settings);
gchar * camel_ews_settings_dup_hosturl (CamelEwsSettings *settings);
void camel_ews_settings_set_hosturl (CamelEwsSettings *settings,
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index a2116e8..2987666 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -35,6 +35,7 @@
#include <libical/ical.h>
#include "e-ews-connection.h"
#include <libedataserver/e-flag.h>
+#include <libedataserver/e-data-server-util.h>
#include "e-ews-message.h"
#include "e-ews-item-change.h"
#include "ews-marshal.h"
@@ -1124,6 +1125,27 @@ ews_connection_authenticate (SoupSession *sess,
}
void
+ews_oal_free (EwsOAL *oal)
+{
+ if (oal != NULL) {
+ g_free (oal->id);
+ g_free (oal->dn);
+ g_free (oal->name);
+ g_free (oal);
+ }
+}
+
+void
+ews_oal_details_free (EwsOALDetails *details)
+{
+ if (details != NULL) {
+ g_free (details->sha);
+ g_free (details->filename);
+ g_free (details);
+ }
+}
+
+void
ews_user_id_free (EwsUserId *id)
{
if (id)
@@ -1271,7 +1293,7 @@ e_ews_connection_new (const gchar *uri,
}
static xmlDoc *
-e_ews_autodiscover_ws_xml (const gchar *email)
+e_ews_autodiscover_ws_xml (const gchar *email_address)
{
xmlDoc *doc;
xmlNode *node;
@@ -1285,7 +1307,7 @@ e_ews_autodiscover_ws_xml (const gchar *email)
node = xmlNewChild(node, ns, (xmlChar *)"Request", NULL);
xmlNewChild(node, ns, (xmlChar *)"EMailAddress",
- (xmlChar *) email);
+ (xmlChar *) email_address);
xmlNewChild(node, ns, (xmlChar *)"AcceptableResponseSchema",
(xmlChar *)"http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a");
@@ -1295,29 +1317,31 @@ e_ews_autodiscover_ws_xml (const gchar *email)
struct _autodiscover_data {
EEwsConnection *cnc;
xmlOutputBuffer *buf;
- GSimpleAsyncResult *simple;
SoupMessage *msgs[4];
- EEwsAutoDiscoverCallback cb;
- gpointer cbdata;
+
+ GCancellable *cancellable;
+ gulong cancel_id;
+
+ /* Results */
+ gchar *as_url;
+ gchar *oab_url;
};
-/* Called in the context e_ews_autodiscover_ws_url() was called from,
- * with the final result. */
-static void autodiscover_done_cb (GObject *cnc, GAsyncResult *res,
- gpointer user_data)
+static void
+autodiscover_data_free (struct _autodiscover_data *ad)
{
- struct _autodiscover_data *ad = user_data;
- EwsUrls *urls = NULL;
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
- GError *error = NULL;
+ g_object_unref (ad->cnc);
+ xmlOutputBufferClose (ad->buf);
- if (!g_simple_async_result_propagate_error (simple, &error))
- urls = g_simple_async_result_get_op_res_gpointer (simple);
+ if (ad->cancellable != NULL) {
+ g_cancellable_disconnect (ad->cancellable, ad->cancel_id);
+ g_object_unref (ad->cancellable);
+ }
- xmlOutputBufferClose (ad->buf);
+ g_free (ad->as_url);
+ g_free (ad->oab_url);
- ad->cb (urls, ad->cbdata, error);
- g_free (ad);
+ g_slice_free (struct _autodiscover_data, ad);
}
static void
@@ -1335,6 +1359,13 @@ ews_dump_raw_soup_response (SoupMessage *msg)
}
+static void
+autodiscover_cancelled_cb (GCancellable *cancellable,
+ SoupSession *soup_session)
+{
+ soup_session_abort (soup_session);
+}
+
/* Called when each soup message completes */
static void
autodiscover_response_cb (SoupSession *session,
@@ -1342,15 +1373,17 @@ autodiscover_response_cb (SoupSession *session,
gpointer data)
{
- GError *error = NULL;
- struct _autodiscover_data *ad = data;
+ GSimpleAsyncResult *simple = data;
+ struct _autodiscover_data *ad;
EwsUrls *urls = NULL;
guint status = msg->status_code;
xmlDoc *doc;
xmlNode *node;
gint idx;
gboolean success = FALSE;
- GSimpleAsyncResult *simple;
+ GError *error = NULL;
+
+ ad = g_simple_async_result_get_op_res_gpointer (simple);
for (idx = 0; idx < 4; idx++) {
if (ad->msgs[idx] == msg)
@@ -1363,38 +1396,29 @@ autodiscover_response_cb (SoupSession *session,
ad->msgs[idx] = NULL;
- /* Take 'simple' from 'ad' before actual call
- to g_simple_async_result_complete_in_idle(),
- for cases where the 'ad' is freed in autodiscover_done_cb()
- before this function finishes. Suggested by Dan Winship.
- */
- simple = ad->simple;
-
if (status != 200) {
g_set_error (
- &error, EWS_CONNECTION_ERROR,
- status,
- _("Code: %d - Unexpected response from server"),
- status);
+ &error, SOUP_HTTP_ERROR, status,
+ "%d %s", status, msg->reason_phrase);
goto failed;
}
ews_dump_raw_soup_response (msg);
- doc = xmlReadMemory (msg->response_body->data, msg->response_body->length,
- "autodiscover.xml", NULL, 0);
+ doc = xmlReadMemory (
+ msg->response_body->data,
+ msg->response_body->length,
+ "autodiscover.xml", NULL, 0);
if (!doc) {
g_set_error (
- &error, EWS_CONNECTION_ERROR,
- -1,
- _("Failed to parse autodiscover response XML"));
+ &error, EWS_CONNECTION_ERROR, -1,
+ _("Failed to parse autodiscover response XML"));
goto failed;
}
node = xmlDocGetRootElement (doc);
if (strcmp((char *)node->name, "Autodiscover")) {
g_set_error (
- &error, EWS_CONNECTION_ERROR,
- -1,
- _("Failed to find <Autodiscover> element\n"));
+ &error, EWS_CONNECTION_ERROR, -1,
+ _("Failed to find <Autodiscover> element"));
goto failed;
}
for (node = node->children; node; node = node->next) {
@@ -1404,9 +1428,8 @@ autodiscover_response_cb (SoupSession *session,
}
if (!node) {
g_set_error (
- &error, EWS_CONNECTION_ERROR,
- -1,
- _("Failed to find <Response> element\n"));
+ &error, EWS_CONNECTION_ERROR, -1,
+ _("Failed to find <Response> element"));
goto failed;
}
for (node = node->children; node; node = node->next) {
@@ -1416,9 +1439,8 @@ autodiscover_response_cb (SoupSession *session,
}
if (!node) {
g_set_error (
- &error, EWS_CONNECTION_ERROR,
- -1,
- _("Failed to find <Account> element\n"));
+ &error, EWS_CONNECTION_ERROR, -1,
+ _("Failed to find <Account> element"));
goto failed;
}
@@ -1435,9 +1457,9 @@ autodiscover_response_cb (SoupSession *session,
g_free (urls->as_url);
g_free (urls->oab_url);
g_free (urls);
- g_set_error (&error, EWS_CONNECTION_ERROR,
- -1,
- _("Failed to find <ASUrl> and <OABUrl> in autodiscover response"));
+ g_set_error (
+ &error, EWS_CONNECTION_ERROR, -1,
+ _("Failed to find <ASUrl> and <OABUrl> in autodiscover response"));
goto failed;
}
@@ -1446,18 +1468,21 @@ autodiscover_response_cb (SoupSession *session,
if (ad->msgs[idx]) {
SoupMessage *m = ad->msgs[idx];
ad->msgs[idx] = NULL;
- soup_session_cancel_message (ad->cnc->priv->soup_session,
- m, SOUP_STATUS_CANCELLED);
+ soup_session_cancel_message (
+ ad->cnc->priv->soup_session,
+ m, SOUP_STATUS_CANCELLED);
}
}
- g_simple_async_result_set_op_res_gpointer (ad->simple, urls, NULL);
- g_simple_async_result_complete_in_idle (ad->simple);
- /* the 'simple' holds reference on 'cnc' and this function
- is called in a dedicated thread, which 'cnc' joins on dispose,
- thus to avoid race condition, unref the object in its own thread */
- ews_unref_in_thread (G_OBJECT (simple));
- return;
+ ad->as_url = urls->as_url;
+ urls->as_url = NULL;
+
+ ad->oab_url = urls->oab_url;
+ urls->oab_url = NULL;
+
+ g_free (urls);
+
+ goto exit;
failed:
for (idx = 0; idx < 4; idx++) {
@@ -1473,12 +1498,11 @@ failed:
* and in some cases (stupid firewalls causing timeouts)
* that's going to be the least interesting one. We probably
* want the *first* error */
- g_simple_async_result_set_from_error (ad->simple, error);
- g_simple_async_result_complete_in_idle (ad->simple);
- /* the 'simple' holds reference on 'cnc' and this function
- is called in a dedicated thread, which 'cnc' joins on dispose,
- thus to avoid race condition, unref the object in its own thread */
- ews_unref_in_thread (G_OBJECT (simple));
+ g_simple_async_result_take_error (simple, error);
+
+exit:
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
}
static void post_restarted (SoupMessage *msg, gpointer data)
@@ -1501,20 +1525,28 @@ e_ews_get_msg_for_url (const gchar *url,
{
SoupMessage *msg;
- msg = soup_message_new (buf?"POST":"GET", url);
- soup_message_headers_append (msg->request_headers,
- "User-Agent", "libews/0.1");
+ if (url == NULL)
+ return NULL;
+
+ msg = soup_message_new (buf != NULL ? "POST" : "GET", url);
- if (buf) {
- soup_message_set_request (msg, "text/xml; charset=utf-8", SOUP_MEMORY_COPY,
- (gchar *) buf->buffer->content,
- buf->buffer->use);
- g_signal_connect (msg, "restarted",
- G_CALLBACK (post_restarted), buf);
+ soup_message_headers_append (
+ msg->request_headers,
+ "User-Agent", "libews/0.1");
+
+ if (buf != NULL) {
+ soup_message_set_request (
+ msg, "text/xml; charset=utf-8", SOUP_MEMORY_COPY,
+ (gchar *) buf->buffer->content, buf->buffer->use);
+ g_signal_connect (
+ msg, "restarted",
+ G_CALLBACK (post_restarted), buf);
}
if (g_getenv ("EWS_DEBUG") && (atoi (g_getenv ("EWS_DEBUG")) >= 1)) {
- soup_buffer_free (soup_message_body_flatten (SOUP_MESSAGE (msg)->request_body));
+ soup_buffer_free (
+ soup_message_body_flatten (
+ SOUP_MESSAGE (msg)->request_body));
/* print request's body */
printf ("\n The request headers");
printf ("\n ===================");
@@ -1526,38 +1558,78 @@ e_ews_get_msg_for_url (const gchar *url,
return msg;
}
+gboolean
+e_ews_autodiscover_ws_url_sync (CamelEwsSettings *settings,
+ const gchar *email_address,
+ const gchar *password,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ g_return_val_if_fail (CAMEL_IS_EWS_SETTINGS (settings), FALSE);
+ g_return_val_if_fail (email_address != NULL, FALSE);
+ g_return_val_if_fail (password != NULL, FALSE);
+
+ closure = e_async_closure_new ();
+
+ e_ews_autodiscover_ws_url (
+ settings, email_address, password, cancellable,
+ e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_ews_autodiscover_ws_url_finish (settings, result, error);
+
+ e_async_closure_free (closure);
+
+ return success;
+}
+
void
-e_ews_autodiscover_ws_url (EEwsAutoDiscoverCallback cb,
- gpointer cbdata,
- const gchar *email,
+e_ews_autodiscover_ws_url (CamelEwsSettings *settings,
+ const gchar *email_address,
const gchar *password,
- const gchar *ews_url,
- const gchar *username)
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
+ CamelNetworkSettings *network_settings;
+ GSimpleAsyncResult *simple;
struct _autodiscover_data *ad;
xmlOutputBuffer *buf;
- GError *error = NULL;
gchar *url1, *url2, *url3, *url4;
gchar *domain;
xmlDoc *doc;
EEwsConnection *cnc;
+ SoupURI *soup_uri = NULL;
gboolean use_secure = TRUE;
+ const gchar *host_url;
+ const gchar *user;
+ GError *error = NULL;
- if (!password || !email) {
- g_set_error (&error, EWS_CONNECTION_ERROR,
- -1, _("Both email and password must be provided"));
- goto err;
- }
-
- domain = strchr (email, '@');
- if (!(domain && *domain)) {
- g_set_error (&error, EWS_CONNECTION_ERROR,
- -1, _("Wrong email id"));
- goto err;
+ g_return_if_fail (CAMEL_IS_EWS_SETTINGS (settings));
+ g_return_if_fail (email_address != NULL);
+ g_return_if_fail (password != NULL);
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (settings), callback,
+ user_data, e_ews_autodiscover_ws_url);
+
+ domain = strchr (email_address, '@');
+ if (domain == NULL || *domain == '\0') {
+ g_simple_async_result_set_error (
+ simple, EWS_CONNECTION_ERROR, -1,
+ "%s", _("Email address is missing a domain part"));
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ return;
}
domain++;
- doc = e_ews_autodiscover_ws_xml (email);
+ doc = e_ews_autodiscover_ws_xml (email_address);
buf = xmlAllocOutputBuffer (NULL);
xmlNodeDumpOutput (buf, doc, xmlDocGetRootElement (doc), 0, 1, NULL);
xmlOutputBufferFlush (buf);
@@ -1566,31 +1638,43 @@ e_ews_autodiscover_ws_url (EEwsAutoDiscoverCallback cb,
url2 = NULL;
url3 = NULL;
url4 = NULL;
- if (ews_url) {
- SoupURI *uri = soup_uri_new (ews_url);
- if (uri) {
- use_secure = g_strcmp0 (soup_uri_get_scheme (uri), "https") == 0;
+ host_url = camel_ews_settings_get_hosturl (settings);
+ if (host_url != NULL)
+ soup_uri = soup_uri_new (host_url);
- url1 = g_strdup_printf ("http%s://%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", soup_uri_get_host (uri));
- url2 = g_strdup_printf ("http%s://autodiscover.%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", soup_uri_get_host (uri));
- soup_uri_free (uri);
- }
+ if (soup_uri != NULL) {
+ const gchar *host = soup_uri_get_host (soup_uri);
+ const gchar *scheme = soup_uri_get_scheme (soup_uri);
+
+ use_secure = g_strcmp0 (scheme, "https") == 0;
+
+ url1 = g_strdup_printf ("http%s://%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", host);
+ url2 = g_strdup_printf ("http%s://autodiscover.%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", host);
+
+ soup_uri_free (soup_uri);
}
url3 = g_strdup_printf ("http%s://%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", domain);
url4 = g_strdup_printf ("http%s://autodiscover.%s/autodiscover/autodiscover.xml", use_secure ? "s" : "", domain);
- cnc = e_ews_connection_new (url3, (username && *username) ? username : email, password, NULL, NULL, &error);
- if (!cnc) {
+ network_settings = CAMEL_NETWORK_SETTINGS (settings);
+ user = camel_network_settings_get_user (network_settings);
+ if (user == NULL || *user == '\0')
+ user = email_address;
+
+ cnc = e_ews_connection_new (url3, user, password, NULL, NULL, &error);
+ if (cnc == NULL) {
g_free (url1);
g_free (url2);
g_free (url3);
g_free (url4);
xmlOutputBufferClose (buf);
xmlFreeDoc (doc);
- err:
- cb (NULL, cbdata, error);
+
+ g_simple_async_result_take_error (simple, error);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
return;
}
@@ -1602,34 +1686,46 @@ e_ews_autodiscover_ws_url (EEwsAutoDiscoverCallback cb,
* to time out. So run both queries in parallel and let the fastest
* (successful) one win.
*/
- ad = g_new0 (struct _autodiscover_data, 1);
- ad->cb = cb;
- ad->cbdata = cbdata;
- ad->cnc = cnc;
- ad->buf = buf;
- ad->simple = g_simple_async_result_new (G_OBJECT (cnc), autodiscover_done_cb,
- ad, e_ews_autodiscover_ws_url);
- ad->msgs[0] = url1 ? e_ews_get_msg_for_url (url1, buf) : NULL;
- ad->msgs[1] = url2 ? e_ews_get_msg_for_url (url2, buf) : NULL;
- ad->msgs[2] = url3 ? e_ews_get_msg_for_url (url3, buf) : NULL;
- ad->msgs[3] = url4 ? e_ews_get_msg_for_url (url4, buf) : NULL;
+ ad = g_slice_new0 (struct _autodiscover_data);
+ ad->cnc = cnc; /* takes ownership */
+ ad->buf = buf; /* takes ownership */
+
+ if (G_IS_CANCELLABLE (cancellable)) {
+ ad->cancellable = g_object_ref (cancellable);
+ ad->cancel_id = g_cancellable_connect (
+ ad->cancellable,
+ G_CALLBACK (autodiscover_cancelled_cb),
+ g_object_ref (cnc->priv->soup_session),
+ (GDestroyNotify) g_object_unref);
+ }
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, ad, (GDestroyNotify) autodiscover_data_free);
+
+ /* Passing a NULL URL string returns NULL. */
+ ad->msgs[0] = e_ews_get_msg_for_url (url1, buf);
+ ad->msgs[1] = e_ews_get_msg_for_url (url2, buf);
+ ad->msgs[2] = e_ews_get_msg_for_url (url3, buf);
+ ad->msgs[3] = e_ews_get_msg_for_url (url4, buf);
/* These have to be submitted only after they're both set in ad->msgs[]
* or there will be races with fast completion */
- if (ad->msgs[0])
- soup_session_queue_message (cnc->priv->soup_session, ad->msgs[0],
- autodiscover_response_cb, ad);
- if (ad->msgs[1])
- soup_session_queue_message (cnc->priv->soup_session, ad->msgs[1],
- autodiscover_response_cb, ad);
- if (ad->msgs[2])
- soup_session_queue_message (cnc->priv->soup_session, ad->msgs[2],
- autodiscover_response_cb, ad);
- if (ad->msgs[3])
- soup_session_queue_message (cnc->priv->soup_session, ad->msgs[3],
- autodiscover_response_cb, ad);
-
- g_object_unref (cnc); /* the GSimpleAsyncResult holds it now */
+ if (ad->msgs[0] != NULL)
+ soup_session_queue_message (
+ cnc->priv->soup_session, ad->msgs[0],
+ autodiscover_response_cb, simple);
+ if (ad->msgs[1] != NULL)
+ soup_session_queue_message (
+ cnc->priv->soup_session, ad->msgs[1],
+ autodiscover_response_cb, simple);
+ if (ad->msgs[2] != NULL)
+ soup_session_queue_message (
+ cnc->priv->soup_session, ad->msgs[2],
+ autodiscover_response_cb, simple);
+ if (ad->msgs[3] != NULL)
+ soup_session_queue_message (
+ cnc->priv->soup_session, ad->msgs[3],
+ autodiscover_response_cb, simple);
xmlFreeDoc (doc);
g_free (url1);
@@ -1638,15 +1734,46 @@ e_ews_autodiscover_ws_url (EEwsAutoDiscoverCallback cb,
g_free (url4);
}
-struct _oal_req_data {
- EEwsConnection *cnc;
+gboolean
+e_ews_autodiscover_ws_url_finish (CamelEwsSettings *settings,
+ GAsyncResult *result,
+ GError **error)
+{
GSimpleAsyncResult *simple;
- SoupMessage *msg;
- GCancellable *cancellable;
- gulong cancel_handler_id;
+ struct _autodiscover_data *ad;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (settings),
+ e_ews_autodiscover_ws_url), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ ad = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_warn_if_fail (ad->as_url != NULL);
+ g_warn_if_fail (ad->oab_url != NULL);
+
+ camel_ews_settings_set_hosturl (settings, ad->as_url);
+ camel_ews_settings_set_oaburl (settings, ad->oab_url);
+
+ return TRUE;
+}
+
+struct _oal_req_data {
+ SoupSession *soup_session;
+ SoupMessage *soup_message;
gchar *oal_id;
gchar *oal_element;
+ GSList *oals;
+ GSList *elements;
+
+ GCancellable *cancellable;
+ gulong cancel_id;
+
/* for dowloading oal file */
gchar *cache_filename;
GError *error;
@@ -1656,6 +1783,28 @@ struct _oal_req_data {
gsize received_size;
};
+static void
+oal_req_data_free (struct _oal_req_data *data)
+{
+ /* The SoupMessage is owned by the SoupSession. */
+ g_object_ref (data->soup_session);
+
+ g_free (data->oal_id);
+ g_free (data->oal_element);
+
+ g_slist_free_full (data->oals, (GDestroyNotify) ews_oal_free);
+ g_slist_free_full (data->elements, (GDestroyNotify) ews_oal_details_free);
+
+ if (data->cancellable != NULL) {
+ g_cancellable_disconnect (data->cancellable, data->cancel_id);
+ g_object_unref (data->cancellable);
+ }
+
+ g_free (data->cache_filename);
+
+ g_slice_free (struct _oal_req_data, data);
+}
+
static gchar *
get_property (xmlNodePtr node_ptr,
const gchar *name)
@@ -1725,56 +1874,65 @@ parse_oal_full_details (xmlNode *node,
}
static void
-oal_response_cb (SoupSession *session,
- SoupMessage *msg,
+oal_response_cb (SoupSession *soup_session,
+ SoupMessage *soup_message,
gpointer user_data)
{
- GError *error = NULL;
- guint status = msg->status_code;
+ GSimpleAsyncResult *simple;
+ struct _oal_req_data *data;
xmlDoc *doc;
xmlNode *node;
- struct _oal_req_data *data = (struct _oal_req_data *) user_data;
- GSList *oals = NULL;
- if (status != 200) {
- g_set_error (&error, EWS_CONNECTION_ERROR, status,
- _("Code: %d - Unexpected response from server"),
- status);
+ simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ data = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (soup_message->status_code != 200) {
+ g_simple_async_result_set_error (
+ simple, SOUP_HTTP_ERROR,
+ soup_message->status_code,
+ "%d %s",
+ soup_message->status_code,
+ soup_message->reason_phrase);
goto exit;
}
- ews_dump_raw_soup_response (msg);
- doc = xmlReadMemory (msg->response_body->data, msg->response_body->length,
- "oab.xml", NULL, 0);
- if (!doc) {
- g_set_error (&error, EWS_CONNECTION_ERROR,
- -1, _("Failed to parse oab XML"));
+ ews_dump_raw_soup_response (soup_message);
+
+ doc = xmlReadMemory (
+ soup_message->response_body->data,
+ soup_message->response_body->length,
+ "oab.xml", NULL, 0);
+ if (doc == NULL) {
+ g_simple_async_result_set_error (
+ simple, EWS_CONNECTION_ERROR, -1,
+ "%s", _("Failed to parse oab XML"));
goto exit;
}
node = xmlDocGetRootElement (doc);
- if (strcmp((char *)node->name, "OAB")) {
- g_set_error (&error, EWS_CONNECTION_ERROR, -1,
- _("Failed to find <OAB> element\n"));
+ if (strcmp ((gchar *) node->name, "OAB") != 0) {
+ g_simple_async_result_set_error (
+ simple, EWS_CONNECTION_ERROR, -1,
+ "%s", _("Failed to find <OAB> element\n"));
goto exit;
}
for (node = node->children; node; node = node->next) {
- if (node->type == XML_ELEMENT_NODE && !strcmp((char *)node->name, "OAL")) {
- if (!data->oal_id) {
+ if (node->type == XML_ELEMENT_NODE && strcmp((gchar *) node->name, "OAL") == 0) {
+ if (data->oal_id != NULL) {
EwsOAL *oal = g_new0 (EwsOAL, 1);
oal->id = get_property (node, "id");
oal->dn = get_property (node, "dn");
oal->name = get_property (node, "name");
- oals = g_slist_prepend (oals, oal);
+ data->oals = g_slist_prepend (data->oals, oal);
} else {
gchar *id = get_property (node, "id");
- if (!strcmp (id, data->oal_id)) {
+ if (strcmp (id, data->oal_id) == 0) {
/* parse details of full_details file */
- oals = parse_oal_full_details (node, data->oal_element);
+ data->elements = parse_oal_full_details (node, data->oal_element);
g_free (id);
break;
@@ -1785,31 +1943,48 @@ oal_response_cb (SoupSession *session,
}
}
- oals = g_slist_reverse (oals);
- g_simple_async_result_set_op_res_gpointer (data->simple, oals, NULL);
+ data->oals = g_slist_reverse (data->oals);
exit:
- if (data->cancellable)
- g_signal_handler_disconnect (data->cancellable, data->cancel_handler_id);
-
- if (error) {
- g_simple_async_result_set_from_error (data->simple, error);
- g_clear_error (&error);
- }
-
- g_simple_async_result_complete_in_idle (data->simple);
- g_free (data->oal_id);
- g_free (data->oal_element);
- g_free (data);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
}
static void
ews_cancel_msg (GCancellable *cancellable,
- gpointer user_data)
+ struct _oal_req_data *data)
{
- struct _oal_req_data *data = (struct _oal_req_data *) user_data;
+ soup_session_cancel_message (
+ data->soup_session,
+ data->soup_message,
+ SOUP_STATUS_CANCELLED);
+}
+
+gboolean
+e_ews_connection_get_oal_list_sync (EEwsConnection *cnc,
+ GSList **oals,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_EWS_CONNECTION (cnc), FALSE);
+
+ closure = e_async_closure_new ();
+
+ e_ews_connection_get_oal_list (
+ cnc, cancellable, e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_ews_connection_get_oal_list_finish (
+ cnc, result, oals, error);
- soup_session_cancel_message (data->cnc->priv->soup_session, SOUP_MESSAGE (data->msg), SOUP_STATUS_CANCELLED);
+ e_async_closure_free (closure);
+
+ return success;
}
void
@@ -1819,28 +1994,37 @@ e_ews_connection_get_oal_list (EEwsConnection *cnc,
gpointer user_data)
{
GSimpleAsyncResult *simple;
- SoupMessage *msg;
+ SoupSession *soup_session;
+ SoupMessage *soup_message;
struct _oal_req_data *data;
- g_return_if_fail (cnc != NULL);
+ g_return_if_fail (E_IS_EWS_CONNECTION (cnc));
- msg = e_ews_get_msg_for_url (cnc->priv->uri, NULL);
+ soup_session = cnc->priv->soup_session;
+ soup_message = e_ews_get_msg_for_url (cnc->priv->uri, NULL);
- simple = g_simple_async_result_new (G_OBJECT (cnc),
- callback,
- user_data,
- e_ews_connection_get_oal_list);
- data = g_new0 (struct _oal_req_data, 1);
- data->cnc = cnc;
- data->simple = simple;
- data->cancellable = cancellable;
- data->msg = msg;
+ data = g_slice_new0 (struct _oal_req_data);
+ data->soup_session = g_object_ref (soup_session);
+ data->soup_message = soup_message; /* the session owns this */
+
+ if (G_IS_CANCELLABLE (cancellable)) {
+ data->cancellable = g_object_ref (cancellable);
+ data->cancel_id = g_cancellable_connect (
+ data->cancellable,
+ G_CALLBACK (ews_cancel_msg),
+ data, (GDestroyNotify) NULL);
+ }
- if (cancellable)
- data->cancel_handler_id = g_cancellable_connect (cancellable,
- G_CALLBACK (ews_cancel_msg), (gpointer) data, NULL);
- soup_session_queue_message (cnc->priv->soup_session, msg,
- oal_response_cb, data);
+ simple = g_simple_async_result_new (
+ G_OBJECT (cnc), callback, user_data,
+ e_ews_connection_get_oal_list);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, data, (GDestroyNotify) oal_req_data_free);
+
+ soup_session_queue_message (
+ soup_session, soup_message,
+ oal_response_cb, simple);
}
gboolean
@@ -1850,8 +2034,9 @@ e_ews_connection_get_oal_list_finish (EEwsConnection *cnc,
GError **error)
{
GSimpleAsyncResult *simple;
+ struct _oal_req_data *data;
- g_return_val_if_fail (cnc != NULL, FALSE);
+ g_return_val_if_fail (E_IS_EWS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (
g_simple_async_result_is_valid (
@@ -1859,15 +2044,61 @@ e_ews_connection_get_oal_list_finish (EEwsConnection *cnc,
FALSE);
simple = G_SIMPLE_ASYNC_RESULT (result);
+ data = g_simple_async_result_get_op_res_gpointer (simple);
if (g_simple_async_result_propagate_error (simple, error))
return FALSE;
- *oals= g_simple_async_result_get_op_res_gpointer (simple);
+ if (oals != NULL) {
+ *oals = data->oals;
+ data->oals = NULL;
+ }
return TRUE;
}
+/**
+ * e_ews_connection_get_oal_detail
+ * @cnc:
+ * @oal_id:
+ * @oal_element:
+ * @elements: "Full" "Diff" "Template" are the possible values.
+ * @cancellable:
+ * @error:
+ *
+ *
+ * Returns:
+ **/
+gboolean
+e_ews_connection_get_oal_detail_sync (EEwsConnection *cnc,
+ const gchar *oal_id,
+ const gchar *oal_element,
+ GSList **elements,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_EWS_CONNECTION (cnc), FALSE);
+
+ closure = e_async_closure_new ();
+
+ e_ews_connection_get_oal_detail (
+ cnc, oal_id, oal_element, cancellable,
+ e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_ews_connection_get_oal_detail_finish (
+ cnc, result, elements, error);
+
+ e_async_closure_free (closure);
+
+ return success;
+}
+
void
e_ews_connection_get_oal_detail (EEwsConnection *cnc,
const gchar *oal_id,
@@ -1877,31 +2108,39 @@ e_ews_connection_get_oal_detail (EEwsConnection *cnc,
gpointer user_data)
{
GSimpleAsyncResult *simple;
- SoupMessage *msg;
+ SoupSession *soup_session;
+ SoupMessage *soup_message;
struct _oal_req_data *data;
- g_return_if_fail (cnc != NULL);
+ g_return_if_fail (E_IS_EWS_CONNECTION (cnc));
- msg = e_ews_get_msg_for_url (cnc->priv->uri, NULL);
+ soup_session = cnc->priv->soup_session;
+ soup_message = e_ews_get_msg_for_url (cnc->priv->uri, NULL);
- simple = g_simple_async_result_new (G_OBJECT (cnc),
- callback,
- user_data,
- e_ews_connection_get_oal_detail);
- data = g_new0 (struct _oal_req_data, 1);
- data->cnc = cnc;
- data->simple = simple;
- data->cancellable = cancellable;
- data->msg = msg;
+ data = g_slice_new0 (struct _oal_req_data);
+ data->soup_session = g_object_ref (soup_session);
+ data->soup_message = soup_message; /* the session owns this */
data->oal_id = g_strdup (oal_id);
data->oal_element = g_strdup (oal_element);
- if (cancellable)
- data->cancel_handler_id = g_cancellable_connect (cancellable,
- G_CALLBACK (ews_cancel_msg), (gpointer) data, NULL);
- soup_session_queue_message (cnc->priv->soup_session, msg,
- oal_response_cb, data);
+ if (G_IS_CANCELLABLE (cancellable)) {
+ data->cancellable = g_object_ref (cancellable);
+ data->cancel_id = g_cancellable_connect (
+ data->cancellable,
+ G_CALLBACK (ews_cancel_msg),
+ data, (GDestroyNotify) NULL);
+ }
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (cnc), callback, user_data,
+ e_ews_connection_get_oal_detail);
+ g_simple_async_result_set_op_res_gpointer (
+ simple, data, (GDestroyNotify) oal_req_data_free);
+
+ soup_session_queue_message (
+ soup_session, soup_message,
+ oal_response_cb, simple);
}
gboolean
@@ -1911,6 +2150,7 @@ e_ews_connection_get_oal_detail_finish (EEwsConnection *cnc,
GError **error)
{
GSimpleAsyncResult *simple;
+ struct _oal_req_data *data;
g_return_val_if_fail (cnc != NULL, FALSE);
g_return_val_if_fail (
@@ -1919,95 +2159,48 @@ e_ews_connection_get_oal_detail_finish (EEwsConnection *cnc,
FALSE);
simple = G_SIMPLE_ASYNC_RESULT (result);
+ data = g_simple_async_result_get_op_res_gpointer (simple);
if (g_simple_async_result_propagate_error (simple, error))
return FALSE;
- *elements = g_simple_async_result_get_op_res_gpointer (simple);
+ if (elements != NULL) {
+ *elements = data->elements;
+ data->elements = NULL;
+ }
return TRUE;
}
-/**
- * e_ews_connection_get_oal_detail_sync:
- * @cnc:
- * @oal_id:
- * @oal_element:
- * @elements: "Full" "Diff" "Template" are the possible values.
- * @cancellable:
- * @error:
- *
- *
- * Returns:
- **/
-gboolean
-e_ews_connection_get_oal_detail_sync (EEwsConnection *cnc,
- const gchar *oal_id,
- const gchar *oal_element,
- GSList **elements,
- GCancellable *cancellable,
- GError **error)
-{
- EwsSyncData *sync_data;
- gboolean result;
-
- g_return_val_if_fail (cnc != NULL, FALSE);
-
- sync_data = g_new0 (EwsSyncData, 1);
- sync_data->eflag = e_flag_new ();
-
- e_ews_connection_get_oal_detail (
- cnc, oal_id, oal_element,
- cancellable,
- ews_sync_reply_cb,
- sync_data);
-
- e_flag_wait (sync_data->eflag);
-
- result = e_ews_connection_get_oal_detail_finish
- (cnc, sync_data->res,
- elements, error);
-
- e_flag_free (sync_data->eflag);
- g_object_unref (sync_data->res);
- g_free (sync_data);
-
- return result;
-}
-
static void
-oal_download_response_cb (SoupSession *session,
- SoupMessage *msg,
+oal_download_response_cb (SoupSession *soup_session,
+ SoupMessage *soup_message,
gpointer user_data)
{
- GError *error = NULL;
- guint status = msg->status_code;
- struct _oal_req_data *data = (struct _oal_req_data *) user_data;
+ GSimpleAsyncResult *simple;
+ struct _oal_req_data *data;
- if (status != 200) {
- g_set_error (&error, EWS_CONNECTION_ERROR, status,
- _("Code: %d - Unexpected response from server"),
- status);
+ simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ data = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (soup_message->status_code != 200) {
+ g_simple_async_result_set_error (
+ simple, SOUP_HTTP_ERROR,
+ soup_message->status_code,
+ "%d %s",
+ soup_message->status_code,
+ soup_message->reason_phrase);
g_unlink (data->cache_filename);
- goto exit;
+
} else if (data->error != NULL) {
- g_propagate_error (&error, data->error);
+ g_simple_async_result_take_error (simple, data->error);
+ data->error = NULL;
g_unlink (data->cache_filename);
- goto exit;
}
- g_simple_async_result_set_op_res_gpointer (data->simple, NULL, NULL);
-
-exit:
- if (error) {
- g_simple_async_result_set_from_error (data->simple, error);
- g_clear_error (&error);
- }
-
- g_simple_async_result_complete_in_idle (data->simple);
- g_free (data->cache_filename);
- g_free (data);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
}
static void
@@ -2069,6 +2262,37 @@ ews_soup_got_chunk (SoupMessage *msg,
}
}
+gboolean
+e_ews_connection_download_oal_file_sync (EEwsConnection *cnc,
+ const gchar *cache_filename,
+ EwsProgressFn progress_fn,
+ gpointer progress_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_EWS_CONNECTION (cnc), FALSE);
+
+ closure = e_async_closure_new ();
+
+ e_ews_connection_download_oal_file (
+ cnc, cache_filename,
+ progress_fn, progress_data, cancellable,
+ e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_ews_connection_download_oal_file_finish (
+ cnc, result, error);
+
+ e_async_closure_free (closure);
+
+ return success;
+}
+
void
e_ews_connection_download_oal_file (EEwsConnection *cnc,
const gchar *cache_filename,
@@ -2079,38 +2303,52 @@ e_ews_connection_download_oal_file (EEwsConnection *cnc,
gpointer user_data)
{
GSimpleAsyncResult *simple;
- SoupMessage *msg;
+ SoupSession *soup_session;
+ SoupMessage *soup_message;
struct _oal_req_data *data;
- g_return_if_fail (cnc != NULL);
+ g_return_if_fail (E_IS_EWS_CONNECTION (cnc));
- msg = e_ews_get_msg_for_url (cnc->priv->uri, NULL);
+ soup_session = cnc->priv->soup_session;
+ soup_message = e_ews_get_msg_for_url (cnc->priv->uri, NULL);
- simple = g_simple_async_result_new (G_OBJECT (cnc),
- callback,
- user_data,
- e_ews_connection_download_oal_file);
- data = g_new0 (struct _oal_req_data, 1);
- data->cnc = cnc;
- data->simple = simple;
- data->cancellable = cancellable;
- data->msg = SOUP_MESSAGE (msg);
+ data = g_slice_new0 (struct _oal_req_data);
+ data->soup_session = g_object_ref (soup_session);
+ data->soup_message = soup_message; /* the session owns this */
data->cache_filename = g_strdup (cache_filename);
data->progress_fn = progress_fn;
data->progress_data = progress_data;
- if (cancellable)
- data->cancel_handler_id = g_cancellable_connect (cancellable,
- G_CALLBACK (ews_cancel_msg), (gpointer) data, NULL);
+ if (G_IS_CANCELLABLE (cancellable)) {
+ data->cancellable = g_object_ref (cancellable);
+ data->cancel_id = g_cancellable_connect (
+ data->cancellable,
+ G_CALLBACK (ews_cancel_msg),
+ data, (GDestroyNotify) NULL);
+ }
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (cnc), callback, user_data,
+ e_ews_connection_download_oal_file);
- soup_message_body_set_accumulate (SOUP_MESSAGE (msg)->response_body,
- FALSE);
- g_signal_connect (msg, "got-headers", G_CALLBACK (ews_soup_got_headers), data);
- g_signal_connect (msg, "got-chunk", G_CALLBACK (ews_soup_got_chunk), data);
- g_signal_connect (msg, "restarted", G_CALLBACK (ews_soup_restarted), data);
+ g_simple_async_result_set_op_res_gpointer (
+ simple, data, (GDestroyNotify) oal_req_data_free);
+
+ soup_message_body_set_accumulate (soup_message->response_body, FALSE);
+
+ g_signal_connect (
+ soup_message, "got-headers",
+ G_CALLBACK (ews_soup_got_headers), data);
+ g_signal_connect (
+ soup_message, "got-chunk",
+ G_CALLBACK (ews_soup_got_chunk), data);
+ g_signal_connect (
+ soup_message, "restarted",
+ G_CALLBACK (ews_soup_restarted), data);
- soup_session_queue_message (cnc->priv->soup_session, SOUP_MESSAGE (msg),
- oal_download_response_cb, data);
+ soup_session_queue_message (
+ soup_session, soup_message,
+ oal_download_response_cb, simple);
}
gboolean
@@ -2122,50 +2360,14 @@ e_ews_connection_download_oal_file_finish (EEwsConnection *cnc,
g_return_val_if_fail (cnc != NULL, FALSE);
g_return_val_if_fail (
- g_simple_async_result_is_valid (
- result, G_OBJECT (cnc), e_ews_connection_download_oal_file),
- FALSE);
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (cnc),
+ e_ews_connection_download_oal_file), FALSE);
simple = G_SIMPLE_ASYNC_RESULT (result);
- if (g_simple_async_result_propagate_error (simple, error))
- return FALSE;
-
- return TRUE;
-}
-
-gboolean
-e_ews_connection_download_oal_file_sync (EEwsConnection *cnc,
- const gchar *cache_filename,
- EwsProgressFn progress_fn,
- gpointer progress_data,
- GCancellable *cancellable,
- GError **error)
-{
- EwsSyncData *sync_data;
- gboolean result;
-
- g_return_val_if_fail (cnc != NULL, FALSE);
-
- sync_data = g_new0 (EwsSyncData, 1);
- sync_data->eflag = e_flag_new ();
-
- e_ews_connection_download_oal_file (
- cnc, cache_filename,
- progress_fn, progress_data,
- cancellable, ews_sync_reply_cb, sync_data);
-
- e_flag_wait (sync_data->eflag);
-
- result = e_ews_connection_download_oal_file_finish
- (cnc, sync_data->res,
- error);
-
- e_flag_free (sync_data->eflag);
- g_object_unref (sync_data->res);
- g_free (sync_data);
-
- return result;
+ /* Assume success unless a GError is set. */
+ return !g_simple_async_result_propagate_error (simple, error);
}
void
@@ -5359,7 +5561,6 @@ e_ews_connection_set_oof_settings_finish (EEwsConnection *cnc,
GError **error)
{
GSimpleAsyncResult *simple;
- EwsAsyncData *async_data;
g_return_val_if_fail (cnc != NULL, FALSE);
g_return_val_if_fail (
@@ -5368,7 +5569,6 @@ e_ews_connection_set_oof_settings_finish (EEwsConnection *cnc,
FALSE);
simple = G_SIMPLE_ASYNC_RESULT (result);
- async_data = g_simple_async_result_get_op_res_gpointer (simple);
if (g_simple_async_result_propagate_error (simple, error))
return FALSE;
diff --git a/src/server/e-ews-connection.h b/src/server/e-ews-connection.h
index a7d7eb2..5a29b6b 100644
--- a/src/server/e-ews-connection.h
+++ b/src/server/e-ews-connection.h
@@ -31,6 +31,7 @@
#include "ews-errors.h"
#include "e-ews-folder.h"
#include "e-ews-item.h"
+#include "camel-ews-settings.h"
G_BEGIN_DECLS
@@ -179,6 +180,9 @@ typedef struct {
gchar *ext_reply; /*External Reply */
} OOFSettings;
+void ews_oal_free (EwsOAL *oal);
+void ews_oal_details_free (EwsOALDetails *details);
+
GType e_ews_connection_get_type (void);
EEwsConnection *e_ews_connection_new (const gchar *uri,
const gchar *username,
@@ -194,13 +198,21 @@ void e_ews_connection_authenticate (EEwsConnection *cnc,
const gchar *passwd,
GError *error);
-typedef void (*EEwsAutoDiscoverCallback) (EwsUrls *urls, gpointer user_data, GError *error);
-void e_ews_autodiscover_ws_url (EEwsAutoDiscoverCallback callback,
- gpointer cbdata,
- const gchar *email,
+gboolean e_ews_autodiscover_ws_url_sync (CamelEwsSettings *settings,
+ const gchar *email_address,
const gchar *password,
- const gchar *ews_url,
- const gchar *username);
+ GCancellable *cancellable,
+ GError **error);
+void e_ews_autodiscover_ws_url (CamelEwsSettings *settings,
+ const gchar *email_address,
+ const gchar *password,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_ews_autodiscover_ws_url_finish
+ (CamelEwsSettings *settings,
+ GAsyncResult *result,
+ GError **error);
void e_ews_connection_set_mailbox (EEwsConnection *cnc,
const gchar *email);
@@ -683,6 +695,11 @@ GSList * e_ews_connection_get_attachments_sync
GCancellable *cancellable,
GError **error);
+gboolean e_ews_connection_get_oal_list_sync
+ (EEwsConnection *cnc,
+ GSList **oals,
+ GCancellable *cancellable,
+ GError **error);
void e_ews_connection_get_oal_list (EEwsConnection *cnc,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -692,7 +709,13 @@ gboolean e_ews_connection_get_oal_list_finish
GAsyncResult *result,
GSList **oals,
GError **error);
-
+gboolean e_ews_connection_get_oal_detail_sync
+ (EEwsConnection *cnc,
+ const gchar *oal_id,
+ const gchar *oal_element,
+ GSList **elements,
+ GCancellable *cancellable,
+ GError **error);
void e_ews_connection_get_oal_detail (EEwsConnection *cnc,
const gchar *oal_id,
const gchar *oal_element,
@@ -704,13 +727,6 @@ gboolean e_ews_connection_get_oal_detail_finish
GAsyncResult *result,
GSList **elements,
GError **error);
-gboolean e_ews_connection_get_oal_detail_sync
- (EEwsConnection *cnc,
- const gchar *oal_id,
- const gchar *oal_element,
- GSList **elements,
- GCancellable *cancellable,
- GError **error);
void e_ews_connection_get_free_busy (EEwsConnection *cnc,
gint pri,
@@ -732,25 +748,24 @@ gboolean e_ews_connection_get_free_busy_sync
GSList **free_busy,
GCancellable *cancellable,
GError **error);
-
-void e_ews_connection_download_oal_file
+gboolean e_ews_connection_download_oal_file_sync
(EEwsConnection *cnc,
const gchar *cache_filename,
EwsProgressFn progress_fn,
gpointer progress_data,
GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-gboolean e_ews_connection_download_oal_file_finish
- (EEwsConnection *cnc,
- GAsyncResult *result,
GError **error);
-gboolean e_ews_connection_download_oal_file_sync
+void e_ews_connection_download_oal_file
(EEwsConnection *cnc,
const gchar *cache_filename,
EwsProgressFn progress_fn,
gpointer progress_data,
GCancellable *cancellable,
+ GAsyncReadyCallback cb,
+ gpointer user_data);
+gboolean e_ews_connection_download_oal_file_finish
+ (EEwsConnection *cnc,
+ GAsyncResult *result,
GError **error);
void e_ews_connection_get_delegate (EEwsConnection *cnc,
diff --git a/src/server/e-source-ews-folder.c b/src/server/e-source-ews-folder.c
new file mode 100644
index 0000000..cb79f8b
--- /dev/null
+++ b/src/server/e-source-ews-folder.c
@@ -0,0 +1,254 @@
+/*
+ * e-source-ews-folder.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-ews-folder.h"
+
+#define E_SOURCE_EWS_FOLDER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SOURCE_EWS_FOLDER, ESourceEwsFolderPrivate))
+
+struct _ESourceEwsFolderPrivate {
+ GMutex *property_lock;
+ gchar *change_key;
+ gchar *id;
+};
+
+enum {
+ PROP_0,
+ PROP_CHANGE_KEY,
+ PROP_ID
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+ ESourceEwsFolder,
+ e_source_ews_folder,
+ E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_ews_folder_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CHANGE_KEY:
+ e_source_ews_folder_set_change_key (
+ E_SOURCE_EWS_FOLDER (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_ID:
+ e_source_ews_folder_set_id (
+ E_SOURCE_EWS_FOLDER (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_ews_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_ews_folder_dup_change_key (
+ E_SOURCE_EWS_FOLDER (object)));
+ return;
+
+ case PROP_ID:
+ g_value_take_string (
+ value,
+ e_source_ews_folder_dup_id (
+ E_SOURCE_EWS_FOLDER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_ews_folder_finalize (GObject *object)
+{
+ ESourceEwsFolderPrivate *priv;
+
+ priv = E_SOURCE_EWS_FOLDER_GET_PRIVATE (object);
+
+ g_mutex_free (priv->property_lock);
+
+ g_free (priv->change_key);
+ g_free (priv->id);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_source_ews_folder_parent_class)->finalize (object);
+}
+
+static void
+e_source_ews_folder_class_init (ESourceEwsFolderClass *class)
+{
+ GObjectClass *object_class;
+ ESourceExtensionClass *extension_class;
+
+ g_type_class_add_private (class, sizeof (ESourceEwsFolderPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = source_ews_folder_set_property;
+ object_class->get_property = source_ews_folder_get_property;
+ object_class->finalize = source_ews_folder_finalize;
+
+ extension_class = E_SOURCE_EXTENSION_CLASS (class);
+ extension_class->name = E_SOURCE_EXTENSION_EWS_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_ews_folder_class_finalize (ESourceEwsFolderClass *class)
+{
+}
+
+static void
+e_source_ews_folder_init (ESourceEwsFolder *extension)
+{
+ extension->priv = E_SOURCE_EWS_FOLDER_GET_PRIVATE (extension);
+ extension->priv->property_lock = g_mutex_new ();
+}
+
+void
+e_source_ews_folder_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_source_ews_folder_register_type (type_module);
+}
+
+const gchar *
+e_source_ews_folder_get_change_key (ESourceEwsFolder *extension)
+{
+ g_return_val_if_fail (E_IS_SOURCE_EWS_FOLDER (extension), NULL);
+
+ return extension->priv->change_key;
+}
+
+gchar *
+e_source_ews_folder_dup_change_key (ESourceEwsFolder *extension)
+{
+ const gchar *protected;
+ gchar *duplicate;
+
+ g_return_val_if_fail (E_IS_SOURCE_EWS_FOLDER (extension), NULL);
+
+ g_mutex_lock (extension->priv->property_lock);
+
+ protected = e_source_ews_folder_get_id (extension);
+ duplicate = g_strdup (protected);
+
+ g_mutex_unlock (extension->priv->property_lock);
+
+ return duplicate;
+}
+
+void
+e_source_ews_folder_set_change_key (ESourceEwsFolder *extension,
+ const gchar *change_key)
+{
+ g_return_if_fail (E_IS_SOURCE_EWS_FOLDER (extension));
+
+ g_mutex_lock (extension->priv->property_lock);
+
+ g_free (extension->priv->change_key);
+ extension->priv->change_key = g_strdup (change_key);
+
+ g_mutex_unlock (extension->priv->property_lock);
+
+ g_object_notify (G_OBJECT (extension), "change-key");
+}
+
+const gchar *
+e_source_ews_folder_get_id (ESourceEwsFolder *extension)
+{
+ g_return_val_if_fail (E_IS_SOURCE_EWS_FOLDER (extension), NULL);
+
+ return extension->priv->id;
+}
+
+gchar *
+e_source_ews_folder_dup_id (ESourceEwsFolder *extension)
+{
+ const gchar *protected;
+ gchar *duplicate;
+
+ g_return_val_if_fail (E_IS_SOURCE_EWS_FOLDER (extension), NULL);
+
+ g_mutex_lock (extension->priv->property_lock);
+
+ protected = e_source_ews_folder_get_id (extension);
+ duplicate = g_strdup (protected);
+
+ g_mutex_unlock (extension->priv->property_lock);
+
+ return duplicate;
+}
+
+void
+e_source_ews_folder_set_id (ESourceEwsFolder *extension,
+ const gchar *id)
+{
+ g_return_if_fail (E_IS_SOURCE_EWS_FOLDER (extension));
+
+ g_mutex_lock (extension->priv->property_lock);
+
+ g_free (extension->priv->id);
+ extension->priv->id = g_strdup (id);
+
+ g_mutex_unlock (extension->priv->property_lock);
+
+ g_object_notify (G_OBJECT (extension), "id");
+}
+
diff --git a/src/server/e-source-ews-folder.h b/src/server/e-source-ews-folder.h
new file mode 100644
index 0000000..3dd30e4
--- /dev/null
+++ b/src/server/e-source-ews-folder.h
@@ -0,0 +1,78 @@
+/*
+ * e-source-ews-folder.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_EWS_FOLDER_H
+#define E_SOURCE_EWS_FOLDER_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_EWS_FOLDER \
+ (e_source_ews_folder_get_type ())
+#define E_SOURCE_EWS_FOLDER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SOURCE_EWS_FOLDER, ESourceEwsFolder))
+#define E_SOURCE_EWS_FOLDER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SOURCE_EWS_FOLDER, ESourceEwsFolderClass))
+#define E_IS_SOURCE_EWS_FOLDER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SOURCE_EWS_FOLDER))
+#define E_IS_SOURCE_EWS_FOLDER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SOURCE_EWS_FOLDER))
+#define E_SOURCE_EWS_FOLDER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SOURCE_EWS_FOLDER, ESourceEwsFolderClass))
+
+#define E_SOURCE_EXTENSION_EWS_FOLDER "Exchange Web Services Folder"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceEwsFolder ESourceEwsFolder;
+typedef struct _ESourceEwsFolderClass ESourceEwsFolderClass;
+typedef struct _ESourceEwsFolderPrivate ESourceEwsFolderPrivate;
+
+struct _ESourceEwsFolder {
+ ESourceExtension parent;
+ ESourceEwsFolderPrivate *priv;
+};
+
+struct _ESourceEwsFolderClass {
+ ESourceExtensionClass parent_class;
+};
+
+GType e_source_ews_folder_get_type (void) G_GNUC_CONST;
+void e_source_ews_folder_type_register
+ (GTypeModule *type_module);
+const gchar * e_source_ews_folder_get_change_key
+ (ESourceEwsFolder *extension);
+gchar * e_source_ews_folder_dup_change_key
+ (ESourceEwsFolder *extension);
+void e_source_ews_folder_set_change_key
+ (ESourceEwsFolder *extension,
+ const gchar *change_key);
+const gchar * e_source_ews_folder_get_id (ESourceEwsFolder *extension);
+gchar * e_source_ews_folder_dup_id (ESourceEwsFolder *extension);
+void e_source_ews_folder_set_id (ESourceEwsFolder *extension,
+ const gchar *id);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_EWS_FOLDER_H */
+
diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
index 0d5e8d8..642cf2f 100644
--- a/src/utils/Makefile.am
+++ b/src/utils/Makefile.am
@@ -17,10 +17,6 @@ libewsutils_la_CPPFLAGS = \
$(NULL)
libewsutils_la_SOURCES = \
- camel-ews-settings.c \
- camel-ews-settings.h \
- ews-esource-utils.h \
- ews-esource-utils.c \
e-sqlite3-vfs.c \
e-sqlite3-vfs.h \
ews-camel-common.c \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]