[evolution-data-server] Bug #597157 - Crashes e-calendar-factory on multiple EDataCal requests
- From: Milan Crha <mcrha src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug #597157 - Crashes e-calendar-factory on multiple EDataCal requests
- Date: Tue, 6 Oct 2009 13:32:00 +0000 (UTC)
commit 937382d73032fb79a07e2c8c466149ae1d01bb1c
Author: Milan Crha <mcrha redhat com>
Date: Tue Oct 6 15:31:12 2009 +0200
Bug #597157 - Crashes e-calendar-factory on multiple EDataCal requests
calendar/libedata-cal/e-data-cal-factory.c | 203 +++++++++++++++++++++-------
calendar/libedata-cal/e-data-cal.c | 1 +
2 files changed, 158 insertions(+), 46 deletions(-)
---
diff --git a/calendar/libedata-cal/e-data-cal-factory.c b/calendar/libedata-cal/e-data-cal-factory.c
index 00a2021..f6ed9db 100644
--- a/calendar/libedata-cal/e-data-cal-factory.c
+++ b/calendar/libedata-cal/e-data-cal-factory.c
@@ -26,6 +26,7 @@
#include <config.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include <dbus/dbus-glib.h>
@@ -43,11 +44,11 @@
#include "e-data-cal-factory.h"
#include "e-cal-backend-loader-factory.h"
+#define d(x)
+
static void impl_CalFactory_getCal (EDataCalFactory *factory, const char *IN_uri, EDataCalObjType type, DBusGMethodInvocation *context);
#include "e-data-cal-factory-glue.h"
-static gchar *nm_dbus_escape_object_path (const gchar *utf8_string);
-
static GMainLoop *loop;
static EDataCalFactory *factory;
extern DBusGConnection *connection;
@@ -79,6 +80,12 @@ struct _EDataCalFactoryPrivate {
gint mode;
+ /* this is for notifications of source changes */
+ ESourceList *lists[E_CAL_SOURCE_TYPE_LAST];
+
+ /* backends divided by their type */
+ GSList *backends_by_type[E_CAL_SOURCE_TYPE_LAST];
+
guint exit_timeout;
};
@@ -126,6 +133,57 @@ icalkind_to_ecalsourcetype (const icalcomponent_kind kind)
return E_CAL_SOURCE_TYPE_LAST;
}
+static void
+update_source_in_backend (ECalBackend *backend, ESource *updated_source)
+{
+ xmlNodePtr xml;
+
+ g_return_if_fail (backend != NULL);
+ g_return_if_fail (updated_source != NULL);
+
+ xml = xmlNewNode (NULL, (const xmlChar *)"dummy");
+ e_source_dump_to_xml_node (updated_source, xml);
+ e_source_update_from_xml_node (e_cal_backend_get_source (backend), xml->children, NULL);
+ xmlFreeNode (xml);
+}
+
+static void
+source_list_changed_cb (ESourceList *list, EDataCalFactory *factory)
+{
+ EDataCalFactoryPrivate *priv;
+ gint i;
+
+ g_return_if_fail (list != NULL);
+ g_return_if_fail (factory != NULL);
+ g_return_if_fail (E_IS_DATA_CAL_FACTORY (factory));
+
+ priv = factory->priv;
+
+ g_mutex_lock (priv->backends_mutex);
+
+ for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) {
+ if (list == priv->lists[i]) {
+ GSList *l;
+
+ for (l = priv->backends_by_type [i]; l; l = l->next) {
+ ECalBackend *backend = l->data;
+ ESource *source, *list_source;
+
+ source = e_cal_backend_get_source (backend);
+ list_source = e_source_list_peek_source_by_uid (priv->lists[i], e_source_peek_uid (source));
+
+ if (list_source) {
+ update_source_in_backend (backend, list_source);
+ }
+ }
+
+ break;
+ }
+ }
+
+ g_mutex_unlock (priv->backends_mutex);
+}
+
static ECalBackendFactory *
get_backend_factory (GHashTable *methods, const gchar *method, icalcomponent_kind kind)
{
@@ -143,21 +201,43 @@ get_backend_factory (GHashTable *methods, const gchar *method, icalcomponent_kin
}
static gchar *
-make_path_name (const gchar* uri)
+construct_cal_factory_path (void)
{
- gchar *s, *path;
- s = nm_dbus_escape_object_path (uri);
- path = g_strdup_printf ("/org/gnome/evolution/dataserver/calendar/%s", s);
- g_free (s);
- return path;
+ static volatile gint counter = 1;
+
+ return g_strdup_printf (
+ "/org/gnome/evolution/dataserver/calendar/%d/%u",
+ getpid (),
+ g_atomic_int_exchange_and_add (&counter, 1));
}
static void
my_remove (gchar *key, GObject *dead)
{
EDataCalFactoryPrivate *priv = factory->priv;
- g_debug ("%s (%p) is dead", key, dead);
+ GHashTableIter iter;
+ gpointer hkey, hvalue;
+
+ d (g_debug ("%s (%p) is dead", key, dead));
+
g_hash_table_remove (priv->calendars, key);
+
+ g_hash_table_iter_init (&iter, priv->connections);
+ while (g_hash_table_iter_next (&iter, &hkey, &hvalue)) {
+ GList *calendars = hvalue;
+
+ if (g_list_find (calendars, dead)) {
+ calendars = g_list_remove (calendars, dead);
+ if (calendars) {
+ g_hash_table_insert (priv->connections, g_strdup (hkey), calendars);
+ } else {
+ g_hash_table_remove (priv->connections, hkey);
+ }
+
+ break;
+ }
+ }
+
g_free (key);
/* If there are no open calendars, start a timer to quit */
@@ -166,6 +246,36 @@ my_remove (gchar *key, GObject *dead)
}
}
+struct find_backend_data
+{
+ const gchar *str_uri;
+ ECalBackend *backend;
+ icalcomponent_kind kind;
+};
+
+static void
+find_backend_cb (gpointer key, gpointer value, gpointer data)
+{
+ struct find_backend_data *fbd = data;
+
+ if (fbd && fbd->str_uri && !fbd->backend) {
+ ECalBackend *backend = value;
+ gchar *str_uri;
+
+ str_uri = e_source_get_uri (e_cal_backend_get_source (backend));
+
+ if (str_uri && g_str_equal (str_uri, fbd->str_uri)) {
+ const gchar *uid_kind = key, *pos;
+
+ pos = strrchr (uid_kind, ':');
+ if (pos && atoi (pos + 1) == fbd->kind)
+ fbd->backend = backend;
+ }
+
+ g_free (str_uri);
+ }
+}
+
/* TODO: Error checking! */
static void
impl_CalFactory_getCal (EDataCalFactory *factory,
@@ -229,6 +339,25 @@ impl_CalFactory_getCal (EDataCalFactory *factory,
/* Look for an existing backend */
backend = g_hash_table_lookup (factory->priv->backends, uid_type_string);
+
+ if (!backend) {
+ /* find backend by URL, if opened, thus functions like e_cal_system_new_* will not
+ create new backends for the same url */
+ struct find_backend_data fbd;
+
+ fbd.str_uri = str_uri;
+ fbd.kind = calobjtype_to_icalkind (type);
+ fbd.backend = NULL;
+
+ g_hash_table_foreach (priv->backends, find_backend_cb, &fbd);
+
+ if (fbd.backend) {
+ backend = fbd.backend;
+ g_object_unref (source);
+ source = g_object_ref (e_cal_backend_get_source (backend));
+ }
+ }
+
if (!backend) {
ECalSourceType st;
@@ -245,18 +374,33 @@ impl_CalFactory_getCal (EDataCalFactory *factory,
goto cleanup;
}
+ st = icalkind_to_ecalsourcetype (e_cal_backend_get_kind (backend));
+ if (st != E_CAL_SOURCE_TYPE_LAST) {
+ if (!priv->lists[st] && e_cal_get_sources (&(priv->lists[st]), st, NULL)) {
+ g_signal_connect (priv->lists[st], "changed", G_CALLBACK (source_list_changed_cb), factory);
+ }
+
+ if (priv->lists[st])
+ priv->backends_by_type[st] = g_slist_prepend (priv->backends_by_type[st], backend);
+ }
+
/* Track the backend */
g_hash_table_insert (priv->backends, g_strdup (uid_type_string), backend);
+ } else if (!e_source_equal (source, e_cal_backend_get_source (backend))) {
+ /* source changed, update it in a backend */
+ update_source_in_backend (backend, source);
}
calendar = e_data_cal_new (backend, source);
e_cal_backend_add_client (backend, calendar);
e_cal_backend_set_mode (backend, priv->mode);
- path = make_path_name (str_uri);
+ path = construct_cal_factory_path ();
dbus_g_connection_register_g_object (connection, path, G_OBJECT (calendar));
g_object_weak_ref (G_OBJECT (calendar), (GWeakNotify)my_remove, g_strdup (path));
+ g_hash_table_insert (priv->calendars, g_strdup (path), calendar);
+
sender = dbus_g_method_get_sender (context);
list = g_hash_table_lookup (priv->connections, sender);
list = g_list_prepend (list, calendar);
@@ -313,7 +457,7 @@ e_data_cal_factory_init (EDataCalFactory *factory)
(GDestroyNotify) g_free, (GDestroyNotify) g_hash_table_destroy);
factory->priv->backends_mutex = g_mutex_new ();
- factory->priv->backends = g_hash_table_new (g_str_hash, g_str_equal);
+ factory->priv->backends = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
factory->priv->calendars = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
factory->priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
@@ -550,40 +694,7 @@ main (gint argc, gchar **argv)
dbus_g_connection_unref (connection);
- return 0;
-}
+ printf ("Bye.\n");
-/* Stolen from http://cvs.gnome.org/viewcvs/NetworkManager/utils/nm-utils.c */
-static gchar *
-nm_dbus_escape_object_path (const gchar *utf8_string)
-{
- const gchar *p;
- GString *string;
-
- g_return_val_if_fail (utf8_string != NULL, NULL);
- g_return_val_if_fail (g_utf8_validate (utf8_string, -1, NULL), NULL);
-
- string = g_string_sized_new ((strlen (utf8_string) + 1) * 2);
-
- for (p = utf8_string; *p != '\0'; p = g_utf8_next_char (p))
- {
- gunichar character;
-
- character = g_utf8_get_char (p);
-
- if (((character >= ((gunichar) 'a')) &&
- (character <= ((gunichar) 'z'))) ||
- ((character >= ((gunichar) 'A')) &&
- (character <= ((gunichar) 'Z'))) ||
- ((character >= ((gunichar) '0')) &&
- (character <= ((gunichar) '9'))))
- {
- g_string_append_c (string, (gchar) character);
- continue;
- }
-
- g_string_append_printf (string, "_%x_", character);
- }
-
- return g_string_free (string, FALSE);
+ return 0;
}
diff --git a/calendar/libedata-cal/e-data-cal.c b/calendar/libedata-cal/e-data-cal.c
index 512188a..132fc34 100644
--- a/calendar/libedata-cal/e-data-cal.c
+++ b/calendar/libedata-cal/e-data-cal.c
@@ -195,6 +195,7 @@ impl_Cal_open (EDataCal *cal,
static gboolean
impl_Cal_close (EDataCal *cal, GError **error)
{
+ e_cal_backend_remove_client (cal->priv->backend, cal);
g_object_unref (cal);
return TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]