diff options
-rw-r--r-- | addressbook/ChangeLog | 77 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-book-listener.c | 4 | ||||
-rw-r--r-- | addressbook/backend/ebook/e-book-types.h | 4 | ||||
-rw-r--r-- | addressbook/backend/idl/addressbook.idl | 4 | ||||
-rw-r--r-- | addressbook/backend/pas/pas-backend-file.c | 93 | ||||
-rw-r--r-- | addressbook/backend/pas/pas-backend-ldap.c | 91 | ||||
-rw-r--r-- | addressbook/backend/pas/pas-backend.c | 87 | ||||
-rw-r--r-- | addressbook/backend/pas/pas-backend.h | 15 | ||||
-rw-r--r-- | addressbook/backend/pas/pas-book-factory.c | 221 | ||||
-rw-r--r-- | addressbook/backend/pas/pas-book-factory.h | 6 |
10 files changed, 511 insertions, 91 deletions
diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog index 40d4cc9ae7..6a025eb26b 100644 --- a/addressbook/ChangeLog +++ b/addressbook/ChangeLog @@ -1,3 +1,80 @@ +2000-04-30 Federico Mena Quintero <federico@helixcode.com> + + * backend/ebook/e-book-types.h (EBookStatus): Added new status + values for the IDL stuff. + + * backend/pas/pas-book-factory.h (PASBookFactoryClass): New + "last_book_gone" signal. + + * backend/pas/pas-book-factory.c + (pas_book_factory_launch_backend): Better error handling. + (pas_book_factory_process_queue): Let + pas_book_factory_process_request() free the request. + (pas_book_factory_process_request): Free the request here. + Perform better error handling. + (free_active_server_map_entry): Free an active server map entry; + free the URI key and unref the backend value. This function was + renamed; the old one was trying to CORBA_Object_unref() a GTK+ + object! + (remove_backends_entry): Free a backend table entry; free the URI + key. + (backend_last_client_gone_cb): Remove the backend from the active + server map and emit the "last_book_gone" signal if appropriate. + (pas_book_factory_get_n_backends): New function to query the + number of running backends in an addressbook factory. + + * backend/idl/addressbook.idl (BookListener::CallStatus): Added a + ProtocolNotSupported code. This is for when the addressbook + factory cannot find a provider for the requested URI. + + * backend/pas/pas-backend.h (PASBackendClass): New + "last_client_gone" signal. + (PASBackendClass): New get_uri virtual method. + + * backend/pas/pas-backend.c (pas_backend_load_uri): Return a + gboolean success code. + (pas_backend_add_client): Return a gboolean success code. + (pas_backend_last_client_gone): New function used by backend + implementations to notify upwards when the backend's last client + is destroyed. + (pas_backend_get_uri): New function to get the URI of a backend. + + * backend/pas/pas-backend-file.c (pas_backend_file_add_client): + Pass the backend as the closure data to the "destroy" handler of + the book. We cannot call pas_book_get_backend() in the callback + since the book's private data has already been destroyed when the + callback is invoked. Alternatively, we could move the private + data destruction step to the book's ::finalize() method. + (pas_backend_file_book_destroy_cb): Get the backend from the + callback's data, not from the book. + (pas_backend_file_remove_client): Remove the book from the list of + clients. When all clients go away, call + pas_backend_last_client_gone(). + (PASBackendFilePrivate): Added an uri field. + (pas_backend_file_get_uri): Implement the get_uri method. + (pas_backend_file_load_uri): Return a gboolean success code. + Also, store the URI in the private structure. + (pas_backend_file_add_client): Return a gboolean success code. + Also, call pas_backend_last_client_gone() if appropriate. + (pas_backend_file_destroy): Free the bf->priv->uri. + + * backend/pas/pas-backend-ldap.c (pas_backend_ldap_add_client): + Pass the backend as the closure data to the "destroy" handler of + the book. See above for rationale. + (pas_backend_ldap_book_destroy_cb): Get the backend from the + callback's data. + (pas_backend_ldap_remove_client): Remove the book from the list of + clients. When all clients go away, call + pas_backend_last_client_gone(). + (pas_backend_ldap_load_uri): Return a gboolean success code. + (pas_backend_ldap_add_client): Return a gboolean success code. + Also, call pas_backend_last_client_gone() if appropriate. + (PASBackendLDAPPrivate): New uri field. + (pas_backend_ldap_get_uri): Implement the get_uri method. + (pas_backend_ldap_load_uri): Store the uri in the private + structure. + (pas_backend_ldap_destroy): Free the bl->priv->uri. + 2000-04-30 Chris Toshok <toshok@helixcode.com> * gui/component/Makefile.am (evolution_addressbook_SOURCES): added diff --git a/addressbook/backend/ebook/e-book-listener.c b/addressbook/backend/ebook/e-book-listener.c index d0ccc46944..5efdaa37df 100644 --- a/addressbook/backend/ebook/e-book-listener.c +++ b/addressbook/backend/ebook/e-book-listener.c @@ -357,6 +357,10 @@ e_book_listener_convert_status (const Evolution_BookListener_CallStatus status) return E_BOOK_STATUS_PERMISSION_DENIED; case Evolution_BookListener_CardNotFound: return E_BOOK_STATUS_CARD_NOT_FOUND; + case Evolution_BookListener_ProtocolNotSupported: + return E_BOOK_STATUS_PROTOCOL_NOT_SUPPORTED; + case Evolution_BookListener_OtherError: + return E_BOOK_STATUS_OTHER_ERROR; default: g_warning ("e_book_listener_convert_status: Unknown status " "from card server: %d\n", (int) status); diff --git a/addressbook/backend/ebook/e-book-types.h b/addressbook/backend/ebook/e-book-types.h index 1d86a5bd4d..a3e8bbc032 100644 --- a/addressbook/backend/ebook/e-book-types.h +++ b/addressbook/backend/ebook/e-book-types.h @@ -21,7 +21,9 @@ typedef enum { E_BOOK_STATUS_UNKNOWN, E_BOOK_STATUS_REPOSITORY_OFFLINE, E_BOOK_STATUS_PERMISSION_DENIED, - E_BOOK_STATUS_CARD_NOT_FOUND + E_BOOK_STATUS_CARD_NOT_FOUND, + E_BOOK_STATUS_PROTOCOL_NOT_SUPPORTED, + E_BOOK_STATUS_OTHER_ERROR } EBookStatus; END_GNOME_DECLS diff --git a/addressbook/backend/idl/addressbook.idl b/addressbook/backend/idl/addressbook.idl index 44987a76fb..b3bcb5ea87 100644 --- a/addressbook/backend/idl/addressbook.idl +++ b/addressbook/backend/idl/addressbook.idl @@ -80,7 +80,9 @@ module Evolution { Success, RepositoryOffline, PermissionDenied, - CardNotFound + CardNotFound, + ProtocolNotSupported, + OtherError }; void respond_create_card (in CallStatus status, in CardId Id); diff --git a/addressbook/backend/pas/pas-backend-file.c b/addressbook/backend/pas/pas-backend-file.c index 20de42808c..e2ca9a7348 100644 --- a/addressbook/backend/pas/pas-backend-file.c +++ b/addressbook/backend/pas/pas-backend-file.c @@ -33,6 +33,7 @@ typedef struct _PASBackendFileSearchContext PASBackendFileSearchContext; struct _PASBackendFilePrivate { GList *clients; gboolean loaded; + char *uri; DB *file_db; GList *book_views; }; @@ -825,11 +826,11 @@ pas_backend_file_process_client_requests (PASBook *book) } static void -pas_backend_file_book_destroy_cb (PASBook *book) +pas_backend_file_book_destroy_cb (PASBook *book, gpointer data) { PASBackendFile *backend; - backend = PAS_BACKEND_FILE (pas_book_get_backend (book)); + backend = PAS_BACKEND_FILE (data); pas_backend_remove_client (PAS_BACKEND (backend), book); } @@ -924,7 +925,7 @@ pas_backend_file_maybe_upgrade_db (PASBackendFile *bf) return ret_val; } -static void +static gboolean pas_backend_file_load_uri (PASBackend *backend, const char *uri) { @@ -937,18 +938,45 @@ pas_backend_file_load_uri (PASBackend *backend, bf->priv->file_db = dbopen (filename, O_RDWR | O_CREAT, 0666, DB_HASH, NULL); + g_free (filename); + if (bf->priv->file_db != NULL) { if (pas_backend_file_maybe_upgrade_db (bf)) bf->priv->loaded = TRUE; /* XXX what if we fail to upgrade it? */ + + bf->priv->uri = g_strdup (uri); + } else { + GList *l; + + for (l = bf->priv->clients; l; l = l->next) { + PASBook *book; + + book = PAS_BOOK (l->data); + pas_book_respond_open (book, Evolution_BookListener_OtherError); + } + + return FALSE; } - else - g_warning ("pas_backend_file_load_uri failed for '%s'\n", filename); - g_free (filename); + return TRUE; } -static void +/* Get_uri handler for the addressbook file backend */ +static const char * +pas_backend_file_get_uri (PASBackend *backend) +{ + PASBackendFile *bf; + + bf = PAS_BACKEND_FILE (backend); + + g_return_val_if_fail (bf->priv->loaded, NULL); + g_assert (bf->priv->uri != NULL); + + return bf->priv->uri; +} + +static gboolean pas_backend_file_add_client (PASBackend *backend, Evolution_BookListener listener) { @@ -964,10 +992,15 @@ pas_backend_file_add_client (PASBackend *backend, backend, listener, pas_backend_file_get_vcard); - g_assert (book != NULL); + if (!book) { + if (!bf->priv->clients) + pas_backend_last_client_gone (backend); + + return FALSE; + } gtk_signal_connect (GTK_OBJECT (book), "destroy", - pas_backend_file_book_destroy_cb, NULL); + pas_backend_file_book_destroy_cb, backend); gtk_signal_connect (GTK_OBJECT (book), "requests_queued", pas_backend_file_process_client_requests, NULL); @@ -983,18 +1016,46 @@ pas_backend_file_add_client (PASBackend *backend, pas_book_respond_open ( book, Evolution_BookListener_Success); } + + return TRUE; } static void pas_backend_file_remove_client (PASBackend *backend, PASBook *book) { + PASBackendFile *bf; + GList *l; + PASBook *lbook; + g_return_if_fail (backend != NULL); - g_return_if_fail (PAS_IS_BACKEND (backend)); + g_return_if_fail (PAS_IS_BACKEND_FILE (backend)); g_return_if_fail (book != NULL); g_return_if_fail (PAS_IS_BOOK (book)); - g_warning ("pas_backend_file_remove_client: Unimplemented!\n"); + bf = PAS_BACKEND_FILE (backend); + + /* Find the book in the list of clients */ + + for (l = bf->priv->clients; l; l = l->next) { + lbook = PAS_BOOK (l->data); + + if (lbook == book) + break; + } + + g_assert (l != NULL); + + /* Disconnect */ + + bf->priv->clients = g_list_remove_link (bf->priv->clients, l); + g_list_free_1 (l); + + /* When all clients go away, notify the parent factory about it so that + * it may decide whether to kill the backend or not. + */ + if (!bf->priv->clients) + pas_backend_last_client_gone (backend); } static gboolean @@ -1031,6 +1092,15 @@ pas_backend_file_new (void) static void pas_backend_file_destroy (GtkObject *object) { + PASBackendFile *bf; + + bf = PAS_BACKEND_FILE (object); + + if (bf->priv->uri) { + g_free (bf->priv->uri); + bf->priv->uri = NULL; + } + GTK_OBJECT_CLASS (pas_backend_file_parent_class)->destroy (object); } @@ -1046,6 +1116,7 @@ pas_backend_file_class_init (PASBackendFileClass *klass) /* Set the virtual methods. */ parent_class->load_uri = pas_backend_file_load_uri; + parent_class->get_uri = pas_backend_file_get_uri; parent_class->add_client = pas_backend_file_add_client; parent_class->remove_client = pas_backend_file_remove_client; diff --git a/addressbook/backend/pas/pas-backend-ldap.c b/addressbook/backend/pas/pas-backend-ldap.c index 82694510ba..f1fa1ea92b 100644 --- a/addressbook/backend/pas/pas-backend-ldap.c +++ b/addressbook/backend/pas/pas-backend-ldap.c @@ -29,6 +29,7 @@ typedef struct _PASBackendLDAPCursorPrivate PASBackendLDAPCursorPrivate; typedef struct _PASBackendLDAPBookView PASBackendLDAPBookView; struct _PASBackendLDAPPrivate { + char *uri; gboolean connected; GList *clients; LDAP *ldap; @@ -842,11 +843,11 @@ pas_backend_ldap_process_client_requests (PASBook *book) } static void -pas_backend_ldap_book_destroy_cb (PASBook *book) +pas_backend_ldap_book_destroy_cb (PASBook *book, gpointer data) { PASBackendLDAP *backend; - backend = PAS_BACKEND_LDAP (pas_book_get_backend (book)); + backend = PAS_BACKEND_LDAP (data); pas_backend_remove_client (PAS_BACKEND (backend), book); } @@ -863,7 +864,7 @@ pas_backend_ldap_get_vcard (PASBook *book, const char *id) /* XXX use ldap_search */ - if (LDAP_SUCCESS == ldap_error) { + if (ldap_error == LDAP_SUCCESS) { /* success */ return g_strdup (""); } @@ -872,7 +873,7 @@ pas_backend_ldap_get_vcard (PASBook *book, const char *id) } } -static void +static gboolean pas_backend_ldap_load_uri (PASBackend *backend, const char *uri) { @@ -883,7 +884,8 @@ pas_backend_ldap_load_uri (PASBackend *backend, g_assert (bl->priv->connected == FALSE); ldap_error = ldap_url_parse ((char*)uri, &lud); - if (LDAP_SUCCESS == ldap_error) { + if (ldap_error == LDAP_SUCCESS) { + bl->priv->uri = g_strdup (uri); bl->priv->ldap_host = g_strdup(lud->lud_host); bl->priv->ldap_port = lud->lud_port; bl->priv->ldap_rootdn = g_strdup(lud->lud_dn); @@ -891,14 +893,32 @@ pas_backend_ldap_load_uri (PASBackend *backend, ldap_free_urldesc(lud); pas_backend_ldap_ensure_connected(bl); - } - else { - g_warning ("pas_backend_ldap_load_uri failed for '%s' (error %s)\n", - uri, ldap_err2string(ldap_error)); + return TRUE; + } else { + GList *l; + + for (l = bl->priv->clients; l; l = l->next) { + PASBook *book; + + book = PAS_BOOK (l->data); + pas_book_respond_open (book, Evolution_BookListener_OtherError); + } + + return FALSE; } } -static void +/* Get_uri handler for the addressbook LDAP backend */ +static const char * +pas_backend_ldap_get_uri (PASBackend *backend) +{ + PASBackendLDAP *bl; + + bl = PAS_BACKEND_LDAP (backend); + return bl->priv->uri; +} + +static gboolean pas_backend_ldap_add_client (PASBackend *backend, Evolution_BookListener listener) { @@ -914,10 +934,15 @@ pas_backend_ldap_add_client (PASBackend *backend, backend, listener, pas_backend_ldap_get_vcard); - g_assert (book != NULL); + if (!book) { + if (!bl->priv->clients) + pas_backend_last_client_gone (backend); + + return FALSE; + } gtk_signal_connect (GTK_OBJECT (book), "destroy", - pas_backend_ldap_book_destroy_cb, NULL); + pas_backend_ldap_book_destroy_cb, backend); gtk_signal_connect (GTK_OBJECT (book), "requests_queued", pas_backend_ldap_process_client_requests, NULL); @@ -933,18 +958,46 @@ pas_backend_ldap_add_client (PASBackend *backend, pas_book_respond_open ( book, Evolution_BookListener_Success); } + + return TRUE; } static void pas_backend_ldap_remove_client (PASBackend *backend, PASBook *book) { + PASBackendLDAP *bl; + GList *l; + PASBook *lbook; + g_return_if_fail (backend != NULL); - g_return_if_fail (PAS_IS_BACKEND (backend)); + g_return_if_fail (PAS_IS_BACKEND_LDAP (backend)); g_return_if_fail (book != NULL); g_return_if_fail (PAS_IS_BOOK (book)); - g_warning ("pas_backend_ldap_remove_client: Unimplemented!\n"); + bl = PAS_BACKEND_LDAP (backend); + + /* Find the book in the list of clients */ + + for (l = bl->priv->clients, l; l = l->next) { + lbook = PAS_BOOK (l->data); + + if (lbook == book) + break; + } + + g_assert (l != NULL); + + /* Disconnect */ + + bl->priv->clients = g_list_remove_link (bl->priv->clients, l); + g_list_free_1 (l); + + /* When all clients go away, notify the parent factory about it so that + * it may decide whether to kill the backend or not. + */ + if (!bl->priv->clients) + pas_backend_last_client_gone (backend); } static gboolean @@ -983,6 +1036,15 @@ pas_backend_ldap_new (void) static void pas_backend_ldap_destroy (GtkObject *object) { + PASBackendLDAP *bl; + + bl = PAS_BACKEND_LDAP (object); + + if (bl->priv->uri) { + g_free (bl->priv->uri); + bl->priv->uri = NULL; + } + GTK_OBJECT_CLASS (pas_backend_ldap_parent_class)->destroy (object); } @@ -998,6 +1060,7 @@ pas_backend_ldap_class_init (PASBackendLDAPClass *klass) /* Set the virtual methods. */ parent_class->load_uri = pas_backend_ldap_load_uri; + parent_class->get_uri = pas_backend_ldap_get_uri; parent_class->add_client = pas_backend_ldap_add_client; parent_class->remove_client = pas_backend_ldap_remove_client; diff --git a/addressbook/backend/pas/pas-backend.c b/addressbook/backend/pas/pas-backend.c index d8aa23fb37..3d315c2faf 100644 --- a/addressbook/backend/pas/pas-backend.c +++ b/addressbook/backend/pas/pas-backend.c @@ -7,45 +7,78 @@ #include <config.h> #include <gtk/gtkobject.h> +#include <gtk/gtksignal.h> #include "pas-backend.h" #define CLASS(o) PAS_BACKEND_CLASS (GTK_OBJECT (o)->klass) +/* Signal IDs */ +enum { + LAST_CLIENT_GONE, + LAST_SIGNAL +}; + +static guint pas_backend_signals[LAST_SIGNAL]; + + gboolean pas_backend_construct (PASBackend *backend) { return TRUE; } -void +gboolean pas_backend_load_uri (PASBackend *backend, const char *uri) { - g_return_if_fail (backend != NULL); - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (uri != NULL); + g_return_val_if_fail (backend != NULL, FALSE); + g_return_val_if_fail (PAS_IS_BACKEND (backend), FALSE); + g_return_val_if_fail (uri != NULL, FALSE); g_assert (CLASS (backend)->load_uri != NULL); - CLASS (backend)->load_uri (backend, uri); + return (* CLASS (backend)->load_uri) (backend, uri); +} + +/** + * pas_backend_get_uri: + * @backend: An addressbook backend. + * + * Queries the URI that an addressbook backend is serving. + * + * Return value: URI for the backend. + **/ +const char * +pas_backend_get_uri (PASBackend *backend) +{ + g_return_val_if_fail (backend != NULL, NULL); + g_return_val_if_fail (PAS_IS_BACKEND (backend), NULL); + + g_assert (CLASS (backend)->get_uri != NULL); + + return (* CLASS (backend)->get_uri) (backend); } /** * pas_backend_add_client: - * @backend: - * @listener: + * @backend: An addressbook backend. + * @listener: Listener for notification to the client. + * + * Adds a client to an addressbook backend. + * + * Return value: TRUE on success, FALSE on failure to add the client. */ -void +gboolean pas_backend_add_client (PASBackend *backend, Evolution_BookListener listener) { - g_return_if_fail (backend != NULL); - g_return_if_fail (PAS_IS_BACKEND (backend)); - g_return_if_fail (listener != CORBA_OBJECT_NIL); + g_return_val_if_fail (backend != NULL, FALSE); + g_return_val_if_fail (PAS_IS_BACKEND (backend), FALSE); + g_return_val_if_fail (listener != CORBA_OBJECT_NIL, FALSE); g_assert (CLASS (backend)->add_client != NULL); - CLASS (backend)->add_client (backend, listener); + return CLASS (backend)->add_client (backend, listener); } void @@ -62,6 +95,23 @@ pas_backend_remove_client (PASBackend *backend, CLASS (backend)->remove_client (backend, book); } +/** + * pas_backend_last_client_gone: + * @backend: An addressbook backend. + * + * Emits the "last_client_gone" signal for the specified backend. Should + * only be called from backend implementations if the backend really does + * not have any more clients. + **/ +void +pas_backend_last_client_gone (PASBackend *backend) +{ + g_return_if_fail (backend != NULL); + g_return_if_fail (PAS_IS_BACKEND (backend)); + + gtk_signal_emit (GTK_OBJECT (backend), pas_backend_signals[LAST_CLIENT_GONE]); +} + static void pas_backend_init (PASBackend *backend) { @@ -70,6 +120,19 @@ pas_backend_init (PASBackend *backend) static void pas_backend_class_init (PASBackendClass *klass) { + GtkObjectClass *object_class; + + object_class = (GtkObjectClass *) klass; + + pas_backend_signals[LAST_CLIENT_GONE] = + gtk_signal_new ("last_client_gone", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (PASBackendClass, last_client_gone), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, pas_backend_signals, LAST_SIGNAL); } /** diff --git a/addressbook/backend/pas/pas-backend.h b/addressbook/backend/pas/pas-backend.h index 46cce03e03..a1d1a291fd 100644 --- a/addressbook/backend/pas/pas-backend.h +++ b/addressbook/backend/pas/pas-backend.h @@ -39,21 +39,28 @@ typedef struct { GtkObjectClass parent_class; /* Virtual methods */ - void (*load_uri) (PASBackend *backend, const char *uri); - void (*add_client) (PASBackend *backend, Evolution_BookListener listener); + gboolean (*load_uri) (PASBackend *backend, const char *uri); + const char *(* get_uri) (PASBackend *backend); + gboolean (*add_client) (PASBackend *backend, Evolution_BookListener listener); void (*remove_client) (PASBackend *backend, PASBook *book); + + /* Notification signals */ + void (* last_client_gone) (PASBackend *backend); } PASBackendClass; typedef PASBackend * (*PASBackendFactoryFn) (void); gboolean pas_backend_construct (PASBackend *backend); -void pas_backend_load_uri (PASBackend *backend, +gboolean pas_backend_load_uri (PASBackend *backend, const char *uri); -void pas_backend_add_client (PASBackend *backend, +const char *pas_backend_get_uri (PASBackend *backend); +gboolean pas_backend_add_client (PASBackend *backend, Evolution_BookListener listener); void pas_backend_remove_client (PASBackend *backend, PASBook *book); +void pas_backend_last_client_gone (PASBackend *backend); + GtkType pas_backend_get_type (void); #define PAS_BACKEND_TYPE (pas_backend_get_type ()) diff --git a/addressbook/backend/pas/pas-book-factory.c b/addressbook/backend/pas/pas-book-factory.c index 77cc269f19..aec28c650e 100644 --- a/addressbook/backend/pas/pas-book-factory.c +++ b/addressbook/backend/pas/pas-book-factory.c @@ -35,6 +35,14 @@ struct _PASBookFactoryPrivate { GList *queued_requests; }; +/* Signal IDs */ +enum { + LAST_BOOK_GONE, + LAST_SIGNAL +}; + +static guint factory_signals[LAST_SIGNAL]; + static char * pas_book_factory_canonicalize_uri (const char *uri) { @@ -77,8 +85,6 @@ pas_book_factory_register_backend (PASBookFactory *factory, g_return_if_fail (proto != NULL); g_return_if_fail (backend != NULL); - - if (g_hash_table_lookup (factory->priv->backends, proto) != NULL) { g_warning ("pas_book_factory_register_backend: " "Proto \"%s\" already registered!\n", proto); @@ -88,11 +94,62 @@ pas_book_factory_register_backend (PASBookFactory *factory, g_strdup (proto), backend); } +/** + * pas_book_factory_get_n_backends: + * @factory: An addressbook factory. + * + * Queries the number of running addressbook backends in an addressbook factory. + * + * Return value: Number of running backends. + **/ +int +pas_book_factory_get_n_backends (PASBookFactory *factory) +{ + g_return_val_if_fail (factory != NULL, -1); + g_return_val_if_fail (PAS_IS_BOOK_FACTORY (factory), -1); + + return g_hash_table_size (factory->priv->active_server_map); +} + +/* Callback used when a backend loses its last connected client */ +static void +backend_last_client_gone_cb (PASBackend *backend, gpointer data) +{ + PASBookFactory *factory; + const char *uri; + gpointer orig_key; + gboolean result; + char *orig_uri; + + factory = PAS_BOOK_FACTORY (data); + + /* Remove the backend from the active server map */ + + uri = pas_backend_get_uri (backend); + g_assert (uri != NULL); + + result = g_hash_table_lookup_extended (factory->priv->active_server_map, uri, + &orig_key, NULL); + g_assert (result != FALSE); + + orig_uri = orig_key; + + g_hash_table_remove (factory->priv->active_server_map, orig_uri); + g_free (orig_uri); + + gtk_object_unref (GTK_OBJECT (backend)); + + /* Notify upstream if there are no more backends */ + + if (g_hash_table_size (factory->priv->active_server_map) == 0) + gtk_signal_emit (GTK_OBJECT (factory), factory_signals[LAST_BOOK_GONE]); +} + static PASBackendFactoryFn pas_book_factory_lookup_backend_factory (PASBookFactory *factory, const char *uri) { - PASBackendFactoryFn backend; + PASBackendFactoryFn backend_fn; char *proto; char *canonical_uri; @@ -110,32 +167,70 @@ pas_book_factory_lookup_backend_factory (PASBookFactory *factory, return NULL; } - backend = g_hash_table_lookup (factory->priv->backends, proto); + backend_fn = g_hash_table_lookup (factory->priv->backends, proto); g_free (proto); g_free (canonical_uri); - return backend; + return backend_fn; } static PASBackend * pas_book_factory_launch_backend (PASBookFactory *factory, - PASBookFactoryQueuedRequest *request) + Evolution_BookListener listener, + const char *uri) { PASBackendFactoryFn backend_factory; PASBackend *backend; backend_factory = pas_book_factory_lookup_backend_factory ( - factory, request->uri); - g_assert (backend_factory != NULL); + factory, uri); + + if (!backend_factory) { + CORBA_Environment ev; + + CORBA_exception_init (&ev); + Evolution_BookListener_respond_open_book ( + listener, + Evolution_BookListener_ProtocolNotSupported, + CORBA_OBJECT_NIL, + &ev); - backend = (backend_factory) (); - g_assert (backend != NULL); + if (ev._major != CORBA_NO_EXCEPTION) + g_message ("pas_book_factory_launch_backend(): could not notify " + "the listener"); + + CORBA_exception_free (&ev); + return NULL; + } + + backend = (* backend_factory) (); + if (!backend) { + CORBA_Environment ev; + + CORBA_exception_init (&ev); + Evolution_BookListener_respond_open_book ( + listener, + Evolution_BookListener_OtherError, + CORBA_OBJECT_NIL, + &ev); + + if (ev._major != CORBA_NO_EXCEPTION) + g_message ("pas_book_factory_launch_backend(): could not notify " + "the listener"); + + CORBA_exception_free (&ev); + return NULL; + } g_hash_table_insert (factory->priv->active_server_map, - g_strdup (request->uri), + g_strdup (uri), backend); + gtk_signal_connect (GTK_OBJECT (backend), "last_client_gone", + backend_last_client_gone_cb, + factory); + return backend; } @@ -144,24 +239,43 @@ pas_book_factory_process_request (PASBookFactory *factory, PASBookFactoryQueuedRequest *request) { PASBackend *backend; + char *uri; + Evolution_BookListener listener; + CORBA_Environment ev; - request = factory->priv->queued_requests->data; + uri = request->uri; + listener = request->listener; + g_free (request); - backend = g_hash_table_lookup (factory->priv->active_server_map, request->uri); + /* Look up the backend and create one if needed */ - if (backend == NULL) { + backend = g_hash_table_lookup (factory->priv->active_server_map, uri); - backend = pas_book_factory_launch_backend (factory, request); - pas_backend_add_client (backend, request->listener); - pas_backend_load_uri (backend, request->uri); - g_free (request->uri); + if (!backend) { + backend = pas_book_factory_launch_backend (factory, listener, uri); + if (!backend) + goto out; - return; + if (!pas_backend_add_client (backend, listener)) + goto out; + + pas_backend_load_uri (backend, uri); + + goto out; } - g_free (request->uri); + pas_backend_add_client (backend, listener); + + out: + g_free (uri); - pas_backend_add_client (backend, request->listener); + CORBA_exception_init (&ev); + CORBA_Object_release (listener, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) + g_message ("pas_book_factory_process_request(): could not release the listener"); + + CORBA_exception_free (&ev); } static gboolean @@ -170,15 +284,16 @@ pas_book_factory_process_queue (PASBookFactory *factory) /* Process pending Book-creation requests. */ if (factory->priv->queued_requests != NULL) { PASBookFactoryQueuedRequest *request; + GList *l; - request = factory->priv->queued_requests->data; + l = factory->priv->queued_requests; + request = l->data; pas_book_factory_process_request (factory, request); - factory->priv->queued_requests = g_list_remove ( - factory->priv->queued_requests, request); - - g_free (request); + factory->priv->queued_requests = g_list_remove_link ( + factory->priv->queued_requests, l); + g_list_free_1 (l); } if (factory->priv->queued_requests == NULL) { @@ -343,7 +458,6 @@ register_factory (CORBA_Object obj) int ret; CORBA_exception_init (&ev); - ret = goad_server_register (NULL, obj, PAS_BOOK_FACTORY_GOAD_ID, "server", &ev); if (ev._major != CORBA_NO_EXCEPTION) { @@ -394,27 +508,26 @@ pas_book_factory_init (PASBookFactory *factory) factory->priv->queued_requests = NULL; } -static gboolean -pas_book_factory_remove_asm_entry (gpointer key, gpointer value, - gpointer data) +static void +free_active_server_map_entry (gpointer key, gpointer value, gpointer data) { - CORBA_Environment ev; + char *uri; + PASBackend *backend; - g_free (key); + uri = key; + g_free (uri); - CORBA_exception_init (&ev); - CORBA_Object_release ((CORBA_Object) value, &ev); - CORBA_exception_free (&ev); - - return TRUE; + backend = PAS_BACKEND (value); + gtk_object_unref (GTK_OBJECT (backend)); } -static gboolean -pas_book_factory_remove_backend_entry (gpointer key, gpointer value, - gpointer data) +static void +remove_backends_entry (gpointer key, gpointer value, gpointer data) { - g_free (key); - return TRUE; + char *uri; + + uri = key; + g_free (uri); } static void @@ -438,15 +551,17 @@ pas_book_factory_destroy (GtkObject *object) g_list_free (factory->priv->queued_requests); factory->priv->queued_requests = NULL; - g_hash_table_foreach_remove (factory->priv->active_server_map, - pas_book_factory_remove_asm_entry, - NULL); + g_hash_table_foreach (factory->priv->active_server_map, + free_active_server_map_entry, + NULL); g_hash_table_destroy (factory->priv->active_server_map); + factory->priv->active_server_map = NULL; - g_hash_table_foreach_remove (factory->priv->backends, - pas_book_factory_remove_backend_entry, - NULL); + g_hash_table_foreach (factory->priv->backends, + remove_backends_entry, + NULL); g_hash_table_destroy (factory->priv->backends); + factory->priv->backends = NULL; g_free (factory->priv); @@ -480,6 +595,16 @@ pas_book_factory_class_init (PASBookFactoryClass *klass) pas_book_factory_parent_class = gtk_type_class (bonobo_object_get_type ()); + factory_signals[LAST_BOOK_GONE] = + gtk_signal_new ("last_book_gone", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (PASBookFactoryClass, last_book_gone), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, factory_signals, LAST_SIGNAL); + object_class->destroy = pas_book_factory_destroy; pas_book_factory_corba_class_init (); diff --git a/addressbook/backend/pas/pas-book-factory.h b/addressbook/backend/pas/pas-book-factory.h index c9607298f5..7e4690adf1 100644 --- a/addressbook/backend/pas/pas-book-factory.h +++ b/addressbook/backend/pas/pas-book-factory.h @@ -21,6 +21,10 @@ typedef struct { typedef struct { BonoboObjectClass parent_class; + + /* Notification signals */ + + void (* last_book_gone) (PASBookFactory *factory); } PASBookFactoryClass; PASBookFactory *pas_book_factory_new (void); @@ -29,6 +33,8 @@ void pas_book_factory_register_backend (PASBookFactory const char *proto, PASBackendFactoryFn backend_factory); +int pas_book_factory_get_n_backends (PASBookFactory *factory); + void pas_book_factory_activate (PASBookFactory *factory); GtkType pas_book_factory_get_type (void); |