aboutsummaryrefslogtreecommitdiffstats
path: root/shell/e-shell-offline-handler.c
diff options
context:
space:
mode:
authorEttore Perazzoli <ettore@src.gnome.org>2001-05-03 09:10:46 +0800
committerEttore Perazzoli <ettore@src.gnome.org>2001-05-03 09:10:46 +0800
commit483ebae5399d6aa7d63e471ea6000021a4be94fb (patch)
tree8de0a4611e800febfffa59c25d3b9d806d380757 /shell/e-shell-offline-handler.c
parent0ac06ee5b0cf27803e037b8bb5f3998898200bd1 (diff)
downloadgsoc2013-evolution-483ebae5399d6aa7d63e471ea6000021a4be94fb.tar.gz
gsoc2013-evolution-483ebae5399d6aa7d63e471ea6000021a4be94fb.tar.zst
gsoc2013-evolution-483ebae5399d6aa7d63e471ea6000021a4be94fb.zip
Add interfaces to the shell to handle off-line operation, as well as a
first (unfinished/untested) implementation for them. svn path=/trunk/; revision=9653
Diffstat (limited to 'shell/e-shell-offline-handler.c')
-rw-r--r--shell/e-shell-offline-handler.c646
1 files changed, 646 insertions, 0 deletions
diff --git a/shell/e-shell-offline-handler.c b/shell/e-shell-offline-handler.c
new file mode 100644
index 0000000000..1967041a7e
--- /dev/null
+++ b/shell/e-shell-offline-handler.c
@@ -0,0 +1,646 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-shell-offline-handler.c
+ *
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ettore Perazzoli <ettore@ximian.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtktypeutils.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkwidget.h>
+
+#include <gal/util/e-util.h>
+
+#include <bonobo/bonobo-main.h>
+
+#include "e-shell-offline-handler.h"
+
+
+#define PARENT_TYPE GTK_TYPE_OBJECT
+static GtkObjectClass *parent_class = NULL;
+
+
+/* Private part. */
+
+struct _OfflineProgressListenerServant {
+ POA_GNOME_Evolution_OfflineProgressListener servant;
+ EShellOfflineHandler *offline_handler;
+ char *component_id;
+};
+typedef struct _OfflineProgressListenerServant OfflineProgressListenerServant;
+
+struct _ComponentInfo {
+ /* Component ID. */
+ char *id;
+
+ /* The `Evolution::Offline' interface for this component (cached just
+ to avoid going through the EComponentRegistry all the time). */
+ GNOME_Evolution_Offline offline_interface;
+
+ /* The interface and servant for the
+ `Evolution::OfflineProgressListener' we have to implement to get
+ notifications about progress of the off-line process. */
+ GNOME_Evolution_OfflineProgressListener progress_listener_interface;
+ OfflineProgressListenerServant *progress_listener_servant;
+
+ /* The current active connections for this component. This is updated
+ by the component itself through the `::ProgressListener' interface;
+ when the count reaches zero, the off-line process is considered to
+ be complete. */
+ GNOME_Evolution_ConnectionList *active_connection_list;
+};
+typedef struct _ComponentInfo ComponentInfo;
+
+struct _EShellOfflineHandlerPrivate {
+ EComponentRegistry *component_registry;
+
+ EShellView *parent_shell_view;
+
+ int num_total_connections;
+ GHashTable *id_to_component_info;
+
+ gboolean procedure_in_progress : 1;
+};
+
+
+/* Signals. */
+
+enum {
+ OFFLINE_PROCEDURE_STARTED,
+ OFFLINE_PROCEDURE_FINISHED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+
+/* Implementation for the OfflineProgressListener interface. */
+
+static PortableServer_ServantBase__epv OfflineProgressListener_base_epv;
+static POA_GNOME_Evolution_OfflineProgressListener__epv OfflineProgressListener_epv;
+static POA_GNOME_Evolution_OfflineProgressListener__vepv OfflineProgressListener_vepv;
+
+static OfflineProgressListenerServant *
+progress_listener_servant_new (EShellOfflineHandler *offline_handler,
+ const char *id)
+{
+ OfflineProgressListenerServant *servant;
+
+ servant = g_new0 (OfflineProgressListenerServant, 1);
+
+ servant->servant.vepv = &OfflineProgressListener_vepv;
+ servant->offline_handler = offline_handler;
+ servant->component_id = g_strdup (id);
+
+ return servant;
+}
+
+static void
+progress_listener_servant_free (OfflineProgressListenerServant *servant)
+{
+ g_free (servant->component_id);
+ g_free (servant);
+}
+
+static GNOME_Evolution_ConnectionList *
+duplicate_connection_list (const GNOME_Evolution_ConnectionList *source)
+{
+ GNOME_Evolution_ConnectionList *copy;
+ int i;
+
+ copy = GNOME_Evolution_ConnectionList__alloc ();
+
+ copy->_length = source->_length;
+ copy->_maximum = source->_length;
+
+ copy->_buffer = CORBA_sequence_GNOME_Evolution_Connection_allocbuf (copy->_maximum);
+
+ for (i = 0; i < source->_length; i++) {
+ copy->_buffer[i].hostName = CORBA_string_dup (source->_buffer[i].hostName);
+ copy->_buffer[i].portNumber = source->_buffer[i].portNumber;
+ }
+
+ return copy;
+}
+
+static void
+impl_OfflineProgressListener_updateProgress (PortableServer_Servant servant,
+ const GNOME_Evolution_ConnectionList *current_active_connections,
+ CORBA_Environment *ev)
+{
+ EShellOfflineHandler *offline_handler;
+ EShellOfflineHandlerPrivate *priv;
+ ComponentInfo *component_info;
+ int connection_delta;
+ const char *component_id;
+
+ component_id = ((OfflineProgressListenerServant *) servant)->component_id;
+
+ offline_handler = ((OfflineProgressListenerServant *) servant)->offline_handler;
+ priv = offline_handler->priv;
+
+ component_info = g_hash_table_lookup (priv->id_to_component_info, component_id);
+ g_assert (component_info != NULL);
+
+ connection_delta = component_info->active_connection_list->_length - current_active_connections->_length;
+ if (connection_delta < 0) {
+ /* FIXME: Should raise an exception or something? */
+ g_warning ("Weird, buggy component increased number of connection when going off-line -- %s",
+ component_id);
+ }
+
+ g_assert (priv->num_total_connections >= connection_delta);
+ priv->num_total_connections -= connection_delta;
+
+ CORBA_free (component_info->active_connection_list);
+ component_info->active_connection_list = duplicate_connection_list (current_active_connections);
+
+ if (priv->num_total_connections == 0)
+ gtk_signal_emit (GTK_OBJECT (offline_handler), signals[OFFLINE_PROCEDURE_FINISHED], TRUE);
+
+ /* TODO: update the dialog. */
+}
+
+static gboolean
+create_progress_listener (EShellOfflineHandler *offline_handler,
+ const char *component_id,
+ GNOME_Evolution_OfflineProgressListener *objref_return,
+ OfflineProgressListenerServant **servant_return)
+{
+ OfflineProgressListenerServant *servant;
+ CORBA_Environment ev;
+
+ *servant_return = NULL;
+ *objref_return = CORBA_OBJECT_NIL;
+
+ OfflineProgressListener_base_epv._private = NULL;
+ OfflineProgressListener_base_epv.finalize = NULL;
+ OfflineProgressListener_base_epv.default_POA = NULL;
+
+ OfflineProgressListener_epv.updateProgress = impl_OfflineProgressListener_updateProgress;
+
+ OfflineProgressListener_vepv._base_epv = &OfflineProgressListener_base_epv;
+ OfflineProgressListener_vepv.GNOME_Evolution_OfflineProgressListener_epv = &OfflineProgressListener_epv;
+
+ servant = progress_listener_servant_new (offline_handler, component_id);
+
+ CORBA_exception_init (&ev);
+
+ POA_GNOME_Evolution_OfflineProgressListener__init ((PortableServer_Servant) servant, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Cannot initialize GNOME::Evolution::Offline::ProgressListener");
+ progress_listener_servant_free (servant);
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ CORBA_free (PortableServer_POA_activate_object (bonobo_poa (), servant, &ev));
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Cannot activate GNOME::Evolution::Offline::ProgressListener");
+ progress_listener_servant_free (servant);
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ *servant_return = servant;
+ *objref_return = PortableServer_POA_servant_to_reference (bonobo_poa (), servant, &ev);
+
+ CORBA_exception_free (&ev);
+
+ return TRUE;
+}
+
+
+/* ComponentInfo handling. */
+
+static ComponentInfo *
+component_info_new (const char *id,
+ const GNOME_Evolution_Offline offline_interface,
+ GNOME_Evolution_OfflineProgressListener progress_listener_interface,
+ OfflineProgressListenerServant *progress_listener_servant,
+ GNOME_Evolution_ConnectionList *active_connection_list)
+{
+ ComponentInfo *new;
+ CORBA_Environment ev;
+
+ CORBA_exception_init (&ev);
+
+ new = g_new (ComponentInfo, 1);
+ new->id = g_strdup (id);
+ new->offline_interface = CORBA_Object_duplicate (offline_interface, &ev);
+ new->progress_listener_interface = progress_listener_interface;
+ new->progress_listener_servant = progress_listener_servant;
+ new->active_connection_list = active_connection_list;
+
+ CORBA_exception_free (&ev);
+
+ return new;
+}
+
+static void
+component_info_free (ComponentInfo *component_info)
+{
+ CORBA_Environment ev;
+
+ CORBA_exception_init (&ev);
+
+ g_free (component_info->id);
+
+ CORBA_Object_release (component_info->offline_interface, &ev);
+
+ POA_GNOME_Evolution_OfflineProgressListener__fini
+ ((POA_GNOME_Evolution_OfflineProgressListener *) component_info->progress_listener_servant, &ev);
+ progress_listener_servant_free (component_info->progress_listener_servant);
+
+ CORBA_Object_release (component_info->progress_listener_interface, &ev);
+
+ CORBA_free (component_info->active_connection_list);
+
+ g_free (component_info);
+
+ CORBA_exception_free (&ev);
+}
+
+
+/* Utility functions. */
+
+static void
+hash_foreach_free_component_info (void *key,
+ void *value,
+ void *user_data)
+{
+ ComponentInfo *component_info;
+
+ component_info = (ComponentInfo *) value;
+ component_info_free (component_info);
+}
+
+
+/* Cancelling the off-line procedure. */
+
+static void
+cancel_offline (EShellOfflineHandler *offline_handler)
+{
+ EShellOfflineHandlerPrivate *priv;
+ GList *component_ids;
+ GList *p;
+
+ priv = offline_handler->priv;
+
+ component_ids = e_component_registry_get_id_list (priv->component_registry);
+
+ for (p = component_ids; p != NULL; p = p->next) {
+ EvolutionShellComponentClient *shell_component_client;
+ GNOME_Evolution_Offline offline_interface;
+ CORBA_Environment ev;
+ const char *id;
+
+ id = (const char *) p->data;
+ shell_component_client = e_component_registry_get_component_by_id (priv->component_registry, id);
+
+ offline_interface = evolution_shell_component_client_get_offline_interface (shell_component_client);
+ if (offline_interface == CORBA_OBJECT_NIL)
+ continue;
+
+ CORBA_exception_init (&ev);
+
+ GNOME_Evolution_Offline_goOnline (offline_interface, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION)
+ g_warning ("Error putting component `%s' on-line.", id);
+
+ CORBA_exception_free (&ev);
+ }
+
+ e_free_string_list (component_ids);
+
+ priv->num_total_connections = 0;
+}
+
+
+/* Preparing the off-line procedure. */
+
+static gboolean
+prepare_for_offline (EShellOfflineHandler *offline_handler)
+{
+ EShellOfflineHandlerPrivate *priv;
+ GList *component_ids;
+ GList *p;
+ gboolean error;
+
+ priv = offline_handler->priv;
+
+ component_ids = e_component_registry_get_id_list (priv->component_registry);
+
+ error = FALSE;
+ for (p = component_ids; p != NULL; p = p->next) {
+ EvolutionShellComponentClient *shell_component_client;
+ GNOME_Evolution_Offline offline_interface;
+ GNOME_Evolution_OfflineProgressListener progress_listener_interface;
+ GNOME_Evolution_ConnectionList *active_connection_list;
+ OfflineProgressListenerServant *progress_listener_servant;
+ ComponentInfo *component_info;
+ CORBA_Environment ev;
+ const char *id;
+
+ id = (const char *) p->data;
+ shell_component_client = e_component_registry_get_component_by_id (priv->component_registry, id);
+ offline_interface = evolution_shell_component_client_get_offline_interface (shell_component_client);
+ if (offline_interface == CORBA_OBJECT_NIL)
+ continue;
+
+ if (! create_progress_listener (offline_handler, id,
+ &progress_listener_interface,
+ &progress_listener_servant)) {
+ g_warning ("Cannot create the Evolution::OfflineProgressListener interface for `%s'", id);
+ continue;
+ }
+
+ CORBA_exception_init (&ev);
+
+ GNOME_Evolution_Offline_prepareForOffline (offline_interface, &active_connection_list, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Cannot prepare component component to go offline -- %s", id);
+
+ POA_GNOME_Evolution_OfflineProgressListener__fini
+ ((POA_GNOME_Evolution_OfflineProgressListener *) progress_listener_servant, &ev);
+ progress_listener_servant_free (progress_listener_servant);
+
+ CORBA_Object_release (progress_listener_interface, &ev);
+
+ CORBA_exception_free (&ev);
+
+ error = TRUE;
+ break;
+ }
+
+ CORBA_exception_free (&ev);
+
+ priv->num_total_connections += active_connection_list->_length;
+
+ component_info = component_info_new (id,
+ offline_interface,
+ progress_listener_interface,
+ progress_listener_servant,
+ active_connection_list);
+
+ g_assert (g_hash_table_lookup (priv->id_to_component_info, component_info->id) == NULL);
+ g_hash_table_insert (priv->id_to_component_info, component_info->id, component_info);
+ }
+
+ /* If an error occurred while preparing, just put all the components
+ on-line again. */
+ if (error)
+ cancel_offline (offline_handler);
+
+ e_free_string_list (component_ids);
+
+ return ! error;
+}
+
+
+/* Finalizing the off-line procedure. */
+
+static void
+finalize_offline_hash_foreach (void *key,
+ void *value,
+ void *user_data)
+{
+ EShellOfflineHandler *offline_handler;
+ EShellOfflineHandlerPrivate *priv;
+ ComponentInfo *component_info;
+ CORBA_Environment ev;
+
+ offline_handler = E_SHELL_OFFLINE_HANDLER (user_data);
+ priv = offline_handler->priv;
+
+ component_info = (ComponentInfo *) value;
+
+ CORBA_exception_init (&ev);
+
+ g_print ("Putting component off-line -- %s", component_info->id);
+
+ GNOME_Evolution_Offline_goOffline (component_info->offline_interface,
+ component_info->progress_listener_interface,
+ &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ /* FIXME: Should detect an error and put all the components
+ on-line again. */
+ g_warning ("Error putting component off-line -- %s", component_info->id);
+ }
+
+ CORBA_exception_free (&ev);
+}
+
+static void
+finalize_offline (EShellOfflineHandler *offline_handler)
+{
+ EShellOfflineHandlerPrivate *priv;
+
+ priv = offline_handler->priv;
+
+ g_hash_table_foreach (priv->id_to_component_info, finalize_offline_hash_foreach, offline_handler);
+
+ if (priv->num_total_connections == 0) {
+ /* Nothing else to do, we are all set. */
+ gtk_signal_emit (GTK_OBJECT (offline_handler), signals[OFFLINE_PROCEDURE_FINISHED], TRUE);
+ }
+}
+
+
+/* The confirmation dialog. */
+
+static void
+pop_up_confirmation_dialog (EShellOfflineHandler *offline_handler)
+{
+ EShellOfflineHandlerPrivate *priv;
+
+ priv = offline_handler->priv;
+
+ g_warning ("Should pop up dialog here");
+
+ finalize_offline (offline_handler);
+}
+
+
+/* GtkObject methods. */
+
+static void
+impl_destroy (GtkObject *object)
+{
+ EShellOfflineHandler *offline_handler;
+ EShellOfflineHandlerPrivate *priv;
+
+ offline_handler = E_SHELL_OFFLINE_HANDLER (object);
+ priv = offline_handler->priv;
+
+ if (priv->component_registry != NULL)
+ gtk_object_unref (GTK_OBJECT (priv->component_registry));
+
+ g_hash_table_foreach (priv->id_to_component_info, hash_foreach_free_component_info, NULL);
+ g_hash_table_destroy (priv->id_to_component_info);
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+
+/* GTK type handling. */
+
+static void
+class_init (EShellOfflineHandlerClass *klass)
+{
+ GtkObjectClass *object_class;
+
+ object_class = GTK_OBJECT_CLASS (klass);
+ object_class->destroy = impl_destroy;
+
+ parent_class = gtk_type_class (gtk_object_get_type ());
+
+ signals[OFFLINE_PROCEDURE_STARTED]
+ = gtk_signal_new ("offline_procedure_started",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EShellOfflineHandlerClass, offline_procedure_started),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
+ signals[OFFLINE_PROCEDURE_FINISHED]
+ = gtk_signal_new ("offline_procedure_finished",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EShellOfflineHandlerClass, offline_procedure_finished),
+ gtk_marshal_NONE__BOOL,
+ GTK_TYPE_NONE, 1,
+ GTK_TYPE_BOOL);
+
+ gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
+}
+
+
+static void
+init (EShellOfflineHandler *shell_offline_handler)
+{
+ EShellOfflineHandlerPrivate *priv;
+
+ priv = g_new (EShellOfflineHandlerPrivate, 1);
+
+ priv->component_registry = NULL;
+ priv->parent_shell_view = NULL;
+ priv->procedure_in_progress = TRUE;
+
+ priv->num_total_connections = 0;
+ priv->id_to_component_info = g_hash_table_new (g_str_hash, g_str_equal);
+
+ shell_offline_handler->priv = priv;
+}
+
+
+/**
+ * e_shell_offline_handler_construct:
+ * @offline_handler: A pointer to an EShellOfflineHandler to construct.
+ * @component_registry: The registry for the components that we want to put
+ * off-line.
+ *
+ * Construct the @offline_handler.
+ **/
+void
+e_shell_offline_handler_construct (EShellOfflineHandler *offline_handler,
+ EComponentRegistry *component_registry)
+{
+ EShellOfflineHandlerPrivate *priv;
+
+ g_return_if_fail (offline_handler != NULL);
+ g_return_if_fail (E_IS_SHELL_OFFLINE_HANDLER (offline_handler));
+ g_return_if_fail (component_registry != NULL);
+ g_return_if_fail (E_IS_COMPONENT_REGISTRY (component_registry));
+
+ g_assert (priv->component_registry == NULL);
+
+ gtk_object_ref (GTK_OBJECT (component_registry));
+ priv->component_registry = component_registry;
+}
+
+/**
+ * e_shell_offline_handler_new:
+ * @component_registry: The registry for the components that we want to put
+ * off-line.
+ *
+ * Create a new offline handler.
+ *
+ * Return value: A pointer to the newly created EShellOfflineHandler object.
+ **/
+EShellOfflineHandler *
+e_shell_offline_handler_new (EComponentRegistry *component_registry)
+{
+ EShellOfflineHandler *offline_handler;
+
+ g_return_val_if_fail (component_registry != NULL, NULL);
+ g_return_val_if_fail (E_IS_COMPONENT_REGISTRY (component_registry), NULL);
+
+ offline_handler = (EShellOfflineHandler *) gtk_type_new (e_shell_offline_handler_get_type ());
+ e_shell_offline_handler_construct (offline_handler, component_registry);
+
+ return offline_handler;
+}
+
+
+/**
+ * e_shell_offline_handler_put_components_offline:
+ * @offline_handler: A pointer to an EShellOfflineHandler object.
+ *
+ * Put the components offline.
+ **/
+void
+e_shell_offline_handler_put_components_offline (EShellOfflineHandler *offline_handler,
+ EShellView *parent_shell_view)
+{
+ EShellOfflineHandlerPrivate *priv;
+
+ g_return_if_fail (offline_handler != NULL);
+ g_return_if_fail (E_IS_SHELL_OFFLINE_HANDLER (offline_handler));
+ g_return_if_fail (parent_shell_view == NULL || E_IS_SHELL_VIEW (parent_shell_view));
+
+ priv = offline_handler->priv;
+
+ priv->procedure_in_progress = TRUE;
+ priv->parent_shell_view = parent_shell_view;
+
+ gtk_signal_emit (GTK_OBJECT (offline_handler), signals[OFFLINE_PROCEDURE_STARTED]);
+
+ if (! prepare_for_offline (offline_handler)) {
+ /* FIXME: Maybe do something smarter here. */
+ g_warning ("Couldn't put components off-line for some internal error");
+ gtk_signal_emit (GTK_OBJECT (offline_handler), signals[OFFLINE_PROCEDURE_FINISHED], FALSE);
+ return;
+ }
+
+ if (priv->num_total_connections == 0 && priv->parent_shell_view != NULL)
+ pop_up_confirmation_dialog (offline_handler);
+ else
+ finalize_offline (offline_handler);
+}
+
+
+E_MAKE_TYPE (e_shell_offline_handler, "EShellOfflineHandler", EShellOfflineHandler, class_init, init, PARENT_TYPE)