[evolution-ews] Bug #670939 - Reminder to change out of office status



commit 952805f476bee0a7eae4092aec690b8923d1514a
Author: Fabiano Fidêncio <fidencio redhat com>
Date:   Tue Mar 26 16:32:24 2013 +0100

    Bug #670939 - Reminder to change out of office status

 src/camel/Makefile.am                              |   31 ++-
 src/camel/camel-ews-enums.h                        |   34 ++
 src/camel/camel-ews-store.c                        |  239 +++++++++-
 src/camel/camel-ews-store.h                        |   15 +
 src/configuration/Makefile.am                      |    2 +
 src/configuration/e-ews-ooo-notificator.c          |  526 ++++++++++++++++++++
 src/configuration/e-ews-ooo-notificator.h          |   64 +++
 src/configuration/module-ews-configuration.c       |    2 +
 .../module-ews-configuration.error.xml             |    4 +
 9 files changed, 914 insertions(+), 3 deletions(-)
---
diff --git a/src/camel/Makefile.am b/src/camel/Makefile.am
index d9a6616..7d16f83 100644
--- a/src/camel/Makefile.am
+++ b/src/camel/Makefile.am
@@ -3,6 +3,24 @@ NULL =
 camel_provider_LTLIBRARIES = libcamelews.la
 camel_provider_DATA = libcamelews.urls
 
+ENUM_TYPES = camel-ews-enums.h
+
+camel-ews-enumtypes.h: $(top_srcdir)/enumtypes.h.template $(ENUM_TYPES)
+       $(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template $(top_srcdir)/enumtypes.h.template \
+               --fhead "#ifndef CAMEL_EWS_ENUMTYPES_H\n#define CAMEL_EWS_ENUMTYPES_H\n" \
+               --ftail "#endif /* CAMEL_EWS_ENUMTYPES_H */\n" \
+               $(ENUM_TYPES)) > $@
+
+camel-ews-enumtypes.c: $(top_srcdir)/enumtypes.h.template $(ENUM_TYPES)
+       $(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template $(top_srcdir)/enumtypes.c.template \
+               --fhead "#include \"camel-ews-enumtypes.h\"" \
+               $(ENUM_TYPES)) > $@
+
+ENUM_GENERATED = \
+       camel-ews-enumtypes.h \
+       camel-ews-enumtypes.c \
+       $(NULL)
+
 libcamelews_la_CPPFLAGS = \
        $(AM_CPPFLAGS) \
        -I$(top_srcdir) \
@@ -21,6 +39,7 @@ libcamelews_la_CPPFLAGS = \
        $(NULL)
 
 libcamelews_la_SOURCES = \
+       camel-ews-enumtypes.c \
        camel-ews-folder.c \
        camel-ews-store-summary.c \
        camel-ews-store.c \
@@ -31,6 +50,8 @@ libcamelews_la_SOURCES = \
        $(NULL)
 
 noinst_HEADERS = \
+       camel-ews-enums.h \
+       camel-ews-enumtypes.h \
        camel-ews-folder.h \
        camel-ews-private.h \
        camel-ews-store-summary.h \
@@ -55,6 +76,14 @@ libcamelews_la_LIBADD = \
        $(E_DATA_SERVER_LIBS) \
        $(NULL)
 
-EXTRA_DIST = libcamelews.urls
+BUILT_SOURCES = \
+       $(ENUM_GENERATED) \
+       $(NULL)
+
+EXTRA_DIST = \
+       libcamelews.urls \
+       $(NULL)
+
+CLEANFILES = $(BUILT_SOURCES)
 
 -include $(top_srcdir)/git.mk
diff --git a/src/camel/camel-ews-enums.h b/src/camel/camel-ews-enums.h
new file mode 100644
index 0000000..8c2af2d
--- /dev/null
+++ b/src/camel/camel-ews-enums.h
@@ -0,0 +1,34 @@
+/*
+ * camel-ews-enums.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 CAMEL_EWS_ENUMS_H
+#define CAMEL_EWS_ENUMS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+       CAMEL_EWS_STORE_OOO_ALERT_STATE_UNKNOWN,
+       CAMEL_EWS_STORE_OOO_ALERT_STATE_NOTIFIED,
+       CAMEL_EWS_STORE_OOO_ALERT_STATE_CLOSED
+} CamelEwsStoreOooAlertState;
+
+G_END_DECLS
+
+#endif /* CAMEL_EWS_ENUMS_H */
diff --git a/src/camel/camel-ews-store.c b/src/camel/camel-ews-store.c
index f8676bb..9f9801f 100644
--- a/src/camel/camel-ews-store.c
+++ b/src/camel/camel-ews-store.c
@@ -44,11 +44,13 @@
 #include "server/camel-ews-settings.h"
 #include "server/e-ews-item-change.h"
 #include "server/e-ews-message.h"
+#include "server/e-ews-oof-settings.h"
 
 #include "camel-ews-folder.h"
 #include "camel-ews-store.h"
 #include "camel-ews-summary.h"
 #include "camel-ews-utils.h"
+#include "camel-ews-enumtypes.h"
 
 #ifdef G_OS_WIN32
 #include <winsock2.h>
@@ -69,6 +71,8 @@ struct _CamelEwsStorePrivate {
        GMutex get_finfo_lock;
        EEwsConnection *connection;
        GMutex connection_lock;
+       gboolean has_ooo_set;
+       CamelEwsStoreOooAlertState ooo_alert_state;
        GSList *public_folders; /* EEwsFolder * objects */
 };
 
@@ -79,6 +83,12 @@ static void camel_ews_store_initable_init (GInitableIface *interface);
 static void camel_ews_subscribable_init (CamelSubscribableInterface *interface);
 static GInitableIface *parent_initable_interface;
 
+enum {
+       PROP_0,
+       PROP_HAS_OOO_SET,
+       PROP_OOO_ALERT_STATE
+};
+
 G_DEFINE_TYPE_WITH_CODE (
        CamelEwsStore, camel_ews_store, CAMEL_TYPE_OFFLINE_STORE,
        G_IMPLEMENT_INTERFACE (
@@ -87,6 +97,96 @@ G_DEFINE_TYPE_WITH_CODE (
                CAMEL_TYPE_SUBSCRIBABLE, camel_ews_subscribable_init))
 
 static void
+ews_store_set_property (GObject *object,
+                        guint property_id,
+                        const GValue *value,
+                        GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_HAS_OOO_SET:
+                       camel_ews_store_set_has_ooo_set (
+                               CAMEL_EWS_STORE (object),
+                               g_value_get_boolean (value));
+                       return;
+               case PROP_OOO_ALERT_STATE:
+                       camel_ews_store_set_ooo_alert_state (
+                               CAMEL_EWS_STORE (object),
+                               g_value_get_enum (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+ews_store_get_property (GObject *object,
+                        guint property_id,
+                        GValue *value,
+                        GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_HAS_OOO_SET:
+                       g_value_set_boolean (
+                               value,
+                               camel_ews_store_get_has_ooo_set (
+                               CAMEL_EWS_STORE (object)));
+                       return;
+               case PROP_OOO_ALERT_STATE:
+                       g_value_set_enum (
+                               value,
+                               camel_ews_store_get_ooo_alert_state (
+                               CAMEL_EWS_STORE (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+void
+camel_ews_store_set_has_ooo_set (CamelEwsStore *ews_store,
+                                 gboolean has_ooo_set)
+{
+       g_return_if_fail (CAMEL_IS_EWS_STORE (ews_store));
+
+       if ((ews_store->priv->has_ooo_set ? 1 : 0) == (has_ooo_set ? 1 : 0))
+               return;
+
+       ews_store->priv->has_ooo_set = has_ooo_set;
+       g_object_notify (G_OBJECT (ews_store), "has-ooo-set");
+}
+
+gboolean
+camel_ews_store_get_has_ooo_set (const CamelEwsStore *ews_store)
+{
+       g_return_val_if_fail (CAMEL_IS_EWS_STORE (ews_store), FALSE);
+
+       return ews_store->priv->has_ooo_set;
+}
+
+void
+camel_ews_store_set_ooo_alert_state (CamelEwsStore *ews_store,
+                                     CamelEwsStoreOooAlertState state)
+{
+       g_return_if_fail (CAMEL_IS_EWS_STORE (ews_store));
+
+       if (ews_store->priv->ooo_alert_state == state)
+               return;
+
+       ews_store->priv->ooo_alert_state = state;
+       g_object_notify (G_OBJECT (ews_store), "ooo-alert-state");
+}
+
+CamelEwsStoreOooAlertState
+camel_ews_store_get_ooo_alert_state (const CamelEwsStore *ews_store)
+{
+       g_return_val_if_fail (
+                       CAMEL_IS_EWS_STORE (ews_store),
+                       CAMEL_EWS_STORE_OOO_ALERT_STATE_UNKNOWN);
+
+       return ews_store->priv->ooo_alert_state;
+}
+
+static void
 ews_migrate_to_user_cache_dir (CamelService *service)
 {
        const gchar *user_data_dir, *user_cache_dir;
@@ -488,6 +588,43 @@ ews_update_folder_hierarchy (CamelEwsStore *ews_store,
        g_free (sync_state);
 }
 
+static void
+ews_update_has_ooo_set (CamelSession *session,
+                       GCancellable *cancellable,
+                       gpointer user_data,
+                       GError **error)
+{
+
+       CamelEwsStore *ews_store = user_data;
+       EEwsOofSettings *oof_settings;
+       EEwsOofState oof_state;
+       GError *local_error = NULL;
+
+       camel_operation_push_message (cancellable, _("Checking \"Out of Office\" settings"));
+
+       oof_settings = e_ews_oof_settings_new_sync (ews_store->priv->connection, cancellable, &local_error);
+       if (local_error != NULL) {
+               g_propagate_error (error, local_error);
+               camel_operation_pop_message (cancellable);
+               return;
+       }
+
+       oof_state = e_ews_oof_settings_get_state (oof_settings);
+       switch (oof_state) {
+               case E_EWS_OOF_STATE_ENABLED:
+                       camel_ews_store_set_has_ooo_set (ews_store, TRUE);
+                       break;
+               case E_EWS_OOF_STATE_DISABLED:
+               case E_EWS_OOF_STATE_SCHEDULED:
+                       camel_ews_store_set_has_ooo_set (ews_store, FALSE);
+                       break;
+               default:
+                       break;
+       }
+
+       camel_operation_pop_message (cancellable);
+}
+
 static gboolean
 ews_connect_sync (CamelService *service,
                   GCancellable *cancellable,
@@ -516,13 +653,23 @@ ews_connect_sync (CamelService *service,
        success = camel_session_authenticate_sync (
                session, service, NULL, cancellable, error);
 
-       g_object_unref (session);
+       if (success) {
+               CamelEwsStoreOooAlertState state;
+
+               state = camel_ews_store_get_ooo_alert_state (ews_store);
+               if (state == CAMEL_EWS_STORE_OOO_ALERT_STATE_UNKNOWN)
+                       camel_session_submit_job (
+                               session,
+                               ews_update_has_ooo_set,
+                               g_object_ref (ews_store),
+                               g_object_unref);
 
-       if (success)
                camel_offline_store_set_online_sync (
                        CAMEL_OFFLINE_STORE (ews_store),
                        TRUE, cancellable, NULL);
+       }
 
+       g_object_unref (session);
        return success;
 }
 
@@ -2591,6 +2738,67 @@ camel_ews_store_maybe_disconnect (CamelEwsStore *store,
 }
 
 static void
+ews_store_unset_oof_settings_state (CamelSession *session,
+                                   GCancellable *cancellable,
+                                   gpointer user_data,
+                                   GError **error)
+{
+
+       CamelEwsStore *ews_store = user_data;
+       EEwsConnection *connection;
+       EEwsOofSettings *oof_settings;
+       EEwsOofState state;
+       GError *local_error = NULL;
+
+       camel_operation_push_message (cancellable, _("Unsetting the \"Out of Office\" status"));
+
+       connection = camel_ews_store_ref_connection (ews_store);
+       oof_settings = e_ews_oof_settings_new_sync (connection, cancellable, &local_error);
+       g_object_unref (connection);
+       if (local_error != NULL) {
+               g_propagate_error (error, local_error);
+               camel_operation_pop_message (cancellable);
+               return;
+       }
+
+       state = e_ews_oof_settings_get_state (oof_settings);
+       if (state == E_EWS_OOF_STATE_DISABLED) {
+               g_object_unref (oof_settings);
+               camel_operation_pop_message (cancellable);
+               return;
+       }
+
+       e_ews_oof_settings_set_state (oof_settings, E_EWS_OOF_STATE_DISABLED);
+       e_ews_oof_settings_submit_sync (oof_settings, cancellable, error);
+       g_object_unref (oof_settings);
+       if (local_error != NULL)
+               g_propagate_error (error, local_error);
+
+       camel_operation_pop_message (cancellable);
+
+}
+
+void
+camel_ews_store_unset_oof_settings_state (CamelEwsStore *ews_store)
+{
+       CamelService *service;
+       CamelSession *session;
+
+       g_return_if_fail (CAMEL_IS_EWS_STORE (ews_store));
+
+       service = CAMEL_SERVICE (ews_store);
+       session = camel_service_ref_session (service);
+
+       camel_session_submit_job (
+               session,
+               ews_store_unset_oof_settings_state,
+               g_object_ref (ews_store),
+               g_object_unref);
+
+       g_object_unref (session);
+}
+
+static void
 ews_store_dispose (GObject *object)
 {
        CamelEwsStore *ews_store;
@@ -2642,9 +2850,36 @@ camel_ews_store_class_init (CamelEwsStoreClass *class)
        g_type_class_add_private (class, sizeof (CamelEwsStorePrivate));
 
        object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = ews_store_set_property;
+       object_class->get_property = ews_store_get_property;
        object_class->dispose = ews_store_dispose;
        object_class->finalize = ews_store_finalize;
 
+       g_object_class_install_property (
+               object_class,
+               PROP_HAS_OOO_SET,
+               g_param_spec_boolean (
+                       "has-ooo-set",
+                       "Has OOO Set",
+                       "Has Out of Office state set",
+                       FALSE,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_OOO_ALERT_STATE,
+               g_param_spec_enum (
+                       "ooo-alert-state",
+                       "Out of Office Alert State",
+                       "The state of the Out of Office Alert",
+                       E_TYPE_EWS_STORE_OOO_ALERT_STATE,
+                       CAMEL_EWS_STORE_OOO_ALERT_STATE_UNKNOWN,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
+
        service_class = CAMEL_SERVICE_CLASS (class);
        service_class->settings_type = CAMEL_TYPE_EWS_SETTINGS;
        service_class->query_auth_types_sync = ews_store_query_auth_types_sync;
diff --git a/src/camel/camel-ews-store.h b/src/camel/camel-ews-store.h
index 0420f47..9d934f6 100644
--- a/src/camel/camel-ews-store.h
+++ b/src/camel/camel-ews-store.h
@@ -25,6 +25,7 @@
 #define CAMEL_EWS_STORE_H
 
 #include <camel/camel.h>
+#include <camel/camel-ews-enums.h>
 
 #include "server/e-ews-connection.h"
 
@@ -93,6 +94,20 @@ void         camel_ews_store_ensure_unique_path
 void           camel_ews_store_update_foreign_subfolders
                                                (CamelEwsStore *ews_store,
                                                 const gchar *fid);
+void           camel_ews_store_set_has_ooo_set
+                                               (CamelEwsStore *ews_store,
+                                                gboolean has_ooo_set);
+gboolean       camel_ews_store_get_has_ooo_set
+                                               (const CamelEwsStore *ews_store);
+void           camel_ews_store_set_ooo_alert_state
+                                               (CamelEwsStore *ews_store,
+                                                CamelEwsStoreOooAlertState state);
+CamelEwsStoreOooAlertState
+               camel_ews_store_get_ooo_alert_state
+                                               (const CamelEwsStore *ews_store);
+void           camel_ews_store_unset_oof_settings_state
+                                               (CamelEwsStore *ews_store);
+
 
 G_END_DECLS
 
diff --git a/src/configuration/Makefile.am b/src/configuration/Makefile.am
index 2896857..e37d41d 100644
--- a/src/configuration/Makefile.am
+++ b/src/configuration/Makefile.am
@@ -41,6 +41,8 @@ module_ews_configuration_la_SOURCES = \
        e-ews-search-user.h \
        e-ews-subscribe-foreign-folder.c \
        e-ews-subscribe-foreign-folder.h \
+       e-ews-ooo-notificator.c \
+       e-ews-ooo-notificator.h \
        $(NULL)
 
 module_ews_configuration_la_LIBADD = \
diff --git a/src/configuration/e-ews-ooo-notificator.c b/src/configuration/e-ews-ooo-notificator.c
new file mode 100644
index 0000000..d97f48d
--- /dev/null
+++ b/src/configuration/e-ews-ooo-notificator.c
@@ -0,0 +1,526 @@
+/*
+ * e-ews-ooo-notificator.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/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "e-ews-ooo-notificator.h"
+#include "camel/camel-ews-store.h"
+#include "server/e-ews-oof-settings.h"
+
+#include <shell/e-shell.h>
+#include <shell/e-shell-view.h>
+#include <mail/e-mail-backend.h>
+#include <mail/e-mail-ui-session.h>
+#include <glib/gi18n-lib.h>
+
+#define E_EWS_OOO_NOTIFICATOR_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+        ((obj), E_TYPE_EWS_OOO_NOTIFICATOR, EEwsOooNotificatorPrivate))
+
+typedef gboolean (*EEwsOooNotificationDispatcherFunction) (gpointer data);
+
+struct _EEwsOooNotificatorPrivate
+{
+       EShell *shell;
+       EMailAccountStore *account_store;
+       GList *stores;
+       GHashTable *alerts;
+};
+
+typedef struct _EEwsOooNotificatorDispatcherData
+{
+       EEwsOooNotificator *extension;
+       CamelEwsStore *ews_store;
+       guint timeout_id;
+} EEwsOooNotificatorDispatcherData;
+
+G_DEFINE_DYNAMIC_TYPE (
+       EEwsOooNotificator,
+       e_ews_ooo_notificator,
+       E_TYPE_EXTENSION)
+
+/* Forward declarations */
+static void e_ews_ooo_notificator_has_ooo_set_cb (EEwsOooNotificator *extension,
+                                                 GParamSpec *pspec,
+                                                 CamelEwsStore *ews_store);
+static void e_ews_ooo_notificator_service_disabled_cb (EEwsOooNotificator *extension,
+                                                      CamelService *service,
+                                                      EMailAccountStore *account_store);
+static void e_ews_ooo_notificator_service_removed_cb (EEwsOooNotificator *extension,
+                                                     CamelService *service,
+                                                     EMailAccountStore *session);
+static void e_ews_ooo_notificator_service_added_cb (EEwsOooNotificator *extension,
+                                                   CamelService *service,
+                                                   EMailAccountStore *session);
+static void e_ews_ooo_notificator_online_cb (EEwsOooNotificator* extension,
+                                            GParamSpec *pspec,
+                                            EShell *shell);
+
+static EShellView *
+e_ews_ooo_notificator_get_extensible (EEwsOooNotificator *extension)
+{
+       EExtensible *extensible;
+
+       extensible = e_extension_get_extensible (E_EXTENSION (extension));
+
+       return E_SHELL_VIEW (extensible);
+}
+
+static void
+e_ews_ooo_notificator_dispatcher_data_free (gpointer user_data)
+{
+       EEwsOooNotificatorDispatcherData *data = user_data;
+
+       if (data->extension)
+               g_object_unref (data->extension);
+       if (data->ews_store)
+               g_object_unref (data->ews_store);
+       g_free (data);
+}
+
+static void
+e_ews_ooo_notificator_unset_on_server_cb (EEwsOooNotificatorDispatcherData *data,
+                                         GtkAction *action)
+{
+       EAlert *alert;
+       camel_ews_store_unset_oof_settings_state (data->ews_store);
+       camel_ews_store_set_ooo_alert_state (
+                       data->ews_store, CAMEL_EWS_STORE_OOO_ALERT_STATE_CLOSED);
+
+       alert = g_hash_table_lookup (data->extension->priv->alerts, data->ews_store);
+       if (alert)
+               g_hash_table_remove (data->extension->priv->alerts, data->ews_store);
+
+       if (data->timeout_id) {
+               g_source_remove (data->timeout_id);
+               data->timeout_id = 0;
+       }
+}
+
+static void
+e_ews_ooo_notificator_dismiss_cb (EEwsOooNotificatorDispatcherData *data,
+                                 gint response_id,
+                                 EAlert *alert)
+{
+
+       if (response_id == GTK_RESPONSE_CLOSE) {
+               camel_ews_store_set_ooo_alert_state (
+                               data->ews_store, CAMEL_EWS_STORE_OOO_ALERT_STATE_CLOSED);
+               g_hash_table_remove (data->extension->priv->alerts, data->ews_store);
+        }
+
+       if (data->timeout_id) {
+               g_source_remove (data->timeout_id);
+               data->timeout_id = 0;
+       }
+}
+
+static void
+e_ews_ooo_notificator_hide_notification (EEwsOooNotificator *extension,
+                                        CamelEwsStore *ews_store)
+{
+       EAlert *alert;
+
+       alert = g_hash_table_lookup (extension->priv->alerts, ews_store);
+       if (alert) {
+               e_alert_response (alert, GTK_RESPONSE_NONE);
+               g_hash_table_remove (extension->priv->alerts, ews_store);
+       }
+}
+
+static gboolean
+e_ews_ooo_notificator_hide_notification_by_timeout_cb (gpointer user_data)
+{
+       EEwsOooNotificatorDispatcherData *data = user_data;
+
+       e_ews_ooo_notificator_hide_notification (data->extension, data->ews_store);
+
+       return FALSE;
+}
+
+static void
+e_ews_ooo_notificator_show_notification (EEwsOooNotificator *extension,
+                                        CamelEwsStore *ews_store)
+{
+       EAlert *alert;
+       EShellView *view;
+       EShellContent *shell_content;
+       EEwsOooNotificatorDispatcherData *data;
+       GtkAction *action;
+       const gchar *account_name;
+
+       data = g_new0 (EEwsOooNotificatorDispatcherData, 1);
+       data->extension = g_object_ref (extension);
+       data->ews_store = g_object_ref (ews_store);
+
+       view = e_ews_ooo_notificator_get_extensible (extension);
+       shell_content = e_shell_view_get_shell_content (view);
+
+       account_name = camel_service_get_display_name (CAMEL_SERVICE (ews_store));
+       alert = e_alert_new ("ews:has-ooo-set", account_name, NULL);
+
+       g_signal_connect_swapped (
+                       alert,
+                       "response",
+                       G_CALLBACK (e_ews_ooo_notificator_dismiss_cb), data);
+
+       action = gtk_action_new (
+                       "ooo-unset-on-server",
+                       _("Unset on Server"),
+                       _("Unset the \"Out of Office\" status"),
+                       GTK_STOCK_OK);
+       g_signal_connect_swapped (
+                       action,
+                       "activate",
+                       G_CALLBACK (e_ews_ooo_notificator_unset_on_server_cb), data);
+       e_alert_add_action (alert, action, 0);
+
+       g_hash_table_insert (extension->priv->alerts, ews_store, alert);
+       e_alert_sink_submit_alert (E_ALERT_SINK (shell_content), alert);
+
+       /* If the user doesn't cancel the notify, it will be hide automatically in 5 minutes */
+       data->timeout_id = g_timeout_add_seconds_full (
+                       G_PRIORITY_DEFAULT, 300,
+                       e_ews_ooo_notificator_hide_notification_by_timeout_cb,
+                       data, e_ews_ooo_notificator_dispatcher_data_free);
+}
+
+static gboolean
+e_ews_ooo_notificator_has_ooo_set (gpointer user_data)
+{
+       EEwsOooNotificatorDispatcherData *data = user_data;
+       CamelEwsStoreOooAlertState alert_state;
+       gboolean has_ooo_set;
+
+       alert_state = camel_ews_store_get_ooo_alert_state (data->ews_store);
+       has_ooo_set = camel_ews_store_get_has_ooo_set (data->ews_store);
+
+       if (has_ooo_set && alert_state == CAMEL_EWS_STORE_OOO_ALERT_STATE_UNKNOWN) {
+               e_ews_ooo_notificator_show_notification (data->extension, data->ews_store);
+               camel_ews_store_set_ooo_alert_state (data->ews_store, 
CAMEL_EWS_STORE_OOO_ALERT_STATE_NOTIFIED);
+       }
+
+       return FALSE;
+}
+
+static gboolean
+e_ews_ooo_notificator_service_disabled (gpointer user_data)
+{
+       EEwsOooNotificatorDispatcherData *data = user_data;
+       CamelEwsStoreOooAlertState state;
+
+       e_ews_ooo_notificator_hide_notification (data->extension, data->ews_store);
+       state = camel_ews_store_get_ooo_alert_state (data->ews_store);
+       if (state != CAMEL_EWS_STORE_OOO_ALERT_STATE_CLOSED)
+               camel_ews_store_set_ooo_alert_state (data->ews_store, 
CAMEL_EWS_STORE_OOO_ALERT_STATE_UNKNOWN);
+       camel_ews_store_set_has_ooo_set (data->ews_store, FALSE);
+
+       return FALSE;
+}
+
+static gboolean
+e_ews_ooo_notificator_service_removed (gpointer user_data)
+{
+       EEwsOooNotificatorDispatcherData *data = user_data;
+
+       e_ews_ooo_notificator_hide_notification (data->extension, data->ews_store);
+       g_signal_handlers_disconnect_by_func (
+                       data->ews_store,
+                       e_ews_ooo_notificator_has_ooo_set_cb,
+                       data->extension);
+       data->extension->priv->stores = g_list_remove (
+                       data->extension->priv->stores, data->ews_store);
+       g_object_unref (data->ews_store);
+
+       return FALSE;
+}
+
+/*
+ * GTK+ UI calls cannot be done in a dedicated thread.
+ * So, let's ensure that our functions (that do something in the UI) will run
+ * in the main thread, calling them through g_timeout_add_full().
+ */
+static void
+e_ews_ooo_notificator_dispatcher (EEwsOooNotificatorDispatcherData *data,
+                                 EEwsOooNotificationDispatcherFunction function,
+                                 GDestroyNotify destroy_data)
+{
+       g_timeout_add_full (G_PRIORITY_DEFAULT, 1, function, data, destroy_data);
+}
+
+static void
+e_ews_ooo_notificator_has_ooo_set_cb (EEwsOooNotificator *extension,
+                                     GParamSpec *pspec,
+                                     CamelEwsStore *ews_store)
+{
+       EEwsOooNotificatorDispatcherData *data;
+
+       data = g_new0 (EEwsOooNotificatorDispatcherData, 1);
+       data->extension = g_object_ref (extension);
+       data->ews_store = g_object_ref (ews_store);
+
+       e_ews_ooo_notificator_dispatcher (
+                       data,
+                       e_ews_ooo_notificator_has_ooo_set,
+                       e_ews_ooo_notificator_dispatcher_data_free);
+}
+
+static void
+e_ews_ooo_notificator_service_disabled_cb (EEwsOooNotificator *extension,
+                                          CamelService *service,
+                                          EMailAccountStore *account_store)
+{
+
+       EEwsOooNotificatorDispatcherData *data;
+
+       if (!CAMEL_IS_EWS_STORE (service))
+               return;
+
+       data = g_new0 (EEwsOooNotificatorDispatcherData, 1);
+       data->extension = g_object_ref (extension);
+       data->ews_store = g_object_ref (CAMEL_EWS_STORE (service));
+
+       e_ews_ooo_notificator_dispatcher (
+                       data,
+                       e_ews_ooo_notificator_service_disabled,
+                       e_ews_ooo_notificator_dispatcher_data_free);
+}
+
+static void
+e_ews_ooo_notificator_service_removed_cb (EEwsOooNotificator *extension,
+                                         CamelService *service,
+                                         EMailAccountStore *session)
+{
+       EEwsOooNotificatorDispatcherData *data;
+
+       if (!CAMEL_IS_EWS_STORE (service))
+               return;
+
+       data = g_new0 (EEwsOooNotificatorDispatcherData, 1);
+       data->extension = g_object_ref (extension);
+       data->ews_store = g_object_ref (CAMEL_EWS_STORE (service));
+
+       e_ews_ooo_notificator_dispatcher (
+                       data,
+                       e_ews_ooo_notificator_service_removed,
+                       e_ews_ooo_notificator_dispatcher_data_free);
+}
+
+static void
+e_ews_ooo_notificator_service_added_cb (EEwsOooNotificator *extension,
+                                       CamelService *service,
+                                       EMailAccountStore *session)
+{
+       CamelEwsStore *ews_store;
+
+       if (!CAMEL_IS_EWS_STORE (service))
+               return;
+
+       ews_store = CAMEL_EWS_STORE (service);
+       g_signal_connect_swapped (
+                       ews_store, "notify::has-ooo-set",
+                       G_CALLBACK (e_ews_ooo_notificator_has_ooo_set_cb), extension);
+       extension->priv->stores = g_list_append (extension->priv->stores, g_object_ref (ews_store));
+}
+
+static void
+e_ews_ooo_notificator_online_cb (EEwsOooNotificator* extension,
+                                GParamSpec *pspec,
+                                EShell *shell)
+{
+       GList *l;
+
+       if (e_shell_get_online (shell))
+               return;
+
+       for (l = extension->priv->stores; l; l = l->next) {
+               EEwsOooNotificatorDispatcherData *data;
+
+               data = g_new0 (EEwsOooNotificatorDispatcherData, 1);
+               data->extension = g_object_ref (extension);
+               data->ews_store = g_object_ref (CAMEL_EWS_STORE (l->data));
+
+               e_ews_ooo_notificator_dispatcher (
+                               data,
+                               e_ews_ooo_notificator_service_disabled,
+                               e_ews_ooo_notificator_dispatcher_data_free);
+       }
+}
+
+static void
+e_ews_ooo_notificator_init (EEwsOooNotificator *extension)
+{
+       extension->priv = E_EWS_OOO_NOTIFICATOR_GET_PRIVATE (extension);
+
+       extension->priv->alerts = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, 
g_object_unref);
+}
+
+static void
+e_ews_ooo_notificator_constructed (GObject *object)
+{
+       EEwsOooNotificator *extension;
+       EShell *shell;
+       EShellView *view;
+       EShellBackend *backend;
+       EMailAccountStore *account_store;
+       EMailSession *session;
+       GList *stores, *l;
+       const gchar *view_name;
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_ews_ooo_notificator_parent_class)->constructed (object);
+
+       extension = E_EWS_OOO_NOTIFICATOR (object);
+       view = e_ews_ooo_notificator_get_extensible (extension);
+       view_name = e_shell_view_get_name (view);
+
+       if (g_strcmp0 (view_name, "mail") != 0)
+               return;
+
+       backend = e_shell_view_get_shell_backend (view);
+       shell = e_shell_backend_get_shell (backend);
+       session = e_mail_backend_get_session (E_MAIL_BACKEND (backend));
+       account_store = e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION (session));
+       stores = camel_session_list_services (CAMEL_SESSION (session));
+
+       extension->priv->shell = shell;
+       extension->priv->account_store = g_object_ref (account_store);
+
+       for (l = stores; l; l = l->next) {
+               CamelService *service = l->data;
+               CamelEwsStore *ews_store;
+               gboolean has_ooo_set;
+
+               if (!CAMEL_IS_EWS_STORE (service))
+                       continue;
+
+               ews_store = CAMEL_EWS_STORE (service);
+               has_ooo_set = camel_ews_store_get_has_ooo_set (ews_store);
+
+               if (has_ooo_set) {
+                       e_ews_ooo_notificator_show_notification (extension, ews_store);
+                       camel_ews_store_set_ooo_alert_state (ews_store, 
CAMEL_EWS_STORE_OOO_ALERT_STATE_NOTIFIED);
+               }
+
+               g_signal_connect_swapped (
+                               ews_store, "notify::has-ooo-set",
+                               G_CALLBACK (e_ews_ooo_notificator_has_ooo_set_cb), extension);
+               extension->priv->stores = g_list_append (extension->priv->stores, g_object_ref (ews_store));
+       }
+
+       g_signal_connect_swapped (
+                       account_store, "service-disabled",
+                       G_CALLBACK (e_ews_ooo_notificator_service_disabled_cb), extension);
+
+       g_signal_connect_swapped (
+                       account_store, "service-removed",
+                       G_CALLBACK (e_ews_ooo_notificator_service_removed_cb), extension);
+
+       g_signal_connect_swapped (
+                       account_store, "service-added",
+                       G_CALLBACK (e_ews_ooo_notificator_service_added_cb), extension);
+
+       g_signal_connect_swapped (
+                       shell, "notify::online",
+                       G_CALLBACK (e_ews_ooo_notificator_online_cb), extension);
+
+       g_list_free_full (stores, g_object_unref);
+}
+
+static void
+e_ews_ooo_notificator_dispose (GObject *object)
+{
+       EEwsOooNotificator *extension;
+       GList *l;
+
+       extension = E_EWS_OOO_NOTIFICATOR (object);
+
+       if (extension->priv->shell) {
+               g_signal_handlers_disconnect_by_data (extension->priv->shell, extension);
+               extension->priv->shell = NULL;
+       }
+
+       if (extension->priv->account_store) {
+               g_signal_handlers_disconnect_by_data (extension->priv->account_store, extension);
+               g_object_unref (extension->priv->account_store);
+               extension->priv->account_store = NULL;
+       }
+
+       for (l = extension->priv->stores; l; l = l->next) {
+               CamelService *service = l->data;
+
+               if (service) {
+                       g_signal_handlers_disconnect_by_data (service, extension);
+                       g_object_unref (service);
+               }
+       }
+       g_list_free (extension->priv->stores);
+       extension->priv->stores = NULL;
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_ews_ooo_notificator_parent_class)->dispose (object);
+}
+
+static void
+e_ews_ooo_notificator_finalize (GObject *object)
+{
+       EEwsOooNotificator *extension;
+
+       extension = E_EWS_OOO_NOTIFICATOR (object);
+
+       if (extension->priv->alerts) {
+               g_hash_table_destroy (extension->priv->alerts);
+               extension->priv->alerts = NULL;
+       }
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (e_ews_ooo_notificator_parent_class)->finalize (object);
+}
+
+static void
+e_ews_ooo_notificator_class_init (EEwsOooNotificatorClass *class)
+{
+       GObjectClass *object_class;
+       EExtensionClass *extension_class;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->constructed = e_ews_ooo_notificator_constructed;
+       object_class->dispose = e_ews_ooo_notificator_dispose;
+       object_class->finalize = e_ews_ooo_notificator_finalize;
+
+       extension_class = E_EXTENSION_CLASS (class);
+       extension_class->extensible_type = E_TYPE_SHELL_VIEW;
+
+       g_type_class_add_private (class, sizeof (EEwsOooNotificatorPrivate));
+}
+
+static void
+e_ews_ooo_notificator_class_finalize (EEwsOooNotificatorClass *class)
+{
+}
+
+void
+e_ews_ooo_notificator_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_ews_ooo_notificator_register_type (type_module);
+}
diff --git a/src/configuration/e-ews-ooo-notificator.h b/src/configuration/e-ews-ooo-notificator.h
new file mode 100644
index 0000000..a80efab
--- /dev/null
+++ b/src/configuration/e-ews-ooo-notificator.h
@@ -0,0 +1,64 @@
+/*
+ * e-ews-ooo-notificator.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_EWS_OOO_NOTIFICATOR_H
+#define E_EWS_OOO_NOTIFICATOR_H
+
+#include <libebackend/libebackend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_EWS_OOO_NOTIFICATOR \
+       (e_ews_ooo_notificator_get_type ())
+#define E_EWS_OOO_NOTIFICATOR(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_EWS_OOO_NOTIFICATOR, EEwsOooNotificator))
+#define E_EWS_OOO_NOTIFICATOR_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_EWS_OOO_NOTIFICATOR, EEwsOooNotificatorClass))
+#define E_IS_EWS_OOO_NOTIFICATOR(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_EWS_OOO_NOTIFICATOR))
+#define E_IS_EWS_OOO_NOTIFICATOR_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_EWS_OOO_NOTIFICATOR))
+#define E_EWS_OOO_NOTIFICATOR_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_EWS_OOO_NOTIFICATOR, EEwsOooNotificatorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EEwsOooNotificator EEwsOooNotificator;
+typedef struct _EEwsOooNotificatorClass EEwsOooNotificatorClass;
+typedef struct _EEwsOooNotificatorPrivate EEwsOooNotificatorPrivate;
+
+struct _EEwsOooNotificator {
+       EExtension parent;
+       EEwsOooNotificatorPrivate *priv;
+};
+
+struct _EEwsOooNotificatorClass {
+       EExtensionClass parent_class;
+};
+
+GType          e_ews_ooo_notificator_get_type (void);
+void           e_ews_ooo_notificator_type_register (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_EWS_OOO_NOTIFICATOR_H */
+
diff --git a/src/configuration/module-ews-configuration.c b/src/configuration/module-ews-configuration.c
index 036b2d9..2e6c7bd 100644
--- a/src/configuration/module-ews-configuration.c
+++ b/src/configuration/module-ews-configuration.c
@@ -31,6 +31,7 @@
 #include "e-mail-config-ews-oal-combo-box.h"
 #include "e-mail-config-ews-delegates-page.h"
 #include "e-mail-config-ews-ooo-page.h"
+#include "e-ews-ooo-notificator.h"
 
 #include "e-ews-config-ui-extension.h"
 #include "server/e-source-ews-folder.h"
@@ -55,6 +56,7 @@ e_module_load (GTypeModule *type_module)
        e_mail_config_ews_delegates_page_type_register (type_module);
        e_mail_config_ews_ooo_page_type_register (type_module);
        e_ews_config_ui_extension_type_register (type_module);
+       e_ews_ooo_notificator_type_register (type_module);
 
        e_source_ews_folder_type_register (type_module);
 }
diff --git a/src/configuration/module-ews-configuration.error.xml 
b/src/configuration/module-ews-configuration.error.xml
index eaa6802..f950531 100644
--- a/src/configuration/module-ews-configuration.error.xml
+++ b/src/configuration/module-ews-configuration.error.xml
@@ -21,4 +21,8 @@
     <_secondary>The reported error was &quot;{0}&quot;.</_secondary>
   </error>
 
+  <error type="info" id="has-ooo-set">
+    <_primary>Your Exchange account "{0}" has the status set as "Out of Office".</_primary>
+  </error>
+
 </error-list>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]