aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Toshok <toshok@ximian.com>2002-03-08 08:51:11 +0800
committerChris Toshok <toshok@src.gnome.org>2002-03-08 08:51:11 +0800
commitda6e1ea98dcf2614ea71ea5dfb88ef63e194c8f6 (patch)
tree613214c31c5e45a6a21357a2e8ca652c2294e413
parenta9791c82f0513cdeb607c94f8b73c8040dc16bf5 (diff)
downloadgsoc2013-evolution-da6e1ea98dcf2614ea71ea5dfb88ef63e194c8f6.tar.gz
gsoc2013-evolution-da6e1ea98dcf2614ea71ea5dfb88ef63e194c8f6.tar.zst
gsoc2013-evolution-da6e1ea98dcf2614ea71ea5dfb88ef63e194c8f6.zip
track union/struct change. (pas_book_queue_remove_card): same.
2002-03-07 Chris Toshok <toshok@ximian.com> * backend/pas/pas-book.c (pas_book_queue_create_card): track union/struct change. (pas_book_queue_remove_card): same. (pas_book_queue_modify_card): same. (pas_book_queue_get_cursor): same. (pas_book_queue_get_vcard): same. (pas_book_queue_authenticate_user): same. (pas_book_queue_get_book_view): same. (pas_book_queue_get_changes): same. (pas_book_free_request): new function - free everything we need to for each type of request. (pas_book_destroy): call pas_book_free_request here instead of just freeing 3 elements of the old struct. yay plugging memleaks. * backend/pas/pas-book.h: make PASRequest a union and split out members into structs, so it's a little clearer which fields are used by which requests. Also, add prototype for pas_book_free_request so backends can just free everything at once (usually in their requests_queued signal func.) * backend/pas/pas-backend-file.c (pas_backend_file_process_create_card): track struct/union change. (pas_backend_file_process_remove_card): same. (pas_backend_file_process_modify_card): same. (pas_backend_file_build_cards_list): same. (pas_backend_file_process_get_vcard): same. (pas_backend_file_process_get_cursor): same. (pas_backend_file_process_get_book_view): same. (pas_backend_file_process_get_changes): same. (pas_backend_file_process_check_connection): same. (pas_backend_file_process_authenticate_user): same. (pas_backend_file_process_get_supported_fields): same. (pas_backend_file_process_client_requests): case the union to the specific struct and pass it to the process_* functions. also, call pas_book_free_request here, instead of relying on each of the functions to free their stuff. svn path=/trunk/; revision=15987
-rw-r--r--addressbook/ChangeLog39
-rw-r--r--addressbook/backend/pas/pas-backend-file.c65
-rw-r--r--addressbook/backend/pas/pas-backend-ldap.c1584
-rw-r--r--addressbook/backend/pas/pas-book.c87
-rw-r--r--addressbook/backend/pas/pas-book.h74
5 files changed, 1136 insertions, 713 deletions
diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog
index e15535e17c..310d5add60 100644
--- a/addressbook/ChangeLog
+++ b/addressbook/ChangeLog
@@ -1,3 +1,42 @@
+2002-03-07 Chris Toshok <toshok@ximian.com>
+
+ * backend/pas/pas-book.c (pas_book_queue_create_card): track
+ union/struct change.
+ (pas_book_queue_remove_card): same.
+ (pas_book_queue_modify_card): same.
+ (pas_book_queue_get_cursor): same.
+ (pas_book_queue_get_vcard): same.
+ (pas_book_queue_authenticate_user): same.
+ (pas_book_queue_get_book_view): same.
+ (pas_book_queue_get_changes): same.
+ (pas_book_free_request): new function - free everything we need to
+ for each type of request.
+ (pas_book_destroy): call pas_book_free_request here instead of
+ just freeing 3 elements of the old struct. yay plugging memleaks.
+
+ * backend/pas/pas-book.h: make PASRequest a union and split out
+ members into structs, so it's a little clearer which fields are
+ used by which requests. Also, add prototype for
+ pas_book_free_request so backends can just free everything at once
+ (usually in their requests_queued signal func.)
+
+ * backend/pas/pas-backend-file.c
+ (pas_backend_file_process_create_card): track struct/union change.
+ (pas_backend_file_process_remove_card): same.
+ (pas_backend_file_process_modify_card): same.
+ (pas_backend_file_build_cards_list): same.
+ (pas_backend_file_process_get_vcard): same.
+ (pas_backend_file_process_get_cursor): same.
+ (pas_backend_file_process_get_book_view): same.
+ (pas_backend_file_process_get_changes): same.
+ (pas_backend_file_process_check_connection): same.
+ (pas_backend_file_process_authenticate_user): same.
+ (pas_backend_file_process_get_supported_fields): same.
+ (pas_backend_file_process_client_requests): case the union to the
+ specific struct and pass it to the process_* functions. also,
+ call pas_book_free_request here, instead of relying on each of the
+ functions to free their stuff.
+
2002-03-07 Dan Winship <danw@ximian.com>
* gui/component/addressbook-storage.c
diff --git a/addressbook/backend/pas/pas-backend-file.c b/addressbook/backend/pas/pas-backend-file.c
index 057012ddaa..acca404ad8 100644
--- a/addressbook/backend/pas/pas-backend-file.c
+++ b/addressbook/backend/pas/pas-backend-file.c
@@ -535,7 +535,7 @@ do_create(PASBackend *backend,
static void
pas_backend_file_process_create_card (PASBackend *backend,
PASBook *book,
- PASRequest *req)
+ PASCreateCardRequest *req)
{
char *id;
char *vcard;
@@ -577,7 +577,7 @@ pas_backend_file_process_create_card (PASBackend *backend,
static void
pas_backend_file_process_remove_card (PASBackend *backend,
PASBook *book,
- PASRequest *req)
+ PASRemoveCardRequest *req)
{
PASBackendFile *bf = PAS_BACKEND_FILE (backend);
DB *db = bf->priv->file_db;
@@ -636,7 +636,7 @@ pas_backend_file_process_remove_card (PASBackend *backend,
static void
pas_backend_file_process_modify_card (PASBackend *backend,
PASBook *book,
- PASRequest *req)
+ PASModifyCardRequest *req)
{
PASBackendFile *bf = PAS_BACKEND_FILE (backend);
DB *db = bf->priv->file_db;
@@ -671,7 +671,6 @@ pas_backend_file_process_modify_card (PASBackend *backend,
pas_book_respond_modify (
book,
GNOME_Evolution_Addressbook_BookListener_CardNotFound);
- g_free (req->id);
return;
}
old_vcard_string = g_strdup(vcard_dbt.data);
@@ -728,8 +727,8 @@ pas_backend_file_process_modify_card (PASBackend *backend,
static void
pas_backend_file_build_cards_list(PASBackend *backend,
- PASBackendFileCursorPrivate *cursor_data,
- char *search)
+ PASBackendFileCursorPrivate *cursor_data,
+ char *search)
{
PASBackendFile *bf = PAS_BACKEND_FILE (backend);
DB *db = bf->priv->file_db;
@@ -788,7 +787,7 @@ pas_backend_file_build_cards_list(PASBackend *backend,
static void
pas_backend_file_process_get_vcard (PASBackend *backend,
PASBook *book,
- PASRequest *req)
+ PASGetVCardRequest *req)
{
PASBackendFile *bf;
DB *db;
@@ -821,7 +820,7 @@ pas_backend_file_process_get_vcard (PASBackend *backend,
static void
pas_backend_file_process_get_cursor (PASBackend *backend,
PASBook *book,
- PASRequest *req)
+ PASGetCursorRequest *req)
{
/*
PASBackendFile *bf = PAS_BACKEND_FILE (backend);
@@ -871,10 +870,9 @@ pas_backend_file_process_get_cursor (PASBackend *backend,
static void
pas_backend_file_process_get_book_view (PASBackend *backend,
PASBook *book,
- PASRequest *req)
+ PASGetBookViewRequest *req)
{
PASBackendFile *bf = PAS_BACKEND_FILE (backend);
- CORBA_Environment ev;
PASBookView *book_view;
PASBackendFileBookView view;
EIterator *iterator;
@@ -889,7 +887,7 @@ pas_backend_file_process_get_book_view (PASBackend *backend,
GTK_SIGNAL_FUNC(view_destroy), book);
view.book_view = book_view;
- view.search = req->search;
+ view.search = g_strdup (req->search);
view.card_sexp = NULL;
view.change_id = NULL;
view.change_context = NULL;
@@ -906,25 +904,12 @@ pas_backend_file_process_get_book_view (PASBackend *backend,
e_iterator_last(iterator);
pas_backend_file_search (bf, book, e_iterator_get(iterator));
gtk_object_unref(GTK_OBJECT(iterator));
-
- g_free(req->search);
- CORBA_exception_init(&ev);
-
- bonobo_object_unref (BONOBO_OBJECT (book_view));
- bonobo_object_release_unref (req->listener, &ev);
-
- if (ev._major != CORBA_NO_EXCEPTION) {
- g_warning("pas_backend_file_process_get_book_view: Exception unreffing "
- "listener.\n");
- }
-
- CORBA_exception_free(&ev);
}
static void
pas_backend_file_process_get_changes (PASBackend *backend,
PASBook *book,
- PASRequest *req)
+ PASGetChangesRequest *req)
{
PASBackendFile *bf = PAS_BACKEND_FILE (backend);
CORBA_Environment ev;
@@ -967,7 +952,7 @@ pas_backend_file_process_get_changes (PASBackend *backend,
pas_backend_file_changes (bf, book, e_iterator_get(iterator));
gtk_object_unref(GTK_OBJECT(iterator));
- g_free(req->search);
+ g_free(req->change_id);
CORBA_exception_init(&ev);
bonobo_object_release_unref (req->listener, &ev);
@@ -982,7 +967,7 @@ pas_backend_file_process_get_changes (PASBackend *backend,
static void
pas_backend_file_process_check_connection (PASBackend *backend,
PASBook *book,
- PASRequest *req)
+ PASCheckConnectionRequest *req)
{
PASBackendFile *bf = PAS_BACKEND_FILE (backend);
@@ -1000,7 +985,7 @@ pas_backend_file_extract_path_from_uri (const char *uri)
static void
pas_backend_file_process_authenticate_user (PASBackend *backend,
PASBook *book,
- PASRequest *req)
+ PASAuthenticateUserRequest *req)
{
pas_book_respond_authenticate_user (book,
GNOME_Evolution_Addressbook_BookListener_Success);
@@ -1009,7 +994,7 @@ pas_backend_file_process_authenticate_user (PASBackend *backend,
static void
pas_backend_file_process_get_supported_fields (PASBackend *backend,
PASBook *book,
- PASRequest *req)
+ PASGetSupportedFieldsRequest *req)
{
EList *fields = e_list_new ((EListCopyFunc)g_strdup, (EListFreeFunc)g_free, NULL);
ECardSimple *simple;
@@ -1047,47 +1032,47 @@ pas_backend_file_process_client_requests (PASBook *book)
switch (req->op) {
case CreateCard:
- pas_backend_file_process_create_card (backend, book, req);
+ pas_backend_file_process_create_card (backend, book, (PASCreateCardRequest*)req);
break;
case RemoveCard:
- pas_backend_file_process_remove_card (backend, book, req);
+ pas_backend_file_process_remove_card (backend, book, (PASRemoveCardRequest*)req);
break;
case ModifyCard:
- pas_backend_file_process_modify_card (backend, book, req);
+ pas_backend_file_process_modify_card (backend, book, (PASModifyCardRequest*)req);
break;
case CheckConnection:
- pas_backend_file_process_check_connection (backend, book, req);
+ pas_backend_file_process_check_connection (backend, book, (PASCheckConnectionRequest*)req);
break;
case GetVCard:
- pas_backend_file_process_get_vcard (backend, book, req);
+ pas_backend_file_process_get_vcard (backend, book, (PASGetVCardRequest*)req);
break;
case GetCursor:
- pas_backend_file_process_get_cursor (backend, book, req);
+ pas_backend_file_process_get_cursor (backend, book, (PASGetCursorRequest*)req);
break;
case GetBookView:
- pas_backend_file_process_get_book_view (backend, book, req);
+ pas_backend_file_process_get_book_view (backend, book, (PASGetBookViewRequest*)req);
break;
case GetChanges:
- pas_backend_file_process_get_changes (backend, book, req);
+ pas_backend_file_process_get_changes (backend, book, (PASGetChangesRequest*)req);
break;
case AuthenticateUser:
- pas_backend_file_process_authenticate_user (backend, book, req);
+ pas_backend_file_process_authenticate_user (backend, book, (PASAuthenticateUserRequest*)req);
break;
case GetSupportedFields:
- pas_backend_file_process_get_supported_fields (backend, book, req);
+ pas_backend_file_process_get_supported_fields (backend, book, (PASGetSupportedFieldsRequest*)req);
break;
}
- g_free (req);
+ pas_book_free_request (req);
}
static void
diff --git a/addressbook/backend/pas/pas-backend-ldap.c b/addressbook/backend/pas/pas-backend-ldap.c
index 6a98246257..aebe05d98d 100644
--- a/addressbook/backend/pas/pas-backend-ldap.c
+++ b/addressbook/backend/pas/pas-backend-ldap.c
@@ -10,8 +10,6 @@
#include "config.h"
#include <fcntl.h>
-#include <time.h>
-#include <lber.h>
#include <gtk/gtksignal.h>
#include <libgnome/gnome-defs.h>
@@ -33,7 +31,7 @@
#endif
#ifdef OPENLDAP2
-#include "ldap_schema.h"
+#include <ldap_schema.h>
#endif
#include <sys/time.h>
@@ -49,8 +47,6 @@
#include <stdlib.h>
-#define LDAP_MAX_SEARCH_RESPONSES 100
-
/* interval for our poll_ldap timeout */
#define LDAP_POLL_INTERVAL 20
@@ -85,11 +81,16 @@ struct _PASBackendLDAPPrivate {
char *uri;
gboolean connected;
GList *clients;
- gchar *ldap_host;
- gchar *ldap_rootdn;
- int ldap_port;
- int ldap_scope;
- int ldap_limit;
+
+ gchar *ldap_host; /* the hostname of the server */
+ int ldap_port; /* the port of the server */
+ char *schema_dn; /* the base dn for schema information */
+ gchar *ldap_rootdn; /* the base dn of our searches */
+ int ldap_scope; /* the scope used for searches */
+ int ldap_limit; /* the search limit */
+
+ gboolean ldap_v3; /* TRUE if the server supports protocol
+ revision 3 (necessary for TLS) */
GList *book_views;
LDAP *ldap;
@@ -99,14 +100,14 @@ struct _PASBackendLDAPPrivate {
/* whether or not there's support for the objectclass we need
to store all our additional fields */
gboolean evolutionPersonSupported;
- gboolean evolutionPersonChecked;
+ gboolean schema_checked;
gboolean writable;
- /* whether or not there's a request in process on our LDAP* */
- LDAPOp *current_op;
- GList *pending_ops;
- int op_idle;
+ /* our operations */
+ GHashTable *id_to_op;
+ int active_ops;
+ int poll_timeout;
};
struct _PASBackendLDAPCursorPrivate {
@@ -122,25 +123,12 @@ struct _PASBackendLDAPBookView {
PASBackendLDAPPrivate *blpriv;
gchar *search;
PASBackendCardSExp *card_sexp;
- int search_timeout;
- int search_msgid;
- LDAPOp *search_op;
-
- /* grouping stuff */
- GList *pending_adds; /* the cards we're sending */
- int num_pending_adds; /* the number waiting to be sent */
- int target_pending_adds; /* the cutoff that forces a flush to the client, if it happens before the timeout */
- int num_sent_this_time; /* the number of cards we sent to the client before the most recent timeout */
- int num_sent_last_time; /* the number of cards we sent to the client before the previous timeout */
- glong grouping_time_start;
-
- /* used by poll_ldap to only send the status messages once */
- gboolean notified_receiving_results;
+ LDAPOp *search_op;
};
-typedef gboolean (*LDAPOpHandler)(PASBackend *backend, LDAPOp *op);
-typedef void (*LDAPOpDtor)(PASBackend *backend, LDAPOp *op);
+typedef void (*LDAPOpHandler)(LDAPOp *op, LDAPMessage *res);
+typedef void (*LDAPOpDtor)(LDAPOp *op);
struct LDAPOp {
LDAPOpHandler handler;
@@ -148,15 +136,17 @@ struct LDAPOp {
PASBackend *backend;
PASBook *book;
PASBookView *view;
+ int id;
};
-static void ldap_op_init (LDAPOp *op, PASBackend *backend, PASBook *book, PASBookView *view, LDAPOpHandler handler, LDAPOpDtor dtor);
-static void ldap_op_process_current (PASBackend *backend);
-static void ldap_op_process (LDAPOp *op);
-static void ldap_op_restart (LDAPOp *op);
-static gboolean ldap_op_process_on_idle (PASBackend *backend);
+static void ldap_op_add (LDAPOp *op, PASBackend *backend, PASBook *book,
+ PASBookView *view, int id, LDAPOpHandler handler, LDAPOpDtor dtor);
static void ldap_op_finished (LDAPOp *op);
+static void ldap_search_op_timeout (LDAPOp *op, glong cur_millis);
+
+static gboolean poll_ldap (PASBackendLDAP *bl);
+
static ECardSimple *build_card_from_entry (LDAP *ldap, LDAPMessage *e, GList **existing_objectclasses);
static void email_populate (ECardSimple *card, char **values);
@@ -274,6 +264,13 @@ struct prop_info {
static int num_prop_infos = sizeof(prop_info) / sizeof(prop_info[0]);
static void
+remove_view (int msgid, LDAPOp *op, PASBookView *view)
+{
+ if (op->view == view)
+ op->view = NULL;
+}
+
+static void
view_destroy(GtkObject *object, gpointer data)
{
CORBA_Environment ev;
@@ -286,26 +283,13 @@ view_destroy(GtkObject *object, gpointer data)
for (list = bl->priv->book_views; list; list = g_list_next(list)) {
PASBackendLDAPBookView *view = list->data;
if (view->book_view == PAS_BOOK_VIEW(object)) {
- if (view->search_timeout != 0) {
- /* we have a search running on the
- ldap connection. remove the timeout
- handler and anbandon the msg id */
- g_source_remove(view->search_timeout);
- if (view->search_msgid != -1)
- ldap_abandon (bl->priv->ldap, view->search_msgid);
-
- /* if the search op is the current op,
- finish it. else, remove it from the
- list and nuke it ourselves. */
- if (view->search_op == bl->priv->current_op)
- ldap_op_finished (view->search_op);
- else {
- bl->priv->pending_ops = g_list_remove (bl->priv->pending_ops,
- view->search_op);
- view->search_op->dtor (view->search_op->backend,
- view->search_op);
- }
- }
+ /* if we have an active search, interrupt it */
+ if (view->search_op)
+ ldap_op_finished (view->search_op);
+ /* and remove us as the view for any other
+ operations that might be using us to spew
+ status messages to the gui */
+ g_hash_table_foreach (bl->priv->id_to_op, (GHFunc)remove_view, view->book_view);
g_free (view->search);
gtk_object_unref (GTK_OBJECT (view->card_sexp));
g_free (view);
@@ -379,12 +363,15 @@ check_schema_support (PASBackendLDAP *bl)
LDAPMessage *resp;
LDAP *ldap = bl->priv->ldap;
- bl->priv->evolutionPersonChecked = TRUE;
+ if (!bl->priv->schema_dn)
+ return;
+
+ bl->priv->schema_checked = TRUE;
attrs[0] = "objectClasses";
attrs[1] = NULL;
- if (ldap_search_ext_s (ldap, "cn=Subschema", LDAP_SCOPE_BASE,
+ if (ldap_search_ext_s (ldap, bl->priv->schema_dn, LDAP_SCOPE_BASE,
"(objectClass=subschema)", attrs, 0,
NULL, NULL, NULL, 0, &resp) == LDAP_SUCCESS) {
char **values;
@@ -422,6 +409,120 @@ check_schema_support (PASBackendLDAP *bl)
}
static void
+get_ldap_library_info ()
+{
+ LDAPAPIInfo info;
+ LDAP *ldap;
+
+ if (LDAP_SUCCESS != ldap_create (&ldap)) {
+ g_warning ("couldn't create LDAP* for getting at the client lib api info");
+ return;
+ }
+
+ info.ldapai_info_version = LDAP_API_INFO_VERSION;
+
+ if (LDAP_OPT_SUCCESS != ldap_get_option (ldap, LDAP_OPT_API_INFO, &info)) {
+ g_warning ("couldn't get ldap api info");
+ }
+ else {
+ int i;
+ g_message ("libldap vendor/version: %s %2d.%02d.%02d",
+ info.ldapai_vendor_name,
+ info.ldapai_vendor_version / 10000,
+ (info.ldapai_vendor_version % 10000) / 1000,
+ info.ldapai_vendor_version % 1000);
+
+ g_message ("extensions present:");
+ for (i = 0; info.ldapai_extensions[i]; i++) {
+ char *extension = info.ldapai_extensions[i];
+ g_message (extension);
+ }
+ }
+
+ ldap_unbind_ext_s (ldap, NULL, NULL);
+}
+
+static void
+query_ldap_root_dse (PASBackendLDAP *bl)
+{
+#define MAX_DSE_ATTRS 20
+ LDAP *ldap = bl->priv->ldap;
+ LDAPMessage *resp;
+ int ldap_error;
+ char *attrs[MAX_DSE_ATTRS], **values;
+ int i = 0;
+ struct timeval timeout;
+
+ attrs[i++] = "supportedControl";
+ attrs[i++] = "supportedExtension";
+ attrs[i++] = "supportedFeatures";
+ attrs[i++] = "supportedSASLMechanisms";
+ attrs[i++] = "supportedLDAPVersion";
+ attrs[i++] = "subschemaSubentry"; /* OpenLDAP's dn for schema information */
+ attrs[i++] = "schemaNamingContext"; /* Active directory's dn for schema information */
+ attrs[i] = NULL;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = LDAP_RESULT_TIMEOUT_MILLIS * 1000;
+
+ ldap_error = ldap_search_ext_s (ldap,
+ LDAP_ROOT_DSE, LDAP_SCOPE_BASE,
+ "(objectclass=*)",
+ attrs, 0, NULL, NULL, NULL, 0, &resp);
+ if (ldap_error != LDAP_SUCCESS) {
+ g_warning ("could not perform query on Root DSE");
+ return;
+ }
+
+ values = ldap_get_values (ldap, resp, "supportedControl");
+ if (values) {
+ for (i = 0; values[i]; i++)
+ g_message ("supported server control: %s", values[i]);
+ ldap_value_free (values);
+ }
+
+ values = ldap_get_values (ldap, resp, "supportedExtension");
+ if (values) {
+ for (i = 0; values[i]; i++) {
+ g_message ("supported server extension: %s", values[i]);
+ if (!strcmp (values[i], LDAP_EXOP_START_TLS)) {
+ g_message ("server reports LDAP_EXOP_START_TLS");
+ }
+ }
+ ldap_value_free (values);
+ }
+
+ values = ldap_get_values (ldap, resp, "supportedSASLMechanisms");
+ if (values) {
+ for (i = 0; values[i]; i++)
+ g_message ("supported SASL mechanism: %s", values[i]);
+ ldap_value_free (values);
+ }
+
+
+ values = ldap_get_values (ldap, resp, "supportedLDAPVersion");
+ if (values) {
+ for (i = 0; values[i]; i++)
+ if (LDAP_VERSION3 == atoi (values[i]))
+ bl->priv->ldap_v3 = TRUE;
+ ldap_value_free (values);
+ }
+
+ values = ldap_get_values (ldap, resp, "subschemaSubentry");
+ if (!values || !values[0])
+ values = ldap_get_values (ldap, resp, "schemaNamingContext");
+ if (values || values[0]) {
+ bl->priv->schema_dn = g_strdup (values[0]);
+ }
+ else {
+ g_warning ("could not determine location of schema information on LDAP server");
+ }
+ if (values)
+ ldap_value_free (values);
+
+}
+
+static void
pas_backend_ldap_connect (PASBackendLDAP *bl)
{
PASBackendLDAPPrivate *blpriv = bl->priv;
@@ -433,14 +534,42 @@ pas_backend_ldap_connect (PASBackendLDAP *bl)
blpriv->ldap = ldap_init (blpriv->ldap_host, blpriv->ldap_port);
#ifdef DEBUG
{
- int debug_level = ~0;
+ int debug_level = 4;
ldap_set_option (blpriv->ldap, LDAP_OPT_DEBUG_LEVEL, &debug_level);
}
#endif
if (NULL != blpriv->ldap) {
- ldap_simple_bind_s(blpriv->ldap,
- NULL /*binddn*/, NULL /*passwd*/);
+ int ldap_error;
+ query_ldap_root_dse (bl);
+
+ if (bl->priv->ldap_v3) {
+ int protocol_version = LDAP_VERSION3;
+ ldap_error = ldap_set_option (blpriv->ldap, LDAP_OPT_PROTOCOL_VERSION, &protocol_version);
+ if (LDAP_OPT_SUCCESS != ldap_error) {
+ g_warning ("failed to set protocol version to LDAPv3");
+ bl->priv->ldap_v3 = FALSE;
+ }
+ }
+
+#if notyet
+ if (TRUE /* the user wants to use TLS */) {
+ if (bl->priv->ldap_v3 /* the server supports v3 */) {
+ ldap_error = ldap_start_tls_s (blpriv->ldap, NULL, NULL);
+ if (LDAP_SUCCESS != ldap_error) {
+ g_warning ("ldap_start_tls_s failed with ldap_error 0x%2x (%s)",
+ ldap_error,
+ ldap_err2string (ldap_error));
+ }
+ else
+ g_message ("TLS active");
+ }
+ else {
+ g_warning ("user wants to use TLS, but server doesn't support LDAPv3");
+ }
+ }
+#endif
+
blpriv->connected = TRUE;
/* check to see if evolutionPerson is supported, if we can (me
@@ -456,141 +585,67 @@ pas_backend_ldap_connect (PASBackendLDAP *bl)
blpriv->ldap_rootdn ? blpriv->ldap_rootdn : "");
blpriv->connected = FALSE;
}
-
-}
-
-static ECardSimple *
-search_for_dn_with_objectclasses (PASBackendLDAP *bl, const char *dn, GList **existing_objectclasses)
-{
- LDAP *ldap = bl->priv->ldap;
- LDAPMessage *res, *e;
- ECardSimple *result = NULL;
-
- if (ldap_search_s (ldap,
- dn,
- LDAP_SCOPE_BASE,
- "(objectclass=*)",
- NULL, 0, &res) == LDAP_SUCCESS) {
- e = ldap_first_entry (ldap, res);
- while (NULL != e) {
- if (!strcmp (ldap_get_dn (ldap, e), dn)) {
- printf ("found it\n");
- result = build_card_from_entry (ldap, e, existing_objectclasses);
- break;
- }
- e = ldap_next_entry (ldap, e);
- }
-
- ldap_msgfree(res);
- }
-
- return result;
-}
-
-static ECardSimple *
-search_for_dn (PASBackendLDAP *bl, const char *dn)
-{
- return search_for_dn_with_objectclasses (bl, dn, NULL);
}
static void
-ldap_op_init (LDAPOp *op, PASBackend *backend,
- PASBook *book, PASBookView *view,
- LDAPOpHandler handler, LDAPOpDtor dtor)
+ldap_op_add (LDAPOp *op, PASBackend *backend,
+ PASBook *book, PASBookView *view,
+ int id,
+ LDAPOpHandler handler, LDAPOpDtor dtor)
{
+ PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
+
op->backend = backend;
op->book = book;
op->view = view;
+ op->id = id;
op->handler = handler;
op->dtor = dtor;
-}
-
-static void
-ldap_op_process_current (PASBackend *backend)
-{
- PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
- LDAPOp *op = bl->priv->current_op;
- if (!bl->priv->connected) {
- if (op->view)
- pas_book_view_notify_status_message (op->view, _("Connecting to LDAP server..."));
- pas_backend_ldap_connect(bl);
- }
+ g_hash_table_insert (bl->priv->id_to_op,
+ &op->id, op);
- if (bl->priv->connected) {
- if (op->handler (backend, op))
- ldap_op_finished (op);
- }
- else {
- if (op->view) {
- pas_book_view_notify_status_message (op->view, _("Unable to connect to LDAP server."));
- pas_book_view_notify_complete (op->view);
- }
+ bl->priv->active_ops ++;
- ldap_op_finished (op);
- }
+ if (bl->priv->poll_timeout == -1)
+ bl->priv->poll_timeout = g_timeout_add (LDAP_POLL_INTERVAL,
+ (GSourceFunc) poll_ldap,
+ bl);
}
static void
-ldap_op_process (LDAPOp *op)
-{
- PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend);
-
- if (bl->priv->current_op) {
- /* operation in progress. queue this op for later and return. */
- if (op->view)
- pas_book_view_notify_status_message (op->view, _("Waiting for connection to LDAP server..."));
- bl->priv->pending_ops = g_list_append (bl->priv->pending_ops, op);
- }
- else {
- /* nothing going on, do this op now */
- bl->priv->current_op = op;
- ldap_op_process_current (op->backend);
- }
-}
-
-static gboolean
-ldap_op_process_on_idle (PASBackend *backend)
+ldap_op_finished (LDAPOp *op)
{
+ PASBackend *backend = op->backend;
PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
- bl->priv->op_idle = 0;
-
- ldap_op_process_current (backend);
-
- return FALSE;
-}
+ g_hash_table_remove (bl->priv->id_to_op, &op->id);
-static void
-ldap_op_restart (LDAPOp *op)
-{
- PASBackend *backend = op->backend;
- PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
+ /* should handle errors here */
+ ldap_abandon (bl->priv->ldap, op->id);
- g_return_if_fail (op == bl->priv->current_op);
+ op->dtor (op);
- bl->priv->op_idle = g_idle_add((GSourceFunc)ldap_op_process_on_idle, backend);
+ bl->priv->active_ops--;
+ if (bl->priv->active_ops == 0) {
+ if (bl->priv->poll_timeout != -1)
+ g_source_remove (bl->priv->poll_timeout);
+ bl->priv->poll_timeout = -1;
+ }
}
static void
-ldap_op_finished (LDAPOp *op)
+ldap_op_change_id (LDAPOp *op, int msg_id)
{
PASBackend *backend = op->backend;
PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
- g_return_if_fail (op == bl->priv->current_op);
-
- op->dtor (backend, op);
+ g_hash_table_remove (bl->priv->id_to_op, &op->id);
- if (bl->priv->pending_ops) {
- bl->priv->current_op = bl->priv->pending_ops->data;
- bl->priv->pending_ops = g_list_remove_link (bl->priv->pending_ops, bl->priv->pending_ops);
+ op->id = msg_id;
- bl->priv->op_idle = g_idle_add((GSourceFunc)ldap_op_process_on_idle, backend);
- }
- else {
- bl->priv->current_op = NULL;
- }
+ g_hash_table_insert (bl->priv->id_to_op,
+ &op->id, op);
}
static int
@@ -867,49 +922,128 @@ add_objectclass_mod (PASBackendLDAP *bl, GPtrArray *mod_array, GList *existing_o
typedef struct {
LDAPOp op;
- char *vcard;
+ char *dn;
+ ECardSimple *new_card;
} LDAPCreateOp;
-static gboolean
-create_card_handler (PASBackend *backend, LDAPOp *op)
+static void
+create_card_handler (LDAPOp *op, LDAPMessage *res)
{
LDAPCreateOp *create_op = (LDAPCreateOp*)op;
+ PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend);
+ LDAP *ldap = bl->priv->ldap;
+ int ldap_error;
+ int response;
+
+ if (LDAP_RES_ADD != ldap_msgtype (res)) {
+ g_warning ("incorrect msg type %d passed to create_card_handler", ldap_msgtype (res));
+ pas_book_respond_create (op->book,
+ GNOME_Evolution_Addressbook_BookListener_OtherError,
+ create_op->dn);
+ ldap_op_finished (op);
+ return;
+ }
+
+ ldap_parse_result (ldap, res, &ldap_error,
+ NULL, NULL, NULL, NULL, 0);
+
+ if (ldap_error == LDAP_SUCCESS) {
+ /* the card was created, let's let the views know about it */
+ GList *l;
+ for (l = bl->priv->book_views; l; l = l->next) {
+ CORBA_Environment ev;
+ gboolean match;
+ PASBackendLDAPBookView *view = l->data;
+
+ CORBA_exception_init(&ev);
+
+ bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
+
+ match = pas_backend_card_sexp_match_vcard (view->card_sexp,
+ e_card_simple_get_vcard_assume_utf8 (create_op->new_card));
+ if (match) {
+ char *vcard = e_card_simple_get_vcard_assume_utf8 (create_op->new_card);
+ pas_book_view_notify_add_1 (view->book_view,
+ vcard);
+ g_free (vcard);
+ }
+ pas_book_view_notify_complete (view->book_view);
+
+ bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
+ }
+ }
+ else {
+ ldap_perror (ldap, "create_card");
+ }
+
+ if (op->view)
+ pas_book_view_notify_complete (op->view);
+
+ /* and lastly respond */
+ response = ldap_error_to_response (ldap_error);
+ pas_book_respond_create (op->book,
+ response,
+ create_op->dn);
+
+ ldap_op_finished (op);
+}
+
+static void
+create_card_dtor (LDAPOp *op)
+{
+ LDAPCreateOp *create_op = (LDAPCreateOp*)op;
+
+ g_free (create_op->dn);
+ gtk_object_unref (GTK_OBJECT (create_op->new_card));
+ g_free (create_op);
+}
+
+static void
+pas_backend_ldap_process_create_card (PASBackend *backend,
+ PASBook *book,
+ PASRequest *req)
+{
+ LDAPCreateOp *create_op = g_new (LDAPCreateOp, 1);
PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
+ PASBookView *book_view = NULL;
+ int create_card_msgid;
ECard *new_ecard;
- ECardSimple *new_card;
- char *dn;
int response;
- int ldap_error;
+ int err;
GPtrArray *mod_array;
LDAPMod **ldap_mods;
LDAP *ldap;
- printf ("vcard = %s\n", create_op->vcard);
+ if (bl->priv->book_views) {
+ PASBackendLDAPBookView *v = bl->priv->book_views->data;
+ book_view = v->book_view;
+ }
+
+ printf ("vcard = %s\n", req->create.vcard);
- new_ecard = e_card_new (create_op->vcard);
- new_card = e_card_simple_new (new_ecard);
+ new_ecard = e_card_new (req->create.vcard);
+ create_op->new_card = e_card_simple_new (new_ecard);
- dn = create_dn_from_ecard (new_card, bl->priv->ldap_rootdn);
- e_card_simple_set_id (new_card, dn); /* for the notification code below */
+ create_op->dn = create_dn_from_ecard (create_op->new_card, bl->priv->ldap_rootdn);
+ e_card_simple_set_id (create_op->new_card, create_op->dn); /* for the notification code below */
ldap = bl->priv->ldap;
/* build our mods */
- mod_array = build_mods_from_ecards (bl, NULL, new_card, NULL);
+ mod_array = build_mods_from_ecards (bl, NULL, create_op->new_card, NULL);
#if 0
if (!mod_array) {
/* there's an illegal field in there. report
UnsupportedAttribute back */
- g_free (dn);
-
- gtk_object_unref (GTK_OBJECT(new_card));
-
- pas_book_respond_create (create_op->op.book,
+ pas_book_respond_create (book,
GNOME_Evolution_Addressbook_BookListener_UnsupportedField,
- dn);
+ create_op->dn);
- return TRUE;
+ g_free (create_op->dn);
+ gtk_object_unref (GTK_OBJECT(create_op->new_card));
+ g_free (create_op);
+ return;
}
#endif
@@ -959,90 +1093,29 @@ create_card_handler (PASBackend *backend, LDAPOp *op)
ldap_mods = (LDAPMod**)mod_array->pdata;
- if (op->view)
- pas_book_view_notify_status_message (op->view, _("Adding card to LDAP server..."));
-
- /* actually perform the ldap add */
- ldap_error = ldap_add_s (ldap, dn, ldap_mods);
-
- if (ldap_error == LDAP_SUCCESS) {
- /* the card was created, let's let the views know about it */
- GList *l;
- for (l = bl->priv->book_views; l; l = l->next) {
- CORBA_Environment ev;
- gboolean match;
- PASBackendLDAPBookView *view = l->data;
-
- CORBA_exception_init(&ev);
-
- bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
-
- match = pas_backend_card_sexp_match_vcard (view->card_sexp,
- e_card_simple_get_vcard_assume_utf8 (new_card));
- if (match)
- pas_book_view_notify_add_1 (view->book_view, e_card_simple_get_vcard_assume_utf8 (new_card));
- pas_book_view_notify_complete (view->book_view);
-
- bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
- }
- }
- else {
- ldap_perror (ldap, "ldap_add_s");
- }
+ if (book_view)
+ pas_book_view_notify_status_message (book_view, _("Adding card to LDAP server..."));
- if (op->view)
- pas_book_view_notify_complete (op->view);
+ err = ldap_add_ext (ldap, create_op->dn, ldap_mods,
+ NULL, NULL, &create_card_msgid);
/* and clean up */
free_mods (mod_array);
- g_free (dn);
-
- gtk_object_unref (GTK_OBJECT(new_card));
-
- /* and lastly respond */
- response = ldap_error_to_response (ldap_error);
- pas_book_respond_create (create_op->op.book,
- response,
- dn);
-
- /* we're synchronous */
- return TRUE;
-}
-static void
-create_card_dtor (PASBackend *backend, LDAPOp *op)
-{
- LDAPCreateOp *create_op = (LDAPCreateOp*)op;
-
- if (op->view)
- bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(op->view)), NULL);
-
- g_free (create_op->vcard);
- g_free (create_op);
-}
-
-static void
-pas_backend_ldap_process_create_card (PASBackend *backend,
- PASBook *book,
- PASRequest *req)
-{
- LDAPCreateOp *create_op = g_new (LDAPCreateOp, 1);
- PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
- PASBookView *book_view = NULL;
-
- if (bl->priv->book_views) {
- PASBackendLDAPBookView *v = bl->priv->book_views->data;
- book_view = v->book_view;
- bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(book_view)), NULL);
+ if (LDAP_SUCCESS != err) {
+ response = ldap_error_to_response (err);
+ pas_book_respond_create (create_op->op.book,
+ response,
+ create_op->dn);
+ create_card_dtor ((LDAPOp*)create_op);
+ return;
+ }
+ else {
+ g_print ("ldap_add_ext returned %d\n", err);
+ ldap_op_add ((LDAPOp*)create_op, backend, book,
+ book_view, create_card_msgid,
+ create_card_handler, create_card_dtor);
}
-
- ldap_op_init ((LDAPOp*)create_op, backend, book,
- book_view,
- create_card_handler, create_card_dtor);
-
- create_op->vcard = req->vcard;
-
- ldap_op_process ((LDAPOp*)create_op);
}
@@ -1051,71 +1124,56 @@ typedef struct {
char *id;
} LDAPRemoveOp;
-static gboolean
-remove_card_handler (PASBackend *backend, LDAPOp *op)
+static void
+remove_card_handler (LDAPOp *op, LDAPMessage *res)
{
LDAPRemoveOp *remove_op = (LDAPRemoveOp*)op;
- PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
- int response;
+ PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend);
int ldap_error;
- ECardSimple *simple;
-
- if (op->view)
- pas_book_view_notify_status_message (op->view, _("Removing card from LDAP server..."));
- simple = search_for_dn (bl, remove_op->id);
+ if (LDAP_RES_DELETE != ldap_msgtype (res)) {
+ g_warning ("incorrect msg type %d passed to remove_card_handler", ldap_msgtype (res));
+ pas_book_respond_remove (op->book,
+ GNOME_Evolution_Addressbook_BookListener_OtherError);
+ ldap_op_finished (op);
+ return;
+ }
- if (simple) {
- ldap_error = ldap_delete_s (bl->priv->ldap, remove_op->id);
+ ldap_parse_result (bl->priv->ldap, res, &ldap_error,
+ NULL, NULL, NULL, NULL, 0);
- if (ldap_error == LDAP_SUCCESS) {
- /* the card was removed, let's let the views know about it */
- GList *l;
- for (l = bl->priv->book_views; l; l = l->next) {
- CORBA_Environment ev;
- gboolean match;
- PASBackendLDAPBookView *view = l->data;
+ if (ldap_error == LDAP_SUCCESS) {
+ /* the card was removed, let's let the views know about it */
+ GList *l;
+ for (l = bl->priv->book_views; l; l = l->next) {
+ CORBA_Environment ev;
+ PASBackendLDAPBookView *view = l->data;
- CORBA_exception_init(&ev);
+ CORBA_exception_init(&ev);
- bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
+ bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
- match = pas_backend_card_sexp_match_vcard (view->card_sexp,
- e_card_simple_get_vcard_assume_utf8 (simple));
- if (match)
- pas_book_view_notify_remove (view->book_view, remove_op->id);
- pas_book_view_notify_complete (view->book_view);
+ pas_book_view_notify_remove (view->book_view, remove_op->id);
- bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
- }
- }
- else {
- ldap_perror (bl->priv->ldap, "ldap_delete_s");
+ bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
}
-
- response = ldap_error_to_response (ldap_error);
}
- else
- response = GNOME_Evolution_Addressbook_BookListener_CardNotFound;
+ else {
+ ldap_perror (bl->priv->ldap, "remove_card");
+ }
pas_book_respond_remove (remove_op->op.book,
- response);
+ ldap_error_to_response (ldap_error));
if (op->view)
pas_book_view_notify_complete (op->view);
-
- /* we're synchronous */
- return TRUE;
}
static void
-remove_card_dtor (PASBackend *backend, LDAPOp *op)
+remove_card_dtor (LDAPOp *op)
{
LDAPRemoveOp *remove_op = (LDAPRemoveOp*)op;
- if (op->view)
- bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(op->view)), NULL);
-
g_free (remove_op->id);
g_free (remove_op);
}
@@ -1128,67 +1186,175 @@ pas_backend_ldap_process_remove_card (PASBackend *backend,
LDAPRemoveOp *remove_op = g_new (LDAPRemoveOp, 1);
PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
PASBookView *book_view = NULL;
+ int remove_msgid;
+ int ldap_error;
if (bl->priv->book_views) {
PASBackendLDAPBookView *v = bl->priv->book_views->data;
book_view = v->book_view;
- bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(book_view)), NULL);
}
- ldap_op_init ((LDAPOp*)remove_op, backend, book,
- book_view,
- remove_card_handler, remove_card_dtor);
+ remove_op->id = g_strdup (req->remove.id);
+
+ if (book_view)
+ pas_book_view_notify_status_message (book_view, _("Removing card from LDAP server..."));
- remove_op->id = req->id;
+ ldap_error = ldap_delete_ext (bl->priv->ldap,
+ remove_op->id,
+ NULL, NULL, &remove_msgid);
- ldap_op_process ((LDAPOp*)remove_op);
+ if (ldap_error != LDAP_SUCCESS) {
+ pas_book_respond_remove (remove_op->op.book,
+ ldap_error_to_response (ldap_error));
+ remove_card_dtor ((LDAPOp*)remove_op);
+ return;
+ }
+ else {
+ g_print ("ldap_delete_ext returned %d\n", ldap_error);
+ ldap_op_add ((LDAPOp*)remove_op, backend, book,
+ book_view, remove_msgid,
+ remove_card_handler, remove_card_dtor);
+ }
}
+/*
+** MODIFY
+**
+** The modification request is actually composed of 2 separate
+** requests. Since we need to get a list of theexisting objectclasses
+** used by the ldap server for the entry, and since the UI only sends
+** us the current card, we need to query the ldap server for the
+** existing card.
+**
+*/
+
typedef struct {
LDAPOp op;
- char *vcard;
+ const char *id; /* the id of the card we're modifying */
+ char *current_vcard; /* current in the LDAP db */
+ ECardSimple *current_card;
+ char *vcard; /* the VCard we want to store */
+ ECardSimple *card;
+ GList *existing_objectclasses;
} LDAPModifyOp;
-static gboolean
-modify_card_handler (PASBackend *backend, LDAPOp *op)
+static void
+modify_card_modify_handler (LDAPOp *op, LDAPMessage *res)
{
LDAPModifyOp *modify_op = (LDAPModifyOp*)op;
- PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
- ECard *new_ecard;
- const char *id;
- int response;
- int ldap_error = LDAP_SUCCESS;
- GPtrArray *mod_array;
- LDAPMod **ldap_mods;
- LDAP *ldap;
- ECardSimple *current_card;
- GList *existing_objectclasses = NULL;
+ PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend);
+ LDAP *ldap = bl->priv->ldap;
+ int ldap_error;
- new_ecard = e_card_new (modify_op->vcard);
- id = e_card_get_id(new_ecard);
+ if (LDAP_RES_MODIFY != ldap_msgtype (res)) {
+ g_warning ("incorrect msg type %d passed to modify_card_handler", ldap_msgtype (res));
+ pas_book_respond_modify (op->book,
+ GNOME_Evolution_Addressbook_BookListener_OtherError);
+ ldap_op_finished (op);
+ return;
+ }
- ldap = bl->priv->ldap;
+ ldap_parse_result (ldap, res, &ldap_error,
+ NULL, NULL, NULL, NULL, 0);
- if (op->view)
- pas_book_view_notify_status_message (op->view, _("Modifying card from LDAP server..."));
+ if (ldap_error == LDAP_SUCCESS) {
+ /* the card was modified, let's let the views know about it */
+ GList *l;
+ for (l = bl->priv->book_views; l; l = l->next) {
+ CORBA_Environment ev;
+ gboolean old_match, new_match;
+ PASBackendLDAPBookView *view = l->data;
+
+ CORBA_exception_init(&ev);
+
+ bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
- current_card = search_for_dn_with_objectclasses (bl, id, &existing_objectclasses);
+ old_match = pas_backend_card_sexp_match_vcard (view->card_sexp,
+ modify_op->current_vcard);
+ new_match = pas_backend_card_sexp_match_vcard (view->card_sexp,
+ modify_op->vcard);
+ if (old_match && new_match)
+ pas_book_view_notify_change_1 (view->book_view, modify_op->vcard);
+ else if (new_match)
+ pas_book_view_notify_add_1 (view->book_view, modify_op->vcard);
+ else /* if (old_match) */
+ pas_book_view_notify_remove (view->book_view, e_card_simple_get_id (modify_op->card));
+ pas_book_view_notify_complete (view->book_view);
- if (current_card) {
- ECardSimple *new_card = e_card_simple_new (new_ecard);
+ bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
+ }
+ }
+ else {
+ ldap_perror (ldap, "ldap_modify_s");
+ }
+
+ /* and lastly respond */
+ pas_book_respond_modify (op->book,
+ ldap_error_to_response (ldap_error));
+ ldap_op_finished (op);
+}
+
+static void
+modify_card_search_handler (LDAPOp *op, LDAPMessage *res)
+{
+ LDAPModifyOp *modify_op = (LDAPModifyOp*)op;
+ PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend);
+ LDAP *ldap = bl->priv->ldap;
+ int msg_type;
+
+ /* if it's successful, we should get called with a
+ RES_SEARCH_ENTRY and a RES_SEARCH_RESULT. if it's
+ unsuccessful, we should only see a RES_SEARCH_RESULT */
+
+ msg_type = ldap_msgtype (res);
+ if (msg_type == LDAP_RES_SEARCH_ENTRY) {
+ LDAPMessage *e = ldap_first_entry(ldap, res);
+
+ if (!e) {
+ g_warning ("uh, this shouldn't happen");
+ pas_book_respond_modify (op->book,
+ GNOME_Evolution_Addressbook_BookListener_OtherError);
+ ldap_op_finished (op);
+ return;
+ }
+
+ modify_op->current_card = build_card_from_entry (ldap, e,
+ &modify_op->existing_objectclasses);
+ modify_op->current_vcard = e_card_simple_get_vcard_assume_utf8 (modify_op->current_card);
+ }
+ else if (msg_type == LDAP_RES_SEARCH_RESULT) {
+ int ldap_error;
+ LDAPMod **ldap_mods;
+ GPtrArray *mod_array;
+ gboolean differences;
gboolean need_new_dn;
+ int modify_card_msgid;
+
+ /* grab the result code, and set up the actual modify
+ if it was successful */
+ ldap_parse_result (bl->priv->ldap, res, &ldap_error,
+ NULL, NULL, NULL, NULL, 0);
+
+ if (ldap_error != LDAP_SUCCESS) {
+ /* more here i'm sure */
+ pas_book_respond_modify (op->book,
+ ldap_error_to_response (ldap_error));
+ ldap_op_finished (op);
+ return;
+ }
/* build our mods */
- mod_array = build_mods_from_ecards (bl, current_card, new_card, &need_new_dn);
- if (mod_array->len > 0) {
+ mod_array = build_mods_from_ecards (bl, modify_op->current_card, modify_op->card, &need_new_dn);
+ differences = mod_array->len > 0;
+ if (differences) {
/* remove the NULL at the end */
g_ptr_array_remove (mod_array, NULL);
/* add our objectclass(es), making sure
- evolutionPerson is there if it's supported */
- add_objectclass_mod (bl, mod_array, existing_objectclasses);
+ evolutionPerson is there if it's supported */
+ add_objectclass_mod (bl, mod_array, modify_op->existing_objectclasses);
/* then put the NULL back */
g_ptr_array_add (mod_array, NULL);
@@ -1196,74 +1362,47 @@ modify_card_handler (PASBackend *backend, LDAPOp *op)
ldap_mods = (LDAPMod**)mod_array->pdata;
/* actually perform the ldap modify */
- ldap_error = ldap_modify_ext_s (ldap, id, ldap_mods, NULL, NULL);
- if (ldap_error == LDAP_SUCCESS) {
+ ldap_error = ldap_modify_ext (ldap, modify_op->id, ldap_mods,
+ NULL, NULL, &modify_card_msgid);
- /* the card was modified, let's let the views know about it */
- GList *l;
- for (l = bl->priv->book_views; l; l = l->next) {
- CORBA_Environment ev;
- gboolean old_match, new_match;
- PASBackendLDAPBookView *view = l->data;
-
- CORBA_exception_init(&ev);
-
- bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
-
- old_match = pas_backend_card_sexp_match_vcard (view->card_sexp,
- e_card_simple_get_vcard_assume_utf8 (current_card));
- new_match = pas_backend_card_sexp_match_vcard (view->card_sexp,
- modify_op->vcard);
- if (old_match && new_match)
- pas_book_view_notify_change_1 (view->book_view, modify_op->vcard);
- else if (new_match)
- pas_book_view_notify_add_1 (view->book_view, modify_op->vcard);
- else /* if (old_match) */
- pas_book_view_notify_remove (view->book_view, e_card_simple_get_id (new_card));
- pas_book_view_notify_complete (view->book_view);
-
- bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(view->book_view)), &ev);
- }
+ if (ldap_error == LDAP_SUCCESS) {
+ op->handler = modify_card_modify_handler;
+ ldap_op_change_id ((LDAPOp*)modify_op,
+ modify_card_msgid);
}
else {
- ldap_perror (ldap, "ldap_modify_s");
+ g_warning ("ldap_modify_ext returned %d\n", ldap_error);
+ pas_book_respond_modify (op->book,
+ ldap_error_to_response (ldap_error));
+ ldap_op_finished (op);
+ return;
}
}
- else {
- g_print ("modify list empty. no modification sent\n");
- }
/* and clean up */
free_mods (mod_array);
- g_list_foreach (existing_objectclasses, (GFunc)g_free, NULL);
- g_list_free (existing_objectclasses);
- gtk_object_unref (GTK_OBJECT(new_card));
- gtk_object_unref (GTK_OBJECT(current_card));
}
else {
- g_print ("didn't find original card\n");
+ g_warning ("unhandled result type %d returned", msg_type);
+ pas_book_respond_modify (op->book,
+ GNOME_Evolution_Addressbook_BookListener_OtherError);
+ ldap_op_finished (op);
}
-
- response = ldap_error_to_response (ldap_error);
- pas_book_respond_modify (modify_op->op.book,
- response);
-
- if (op->view)
- pas_book_view_notify_complete (op->view);
-
- /* we're synchronous */
- return TRUE;
}
static void
-modify_card_dtor (PASBackend *backend, LDAPOp *op)
+modify_card_dtor (LDAPOp *op)
{
LDAPModifyOp *modify_op = (LDAPModifyOp*)op;
- if (op->view)
- bonobo_object_release_unref(bonobo_object_corba_objref(BONOBO_OBJECT(op->view)), NULL);
-
+ g_list_foreach (modify_op->existing_objectclasses, (GFunc)g_free, NULL);
+ g_list_free (modify_op->existing_objectclasses);
+ g_free (modify_op->current_vcard);
+ if (modify_op->current_card)
+ gtk_object_unref (GTK_OBJECT (modify_op->current_card));
g_free (modify_op->vcard);
+ if (modify_op->card)
+ gtk_object_unref (GTK_OBJECT (modify_op->card));
g_free (modify_op);
}
@@ -1272,55 +1411,154 @@ pas_backend_ldap_process_modify_card (PASBackend *backend,
PASBook *book,
PASRequest *req)
{
- LDAPModifyOp *modify_op = g_new (LDAPModifyOp, 1);
+ LDAPModifyOp *modify_op = g_new0 (LDAPModifyOp, 1);
PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
+ ECard *new_ecard;
+ int ldap_error;
+ LDAP *ldap;
+ int modify_card_msgid;
PASBookView *book_view = NULL;
if (bl->priv->book_views) {
PASBackendLDAPBookView *v = bl->priv->book_views->data;
book_view = v->book_view;
- bonobo_object_dup_ref(bonobo_object_corba_objref(BONOBO_OBJECT(book_view)), NULL);
}
- ldap_op_init ((LDAPOp*)modify_op, backend, book,
- book_view,
- modify_card_handler, modify_card_dtor);
+ modify_op->vcard = g_strdup (req->modify.vcard);
+ new_ecard = e_card_new (modify_op->vcard);
+ modify_op->card = e_card_simple_new (new_ecard);
+ gtk_object_unref (GTK_OBJECT (new_ecard));
+ modify_op->id = e_card_simple_get_id(modify_op->card);
+
+ ldap = bl->priv->ldap;
+
+ if (book_view)
+ pas_book_view_notify_status_message (book_view, _("Modifying card from LDAP server..."));
- modify_op->vcard = req->vcard;
+ ldap_error = ldap_search_ext (ldap, modify_op->id,
+ LDAP_SCOPE_BASE,
+ "(objectclass=*)",
+ NULL, 0, NULL, NULL,
+ NULL, /* XXX timeout */
+ 1, &modify_card_msgid);
- ldap_op_process ((LDAPOp*)modify_op);
+ if (ldap_error == LDAP_SUCCESS) {
+ ldap_op_add ((LDAPOp*)modify_op, backend, book,
+ book_view, modify_card_msgid,
+ modify_card_search_handler, modify_card_dtor);
+ }
+ else {
+ g_warning ("ldap_search_ext returned %d\n", ldap_error);
+ pas_book_respond_modify (book,
+ GNOME_Evolution_Addressbook_BookListener_OtherError);
+ modify_card_dtor ((LDAPOp*)modify_op);
+ }
}
+typedef struct {
+ LDAPOp op;
+} LDAPGetVCardOp;
+
+static void
+get_vcard_handler (LDAPOp *op, LDAPMessage *res)
+{
+ PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend);
+ int msg_type;
+
+ /* the msg_type will be either SEARCH_ENTRY (if we're
+ successful) or SEARCH_RESULT (if we're not), so we finish
+ the op after either */
+ msg_type = ldap_msgtype (res);
+ if (msg_type == LDAP_RES_SEARCH_ENTRY) {
+ LDAPMessage *e = ldap_first_entry(bl->priv->ldap, res);
+ ECardSimple *simple;
+ char *vcard;
+
+ if (!e) {
+ g_warning ("uh, this shouldn't happen");
+ pas_book_respond_get_vcard (op->book,
+ GNOME_Evolution_Addressbook_BookListener_OtherError,
+ "");
+ ldap_op_finished (op);
+ return;
+ }
+
+ simple = build_card_from_entry (bl->priv->ldap, e, NULL);
+ vcard = e_card_simple_get_vcard_assume_utf8 (simple);
+ pas_book_respond_get_vcard (op->book,
+ GNOME_Evolution_Addressbook_BookListener_Success,
+ vcard);
+ g_free (vcard);
+ gtk_object_unref (GTK_OBJECT (simple));
+ ldap_op_finished (op);
+ }
+ else if (msg_type == LDAP_RES_SEARCH_RESULT) {
+ int ldap_error;
+ ldap_parse_result (bl->priv->ldap, res, &ldap_error,
+ NULL, NULL, NULL, NULL, 0);
+ pas_book_respond_get_vcard (op->book, ldap_error_to_response (ldap_error), "");
+ ldap_op_finished (op);
+ }
+ else {
+ g_warning ("unhandled result type %d returned", msg_type);
+ pas_book_respond_get_vcard (op->book, GNOME_Evolution_Addressbook_BookListener_OtherError,
+ "");
+ ldap_op_finished (op);
+ }
+
+}
+
+static void
+get_vcard_dtor (LDAPOp *op)
+{
+ LDAPGetVCardOp *get_vcard_op = (LDAPGetVCardOp*)op;
+
+ g_free (get_vcard_op);
+}
+
static void
pas_backend_ldap_process_get_vcard (PASBackend *backend,
PASBook *book,
PASRequest *req)
{
- PASBackendLDAP *bl;
- ECardSimple *simple;
-
- bl = PAS_BACKEND_LDAP (pas_book_get_backend (book));
+ LDAPGetVCardOp *get_vcard_op = g_new0 (LDAPGetVCardOp, 1);
+ PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
+ LDAP *ldap = bl->priv->ldap;
+ int get_vcard_msgid;
+ PASBookView *book_view = NULL;
+ int ldap_error;
- simple = search_for_dn (bl, req->id);
+ if (bl->priv->book_views) {
+ PASBackendLDAPBookView *v = bl->priv->book_views->data;
+ book_view = v->book_view;
+ }
+
+ ldap_error = ldap_search_ext (ldap, req->get_vcard.id,
+ LDAP_SCOPE_BASE,
+ "(objectclass=*)",
+ NULL, 0, NULL, NULL,
+ NULL, /* XXX timeout */
+ 1, &get_vcard_msgid);
- if (simple) {
- pas_book_respond_get_vcard (book,
- GNOME_Evolution_Addressbook_BookListener_Success,
- e_card_simple_get_vcard_assume_utf8 (simple));
- gtk_object_unref (GTK_OBJECT (simple));
+ if (ldap_error == LDAP_SUCCESS) {
+ ldap_op_add ((LDAPOp*)get_vcard_op, backend, book,
+ book_view, get_vcard_msgid,
+ get_vcard_handler, get_vcard_dtor);
}
else {
pas_book_respond_get_vcard (book,
- GNOME_Evolution_Addressbook_BookListener_CardNotFound,
+ ldap_error_to_response (ldap_error),
"");
+ get_vcard_dtor ((LDAPOp*)get_vcard_op);
}
}
typedef struct {
LDAPOp op;
- PASBook *book;
+ PASBackendLDAPCursorPrivate *cursor_data;
+ gboolean responded; /* if FALSE, we need to free cursor_data in the dtor */
} LDAPGetCursorOp;
static long
@@ -1344,22 +1582,25 @@ get_nth(PASCardCursor *cursor, long n, gpointer data)
static void
cursor_destroy(GtkObject *object, gpointer data)
{
- CORBA_Environment ev;
- GNOME_Evolution_Addressbook_Book corba_book;
PASBackendLDAPCursorPrivate *cursor_data = (PASBackendLDAPCursorPrivate *) data;
- corba_book = bonobo_object_corba_objref(BONOBO_OBJECT(cursor_data->book));
+ if (cursor_data->book) {
+ CORBA_Environment ev;
+ GNOME_Evolution_Addressbook_Book corba_book;
- CORBA_exception_init(&ev);
+ corba_book = bonobo_object_corba_objref(BONOBO_OBJECT(cursor_data->book));
- GNOME_Evolution_Addressbook_Book_unref(corba_book, &ev);
+ CORBA_exception_init(&ev);
+
+ GNOME_Evolution_Addressbook_Book_unref(corba_book, &ev);
- if (ev._major != CORBA_NO_EXCEPTION) {
- g_warning("cursor_destroy: Exception unreffing "
- "corba book.\n");
- }
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning("cursor_destroy: Exception unreffing "
+ "corba book.\n");
+ }
- CORBA_exception_free(&ev);
+ CORBA_exception_free(&ev);
+ }
/* free the ldap specific cursor information */
g_list_foreach (cursor_data->elements, (GFunc)g_free, NULL);
@@ -1369,97 +1610,72 @@ cursor_destroy(GtkObject *object, gpointer data)
}
static void
-pas_backend_ldap_build_all_cards_list(PASBackend *backend,
- PASBackendLDAPCursorPrivate *cursor_data)
+get_cursor_handler (LDAPOp *op, LDAPMessage *res)
{
- PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
- LDAP *ldap = bl->priv->ldap;
- int ldap_error;
- LDAPMessage *res, *e;
-
- if ((ldap_error = ldap_search_s (ldap,
- bl->priv->ldap_rootdn,
- bl->priv->ldap_scope,
- "(objectclass=*)",
- NULL, 0, &res)) != LDAP_SUCCESS) {
- g_warning ("ldap error '%s' in "
- "pas_backend_ldap_build_all_cards_list\n",
- ldap_err2string(ldap_error));
- }
+ LDAPGetCursorOp *cursor_op = (LDAPGetCursorOp*)op;
+ PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend);
+ LDAP *ldap = bl->priv->ldap;
+ int msg_type;
- cursor_data->elements = NULL;
+ msg_type = ldap_msgtype (res);
+ if (msg_type == LDAP_RES_SEARCH_ENTRY) {
+ LDAPMessage *e;
- cursor_data->num_elements = ldap_count_entries (ldap, res);
+ e = ldap_first_entry (ldap, res);
+ while (e) {
+ ECardSimple *simple;
+
+ simple = build_card_from_entry (ldap, e, NULL);
+ if (simple) {
+ char *vcard = e_card_simple_get_vcard_assume_utf8 (simple);
+ cursor_op->cursor_data->num_elements ++;
+ cursor_op->cursor_data->elements = g_list_prepend (cursor_op->cursor_data->elements,
+ vcard);
+ gtk_object_unref (GTK_OBJECT (simple));
+ }
+ }
+ }
+ else if (msg_type == LDAP_RES_SEARCH_RESULT) {
+ PASCardCursor *cursor = CORBA_OBJECT_NIL;
+ int ldap_error;
+ ldap_parse_result (bl->priv->ldap, res, &ldap_error,
+ NULL, NULL, NULL, NULL, 0);
- e = ldap_first_entry(ldap, res);
+ if (ldap_error == LDAP_SUCCESS) {
+ cursor = pas_card_cursor_new(get_length,
+ get_nth,
+ cursor_op->cursor_data);
- while (NULL != e) {
+ gtk_signal_connect(GTK_OBJECT(cursor), "destroy",
+ GTK_SIGNAL_FUNC(cursor_destroy), cursor_op->cursor_data);
- /* for now just make a list of the dn's */
-#if 0
- for ( a = ldap_first_attribute( ldap, e, &ber ); a != NULL;
- a = ldap_next_attribute( ldap, e, ber ) ) {
+ cursor_op->responded = TRUE;
}
-#else
- cursor_data->elements = g_list_prepend(cursor_data->elements,
- g_strdup(ldap_get_dn(ldap, e)));
-#endif
- e = ldap_next_entry(ldap, e);
- }
+ pas_book_respond_get_cursor (cursor_op->cursor_data->book,
+ ldap_error_to_response (ldap_error),
+ cursor);
- ldap_msgfree(res);
+ ldap_op_finished (op);
+ }
+ else {
+ g_warning ("unhandled result type %d returned", msg_type);
+ pas_book_respond_get_cursor (op->book,
+ GNOME_Evolution_Addressbook_BookListener_OtherError,
+ CORBA_OBJECT_NIL);
+ ldap_op_finished (op);
+ }
}
-
-static gboolean
-get_cursor_handler (PASBackend *backend, LDAPOp *op)
+static void
+get_cursor_dtor (LDAPOp *op)
{
LDAPGetCursorOp *cursor_op = (LDAPGetCursorOp*)op;
- CORBA_Environment ev;
- int ldap_error = 0;
- PASCardCursor *cursor;
- GNOME_Evolution_Addressbook_Book corba_book;
- PASBackendLDAPCursorPrivate *cursor_data;
- PASBook *book = cursor_op->book;
-
- cursor_data = g_new(PASBackendLDAPCursorPrivate, 1);
- cursor_data->backend = backend;
- cursor_data->book = book;
-
- pas_backend_ldap_build_all_cards_list(backend, cursor_data);
-
- corba_book = bonobo_object_corba_objref(BONOBO_OBJECT(book));
- CORBA_exception_init(&ev);
-
- GNOME_Evolution_Addressbook_Book_ref(corba_book, &ev);
-
- if (ev._major != CORBA_NO_EXCEPTION) {
- g_warning("pas_backend_file_process_get_cursor: Exception reffing "
- "corba book.\n");
+ if (!cursor_op->responded) {
+ cursor_destroy (NULL, cursor_op->cursor_data);
}
- CORBA_exception_free(&ev);
-
- cursor = pas_card_cursor_new(get_length,
- get_nth,
- cursor_data);
-
- gtk_signal_connect(GTK_OBJECT(cursor), "destroy",
- GTK_SIGNAL_FUNC(cursor_destroy), cursor_data);
-
- pas_book_respond_get_cursor (book,
- ldap_error_to_response (ldap_error),
- cursor);
-
- /* we're synchronous */
- return TRUE;
-}
-
-static void
-get_cursor_dtor (PASBackend *backend, LDAPOp *op)
-{
g_free (op);
}
@@ -1468,11 +1684,53 @@ pas_backend_ldap_process_get_cursor (PASBackend *backend,
PASBook *book,
PASRequest *req)
{
- LDAPGetCursorOp *op = g_new (LDAPGetCursorOp, 1);
+ PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
+ LDAP *ldap = bl->priv->ldap;
+ int ldap_error;
+ int get_cursor_msgid;
+ LDAPGetCursorOp *cursor_op;
+
+ cursor_op = g_new0 (LDAPGetCursorOp, 1);
+ cursor_op->cursor_data = g_new0 (PASBackendLDAPCursorPrivate, 1);
+
+ ldap_error = ldap_search_ext (ldap,
+ bl->priv->ldap_rootdn,
+ bl->priv->ldap_scope,
+ "(objectclass=*)",
+ NULL, 0,
+ NULL, NULL, NULL, /* timeout */
+ bl->priv->ldap_limit, &get_cursor_msgid);
+
+ if (ldap_error == LDAP_SUCCESS) {
+ CORBA_Environment ev;
+ GNOME_Evolution_Addressbook_Book corba_book;
+
+ corba_book = bonobo_object_corba_objref(BONOBO_OBJECT(book));
+
+ CORBA_exception_init(&ev);
- ldap_op_init ((LDAPOp*)op, backend, book, NULL, get_cursor_handler, get_cursor_dtor);
+ GNOME_Evolution_Addressbook_Book_ref(corba_book, &ev);
- ldap_op_process ((LDAPOp*)op);
+ cursor_op->cursor_data->backend = backend;
+ cursor_op->cursor_data->book = book;
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning("pas_backend_ldap_process_get_cursor: Exception reffing "
+ "corba book.\n");
+ }
+
+ CORBA_exception_free(&ev);
+
+
+ ldap_op_add ((LDAPOp*)cursor_op, backend, book,
+ NULL, get_cursor_msgid, get_cursor_handler, get_cursor_dtor);
+ }
+ else {
+ pas_book_respond_get_cursor (book,
+ ldap_error_to_response (ldap_error),
+ CORBA_OBJECT_NIL);
+ get_cursor_dtor ((LDAPOp*)cursor_op);
+ }
}
@@ -2191,9 +2449,18 @@ query_prop_to_ldap(gchar *query_prop)
typedef struct {
LDAPOp op;
- char *ldap_query;
- PASBackendLDAP *bl;
PASBackendLDAPBookView *view;
+
+ /* grouping stuff */
+ GList *pending_adds; /* the cards we're sending */
+ int num_pending_adds; /* the number waiting to be sent */
+ int target_pending_adds; /* the cutoff that forces a flush to the client, if it happens before the timeout */
+ int num_sent_this_time; /* the number of cards we sent to the client before the most recent timeout */
+ int num_sent_last_time; /* the number of cards we sent to the client before the previous timeout */
+ glong grouping_time_start;
+
+ /* used by search_handler to only send the status messages once */
+ gboolean notified_receiving_results;
} LDAPSearchOp;
static ECardSimple *
@@ -2263,25 +2530,13 @@ build_card_from_entry (LDAP *ldap, LDAPMessage *e, GList **existing_objectclasse
return card;
}
-static void
-send_pending_adds (PASBackendLDAPBookView *view)
-{
- view->num_sent_this_time += view->num_pending_adds;
- pas_book_view_notify_add (view->book_view, view->pending_adds);
- g_list_foreach (view->pending_adds, (GFunc)g_free, NULL);
- view->pending_adds = NULL;
- view->num_pending_adds = 0;
-}
-
static gboolean
-poll_ldap (LDAPSearchOp *op)
+poll_ldap (PASBackendLDAP *bl)
{
- PASBackendLDAPBookView *view = op->view;
- PASBackendLDAP *bl = op->bl;
+ GList *list;
LDAP *ldap = bl->priv->ldap;
int rc;
- LDAPMessage *res, *e;
- static int received = 0;
+ LDAPMessage *res;
GTimeVal cur_time;
glong cur_millis;
struct timeval timeout;
@@ -2289,13 +2544,9 @@ poll_ldap (LDAPSearchOp *op)
timeout.tv_sec = 0;
timeout.tv_usec = LDAP_RESULT_TIMEOUT_MILLIS * 1000;
- if (!view->notified_receiving_results) {
- view->notified_receiving_results = TRUE;
- pas_book_view_notify_status_message (view->book_view, _("Receiving LDAP search results..."));
- }
-
- rc = ldap_result (ldap, view->search_msgid, 0, &timeout, &res);
+ rc = ldap_result (ldap, LDAP_RES_ANY, 0, &timeout, &res);
if (rc != 0) {/* rc == 0 means timeout exceeded */
+#if 0
if (rc == -1 && received == 0) {
pas_book_view_notify_status_message (view->book_view, _("Restarting search."));
/* connection went down and we never got any. */
@@ -2305,139 +2556,134 @@ poll_ldap (LDAPSearchOp *op)
ldap_op_restart ((LDAPOp*)op);
return FALSE;
}
-
- if (rc != LDAP_RES_SEARCH_ENTRY) {
- view->search_timeout = 0;
- if (view->num_pending_adds)
- send_pending_adds (view);
- pas_book_view_notify_complete (view->book_view);
- ldap_op_finished ((LDAPOp*)op);
- received = 0;
- return FALSE;
+#endif
+ if (rc == -1) {
+ g_warning ("ldap_result returned -1");
}
+ else {
+ int msgid = ldap_msgid (res);
+ LDAPOp *op;
- received = 1;
-
- e = ldap_first_entry(ldap, res);
-
- while (NULL != e) {
- ECardSimple *card = build_card_from_entry (ldap, e, NULL);
-
- view->pending_adds = g_list_append (view->pending_adds,
- e_card_simple_get_vcard_assume_utf8 (card));
- view->num_pending_adds ++;
+ op = g_hash_table_lookup (bl->priv->id_to_op, &msgid);
+ if (!op)
+ g_error ("unknown operation, msgid = %d", msgid);
- gtk_object_unref (GTK_OBJECT(card));
+ op->handler (op, res);
- e = ldap_next_entry(ldap, e);
+ ldap_msgfree(res);
}
-
- ldap_msgfree(res);
}
g_get_current_time (&cur_time);
cur_millis = TV_TO_MILLIS (cur_time);
+
+ for (list = bl->priv->book_views; list; list = g_list_next(list)) {
+ PASBackendLDAPBookView *view = list->data;
+ if (view->search_op)
+ ldap_search_op_timeout (view->search_op, cur_millis);
+ }
+
+ return TRUE;
+}
+
+static void
+send_pending_adds (LDAPSearchOp *search_op)
+{
+ search_op->num_sent_this_time += search_op->num_pending_adds;
+ pas_book_view_notify_add (search_op->op.view, search_op->pending_adds);
+ g_list_foreach (search_op->pending_adds, (GFunc)g_free, NULL);
+ search_op->pending_adds = NULL;
+ search_op->num_pending_adds = 0;
+}
- if (cur_millis - view->grouping_time_start > GROUPING_MINIMUM_WAIT) {
+static void
+ldap_search_op_timeout (LDAPOp *op, glong cur_millis)
+{
+ LDAPSearchOp *search_op = (LDAPSearchOp*)op;
+
+ if (cur_millis - search_op->grouping_time_start > GROUPING_MINIMUM_WAIT) {
- if (view->num_pending_adds >= view->target_pending_adds)
- send_pending_adds (view);
+ if (search_op->num_pending_adds >= search_op->target_pending_adds)
+ send_pending_adds (search_op);
- if (cur_millis - view->grouping_time_start > GROUPING_MAXIMUM_WAIT) {
+ if (cur_millis - search_op->grouping_time_start > GROUPING_MAXIMUM_WAIT) {
GTimeVal new_start;
- if (view->num_pending_adds)
- send_pending_adds (view);
- view->target_pending_adds = MIN (GROUPING_MAXIMUM_SIZE,
- (view->num_sent_this_time + view->num_sent_last_time) / 2);
- view->target_pending_adds = MAX (view->target_pending_adds, 1);
+ if (search_op->num_pending_adds)
+ send_pending_adds (search_op);
+ search_op->target_pending_adds = MIN (GROUPING_MAXIMUM_SIZE,
+ (search_op->num_sent_this_time + search_op->num_sent_last_time) / 2);
+ search_op->target_pending_adds = MAX (search_op->target_pending_adds, 1);
#ifdef PERFORMANCE_SPEW
printf ("num sent this time %d, last time %d, target pending adds set to %d\n",
- view->num_sent_this_time,
- view->num_sent_last_time,
- view->target_pending_adds);
+ search_op->num_sent_this_time,
+ search_op->num_sent_last_time,
+ search_op->target_pending_adds);
#endif
g_get_current_time (&new_start);
- view->grouping_time_start = TV_TO_MILLIS (new_start);
- view->num_sent_last_time = view->num_sent_this_time;
- view->num_sent_this_time = 0;
+ search_op->grouping_time_start = TV_TO_MILLIS (new_start);
+ search_op->num_sent_last_time = search_op->num_sent_this_time;
+ search_op->num_sent_this_time = 0;
}
}
-
- return TRUE;
}
-static gboolean
-ldap_search_handler (PASBackend *backend, LDAPOp *op)
+static void
+ldap_search_handler (LDAPOp *op, LDAPMessage *res)
{
- LDAPSearchOp *search_op = (LDAPSearchOp*) op;
-
- if (op->view)
- pas_book_view_notify_status_message (op->view, _("Searching..."));
+ LDAPSearchOp *search_op = (LDAPSearchOp*)op;
+ PASBackendLDAP *bl = PAS_BACKEND_LDAP (op->backend);
+ LDAP *ldap = bl->priv->ldap;
+ LDAPMessage *e;
+ int msg_type;
- /* it might not be NULL if we've been restarted */
- if (search_op->ldap_query == NULL)
- search_op->ldap_query = pas_backend_ldap_build_query(PAS_BACKEND_LDAP (backend), search_op->view->search);
+ if (!search_op->notified_receiving_results) {
+ search_op->notified_receiving_results = TRUE;
+ pas_book_view_notify_status_message (op->view, _("Receiving LDAP search results..."));
+ }
- if (search_op->ldap_query != NULL) {
- PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
- PASBackendLDAPBookView *view = search_op->view;
- LDAP *ldap = bl->priv->ldap;
- int ldap_err;
- GTimeVal search_start;
+ msg_type = ldap_msgtype (res);
+ if (msg_type == LDAP_RES_SEARCH_ENTRY) {
+ e = ldap_first_entry(ldap, res);
- view->pending_adds = NULL;
- view->num_pending_adds = 0;
- view->target_pending_adds = GROUPING_INITIAL_SIZE;
+ while (NULL != e) {
+ ECardSimple *card = build_card_from_entry (ldap, e, NULL);
- g_get_current_time (&search_start);
- view->grouping_time_start = TV_TO_MILLIS (search_start);
- view->num_sent_last_time = 0;
- view->num_sent_this_time = 0;
- view->notified_receiving_results = FALSE;
+ search_op->pending_adds = g_list_append (search_op->pending_adds,
+ e_card_simple_get_vcard_assume_utf8 (card));
+ search_op->num_pending_adds ++;
- ldap_err = ldap_search_ext (ldap, bl->priv->ldap_rootdn,
- bl->priv->ldap_scope,
- search_op->ldap_query,
- NULL, 0,
- NULL, /* XXX */
- NULL, /* XXX */
- NULL,
- bl->priv->ldap_limit, &view->search_msgid);
-
- if (ldap_err != LDAP_SUCCESS) {
- pas_book_view_notify_status_message (view->book_view, ldap_err2string(ldap_err));
- return TRUE; /* act synchronous in this case */
- }
+ gtk_object_unref (GTK_OBJECT(card));
- if (view->search_msgid == -1) {
- pas_book_view_notify_status_message (view->book_view, ldap_err2string(ldap_err));
- return TRUE; /* act synchronous in this case */
- }
- else {
- view->search_timeout = g_timeout_add (LDAP_POLL_INTERVAL,
- (GSourceFunc) poll_ldap,
- search_op);
+ e = ldap_next_entry(ldap, e);
}
-
- /* we're async */
- return FALSE;
+ }
+ else if (msg_type == LDAP_RES_SEARCH_RESULT) {
+ /* the entry that marks the end of our search */
+ if (search_op->num_pending_adds)
+ send_pending_adds (search_op);
+ pas_book_view_notify_complete (search_op->op.view);
+ ldap_op_finished (op);
}
else {
- /* error doing the conversion to an ldap query, let's
- end this now by acting like we're synchronous. */
- g_warning ("LDAP problem converting search query %s\n", search_op->view->search);
- return TRUE;
+ g_warning ("unhandled search result type %d returned", msg_type);
+ if (search_op->num_pending_adds)
+ send_pending_adds (search_op);
+ pas_book_view_notify_complete (search_op->op.view);
+ ldap_op_finished (op);
}
}
static void
-ldap_search_dtor (PASBackend *backend, LDAPOp *op)
+ldap_search_dtor (LDAPOp *op)
{
LDAPSearchOp *search_op = (LDAPSearchOp*) op;
- g_free (search_op->ldap_query);
+ /* unhook us from our PASBackendLDAPBookView */
+ if (search_op->view)
+ search_op->view->search_op = NULL;
+
g_free (search_op);
}
@@ -2446,19 +2692,64 @@ pas_backend_ldap_search (PASBackendLDAP *bl,
PASBook *book,
PASBackendLDAPBookView *view)
{
- LDAPSearchOp *op = g_new (LDAPSearchOp, 1);
+ LDAPSearchOp *search_op = g_new0 (LDAPSearchOp, 1);
+ char *ldap_query;
- ldap_op_init ((LDAPOp*)op, PAS_BACKEND(bl), book, view->book_view, ldap_search_handler, ldap_search_dtor);
+ pas_book_view_notify_status_message (view->book_view, _("Searching..."));
- op->ldap_query = NULL;
- op->view = view;
- op->bl = bl;
+ ldap_query = pas_backend_ldap_build_query(bl, view->search);
- /* keep track of the search op so we can delete it from the
- list if the view is destroyed */
- view->search_op = (LDAPOp*)op;
+ if (ldap_query != NULL) {
+ LDAP *ldap = bl->priv->ldap;
+ int ldap_err;
+ GTimeVal search_start;
+ int search_msgid;
+
+ ldap_err = ldap_search_ext (ldap, bl->priv->ldap_rootdn,
+ bl->priv->ldap_scope,
+ ldap_query,
+ NULL, 0,
+ NULL, /* XXX */
+ NULL, /* XXX */
+ NULL, /* XXX timeout */
+ bl->priv->ldap_limit, &search_msgid);
+
+ g_free (ldap_query);
+
+ if (ldap_err != LDAP_SUCCESS) {
+ pas_book_view_notify_status_message (view->book_view, ldap_err2string(ldap_err));
+ return;
+ }
+ else if (search_msgid == -1) {
+ pas_book_view_notify_status_message (view->book_view,
+ _("Error performing search"));
+ return;
+ }
+ else {
+ LDAPSearchOp *op = g_new0 (LDAPSearchOp, 1);
+
+ op->target_pending_adds = GROUPING_INITIAL_SIZE;
+
+ g_get_current_time (&search_start);
+ op->grouping_time_start = TV_TO_MILLIS (search_start);
+
+ op->view = view;
+
+ view->search_op = (LDAPOp*)op;
+
+ ldap_op_add ((LDAPOp*)op, PAS_BACKEND(bl), book, view->book_view,
+ search_msgid,
+ ldap_search_handler, ldap_search_dtor);
+
+ }
+ return;
+ }
+ else {
+ g_warning ("LDAP problem converting search query %s\n", search_op->view->search);
+ pas_book_view_notify_status_message (view->book_view, _("Could not parse query string"));
+ return;
+ }
- ldap_op_process ((LDAPOp*)op);
}
static void
@@ -2467,13 +2758,12 @@ pas_backend_ldap_process_get_book_view (PASBackend *backend,
PASRequest *req)
{
PASBackendLDAP *bl = PAS_BACKEND_LDAP (backend);
- CORBA_Environment ev;
PASBookView *book_view;
PASBackendLDAPBookView *view;
- g_return_if_fail (req->listener != NULL);
+ g_return_if_fail (req->get_book_view.listener != NULL);
- book_view = pas_book_view_new (req->listener);
+ book_view = pas_book_view_new (req->get_book_view.listener);
bonobo_object_ref(BONOBO_OBJECT(book));
gtk_signal_connect(GTK_OBJECT(book_view), "destroy",
@@ -2481,7 +2771,7 @@ pas_backend_ldap_process_get_book_view (PASBackend *backend,
view = g_new0(PASBackendLDAPBookView, 1);
view->book_view = book_view;
- view->search = g_strdup(req->search);
+ view->search = g_strdup(req->get_book_view.search);
view->card_sexp = pas_backend_card_sexp_new (view->search);
view->blpriv = bl->priv;
@@ -2495,18 +2785,7 @@ pas_backend_ldap_process_get_book_view (PASBackend *backend,
pas_backend_ldap_search (bl, book, view);
- g_free (req->search);
- CORBA_exception_init(&ev);
-
bonobo_object_unref (BONOBO_OBJECT (book_view));
- bonobo_object_release_unref(req->listener, &ev);
-
- if (ev._major != CORBA_NO_EXCEPTION) {
- g_warning("pas_backend_file_process_get_book_view: Exception reffing "
- "corba book.\n");
- }
- CORBA_exception_free(&ev);
-
}
static void
@@ -2528,9 +2807,9 @@ pas_backend_ldap_process_authenticate_user (PASBackend *backend,
int ldap_error;
char *dn = NULL;
- if (!strcmp (req->auth_method, "ldap/simple-email")) {
+ if (!strcmp (req->auth_user.auth_method, "ldap/simple-email")) {
LDAPMessage *res, *e;
- char *query = g_strdup_printf ("(mail=%s)", req->user);
+ char *query = g_strdup_printf ("(mail=%s)", req->auth_user.user);
ldap_error = ldap_search_s (bl->priv->ldap,
bl->priv->ldap_rootdn,
@@ -2550,15 +2829,15 @@ pas_backend_ldap_process_authenticate_user (PASBackend *backend,
return;
}
}
- else {
- dn = g_strdup (req->user);
+ else if (!strcmp (req->auth_user.auth_method, "ldap/simple-binddn")) {
+ dn = g_strdup (req->auth_user.user);
}
/* now authenticate against the DN we were either supplied or queried for */
printf ("authenticating as %s\n", dn);
ldap_error = ldap_simple_bind_s(bl->priv->ldap,
dn,
- req->passwd);
+ req->auth_user.passwd);
g_free (dn);
pas_book_respond_authenticate_user (book,
@@ -2566,7 +2845,7 @@ pas_backend_ldap_process_authenticate_user (PASBackend *backend,
bl->priv->writable = (ldap_error == LDAP_SUCCESS);
- if (!bl->priv->evolutionPersonChecked)
+ if (!bl->priv->schema_checked)
check_schema_support (bl);
pas_book_report_writable (book, bl->priv->writable);
@@ -2639,7 +2918,7 @@ pas_backend_ldap_process_client_requests (PASBook *book)
break;
}
- g_free (req);
+ pas_book_free_request (req);
}
static void
@@ -2845,10 +3124,14 @@ pas_backend_ldap_new (void)
return PAS_BACKEND (backend);
}
-static void
-call_dtor (LDAPOp *op, gpointer data)
+static gboolean
+call_dtor (int msgid, LDAPOp *op, gpointer data)
{
- op->dtor (op->backend, op);
+ ldap_abandon (PAS_BACKEND_LDAP(op->backend)->priv->ldap, op->id);
+
+ op->dtor (op);
+
+ return TRUE;
}
static void
@@ -2858,8 +3141,11 @@ pas_backend_ldap_destroy (GtkObject *object)
bl = PAS_BACKEND_LDAP (object);
- g_list_foreach (bl->priv->pending_ops, (GFunc)call_dtor, NULL);
- g_list_free (bl->priv->pending_ops);
+ g_hash_table_foreach_remove (bl->priv->id_to_op, (GHRFunc)call_dtor, NULL);
+ g_hash_table_destroy (bl->priv->id_to_op);
+
+ if (bl->priv->poll_timeout != -1)
+ g_source_remove (bl->priv->poll_timeout);
if (bl->priv->supported_fields)
gtk_object_unref (GTK_OBJECT (bl->priv->supported_fields));
@@ -2875,6 +3161,9 @@ pas_backend_ldap_class_init (PASBackendLDAPClass *klass)
GtkObjectClass *object_class = (GtkObjectClass *) klass;
PASBackendClass *parent_class;
+ /* get client side information (extensions present in the library) */
+ get_ldap_library_info ();
+
pas_backend_ldap_parent_class = gtk_type_class (pas_backend_get_type ());
parent_class = PAS_BACKEND_CLASS (klass);
@@ -2897,8 +3186,9 @@ pas_backend_ldap_init (PASBackendLDAP *backend)
priv = g_new0 (PASBackendLDAPPrivate, 1);
priv->supported_fields = e_list_new ((EListCopyFunc)g_strdup, (EListFreeFunc)g_free, NULL);
- priv->ldap_limit = 100;
-
+ priv->ldap_limit = 100;
+ priv->id_to_op = g_hash_table_new (g_int_hash, g_int_equal);
+ priv->poll_timeout = -1;
backend->priv = priv;
}
diff --git a/addressbook/backend/pas/pas-book.c b/addressbook/backend/pas/pas-book.c
index b0b35b2c0f..9bb2cd348e 100644
--- a/addressbook/backend/pas/pas-book.c
+++ b/addressbook/backend/pas/pas-book.c
@@ -74,7 +74,7 @@ pas_book_queue_create_card (PASBook *book, const char *vcard)
req = g_new0 (PASRequest, 1);
req->op = CreateCard;
- req->vcard = g_strdup (vcard);
+ req->create.vcard = g_strdup (vcard);
pas_book_queue_request (book, req);
}
@@ -86,7 +86,7 @@ pas_book_queue_remove_card (PASBook *book, const char *id)
req = g_new0 (PASRequest, 1);
req->op = RemoveCard;
- req->id = g_strdup (id);
+ req->remove.id = g_strdup (id);
pas_book_queue_request (book, req);
}
@@ -98,7 +98,7 @@ pas_book_queue_modify_card (PASBook *book, const char *vcard)
req = g_new0 (PASRequest, 1);
req->op = ModifyCard;
- req->vcard = g_strdup (vcard);
+ req->modify.vcard = g_strdup (vcard);
pas_book_queue_request (book, req);
}
@@ -110,7 +110,7 @@ pas_book_queue_get_cursor (PASBook *book, const char *search)
req = g_new0 (PASRequest, 1);
req->op = GetCursor;
- req->search = g_strdup(search);
+ req->get_cursor.search = g_strdup(search);
pas_book_queue_request (book, req);
}
@@ -122,7 +122,7 @@ pas_book_queue_get_vcard (PASBook *book, const char *id)
req = g_new0 (PASRequest, 1);
req->op = GetVCard;
- req->id = g_strdup(id);
+ req->get_vcard.id = g_strdup(id);
pas_book_queue_request (book, req);
}
@@ -135,9 +135,9 @@ pas_book_queue_authenticate_user (PASBook *book,
req = g_new0 (PASRequest, 1);
req->op = AuthenticateUser;
- req->user = g_strdup(user);
- req->passwd = g_strdup(passwd);
- req->auth_method = g_strdup(auth_method);
+ req->auth_user.user = g_strdup(user);
+ req->auth_user.passwd = g_strdup(passwd);
+ req->auth_user.auth_method = g_strdup(auth_method);
pas_book_queue_request (book, req);
}
@@ -162,11 +162,11 @@ pas_book_queue_get_book_view (PASBook *book, const GNOME_Evolution_Addressbook_B
req = g_new0 (PASRequest, 1);
req->op = GetBookView;
- req->search = g_strdup(search);
+ req->get_book_view.search = g_strdup(search);
CORBA_exception_init (&ev);
- req->listener = bonobo_object_dup_ref(listener, &ev);
+ req->get_book_view.listener = bonobo_object_dup_ref(listener, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("pas_book_queue_get_book_view: Exception "
@@ -186,11 +186,11 @@ pas_book_queue_get_changes (PASBook *book, const GNOME_Evolution_Addressbook_Boo
req = g_new0 (PASRequest, 1);
req->op = GetChanges;
- req->change_id= g_strdup(change_id);
+ req->get_changes.change_id= g_strdup(change_id);
CORBA_exception_init (&ev);
- req->listener = bonobo_object_dup_ref(listener, &ev);
+ req->get_changes.listener = bonobo_object_dup_ref(listener, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("pas_book_queue_get_changes: Exception "
@@ -766,6 +766,63 @@ pas_book_new (PASBackend *backend,
return book;
}
+void
+pas_book_free_request (PASRequest *req)
+{
+ CORBA_Environment ev;
+ switch (req->op) {
+ case CreateCard:
+ g_free (req->create.id);
+ g_free (req->create.vcard);
+ break;
+ case RemoveCard:
+ g_free (req->remove.id);
+ break;
+ case ModifyCard:
+ g_free (req->modify.vcard);
+ break;
+ case GetVCard:
+ g_free (req->get_vcard.id);
+ break;
+ case GetCursor:
+ g_free (req->get_cursor.search);
+ break;
+ case GetBookView:
+ g_free (req->get_book_view.search);
+ CORBA_exception_init (&ev);
+ bonobo_object_release_unref (req->get_book_view.listener, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION)
+ g_message ("pas_book_free_request(GetBookView): could not release the listener");
+
+ CORBA_exception_free (&ev);
+ break;
+ case GetChanges:
+ g_free (req->get_changes.change_id);
+ CORBA_exception_init (&ev);
+ bonobo_object_release_unref (req->get_changes.listener, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION)
+ g_message ("pas_book_free_request(GetChanges): could not release the listener");
+
+ CORBA_exception_free (&ev);
+ break;
+ case CheckConnection:
+ /* nothing to free */
+ break;
+ case AuthenticateUser:
+ g_free (req->auth_user.user);
+ g_free (req->auth_user.passwd);
+ g_free (req->auth_user.auth_method);
+ break;
+ case GetSupportedFields:
+ /* nothing to free */
+ break;
+ }
+
+ g_free (req);
+}
+
static void
pas_book_destroy (GtkObject *object)
{
@@ -774,11 +831,7 @@ pas_book_destroy (GtkObject *object)
CORBA_Environment ev;
for (l = book->priv->request_queue; l != NULL; l = l->next) {
- PASRequest *req = l->data;
-
- g_free (req->id);
- g_free (req->vcard);
- g_free (req);
+ pas_book_free_request ((PASRequest *)l->data);
}
g_list_free (book->priv->request_queue);
diff --git a/addressbook/backend/pas/pas-book.h b/addressbook/backend/pas/pas-book.h
index 8afba26b45..a6f2fda3cc 100644
--- a/addressbook/backend/pas/pas-book.h
+++ b/addressbook/backend/pas/pas-book.h
@@ -38,16 +38,71 @@ typedef enum {
} PASOperation;
typedef struct {
- PASOperation op;
- char *id;
- char *vcard;
- char *search;
- char *change_id;
- char *user;
- char *passwd;
- char *auth_method;
+ PASOperation op;
+ char *id;
+ char *vcard;
+} PASCreateCardRequest;
+
+typedef struct {
+ PASOperation op;
+ char *id;
+} PASRemoveCardRequest;
+
+typedef struct {
+ PASOperation op;
+ char *vcard;
+} PASModifyCardRequest;
+
+typedef struct {
+ PASOperation op;
+ char *id;
+} PASGetVCardRequest;
+
+typedef struct {
+ PASOperation op;
+ char *search;
+} PASGetCursorRequest;
+
+typedef struct {
+ PASOperation op;
+ char *search;
GNOME_Evolution_Addressbook_BookViewListener listener;
- GNOME_Evolution_Addressbook_stringlist fields;
+} PASGetBookViewRequest;
+
+typedef struct {
+ PASOperation op;
+ char *change_id;
+ GNOME_Evolution_Addressbook_BookViewListener listener;
+} PASGetChangesRequest;
+
+typedef struct {
+ PASOperation op;
+} PASCheckConnectionRequest;
+
+typedef struct {
+ PASOperation op;
+ char *user;
+ char *passwd;
+ char *auth_method;
+} PASAuthenticateUserRequest;
+
+typedef struct {
+ PASOperation op;
+} PASGetSupportedFieldsRequest;
+
+typedef union {
+ PASOperation op;
+
+ PASCreateCardRequest create;
+ PASRemoveCardRequest remove;
+ PASModifyCardRequest modify;
+ PASGetVCardRequest get_vcard;
+ PASGetCursorRequest get_cursor;
+ PASGetBookViewRequest get_book_view;
+ PASGetChangesRequest get_changes;
+ PASCheckConnectionRequest check_connection;
+ PASAuthenticateUserRequest auth_user;
+ PASGetSupportedFieldsRequest get_supported_fields;
} PASRequest;
struct _PASBook {
@@ -71,6 +126,7 @@ PASBackend *pas_book_get_backend (PASBook
GNOME_Evolution_Addressbook_BookListener pas_book_get_listener (PASBook *book);
int pas_book_check_pending (PASBook *book);
PASRequest *pas_book_pop_request (PASBook *book);
+void pas_book_free_request (PASRequest *request);
void pas_book_respond_open (PASBook *book,
GNOME_Evolution_Addressbook_BookListener_CallStatus status);
void pas_book_respond_create (PASBook *book,