1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* e-book-backend-ldap.c - LDAP contact backend.
5 * Copyright (C) 2005 Novell, Inc.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
21 * Authors: Chris Toshok <toshok@ximian.com>
22 * Hans Petter Jansson <hpj@novell.com>
40 #define LDAP_DEBUG_ADD
41 #define LDAP_DEBUG_MODIFY
48 #define interface windows_interface
52 #include "openldap-extract.h"
59 #if LDAP_VENDOR_VERSION > 20000
67 #include <ldap_schema.h>
72 #include "openldap-extract.h"
80 #include <glib/gi18n-lib.h>
81 #include "libedataserver/e-sexp.h"
82 #include <libebook/e-contact.h>
84 #include <libedata-book/e-book-backend-sexp.h>
85 #include <libedata-book/e-data-book.h>
86 #include <libedata-book/e-data-book-view.h>
87 #include <libedata-book/e-book-backend-cache.h>
88 #include <libedata-book/e-book-backend-summary.h>
89 #include "e-book-backend-ldap.h"
91 /* this is broken currently, don't enable it */
92 /*#define ENABLE_SASL_BINDS*/
95 E_BOOK_BACKEND_LDAP_TLS_NO,
96 E_BOOK_BACKEND_LDAP_TLS_ALWAYS,
97 E_BOOK_BACKEND_LDAP_TLS_WHEN_POSSIBLE,
98 } EBookBackendLDAPUseTLS;
100 /* interval for our poll_ldap timeout */
101 #define LDAP_POLL_INTERVAL 20
103 /* timeout for ldap_result */
104 #define LDAP_RESULT_TIMEOUT_MILLIS 10
106 #define TV_TO_MILLIS(timeval) ((timeval).tv_sec * 1000 + (timeval).tv_usec / 1000)
108 /* the objectClasses we need */
110 #define PERSON "person"
111 #define ORGANIZATIONALPERSON "organizationalPerson"
112 #define INETORGPERSON "inetOrgPerson"
113 #define CALENTRY "calEntry"
114 #define EVOLUTIONPERSON "evolutionPerson"
115 #define GROUPOFNAMES "groupOfNames"
117 static gboolean enable_debug = FALSE;
119 static gchar *query_prop_to_ldap(gchar *query_prop);
120 static gchar *e_book_backend_ldap_build_query (EBookBackendLDAP *bl, const char *query);
122 static EBookBackendClass *e_book_backend_ldap_parent_class;
123 typedef struct LDAPOp LDAPOp;
126 struct _EBookBackendLDAPPrivate {
129 gchar *ldap_host; /* the hostname of the server */
130 int ldap_port; /* the port of the server */
131 char *schema_dn; /* the base dn for schema information */
132 gchar *ldap_rootdn; /* the base dn of our searches */
133 int ldap_scope; /* the scope used for searches */
134 gchar *ldap_search_filter;
135 int ldap_limit; /* the search limit */
136 int ldap_timeout; /* the search timeout */
141 gboolean ldap_v3; /* TRUE if the server supports protocol
142 revision 3 (necessary for TLS) */
143 gboolean starttls; /* TRUE if the *library* supports
144 starttls. will be false if openssl
145 was not built into openldap. */
146 EBookBackendLDAPUseTLS use_tls;
150 GList *supported_fields;
151 GList *supported_auth_methods;
153 EBookBackendCache *cache;
155 /* whether or not there's support for the objectclass we need
156 to store all our additional fields */
157 gboolean evolutionPersonSupported;
158 gboolean calEntrySupported;
159 gboolean evolutionPersonChecked;
160 gboolean marked_for_offline;
164 GStaticRecMutex op_hash_mutex;
165 GHashTable *id_to_op;
169 /* summary file related */
170 char *summary_file_name;
171 gboolean is_summary_ready;
172 EBookBackendSummary *summary;
181 typedef void (*LDAPOpHandler)(LDAPOp *op, LDAPMessage *res);
182 typedef void (*LDAPOpDtor)(LDAPOp *op);
185 LDAPOpHandler handler;
187 EBookBackend *backend;
190 guint32 opid; /* the libebook operation id */
191 int id; /* the ldap msg id */
194 static GStaticRecMutex eds_ldap_handler_lock = G_STATIC_REC_MUTEX_INIT;
196 static void ldap_op_add (LDAPOp *op, EBookBackend *backend, EDataBook *book,
197 EDataBookView *view, int opid, int msgid, LDAPOpHandler handler, LDAPOpDtor dtor);
198 static void ldap_op_finished (LDAPOp *op);
200 static gboolean poll_ldap (EBookBackendLDAP *bl);
202 static EContact *build_contact_from_entry (EBookBackendLDAP *bl, LDAPMessage *e, GList **existing_objectclasses);
204 static void email_populate (EContact *contact, char **values);
205 static struct berval** email_ber (EContact *contact);
206 static gboolean email_compare (EContact *contact1, EContact *contact2);
208 static void member_populate (EContact *contact, char **values);
209 static struct berval** member_ber (EContact *contact);
210 static gboolean member_compare (EContact *contact1, EContact *contact2);
212 static void homephone_populate (EContact *contact, char **values);
213 static struct berval** homephone_ber (EContact *contact);
214 static gboolean homephone_compare (EContact *contact1, EContact *contact2);
216 static void business_populate (EContact *contact, char **values);
217 static struct berval** business_ber (EContact *contact);
218 static gboolean business_compare (EContact *contact1, EContact *contact2);
220 static void anniversary_populate (EContact *contact, char **values);
221 static struct berval** anniversary_ber (EContact *contact);
222 static gboolean anniversary_compare (EContact *contact1, EContact *contact2);
224 static void birthday_populate (EContact *contact, char **values);
225 static struct berval** birthday_ber (EContact *contact);
226 static gboolean birthday_compare (EContact *contact1, EContact *contact2);
228 static void category_populate (EContact *contact, char **values);
229 static struct berval** category_ber (EContact *contact);
230 static gboolean category_compare (EContact *contact1, EContact *contact2);
232 static void home_address_populate(EContact * card, char **values);
233 static struct berval **home_address_ber(EContact * card);
234 static gboolean home_address_compare(EContact * ecard1, EContact * ecard2);
236 static void work_address_populate(EContact * card, char **values);
237 static struct berval **work_address_ber(EContact * card);
238 static gboolean work_address_compare(EContact * ecard1, EContact * ecard2);
240 static void other_address_populate(EContact * card, char **values);
241 static struct berval **other_address_ber(EContact * card);
242 static gboolean other_address_compare(EContact * ecard1, EContact * ecard2);
244 static void work_city_populate(EContact * card, char **values);
245 static void work_state_populate(EContact * card, char **values);
246 static void work_po_populate(EContact * card, char **values);
247 static void work_zip_populate(EContact * card, char **values);
248 static void work_country_populate(EContact * card, char **values);
249 static void home_city_populate(EContact * card, char **values);
250 static void home_state_populate(EContact * card, char **values);
251 static void home_zip_populate(EContact * card, char **values);
252 static void home_country_populate(EContact * card, char **values);
254 static void photo_populate (EContact *contact, struct berval **ber_values);
255 static struct berval **photo_ber (EContact * contact);
256 static gboolean photo_compare(EContact * ecard1, EContact * ecard2);
258 static void cert_populate (EContact *contact, struct berval **ber_values);
260 static struct prop_info {
261 EContactField field_id;
263 #define PROP_TYPE_STRING 0x01
264 #define PROP_TYPE_COMPLEX 0x02
265 #define PROP_TYPE_BINARY 0x04
267 #define PROP_EVOLVE 0x10
268 #define PROP_WRITE_ONLY 0x20
269 #define PROP_TYPE_GROUP 0x40
272 /* the remaining items are only used for the TYPE_COMPLEX props */
274 /* used when reading from the ldap server populates EContact with the values in **values. */
275 void (*populate_contact_func)(EContact *contact, char **values);
276 /* used when writing to an ldap server. returns a NULL terminated array of berval*'s */
277 struct berval** (*ber_func)(EContact *contact);
278 /* used to compare list attributes */
279 gboolean (*compare_func)(EContact *contact1, EContact *contact2);
281 void (*binary_populate_contact_func)(EContact *contact, struct berval **ber_values);
285 #define BINARY_PROP(fid,a,ctor,ber,cmp) {fid, a, PROP_TYPE_BINARY, NULL, ber, cmp, ctor}
286 #define COMPLEX_PROP(fid,a,ctor,ber,cmp) {fid, a, PROP_TYPE_COMPLEX, ctor, ber, cmp}
287 #define E_COMPLEX_PROP(fid,a,ctor,ber,cmp) {fid, a, PROP_TYPE_COMPLEX | PROP_EVOLVE, ctor, ber, cmp}
288 #define STRING_PROP(fid,a) {fid, a, PROP_TYPE_STRING}
289 #define WRITE_ONLY_STRING_PROP(fid,a) {fid, a, PROP_TYPE_STRING | PROP_WRITE_ONLY}
290 #define E_STRING_PROP(fid,a) {fid, a, PROP_TYPE_STRING | PROP_EVOLVE}
291 #define GROUP_PROP(fid,a,ctor,ber,cmp) {fid, a, PROP_TYPE_GROUP, ctor, ber, cmp}
292 #define ADDRESS_STRING_PROP(fid,a, ctor) {fid, a, PROP_TYPE_COMPLEX, ctor}
296 STRING_PROP (E_CONTACT_FULL_NAME, "cn" ),
297 WRITE_ONLY_STRING_PROP (E_CONTACT_FAMILY_NAME, "sn" ),
299 /* email addresses */
300 COMPLEX_PROP (E_CONTACT_EMAIL, "mail", email_populate, email_ber, email_compare),
301 GROUP_PROP (E_CONTACT_EMAIL, "member", member_populate, member_ber, member_compare),
304 E_STRING_PROP (E_CONTACT_PHONE_PRIMARY, "primaryPhone"),
305 COMPLEX_PROP (E_CONTACT_PHONE_BUSINESS, "telephoneNumber", business_populate, business_ber, business_compare),
306 COMPLEX_PROP (E_CONTACT_PHONE_HOME, "homePhone", homephone_populate, homephone_ber, homephone_compare),
307 STRING_PROP (E_CONTACT_PHONE_MOBILE, "mobile"),
308 E_STRING_PROP (E_CONTACT_PHONE_CAR, "carPhone"),
309 STRING_PROP (E_CONTACT_PHONE_BUSINESS_FAX, "facsimileTelephoneNumber"),
310 E_STRING_PROP (E_CONTACT_PHONE_HOME_FAX, "homeFacsimileTelephoneNumber"),
311 E_STRING_PROP (E_CONTACT_PHONE_OTHER, "otherPhone"),
312 E_STRING_PROP (E_CONTACT_PHONE_OTHER_FAX, "otherFacsimileTelephoneNumber"),
313 STRING_PROP (E_CONTACT_PHONE_ISDN, "internationaliSDNNumber"),
314 STRING_PROP (E_CONTACT_PHONE_PAGER, "pager"),
315 E_STRING_PROP (E_CONTACT_PHONE_RADIO, "radio"),
316 E_STRING_PROP (E_CONTACT_PHONE_TELEX, "telex"),
317 E_STRING_PROP (E_CONTACT_PHONE_ASSISTANT, "assistantPhone"),
318 E_STRING_PROP (E_CONTACT_PHONE_COMPANY, "companyPhone"),
319 E_STRING_PROP (E_CONTACT_PHONE_CALLBACK, "callbackPhone"),
320 E_STRING_PROP (E_CONTACT_PHONE_TTYTDD, "tty"),
322 /* org information */
323 STRING_PROP (E_CONTACT_ORG, "o"),
324 STRING_PROP (E_CONTACT_ORG_UNIT, "ou"),
325 STRING_PROP (E_CONTACT_OFFICE, "roomNumber"),
326 STRING_PROP (E_CONTACT_TITLE, "title"),
327 E_STRING_PROP (E_CONTACT_ROLE, "businessRole"),
328 E_STRING_PROP (E_CONTACT_MANAGER, "managerName"),
329 E_STRING_PROP (E_CONTACT_ASSISTANT, "assistantName"),
332 COMPLEX_PROP (E_CONTACT_ADDRESS_LABEL_WORK, "postalAddress", work_address_populate, work_address_ber, work_address_compare),
333 ADDRESS_STRING_PROP(E_CONTACT_ADDRESS_WORK, "l", work_city_populate),
334 ADDRESS_STRING_PROP(E_CONTACT_ADDRESS_WORK, "st", work_state_populate),
335 ADDRESS_STRING_PROP(E_CONTACT_ADDRESS_WORK, "postofficebox", work_po_populate),
336 ADDRESS_STRING_PROP(E_CONTACT_ADDRESS_WORK, "postalcode", work_zip_populate),
337 ADDRESS_STRING_PROP(E_CONTACT_ADDRESS_WORK, "c", work_country_populate),
339 COMPLEX_PROP (E_CONTACT_ADDRESS_LABEL_HOME, "homePostalAddress", home_address_populate, home_address_ber, home_address_compare),
340 ADDRESS_STRING_PROP(E_CONTACT_ADDRESS_HOME, "mozillaHomeLocalityName", home_city_populate),
341 ADDRESS_STRING_PROP(E_CONTACT_ADDRESS_HOME, "mozillaHomeState", home_state_populate),
342 ADDRESS_STRING_PROP(E_CONTACT_ADDRESS_HOME, "mozillaHomePostalCode", home_zip_populate),
343 ADDRESS_STRING_PROP(E_CONTACT_ADDRESS_HOME, "mozillaHomeCountryName", home_country_populate),
345 E_COMPLEX_PROP(E_CONTACT_ADDRESS_LABEL_OTHER, "otherPostalAddress", other_address_populate, other_address_ber, other_address_compare),
348 BINARY_PROP (E_CONTACT_PHOTO, "jpegPhoto", photo_populate, photo_ber, photo_compare),
350 /* certificate foo. */
351 BINARY_PROP (E_CONTACT_X509_CERT, "userCertificate", cert_populate, NULL/*XXX*/, NULL/*XXX*/),
353 /* hm, which do we use? the inetOrgPerson schema says that
354 userSMIMECertificate should be used in favor of
355 userCertificate for S/MIME applications. */
356 BINARY_PROP (E_CONTACT_X509_CERT, "userSMIMECertificate", cert_populate, NULL/*XXX*/, NULL/*XXX*/),
360 STRING_PROP (E_CONTACT_HOMEPAGE_URL, "labeledURI"),
361 /* map nickname to displayName */
362 STRING_PROP (E_CONTACT_NICKNAME, "displayName"),
363 E_STRING_PROP (E_CONTACT_SPOUSE, "spouseName"),
364 E_STRING_PROP (E_CONTACT_NOTE, "note"),
365 E_COMPLEX_PROP (E_CONTACT_ANNIVERSARY, "anniversary", anniversary_populate, anniversary_ber, anniversary_compare),
366 E_COMPLEX_PROP (E_CONTACT_BIRTH_DATE, "birthDate", birthday_populate, birthday_ber, birthday_compare),
367 E_STRING_PROP (E_CONTACT_MAILER, "mailer"),
369 E_STRING_PROP (E_CONTACT_FILE_AS, "fileAs"),
371 E_COMPLEX_PROP (E_CONTACT_CATEGORY_LIST, "category", category_populate, category_ber, category_compare),
373 STRING_PROP (E_CONTACT_CALENDAR_URI, "calCalURI"),
374 STRING_PROP (E_CONTACT_FREEBUSY_URL, "calFBURL"),
375 STRING_PROP (E_CONTACT_ICS_CALENDAR, "icsCalendar"),
379 #undef E_COMPLEX_PROP
384 static int num_prop_infos = sizeof(prop_info) / sizeof(prop_info[0]);
388 remove_view (int msgid, LDAPOp *op, EDataBookView *view)
390 if (op->view == view)
395 view_destroy(gpointer data, GObject *where_object_was)
397 EDataBook *book = (EDataBook *)data;
398 EBookBackendLDAP *bl;
401 d(printf ("view_destroy (%p)\n", where_object_was));
403 bl = E_BOOK_BACKEND_LDAP(e_data_book_get_backend(book));
405 iter = e_list_get_iterator (bl->priv->book_views);
407 while (e_iterator_is_valid (iter)) {
408 EBookBackendLDAPBookView *view = (EBookBackendLDAPBookView*)e_iterator_get (iter);
410 if (view->book_view == (EDataBookView*)where_object_was) {
411 GNOME_Evolution_Addressbook_Book corba_book;
412 CORBA_Environment ev;
414 /* if we have an active search, interrupt it */
415 if (view->search_op) {
416 ldap_op_finished (view->search_op);
418 /* and remove us as the view for any other
419 operations that might be using us to spew
420 status messages to the gui */
421 g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
422 g_hash_table_foreach (bl->priv->id_to_op, (GHFunc)remove_view, view->book_view);
423 g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
425 /* free up the view structure */
426 g_free (view->search);
429 /* and remove it from our list */
430 e_iterator_delete (iter);
432 /* unref the book now */
433 corba_book = bonobo_object_corba_objref(BONOBO_OBJECT(book));
435 CORBA_exception_init(&ev);
437 GNOME_Evolution_Addressbook_Book_unref(corba_book, &ev);
439 if (ev._major != CORBA_NO_EXCEPTION) {
440 g_warning("view_destroy: Exception unreffing "
444 CORBA_exception_free(&ev);
448 e_iterator_next (iter);
451 g_object_unref (iter);
457 book_view_notify_status (EDataBookView *view, const char *status)
461 e_data_book_view_notify_status_message (view, status);
464 static EDataBookView*
465 find_book_view (EBookBackendLDAP *bl)
467 EList *views = e_book_backend_get_book_views (E_BOOK_BACKEND (bl));
468 EIterator *iter = e_list_get_iterator (views);
469 EDataBookView *rv = NULL;
471 if (e_iterator_is_valid (iter)) {
472 /* just always use the first book view */
473 EDataBookView *v = (EDataBookView*)e_iterator_get(iter);
478 g_object_unref (iter);
479 g_object_unref (views);
485 add_to_supported_fields (EBookBackendLDAP *bl, char **attrs, GHashTable *attr_hash)
488 for (i = 0; attrs[i]; i ++) {
489 char *query_prop = g_hash_table_lookup (attr_hash, attrs[i]);
492 bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (query_prop));
494 /* handle the list attributes here */
495 if (!strcmp (query_prop, e_contact_field_name (E_CONTACT_EMAIL))) {
496 bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_1)));
497 bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_2)));
498 bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_3)));
499 bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_4)));
501 else if (!strcmp (query_prop, e_contact_field_name (E_CONTACT_PHONE_BUSINESS))) {
502 bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_PHONE_BUSINESS_2)));
504 else if (!strcmp (query_prop, e_contact_field_name (E_CONTACT_PHONE_HOME))) {
505 bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name(E_CONTACT_PHONE_HOME_2)));
507 else if (!strcmp (query_prop, e_contact_field_name (E_CONTACT_CATEGORY_LIST) )) {
508 bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_CATEGORIES)));
516 add_oc_attributes_to_supported_fields (EBookBackendLDAP *bl, LDAPObjectClass *oc)
519 GHashTable *attr_hash = g_hash_table_new (g_str_hash, g_str_equal);
521 for (i = 0; i < num_prop_infos; i ++)
522 g_hash_table_insert (attr_hash, prop_info[i].ldap_attr, (char*)e_contact_field_name (prop_info[i].field_id));
524 if (oc->oc_at_oids_must)
525 add_to_supported_fields (bl, oc->oc_at_oids_must, attr_hash);
527 if (oc->oc_at_oids_may)
528 add_to_supported_fields (bl, oc->oc_at_oids_may, attr_hash);
530 g_hash_table_destroy (attr_hash);
534 check_schema_support (EBookBackendLDAP *bl)
539 struct timeval timeout;
541 ldap = bl->priv->ldap;
546 if (!bl->priv->schema_dn)
549 bl->priv->evolutionPersonChecked = TRUE;
551 attrs[0] = "objectClasses";
557 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
558 if (ldap_search_ext_s (ldap, bl->priv->schema_dn, LDAP_SCOPE_BASE,
559 "(objectClass=subschema)", attrs, 0,
560 NULL, NULL, &timeout, LDAP_NO_LIMIT, &resp) == LDAP_SUCCESS) {
563 values = ldap_get_values (ldap, resp, "objectClasses");
564 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
568 for (i = 0; values[i]; i ++) {
572 LDAPObjectClass *oc = ldap_str2objectclass (values[i], &code, &err, 0);
577 for (j = 0; oc->oc_names[j]; j++)
578 if (!g_ascii_strcasecmp (oc->oc_names[j], EVOLUTIONPERSON)) {
579 g_print ("support found on ldap server for objectclass evolutionPerson\n");
580 bl->priv->evolutionPersonSupported = TRUE;
582 add_oc_attributes_to_supported_fields (bl, oc);
584 else if (!g_ascii_strcasecmp (oc->oc_names[j], CALENTRY)) {
585 g_print ("support found on ldap server for objectclass calEntry\n");
586 bl->priv->calEntrySupported = TRUE;
587 add_oc_attributes_to_supported_fields (bl, oc);
589 else if (!g_ascii_strcasecmp (oc->oc_names[j], INETORGPERSON)
590 || !g_ascii_strcasecmp (oc->oc_names[j], ORGANIZATIONALPERSON)
591 || !g_ascii_strcasecmp (oc->oc_names[j], PERSON)
592 || !g_ascii_strcasecmp (oc->oc_names[j], GROUPOFNAMES)) {
593 add_oc_attributes_to_supported_fields (bl, oc);
596 ldap_objectclass_free (oc);
599 ldap_value_free (values);
602 /* the reason for this is so that if the user
603 ends up authenticating to the ldap server,
604 we will requery for the subschema values.
605 This makes it a bit more robust in the face
606 of draconian acl's that keep subschema
607 reads from working until the user is
609 if (!e_book_backend_is_writable (E_BOOK_BACKEND (bl))) {
610 g_warning ("subschema read returned nothing before successful auth");
611 bl->priv->evolutionPersonChecked = FALSE;
614 g_warning ("subschema read returned nothing after successful auth");
621 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
628 get_ldap_library_info (void)
633 ldap = ldap_init (NULL, 0);
635 g_warning ("couldn't create LDAP* for getting at the client lib api info");
639 info.ldapai_info_version = LDAP_API_INFO_VERSION;
641 if (LDAP_OPT_SUCCESS != ldap_get_option (ldap, LDAP_OPT_API_INFO, &info)) {
642 g_warning ("couldn't get ldap api info");
646 g_message ("libldap vendor/version: %s %2d.%02d.%02d",
647 info.ldapai_vendor_name,
648 info.ldapai_vendor_version / 10000,
649 (info.ldapai_vendor_version % 10000) / 1000,
650 info.ldapai_vendor_version % 1000);
652 g_message ("library extensions present:");
653 /* yuck. we have to free these? */
654 for (i = 0; info.ldapai_extensions[i]; i++) {
655 char *extension = info.ldapai_extensions[i];
656 g_message (extension);
657 ldap_memfree (extension);
659 ldap_memfree (info.ldapai_extensions);
660 ldap_memfree (info.ldapai_vendor_name);
668 query_ldap_root_dse (EBookBackendLDAP *bl)
670 #define MAX_DSE_ATTRS 20
673 int ldap_error = LDAP_OTHER;
674 char *attrs[MAX_DSE_ATTRS], **values;
676 struct timeval timeout;
678 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
679 ldap = bl->priv->ldap;
681 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
684 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
686 attrs[i++] = "supportedControl";
687 attrs[i++] = "supportedExtension";
688 attrs[i++] = "supportedFeatures";
689 attrs[i++] = "supportedSASLMechanisms";
690 attrs[i++] = "supportedLDAPVersion";
691 attrs[i++] = "subschemaSubentry"; /* OpenLDAP's dn for schema information */
692 attrs[i++] = "schemaNamingContext"; /* Active directory's dn for schema information */
698 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
699 ldap_error = ldap_search_ext_s (ldap,
700 LDAP_ROOT_DSE, LDAP_SCOPE_BASE,
702 attrs, 0, NULL, NULL, &timeout, LDAP_NO_LIMIT, &resp);
703 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
704 if (ldap_error != LDAP_SUCCESS) {
705 g_warning ("could not perform query on Root DSE (ldap_error 0x%02x)", ldap_error);
709 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
710 values = ldap_get_values (ldap, resp, "supportedControl");
711 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
713 for (i = 0; values[i]; i++)
714 g_message ("supported server control: %s", values[i]);
715 ldap_value_free (values);
718 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
719 values = ldap_get_values (ldap, resp, "supportedExtension");
720 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
722 for (i = 0; values[i]; i++) {
723 g_message ("supported server extension: %s", values[i]);
724 if (!strcmp (values[i], LDAP_EXOP_START_TLS)) {
725 g_message ("server reports LDAP_EXOP_START_TLS");
728 ldap_value_free (values);
731 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
732 values = ldap_get_values (ldap, resp, "supportedSASLMechanisms");
733 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
736 if (bl->priv->supported_auth_methods) {
737 g_list_foreach (bl->priv->supported_auth_methods, (GFunc)g_free, NULL);
738 g_list_free (bl->priv->supported_auth_methods);
740 bl->priv->supported_auth_methods = NULL;
742 auth_method = g_strdup_printf ("ldap/simple-binddn|%s", _("Using Distinguished Name (DN)"));
743 bl->priv->supported_auth_methods = g_list_append (bl->priv->supported_auth_methods, auth_method);
745 auth_method = g_strdup_printf ("ldap/simple-email|%s", _("Using Email Address"));
746 bl->priv->supported_auth_methods = g_list_append (bl->priv->supported_auth_methods, auth_method);
748 for (i = 0; values[i]; i++) {
749 auth_method = g_strdup_printf ("sasl/%s|%s", values[i], values[i]);
750 bl->priv->supported_auth_methods = g_list_append (bl->priv->supported_auth_methods, auth_method);
751 g_message ("supported SASL mechanism: %s", values[i]);
753 ldap_value_free (values);
756 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
757 values = ldap_get_values (ldap, resp, "subschemaSubentry");
758 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
759 if (!values || !values[0]) {
760 if (values) ldap_value_free (values);
761 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
762 values = ldap_get_values (ldap, resp, "schemaNamingContext");
763 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
765 if (values && values[0]) {
766 g_free (bl->priv->schema_dn);
767 bl->priv->schema_dn = g_strdup (values[0]);
770 g_warning ("could not determine location of schema information on LDAP server");
773 ldap_value_free (values);
780 static GNOME_Evolution_Addressbook_CallStatus
781 e_book_backend_ldap_connect (EBookBackendLDAP *bl)
783 EBookBackendLDAPPrivate *blpriv = bl->priv;
784 int protocol_version = LDAP_VERSION3;
792 printf ("e_book_backend_ldap_connect ... \n");
793 g_get_current_time (&start);
796 /* close connection first if it's open first */
797 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
799 ldap_unbind (blpriv->ldap);
803 if (bl->priv->use_tls != E_BOOK_BACKEND_LDAP_TLS_NO) {
804 char *evolution_dir_path =
805 g_build_path ("/", g_get_home_dir (), ".evolution", NULL);
806 ldap_flag = ldapssl_client_init (evolution_dir_path, NULL);
807 g_free (evolution_dir_path);
811 blpriv->ldap = ldap_init (blpriv->ldap_host, blpriv->ldap_port);
813 #if defined (DEBUG) && defined (LDAP_OPT_DEBUG_LEVEL)
816 ldap_set_option (blpriv->ldap, LDAP_OPT_DEBUG_LEVEL, &debug_level);
819 if (NULL != blpriv->ldap) {
822 ldap_error = ldap_set_option (blpriv->ldap, LDAP_OPT_PROTOCOL_VERSION, &protocol_version);
823 if (LDAP_SUCCESS != ldap_error) {
824 g_warning ("failed to set protocol version to LDAPv3");
825 bl->priv->ldap_v3 = FALSE;
828 bl->priv->ldap_v3 = TRUE;
830 if (bl->priv->use_tls != E_BOOK_BACKEND_LDAP_TLS_NO) {
833 if (!bl->priv->ldap_v3 && bl->priv->use_tls == E_BOOK_BACKEND_LDAP_TLS_ALWAYS) {
834 g_message ("TLS not available (fatal version), v3 protocol could not be established (ldap_error 0x%02x)", ldap_error);
835 ldap_unbind (blpriv->ldap);
837 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
838 return GNOME_Evolution_Addressbook_TLSNotAvailable;
841 if (bl->priv->ldap_port == LDAPS_PORT && bl->priv->use_tls == E_BOOK_BACKEND_LDAP_TLS_ALWAYS) {
843 if (ldap_flag >= 0) {
844 ldap_error = ldapssl_install_routines (blpriv->ldap);
846 ldap_error = LDAP_NOT_SUPPORTED;
848 if (LDAP_SUCCESS == ldap_error) {
849 ldap_error = ldap_set_option (blpriv->ldap, LDAP_OPT_SSL, LDAP_OPT_ON );
850 ldap_set_option(blpriv->ldap, LDAP_OPT_RECONNECT, LDAP_OPT_ON );
853 #if defined (LDAP_OPT_X_TLS_HARD) && defined (LDAP_OPT_X_TLS)
854 tls_level = LDAP_OPT_X_TLS_HARD;
855 ldap_set_option (blpriv->ldap, LDAP_OPT_X_TLS, &tls_level);
856 #elif defined (G_OS_WIN32)
857 tls_level = LDAP_OPT_ON;
858 ldap_set_option (blpriv->ldap, LDAP_OPT_SSL, &tls_level);
860 g_message ("TLS option not available");
864 else if (bl->priv->use_tls) {
866 if (ldap_flag >= 0) {
867 ldap_error = ldapssl_install_routines (blpriv->ldap);
869 ldap_error = LDAP_NOT_SUPPORTED;
871 if (LDAP_SUCCESS == ldap_error) {
872 ldap_error = ldap_set_option (blpriv->ldap, LDAP_OPT_SSL, LDAP_OPT_ON );
873 ldap_set_option(blpriv->ldap, LDAP_OPT_RECONNECT, LDAP_OPT_ON );
876 ldap_error = ldap_start_tls_s (blpriv->ldap, NULL, NULL);
878 if (LDAP_SUCCESS != ldap_error) {
879 if (bl->priv->use_tls == E_BOOK_BACKEND_LDAP_TLS_ALWAYS) {
880 g_message ("TLS not available (fatal version), (ldap_error 0x%02x)", ldap_error);
881 ldap_unbind (blpriv->ldap);
883 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
884 return GNOME_Evolution_Addressbook_TLSNotAvailable;
887 g_message ("TLS not available (ldap_error 0x%02x)", ldap_error);
891 g_message ("TLS active");
895 /* bind anonymously initially, we'll actually
896 authenticate the user properly later (in
897 authenticate_user) if they've selected
899 ldap_error = ldap_simple_bind_s (blpriv->ldap, NULL, NULL);
900 if (ldap_error == LDAP_PROTOCOL_ERROR) {
901 g_warning ("failed to bind using v3. trying v2.");
902 /* server doesn't support v3 binds, so let's
903 drop it down to v2 and try again. */
904 bl->priv->ldap_v3 = FALSE;
906 protocol_version = LDAP_VERSION2;
907 ldap_set_option (blpriv->ldap, LDAP_OPT_PROTOCOL_VERSION, &protocol_version);
909 ldap_error = ldap_simple_bind_s (blpriv->ldap, NULL, NULL);
912 if (ldap_error == LDAP_PROTOCOL_ERROR) {
913 g_warning ("failed to bind using either v3 or v2 binds.");
914 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
915 return GNOME_Evolution_Addressbook_OtherError;
917 else if (ldap_error == LDAP_SERVER_DOWN) {
918 /* we only want this to be fatal if the server is down. */
919 g_warning ("failed to bind anonymously while connecting (ldap_error 0x%02x)", ldap_error);
920 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
921 return GNOME_Evolution_Addressbook_RepositoryOffline;
924 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
925 ldap_error = query_ldap_root_dse (bl);
926 /* query_ldap_root_dse will cause the actual
927 connect(), so any tcpip problems will show up
930 /* we can't just check for LDAP_SUCCESS here since in
931 older servers (namely openldap1.x servers), there's
932 not a root DSE at all, so the query will fail with
933 LDAP_NO_SUCH_OBJECT, and GWIA's LDAP server (which
934 is v2 based and doesn't have a root dse) seems to
935 fail with LDAP_PARTIAL_RESULTS. */
936 if (ldap_error == LDAP_SUCCESS
937 || ldap_error == LDAP_PARTIAL_RESULTS
938 || LDAP_NAME_ERROR (ldap_error)) {
939 blpriv->connected = TRUE;
941 /* check to see if evolutionPerson is supported, if we can (me
942 might not be able to if we can't authenticate. if we
943 can't, try again in auth_user.) */
944 if (!bl->priv->evolutionPersonChecked)
945 check_schema_support (bl);
947 e_book_backend_set_is_loaded (E_BOOK_BACKEND (bl), TRUE);
950 printf ("e_book_backend_ldap_connect ... success \n");
951 g_get_current_time (&end);
952 diff = end.tv_sec * 1000 + end.tv_usec/1000;
953 diff -= start.tv_sec * 1000 + start.tv_usec/1000;
954 printf("e_book_backend_ldap_connect took %ld.%03ld seconds\n",
955 diff/1000,diff%1000);
957 return GNOME_Evolution_Addressbook_Success;
960 g_warning ("Failed to perform root dse query anonymously, (ldap_error 0x%02x)", ldap_error);
963 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
966 g_warning ("e_book_backend_ldap_connect failed for "
967 "'ldap://%s:%d/%s'\n",
970 blpriv->ldap_rootdn ? blpriv->ldap_rootdn : "");
971 blpriv->connected = FALSE;
972 return GNOME_Evolution_Addressbook_RepositoryOffline;
976 e_book_backend_ldap_reconnect (EBookBackendLDAP *bl, EDataBookView *book_view, int ldap_status)
982 printf ("e_book_backend_ldap_reconnect ... \n");
983 g_get_current_time (&start);
986 if (!bl->priv->ldap) {
988 printf ("e_book_backend_ldap_reconnect ... ldap handler is NULL\n");
992 /* we need to reconnect if we were previously connected */
993 if (bl->priv->connected && ldap_status == LDAP_SERVER_DOWN) {
994 GNOME_Evolution_Addressbook_CallStatus status;
995 int ldap_error = LDAP_SUCCESS;
998 book_view_notify_status (book_view, _("Reconnecting to LDAP server..."));
1000 status = e_book_backend_ldap_connect (bl);
1002 if (status != GNOME_Evolution_Addressbook_Success) {
1004 book_view_notify_status (book_view, "");
1006 printf ("e_book_backend_ldap_reconnect ... failed (server down?)\n");
1010 if (bl->priv->auth_dn) {
1011 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
1012 ldap_error = ldap_simple_bind_s(bl->priv->ldap,
1014 bl->priv->auth_passwd);
1015 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
1018 book_view_notify_status (book_view, "");
1021 printf ("e_book_backend_ldap_reconnect ... returning %d\n", ldap_error);
1022 g_get_current_time (&end);
1023 diff = end.tv_sec * 1000 + end.tv_usec/1000;
1024 diff -= start.tv_sec * 1000 + start.tv_usec/1000;
1025 printf("e_book_backend_ldap_reconnect took %ld.%03ld seconds\n",
1026 diff/1000,diff%1000);
1029 return (ldap_error == LDAP_SUCCESS);
1037 ldap_op_add (LDAPOp *op, EBookBackend *backend,
1038 EDataBook *book, EDataBookView *view,
1041 LDAPOpHandler handler, LDAPOpDtor dtor)
1043 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
1045 op->backend = backend;
1050 op->handler = handler;
1053 g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
1054 if (g_hash_table_lookup (bl->priv->id_to_op, &op->id)) {
1055 g_warning ("conflicting ldap msgid's");
1058 g_hash_table_insert (bl->priv->id_to_op,
1061 bl->priv->active_ops ++;
1063 if (bl->priv->poll_timeout == -1) {
1064 bl->priv->poll_timeout = g_timeout_add (LDAP_POLL_INTERVAL,
1065 (GSourceFunc) poll_ldap,
1068 g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
1072 ldap_op_finished (LDAPOp *op)
1074 EBookBackend *backend = op->backend;
1075 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
1077 g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
1078 g_hash_table_remove (bl->priv->id_to_op, &op->id);
1080 /* should handle errors here */
1081 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
1083 ldap_abandon (bl->priv->ldap, op->id);
1084 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
1089 bl->priv->active_ops--;
1091 if (bl->priv->active_ops == 0) {
1092 if (bl->priv->poll_timeout != -1)
1093 g_source_remove (bl->priv->poll_timeout);
1094 bl->priv->poll_timeout = -1;
1096 g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
1100 ldap_op_change_id (LDAPOp *op, int msg_id)
1102 EBookBackend *backend = op->backend;
1103 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
1105 g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
1106 g_hash_table_remove (bl->priv->id_to_op, &op->id);
1110 g_hash_table_insert (bl->priv->id_to_op,
1112 g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
1116 ldap_error_to_response (int ldap_error)
1118 if (ldap_error == LDAP_SUCCESS)
1119 return GNOME_Evolution_Addressbook_Success;
1120 else if (ldap_error == LDAP_INVALID_DN_SYNTAX)
1121 return GNOME_Evolution_Addressbook_OtherError;
1122 else if (LDAP_NAME_ERROR (ldap_error))
1123 return GNOME_Evolution_Addressbook_ContactNotFound;
1124 else if (ldap_error == LDAP_INSUFFICIENT_ACCESS)
1125 return GNOME_Evolution_Addressbook_PermissionDenied;
1126 else if (ldap_error == LDAP_SERVER_DOWN)
1127 return GNOME_Evolution_Addressbook_RepositoryOffline;
1128 else if (ldap_error == LDAP_ALREADY_EXISTS)
1129 return GNOME_Evolution_Addressbook_ContactIdAlreadyExists;
1131 return GNOME_Evolution_Addressbook_OtherError;
1136 create_dn_from_contact (EContact *contact, const char *root_dn)
1138 char *cn, *cn_part = NULL;
1141 cn = e_contact_get (contact, E_CONTACT_FULL_NAME);
1143 if (strchr (cn, ',')) {
1144 /* need to escape commas */
1145 char *new_cn = g_malloc0 (strlen (cn) * 3 + 1);
1148 for (i = 0, j = 0; i < strlen (cn); i ++) {
1150 sprintf (new_cn + j, "%%%02X", cn[i]);
1154 new_cn[j++] = cn[i];
1157 cn_part = g_strdup_printf ("cn=%s", new_cn);
1161 cn_part = g_strdup_printf ("cn=%s", cn);
1165 cn_part = g_strdup ("");
1168 dn = g_strdup_printf ("%s%s%s", cn_part,
1169 (root_dn && strlen(root_dn)) ? "," : "",
1170 (root_dn && strlen(root_dn)) ? root_dn: "");
1174 g_print ("generated dn: %s\n", dn);
1180 free_mods (GPtrArray *mods)
1185 while ((mod = g_ptr_array_index (mods, i++))) {
1187 g_free (mod->mod_type);
1189 if (mod->mod_op & LDAP_MOD_BVALUES && mod->mod_bvalues) {
1190 for (j = 0; mod->mod_bvalues[j]; j++) {
1191 g_free (mod->mod_bvalues[j]->bv_val);
1192 g_free (mod->mod_bvalues[j]);
1195 else if (mod->mod_values) {
1196 for (j = 0; mod->mod_values[j]; j++)
1197 g_free (mod->mod_values[j]);
1202 g_ptr_array_free (mods, TRUE);
1206 build_mods_from_contacts (EBookBackendLDAP *bl, EContact *current, EContact *new, gboolean *new_dn_needed)
1208 gboolean adding = (current == NULL), is_list = FALSE;
1209 GPtrArray *result = g_ptr_array_new();
1213 *new_dn_needed = FALSE;
1214 if (e_contact_get (new, E_CONTACT_IS_LIST))
1217 /* we walk down the list of properties we can deal with (that
1218 big table at the top of the file) */
1220 for (i = 0; i < num_prop_infos; i ++) {
1222 gboolean new_prop_present = FALSE;
1223 gboolean current_prop_present = FALSE;
1224 struct berval** new_prop_bers = NULL;
1225 char *new_prop = NULL;
1226 char *current_prop = NULL;
1228 /* XXX if it's an evolutionPerson prop and the ldap
1229 server doesn't support that objectclass, skip it. */
1230 if (prop_info[i].prop_type & PROP_EVOLVE ) {
1231 if (!bl->priv->evolutionPersonSupported)
1236 if (((prop_info[i].prop_type & PROP_TYPE_COMPLEX) ||
1237 (prop_info[i].prop_type & PROP_TYPE_BINARY)) && is_list) {
1241 /* get the value for the new contact, and compare it to
1242 the value in the current contact to see if we should
1243 update it -- if adding is TRUE, short circuit the
1245 if (prop_info[i].prop_type & PROP_TYPE_STRING) {
1246 new_prop = e_contact_get (new, prop_info[i].field_id);
1247 new_prop_present = (new_prop != NULL);
1250 new_prop_bers = prop_info[i].ber_func ? prop_info[i].ber_func (new) : NULL;
1251 new_prop_present = (new_prop_bers != NULL);
1254 /* need to set INCLUDE to true if the field needs to
1255 show up in the ldap modify request */
1257 /* if we're creating a new contact, include it if the
1258 field is there at all */
1259 if (prop_info[i].prop_type & PROP_TYPE_STRING)
1260 include = (new_prop_present && *new_prop); /* empty strings cause problems */
1262 include = new_prop_present;
1265 /* if we're modifying an existing contact,
1266 include it if the current field value is
1267 different than the new one, if it didn't
1268 exist previously, or if it's been
1270 if (prop_info[i].prop_type & PROP_TYPE_STRING) {
1271 current_prop = e_contact_get (current, prop_info[i].field_id);
1272 current_prop_present = (current_prop != NULL);
1274 if (new_prop && current_prop)
1275 include = *new_prop && strcmp (new_prop, current_prop);
1277 include = (new_prop != current_prop) && (!new_prop || *new_prop); /* empty strings cause problems */
1281 struct berval **current_prop_bers = prop_info[i].ber_func ? prop_info[i].ber_func (current) : NULL;
1283 current_prop_present = (current_prop_bers != NULL);
1285 /* free up the current_prop_bers */
1286 if (current_prop_bers) {
1287 for (j = 0; current_prop_bers[j]; j++) {
1288 g_free (current_prop_bers[j]->bv_val);
1289 g_free (current_prop_bers[j]);
1291 g_free (current_prop_bers);
1294 include = prop_info[i].compare_func ? !prop_info[i].compare_func (new, current) : FALSE;
1299 LDAPMod *mod = g_new (LDAPMod, 1);
1301 /* the included attribute has changed - we
1302 need to update the dn if it's one of the
1303 attributes we compute the dn from. */
1305 *new_dn_needed |= prop_info[i].prop_type & PROP_DN;
1308 mod->mod_op = LDAP_MOD_ADD;
1311 if (!new_prop_present)
1312 mod->mod_op = LDAP_MOD_DELETE;
1313 else if (!current_prop_present)
1314 mod->mod_op = LDAP_MOD_ADD;
1316 mod->mod_op = LDAP_MOD_REPLACE;
1319 mod->mod_type = g_strdup (prop_info[i].ldap_attr);
1321 if (prop_info[i].prop_type & PROP_TYPE_STRING) {
1322 mod->mod_values = g_new (char*, 2);
1323 mod->mod_values[0] = new_prop;
1324 mod->mod_values[1] = NULL;
1326 else { /* PROP_TYPE_COMPLEX/PROP_TYPE_GROUP */
1327 mod->mod_op |= LDAP_MOD_BVALUES;
1328 mod->mod_bvalues = new_prop_bers;
1331 g_ptr_array_add (result, mod);
1335 /* NULL terminate the list of modifications */
1336 g_ptr_array_add (result, NULL);
1341 add_objectclass_mod (EBookBackendLDAP *bl, GPtrArray *mod_array, GList *existing_objectclasses, gboolean is_list)
1343 #define FIND_INSERT(oc) \
1344 if (!g_list_find_custom (existing_objectclasses, (oc), (GCompareFunc)g_ascii_strcasecmp)) \
1345 g_ptr_array_add (objectclasses, g_strdup ((oc)))
1346 #define INSERT(oc) \
1347 g_ptr_array_add (objectclasses, g_strdup ((oc)))
1349 LDAPMod *objectclass_mod;
1350 GPtrArray *objectclasses = g_ptr_array_new();
1352 if (existing_objectclasses) {
1353 objectclass_mod = g_new (LDAPMod, 1);
1354 objectclass_mod->mod_op = LDAP_MOD_ADD;
1355 objectclass_mod->mod_type = g_strdup ("objectClass");
1357 /* yes, this is a linear search for each of our
1358 objectclasses, but really, how many objectclasses
1359 are there going to be in any sane ldap entry? */
1362 FIND_INSERT (GROUPOFNAMES);
1365 FIND_INSERT (PERSON);
1366 FIND_INSERT (ORGANIZATIONALPERSON);
1367 FIND_INSERT (INETORGPERSON);
1368 if (bl->priv->calEntrySupported)
1369 FIND_INSERT (CALENTRY);
1370 if (bl->priv->evolutionPersonSupported)
1371 FIND_INSERT (EVOLUTIONPERSON);
1374 if (objectclasses->len) {
1375 g_ptr_array_add (objectclasses, NULL);
1376 objectclass_mod->mod_values = (char**)objectclasses->pdata;
1377 g_ptr_array_add (mod_array, objectclass_mod);
1378 g_ptr_array_free (objectclasses, FALSE);
1381 g_ptr_array_free (objectclasses, TRUE);
1382 g_free (objectclass_mod->mod_type);
1383 g_free (objectclass_mod);
1387 objectclass_mod = g_new (LDAPMod, 1);
1388 objectclass_mod->mod_op = LDAP_MOD_ADD;
1389 objectclass_mod->mod_type = g_strdup ("objectClass");
1393 INSERT(GROUPOFNAMES);
1397 INSERT(ORGANIZATIONALPERSON);
1398 INSERT(INETORGPERSON);
1399 if (bl->priv->calEntrySupported)
1401 if (bl->priv->evolutionPersonSupported)
1402 INSERT(EVOLUTIONPERSON);
1404 g_ptr_array_add (objectclasses, NULL);
1405 objectclass_mod->mod_values = (char**)objectclasses->pdata;
1406 g_ptr_array_add (mod_array, objectclass_mod);
1407 g_ptr_array_free (objectclasses, FALSE);
1414 EContact *new_contact;
1418 create_contact_handler (LDAPOp *op, LDAPMessage *res)
1420 LDAPCreateOp *create_op = (LDAPCreateOp*)op;
1421 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (op->backend);
1423 char *ldap_error_msg;
1427 ldap = bl->priv->ldap;
1429 e_data_book_respond_create (op->book,
1431 GNOME_Evolution_Addressbook_OtherError,
1433 ldap_op_finished (op);
1437 if (LDAP_RES_ADD != ldap_msgtype (res)) {
1438 g_warning ("incorrect msg type %d passed to create_contact_handler", ldap_msgtype (res));
1439 e_data_book_respond_create (op->book,
1441 GNOME_Evolution_Addressbook_OtherError,
1443 ldap_op_finished (op);
1447 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
1448 ldap_parse_result (ldap, res, &ldap_error,
1449 NULL, &ldap_error_msg, NULL, NULL, 0);
1450 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
1451 if (ldap_error != LDAP_SUCCESS) {
1452 g_warning ("create_contact_handler: %02X (%s), additional info: %s",
1454 ldap_err2string (ldap_error), ldap_error_msg);
1456 if (bl->priv->cache)
1457 e_book_backend_cache_add_contact (bl->priv->cache, create_op->new_contact);
1459 ldap_memfree (ldap_error_msg);
1461 /* and lastly respond */
1462 response = ldap_error_to_response (ldap_error);
1463 e_data_book_respond_create (op->book,
1466 create_op->new_contact);
1468 ldap_op_finished (op);
1472 create_contact_dtor (LDAPOp *op)
1474 LDAPCreateOp *create_op = (LDAPCreateOp*)op;
1476 g_free (create_op->dn);
1477 g_object_unref (create_op->new_contact);
1482 e_book_backend_ldap_create_contact (EBookBackend *backend,
1487 LDAPCreateOp *create_op = g_new (LDAPCreateOp, 1);
1488 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
1489 EDataBookView *book_view;
1490 int create_contact_msgid;
1493 GPtrArray *mod_array;
1494 LDAPMod **ldap_mods;
1498 switch (bl->priv->mode) {
1500 case GNOME_Evolution_Addressbook_MODE_LOCAL :
1501 e_data_book_respond_create(book, opid, GNOME_Evolution_Addressbook_RepositoryOffline, NULL);
1503 case GNOME_Evolution_Addressbook_MODE_REMOTE :
1505 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
1506 if (!bl->priv->ldap) {
1507 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
1508 e_data_book_respond_create (book, opid, GNOME_Evolution_Addressbook_OtherError, NULL);
1511 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
1513 book_view = find_book_view (bl);
1515 printf ("Create Contact: vcard = %s\n", vcard);
1517 create_op->new_contact = e_contact_new_from_vcard (vcard);
1519 create_op->dn = create_dn_from_contact (create_op->new_contact, bl->priv->ldap_rootdn);
1520 e_contact_set (create_op->new_contact, E_CONTACT_UID, create_op->dn);
1522 /* build our mods */
1523 mod_array = build_mods_from_contacts (bl, NULL, create_op->new_contact, NULL);
1527 /* there's an illegal field in there. report
1528 UnsupportedAttribute back */
1529 e_data_book_respond_create (book,
1530 GNOME_Evolution_Addressbook_BookListener_UnsupportedField,
1533 g_free (create_op->dn);
1534 g_object_unref (create_op->new_contact);
1540 /* remove the NULL at the end */
1541 g_ptr_array_remove (mod_array, NULL);
1543 /* add our objectclass(es) */
1544 if (e_contact_get (create_op->new_contact, E_CONTACT_IS_LIST))
1545 add_objectclass_mod (bl, mod_array, NULL, TRUE);
1547 add_objectclass_mod (bl, mod_array, NULL, FALSE);
1549 /* then put the NULL back */
1550 g_ptr_array_add (mod_array, NULL);
1552 #ifdef LDAP_DEBUG_ADD
1555 printf ("Sending the following to the server as ADD\n");
1557 for (i = 0; g_ptr_array_index(mod_array, i); i ++) {
1558 LDAPMod *mod = g_ptr_array_index(mod_array, i);
1559 if (mod->mod_op & LDAP_MOD_DELETE)
1561 else if (mod->mod_op & LDAP_MOD_REPLACE)
1565 if (mod->mod_op & LDAP_MOD_BVALUES)
1570 printf (" %s:\n", mod->mod_type);
1572 if (mod->mod_op & LDAP_MOD_BVALUES) {
1574 for (j = 0; mod->mod_bvalues[j] && mod->mod_bvalues[j]->bv_val; j++)
1575 printf ("\t\t'%s'\n", mod->mod_bvalues[j]->bv_val);
1580 for (j = 0; mod->mod_values[j]; j++)
1581 printf ("\t\t'%s'\n", mod->mod_values[j]);
1587 ldap_mods = (LDAPMod**)mod_array->pdata;
1589 ldap = bl->priv->ldap;
1592 book_view_notify_status (book_view, _("Adding contact to LDAP server..."));
1593 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
1594 err = ldap_add_ext (ldap, create_op->dn, ldap_mods,
1595 NULL, NULL, &create_contact_msgid);
1596 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
1598 } while (e_book_backend_ldap_reconnect (bl, book_view, err));
1601 free_mods (mod_array);
1603 if (LDAP_SUCCESS != err) {
1604 response = ldap_error_to_response (err);
1605 e_data_book_respond_create (create_op->op.book,
1609 create_contact_dtor ((LDAPOp*)create_op);
1613 g_print ("ldap_add_ext returned %d\n", err);
1614 ldap_op_add ((LDAPOp*)create_op, backend, book,
1615 book_view, opid, create_contact_msgid,
1616 create_contact_handler, create_contact_dtor);
1628 remove_contact_handler (LDAPOp *op, LDAPMessage *res)
1630 LDAPRemoveOp *remove_op = (LDAPRemoveOp*)op;
1631 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (op->backend);
1632 char *ldap_error_msg;
1636 if (!bl->priv->ldap) {
1637 e_data_book_respond_remove_contacts (op->book, op->opid, GNOME_Evolution_Addressbook_OtherError, NULL);
1638 ldap_op_finished (op);
1642 if (LDAP_RES_DELETE != ldap_msgtype (res)) {
1643 g_warning ("incorrect msg type %d passed to remove_contact_handler", ldap_msgtype (res));
1644 e_data_book_respond_remove_contacts (op->book,
1646 GNOME_Evolution_Addressbook_OtherError,
1648 ldap_op_finished (op);
1652 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
1653 ldap_parse_result (bl->priv->ldap, res, &ldap_error,
1654 NULL, &ldap_error_msg, NULL, NULL, 0);
1655 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
1656 if (ldap_error != LDAP_SUCCESS) {
1657 g_warning ("remove_contact_handler: %02X (%s), additional info: %s",
1659 ldap_err2string (ldap_error), ldap_error_msg);
1661 /* Remove from cache too */
1662 if (bl->priv->cache)
1663 e_book_backend_cache_remove_contact (bl->priv->cache, remove_op->id);
1666 ldap_memfree (ldap_error_msg);
1668 ids = g_list_append (ids, remove_op->id);
1669 e_data_book_respond_remove_contacts (remove_op->op.book,
1671 ldap_error_to_response (ldap_error),
1677 remove_contact_dtor (LDAPOp *op)
1679 LDAPRemoveOp *remove_op = (LDAPRemoveOp*)op;
1681 g_free (remove_op->id);
1686 e_book_backend_ldap_remove_contacts (EBookBackend *backend,
1691 LDAPRemoveOp *remove_op = g_new (LDAPRemoveOp, 1);
1692 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
1693 EDataBookView *book_view;
1697 switch (bl->priv->mode) {
1699 case GNOME_Evolution_Addressbook_MODE_LOCAL :
1700 e_data_book_respond_remove_contacts (book, opid, GNOME_Evolution_Addressbook_RepositoryOffline, NULL);
1703 case GNOME_Evolution_Addressbook_MODE_REMOTE :
1704 if (!bl->priv->ldap) {
1705 e_data_book_respond_remove_contacts (book, opid, GNOME_Evolution_Addressbook_OtherError, NULL);
1710 book_view = find_book_view (bl);
1713 ** since we didn't pass "bulk-removes" in our static
1714 ** capabilities, we should only get 1 length lists here, so
1715 ** the id we're deleting is the first and only id in the list.
1717 remove_op->id = g_strdup (ids->data);
1720 book_view_notify_status (book_view, _("Removing contact from LDAP server..."));
1722 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
1723 ldap_error = ldap_delete_ext (bl->priv->ldap,
1725 NULL, NULL, &remove_msgid);
1726 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
1727 } while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
1729 if (ldap_error != LDAP_SUCCESS) {
1730 e_data_book_respond_remove_contacts (remove_op->op.book,
1732 ldap_error_to_response (ldap_error),
1734 remove_contact_dtor ((LDAPOp*)remove_op);
1738 g_print ("ldap_delete_ext returned %d\n", ldap_error);
1739 ldap_op_add ((LDAPOp*)remove_op, backend, book,
1740 book_view, opid, remove_msgid,
1741 remove_contact_handler, remove_contact_dtor);
1751 ** The modification request is actually composed of 2 separate
1752 ** requests. Since we need to get a list of theexisting objectclasses
1753 ** used by the ldap server for the entry, and since the UI only sends
1754 ** us the current contact, we need to query the ldap server for the
1755 ** existing contact.
1761 const char *id; /* the id of the contact we're modifying */
1762 EContact *current_contact;
1764 GList *existing_objectclasses;
1768 modify_contact_modify_handler (LDAPOp *op, LDAPMessage *res)
1770 LDAPModifyOp *modify_op = (LDAPModifyOp*)op;
1771 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (op->backend);
1773 char *ldap_error_msg;
1776 ldap = bl->priv->ldap;
1778 e_data_book_respond_modify (op->book,
1780 GNOME_Evolution_Addressbook_OtherError,
1782 ldap_op_finished (op);
1786 if (LDAP_RES_MODIFY != ldap_msgtype (res)) {
1787 g_warning ("incorrect msg type %d passed to modify_contact_handler", ldap_msgtype (res));
1788 e_data_book_respond_modify (op->book,
1790 GNOME_Evolution_Addressbook_OtherError,
1792 ldap_op_finished (op);
1796 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
1797 ldap_parse_result (ldap, res, &ldap_error,
1798 NULL, &ldap_error_msg, NULL, NULL, 0);
1799 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
1800 if (ldap_error != LDAP_SUCCESS) {
1801 g_warning ("modify_contact_handler: %02X (%s), additional info: %s",
1803 ldap_err2string (ldap_error), ldap_error_msg);
1805 if (bl->priv->cache)
1806 e_book_backend_cache_add_contact (bl->priv->cache, modify_op->contact);
1808 ldap_memfree (ldap_error_msg);
1810 /* and lastly respond */
1811 e_data_book_respond_modify (op->book,
1813 ldap_error_to_response (ldap_error),
1814 modify_op->contact);
1815 ldap_op_finished (op);
1819 modify_contact_search_handler (LDAPOp *op, LDAPMessage *res)
1821 LDAPModifyOp *modify_op = (LDAPModifyOp*)op;
1822 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (op->backend);
1826 ldap = bl->priv->ldap;
1828 e_data_book_respond_modify (op->book, op->opid,
1829 GNOME_Evolution_Addressbook_OtherError, NULL);
1830 ldap_op_finished (op);
1834 /* if it's successful, we should get called with a
1835 RES_SEARCH_ENTRY and a RES_SEARCH_RESULT. if it's
1836 unsuccessful, we should only see a RES_SEARCH_RESULT */
1838 msg_type = ldap_msgtype (res);
1839 if (msg_type == LDAP_RES_SEARCH_ENTRY) {
1840 LDAPMessage *e = ldap_first_entry(ldap, res);
1843 g_warning ("uh, this shouldn't happen");
1844 e_data_book_respond_modify (op->book,
1846 GNOME_Evolution_Addressbook_OtherError,
1848 ldap_op_finished (op);
1852 modify_op->current_contact = build_contact_from_entry (bl, e,
1853 &modify_op->existing_objectclasses);
1855 else if (msg_type == LDAP_RES_SEARCH_RESULT) {
1856 char *ldap_error_msg;
1858 LDAPMod **ldap_mods;
1859 GPtrArray *mod_array;
1860 gboolean differences;
1861 gboolean need_new_dn;
1862 int modify_contact_msgid;
1864 /* grab the result code, and set up the actual modify
1865 if it was successful */
1866 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
1867 ldap_parse_result (bl->priv->ldap, res, &ldap_error,
1868 NULL, &ldap_error_msg, NULL, NULL, 0);
1869 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
1870 if (ldap_error != LDAP_SUCCESS) {
1871 g_warning ("modify_contact_search_handler: %02X (%s), additional info: %s",
1873 ldap_err2string (ldap_error), ldap_error_msg);
1875 ldap_memfree (ldap_error_msg);
1877 if (ldap_error != LDAP_SUCCESS) {
1878 /* more here i'm sure */
1879 e_data_book_respond_modify (op->book,
1881 ldap_error_to_response (ldap_error),
1883 ldap_op_finished (op);
1887 /* build our mods */
1888 mod_array = build_mods_from_contacts (bl, modify_op->current_contact, modify_op->contact, &need_new_dn);
1889 differences = mod_array->len > 0;
1892 /* remove the NULL at the end */
1893 g_ptr_array_remove (mod_array, NULL);
1895 /* add our objectclass(es), making sure
1896 evolutionPerson is there if it's supported */
1897 if (e_contact_get (modify_op->current_contact, E_CONTACT_IS_LIST))
1898 add_objectclass_mod (bl, mod_array, modify_op->existing_objectclasses, TRUE);
1900 add_objectclass_mod (bl, mod_array, modify_op->existing_objectclasses, FALSE);
1902 /* then put the NULL back */
1903 g_ptr_array_add (mod_array, NULL);
1905 ldap_mods = (LDAPMod**)mod_array->pdata;
1907 #ifdef LDAP_DEBUG_MODIFY
1910 printf ("Sending the following to the server as MOD\n");
1912 for (i = 0; g_ptr_array_index(mod_array, i); i ++) {
1913 LDAPMod *mod = g_ptr_array_index(mod_array, i);
1914 if (mod->mod_op & LDAP_MOD_DELETE)
1916 else if (mod->mod_op & LDAP_MOD_REPLACE)
1920 if (mod->mod_op & LDAP_MOD_BVALUES)
1925 printf (" %s:\n", mod->mod_type);
1927 if (mod->mod_op & LDAP_MOD_BVALUES) {
1929 for (j = 0; mod->mod_bvalues[j] && mod->mod_bvalues[j]->bv_val; j++)
1930 printf ("\t\t'%s'\n", mod->mod_bvalues[j]->bv_val);
1934 for (j = 0; mod->mod_values[j]; j++)
1935 printf ("\t\t'%s'\n", mod->mod_values[j]);
1940 /* actually perform the ldap modify */
1941 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
1942 ldap_error = ldap_modify_ext (ldap, modify_op->id, ldap_mods,
1943 NULL, NULL, &modify_contact_msgid);
1944 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
1946 if (ldap_error == LDAP_SUCCESS) {
1947 op->handler = modify_contact_modify_handler;
1948 ldap_op_change_id ((LDAPOp*)modify_op,
1949 modify_contact_msgid);
1952 g_warning ("ldap_modify_ext returned %d\n", ldap_error);
1953 e_data_book_respond_modify (op->book,
1955 ldap_error_to_response (ldap_error),
1957 ldap_op_finished (op);
1958 free_mods (mod_array);
1964 free_mods (mod_array);
1967 g_warning ("unhandled result type %d returned", msg_type);
1968 e_data_book_respond_modify (op->book,
1970 GNOME_Evolution_Addressbook_OtherError,
1972 ldap_op_finished (op);
1977 modify_contact_dtor (LDAPOp *op)
1979 LDAPModifyOp *modify_op = (LDAPModifyOp*)op;
1981 g_list_foreach (modify_op->existing_objectclasses, (GFunc)g_free, NULL);
1982 g_list_free (modify_op->existing_objectclasses);
1983 if (modify_op->current_contact)
1984 g_object_unref (modify_op->current_contact);
1985 if (modify_op->contact)
1986 g_object_unref (modify_op->contact);
1991 e_book_backend_ldap_modify_contact (EBookBackend *backend,
1996 LDAPModifyOp *modify_op = g_new0 (LDAPModifyOp, 1);
1997 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
2000 int modify_contact_msgid;
2001 EDataBookView *book_view;
2004 switch (bl->priv->mode) {
2006 case GNOME_Evolution_Addressbook_MODE_LOCAL :
2007 e_data_book_respond_modify(book, opid, GNOME_Evolution_Addressbook_RepositoryOffline, NULL);
2009 case GNOME_Evolution_Addressbook_MODE_REMOTE :
2010 if (!bl->priv->ldap) {
2011 e_data_book_respond_modify (book, opid, GNOME_Evolution_Addressbook_OtherError, NULL);
2016 book_view = find_book_view (bl);
2018 printf ("Modify Contact: vcard = %s\n", vcard);
2019 modify_op->contact = e_contact_new_from_vcard (vcard);
2020 modify_op->id = e_contact_get_const (modify_op->contact, E_CONTACT_UID);
2022 ldap = bl->priv->ldap;
2025 book_view_notify_status (book_view, _("Modifying contact from LDAP server..."));
2027 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
2028 ldap_error = ldap_search_ext (ldap, modify_op->id,
2031 NULL, 0, NULL, NULL,
2032 NULL, /* XXX timeout */
2033 1, &modify_contact_msgid);
2034 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
2036 } while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
2038 if (ldap_error == LDAP_SUCCESS) {
2039 ldap_op_add ((LDAPOp*)modify_op, backend, book,
2040 book_view, opid, modify_contact_msgid,
2041 modify_contact_search_handler, modify_contact_dtor);
2044 g_warning ("ldap_search_ext returned %d\n", ldap_error);
2045 e_data_book_respond_modify (book,
2047 GNOME_Evolution_Addressbook_OtherError,
2049 modify_contact_dtor ((LDAPOp*)modify_op);
2060 get_contact_handler (LDAPOp *op, LDAPMessage *res)
2062 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (op->backend);
2064 GTimeVal start, end;
2068 printf ("get_contact_handler ... \n");
2069 g_get_current_time (&start);
2072 if (!bl->priv->ldap) {
2073 e_data_book_respond_get_contact (op->book, op->opid, GNOME_Evolution_Addressbook_OtherError, "");
2074 ldap_op_finished (op);
2076 printf ("get_contact_handler... ldap handler is NULL \n");
2080 /* the msg_type will be either SEARCH_ENTRY (if we're
2081 successful) or SEARCH_RESULT (if we're not), so we finish
2082 the op after either */
2083 msg_type = ldap_msgtype (res);
2084 if (msg_type == LDAP_RES_SEARCH_ENTRY) {
2085 LDAPMessage *e = ldap_first_entry (bl->priv->ldap, res);
2091 g_warning ("uh, this shouldn't happen");
2092 e_data_book_respond_get_contact (op->book,
2094 GNOME_Evolution_Addressbook_OtherError,
2096 ldap_op_finished (op);
2100 contact = build_contact_from_entry (bl, e, NULL);
2102 vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
2103 e_data_book_respond_get_contact (op->book,
2105 GNOME_Evolution_Addressbook_Success,
2108 g_object_unref (contact);
2109 ldap_op_finished (op);
2112 g_get_current_time (&end);
2113 diff = end.tv_sec * 1000 + end.tv_usec/1000;
2114 diff -= start.tv_sec * 1000 + start.tv_usec/1000;
2115 printf ("get_contact_handler took %ld.%03ld seconds \n",
2116 diff/1000, diff%1000);
2119 else if (msg_type == LDAP_RES_SEARCH_RESULT) {
2120 char *ldap_error_msg;
2123 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
2124 ldap_parse_result (bl->priv->ldap, res, &ldap_error,
2125 NULL, &ldap_error_msg, NULL, NULL, 0);
2126 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
2127 if (ldap_error != LDAP_SUCCESS) {
2128 g_warning ("get_contact_handler: %02X (%s), additional info: %s",
2130 ldap_err2string (ldap_error), ldap_error_msg);
2132 ldap_memfree (ldap_error_msg);
2134 e_data_book_respond_get_contact (op->book,
2136 ldap_error_to_response (ldap_error),
2138 ldap_op_finished (op);
2141 g_warning ("unhandled result type %d returned", msg_type);
2142 e_data_book_respond_get_contact (op->book,
2144 GNOME_Evolution_Addressbook_OtherError,
2146 ldap_op_finished (op);
2152 get_contact_dtor (LDAPOp *op)
2154 LDAPGetContactOp *get_contact_op = (LDAPGetContactOp*)op;
2156 g_free (get_contact_op);
2160 e_book_backend_ldap_get_contact (EBookBackend *backend,
2165 LDAPGetContactOp *get_contact_op;
2166 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
2168 int get_contact_msgid;
2169 EDataBookView *book_view;
2171 GTimeVal start, end;
2174 switch (bl->priv->mode) {
2176 case GNOME_Evolution_Addressbook_MODE_LOCAL :
2177 if (bl->priv->marked_for_offline && bl->priv->cache) {
2178 EContact *contact = e_book_backend_cache_get_contact (bl->priv->cache, id);
2182 e_data_book_respond_get_contact (book, opid, GNOME_Evolution_Addressbook_OtherError, "");
2186 vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
2188 e_data_book_respond_get_contact (book,
2190 GNOME_Evolution_Addressbook_Success,
2193 g_object_unref (contact);
2197 e_data_book_respond_get_contact(book, opid, GNOME_Evolution_Addressbook_RepositoryOffline, "");
2200 case GNOME_Evolution_Addressbook_MODE_REMOTE :
2203 printf("e_book_backend_ldap_get_contact ... \n");
2204 g_get_current_time (&start);
2206 ldap = bl->priv->ldap;
2209 e_data_book_respond_get_contact (book, opid, GNOME_Evolution_Addressbook_OtherError, "");
2211 printf("e_book_backend_ldap_get_contact ... ldap handler is NULL\n");
2215 get_contact_op = g_new0 (LDAPGetContactOp, 1);
2216 book_view = find_book_view (bl);
2219 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
2220 ldap_error = ldap_search_ext (ldap, id,
2223 NULL, 0, NULL, NULL,
2224 NULL, /* XXX timeout */
2225 1, &get_contact_msgid);
2226 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
2227 } while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
2229 if (ldap_error == LDAP_SUCCESS) {
2230 ldap_op_add ((LDAPOp*)get_contact_op, backend, book,
2231 book_view, opid, get_contact_msgid,
2232 get_contact_handler, get_contact_dtor);
2235 printf("e_book_backend_ldap_get_contact invoked get_contact_handler\n");
2236 g_get_current_time (&end);
2237 diff = end.tv_sec * 1000 + end.tv_usec/1000;
2238 diff -= start.tv_sec * 1000 + start.tv_usec/1000;
2239 printf("and took %ld.%03ld seconds\n",
2240 diff/1000, diff%1000);
2244 e_data_book_respond_get_contact (book,
2246 ldap_error_to_response (ldap_error),
2248 get_contact_dtor ((LDAPOp*)get_contact_op);
2257 } LDAPGetContactListOp;
2260 contact_list_handler (LDAPOp *op, LDAPMessage *res)
2262 LDAPGetContactListOp *contact_list_op = (LDAPGetContactListOp*)op;
2263 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (op->backend);
2267 GTimeVal start, end;
2271 printf ("contact_list_handler ...\n");
2272 g_get_current_time (&start);
2274 ldap = bl->priv->ldap;
2276 e_data_book_respond_get_contact_list (op->book, op->opid, GNOME_Evolution_Addressbook_OtherError, NULL);
2277 ldap_op_finished (op);
2279 printf ("contact_list_handler ... ldap handler is NULL \n");
2283 msg_type = ldap_msgtype (res);
2284 if (msg_type == LDAP_RES_SEARCH_ENTRY) {
2285 e = ldap_first_entry (ldap, res);
2291 contact = build_contact_from_entry (bl, e, NULL);
2293 vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
2295 printf ("vcard = %s\n", vcard);
2297 contact_list_op->contacts = g_list_append (contact_list_op->contacts,
2300 g_object_unref (contact);
2302 e = ldap_next_entry(ldap, e);
2305 else if (msg_type == LDAP_RES_SEARCH_RESULT) {
2306 char *ldap_error_msg;
2309 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
2310 ldap_parse_result (ldap, res, &ldap_error,
2311 NULL, &ldap_error_msg, NULL, NULL, 0);
2312 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
2313 if (ldap_error != LDAP_SUCCESS) {
2314 g_warning ("contact_list_handler: %02X (%s), additional info: %s",
2316 ldap_err2string (ldap_error), ldap_error_msg);
2318 ldap_memfree (ldap_error_msg);
2320 g_warning ("search returned %d\n", ldap_error);
2322 if (ldap_error == LDAP_TIMELIMIT_EXCEEDED)
2323 e_data_book_respond_get_contact_list (op->book,
2325 GNOME_Evolution_Addressbook_SearchTimeLimitExceeded,
2326 contact_list_op->contacts);
2327 else if (ldap_error == LDAP_SIZELIMIT_EXCEEDED)
2328 e_data_book_respond_get_contact_list (op->book,
2330 GNOME_Evolution_Addressbook_SearchSizeLimitExceeded,
2331 contact_list_op->contacts);
2332 else if (ldap_error == LDAP_SUCCESS)
2333 e_data_book_respond_get_contact_list (op->book,
2335 GNOME_Evolution_Addressbook_Success,
2336 contact_list_op->contacts);
2338 e_data_book_respond_get_contact_list (op->book,
2340 GNOME_Evolution_Addressbook_OtherError,
2341 contact_list_op->contacts);
2343 ldap_op_finished (op);
2345 printf ("contact_list_handler success ");
2346 g_get_current_time (&end);
2347 diff = end.tv_sec * 1000 + end.tv_usec/1000;
2348 diff -= start.tv_sec * 1000 + start.tv_usec/1000;
2349 printf("and took %ld.%03ld seconds\n", diff/1000, diff%1000);
2353 g_warning ("unhandled search result type %d returned", msg_type);
2354 e_data_book_respond_get_contact_list (op->book,
2356 GNOME_Evolution_Addressbook_OtherError,
2358 ldap_op_finished (op);
2363 contact_list_dtor (LDAPOp *op)
2365 LDAPGetContactListOp *contact_list_op = (LDAPGetContactListOp*)op;
2367 g_free (contact_list_op);
2372 e_book_backend_ldap_get_contact_list (EBookBackend *backend,
2377 LDAPGetContactListOp *contact_list_op;
2378 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
2380 int contact_list_msgid;
2381 EDataBookView *book_view;
2384 GTimeVal start, end;
2388 printf ("e_book_backend_ldap_get_contact_list ... \n");
2389 g_get_current_time (&start);
2392 switch (bl->priv->mode) {
2394 case GNOME_Evolution_Addressbook_MODE_LOCAL :
2395 if (bl->priv->marked_for_offline && bl->priv->cache) {
2397 GList *vcard_strings = NULL;
2400 contacts = e_book_backend_cache_get_contacts (bl->priv->cache, query);
2402 for (l = contacts; l; l = g_list_next (l)) {
2403 EContact *contact = l->data;
2404 vcard_strings = g_list_prepend (vcard_strings, e_vcard_to_string (E_VCARD (contact),
2405 EVC_FORMAT_VCARD_30));
2406 g_object_unref (contact);
2409 g_list_free (contacts);
2410 e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_Success, vcard_strings);
2414 e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_RepositoryOffline,
2418 case GNOME_Evolution_Addressbook_MODE_REMOTE:
2419 ldap = bl->priv->ldap;
2422 e_data_book_respond_get_contact_list (book, opid, GNOME_Evolution_Addressbook_OtherError, NULL);
2424 printf ("e_book_backend_ldap_get_contact_list... ldap handler is NULL\n");
2428 contact_list_op = g_new0 (LDAPGetContactListOp, 1);
2429 book_view = find_book_view (bl);
2431 ldap_query = e_book_backend_ldap_build_query (bl, query);
2433 printf ("getting contact list with filter: %s\n", ldap_query);
2436 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
2437 ldap_error = ldap_search_ext (ldap,
2438 bl->priv->ldap_rootdn,
2439 bl->priv->ldap_scope,
2441 NULL, 0, NULL, NULL,
2442 NULL, /* XXX timeout */
2443 LDAP_NO_LIMIT, &contact_list_msgid);
2444 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
2445 } while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
2447 g_free (ldap_query);
2449 if (ldap_error == LDAP_SUCCESS) {
2450 ldap_op_add ((LDAPOp*)contact_list_op, backend, book,
2451 book_view, opid, contact_list_msgid,
2452 contact_list_handler, contact_list_dtor);
2454 g_get_current_time (&end);
2456 diff = end.tv_sec * 1000 + end.tv_usec/1000;
2457 diff -= start.tv_sec * 1000 + start.tv_usec/1000;
2459 printf ("e_book_backend_ldap_get_contact_list invoked contact_list_handler ");
2460 printf ("and took %ld.%03ld seconds\n", diff/1000, diff%1000);
2464 e_data_book_respond_get_contact_list (book,
2466 ldap_error_to_response (ldap_error),
2468 contact_list_dtor ((LDAPOp*)contact_list_op);
2473 static EContactField email_ids[4] = {
2480 /* List property functions */
2482 email_populate(EContact *contact, char **values)
2485 for (i = 0; values[i] && i < 4; i ++)
2486 e_contact_set (contact, email_ids[i], values[i]);
2489 static struct berval**
2490 email_ber(EContact *contact)
2492 struct berval** result;
2493 const char *emails[4];
2496 if (e_contact_get (contact, E_CONTACT_IS_LIST))
2499 for (i = 0; i < 4; i ++) {
2500 emails[i] = e_contact_get (contact, email_ids[i]);
2508 result = g_new (struct berval*, num + 1);
2510 for (i = 0; i < num; i ++)
2511 result[i] = g_new (struct berval, 1);
2514 for (i = 0; i < 4; i ++) {
2516 result[j]->bv_val = g_strdup (emails[i]);
2517 result[j++]->bv_len = strlen (emails[i]);
2527 email_compare (EContact *contact1, EContact *contact2)
2529 const char *email1, *email2;
2532 if (e_contact_get (contact1, E_CONTACT_IS_LIST))
2536 for (i = 0; i < 4; i ++) {
2538 email1 = e_contact_get_const (contact1, email_ids[i]);
2539 email2 = e_contact_get_const (contact2, email_ids[i]);
2541 if (email1 && email2)
2542 equal = !strcmp (email1, email2);
2544 equal = (!!email1 == !!email2);
2555 member_populate (EContact *contact, char **values)
2558 gchar **member_info;
2560 for (i = 0; values[i]; i ++) {
2561 EVCardAttribute *attr;
2563 member_info = g_strsplit (values [i], ";", -1);
2565 attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
2566 e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_X_DEST_EMAIL), member_info [0]);
2567 e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_X_DEST_CONTACT_UID), member_info [1]);
2568 if (member_info [2])
2569 e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_X_DEST_NAME), member_info [2]);
2570 e_vcard_attribute_add_value (attr, member_info [0]);
2571 e_vcard_add_attribute (E_VCARD (contact), attr);
2575 static struct berval**
2576 member_ber (EContact *contact)
2578 struct berval** result;
2579 GList *members, *l, *p;
2583 if (!(e_contact_get (contact, E_CONTACT_IS_LIST)))
2586 members = e_contact_get_attributes (contact, E_CONTACT_EMAIL);
2587 num = g_list_length (members);
2591 result = g_new (struct berval*, num + 1);
2593 for (l = members; l != NULL; l = g_list_next (l)) {
2594 EVCardAttribute *attr = l->data;
2597 for (p = e_vcard_attribute_get_params (attr); p; p = p->next) {
2598 EVCardAttributeParam *param = p->data;
2599 const char *param_name = e_vcard_attribute_param_get_name (param);
2601 if (!g_ascii_strcasecmp (param_name, EVC_X_DEST_CONTACT_UID)) {
2602 GList *v = e_vcard_attribute_param_get_values (param);
2603 dn = v ? v->data : NULL;
2605 result[i] = g_new (struct berval, 1);
2606 result[i]->bv_val = g_strdup (dn);
2607 result[i]->bv_len = strlen (dn);
2618 member_compare (EContact *contact_new, EContact *contact_current)
2620 GList *members_new, *members_cur, *l1, *l2, *p_new, *p_cur;
2621 int len1 = 0, len2 = 0;
2622 char *list_name1, *list_name2;
2625 if (!(e_contact_get (contact_new, E_CONTACT_IS_LIST)))
2627 if (!(e_contact_get (contact_current, E_CONTACT_IS_LIST)))
2630 list_name1 = e_contact_get (contact_new, E_CONTACT_FULL_NAME);
2631 list_name2 = e_contact_get (contact_current, E_CONTACT_FULL_NAME);
2632 if (list_name1 && list_name2)
2633 equal = !strcmp (list_name1, list_name2);
2635 equal = (!!list_name1 == !!list_name2);
2640 members_new = e_contact_get_attributes (contact_new, E_CONTACT_EMAIL);
2641 len1 = g_list_length (members_new);
2642 members_cur = e_contact_get_attributes (contact_current, E_CONTACT_EMAIL);
2643 len2 = g_list_length (members_cur);
2647 for (l1 = members_new; l1 != NULL; l1 = g_list_next (l1)) {
2648 EVCardAttribute *attr_new = l1->data;
2649 char *dn_new = NULL;
2651 for (p_new = e_vcard_attribute_get_params (attr_new); p_new; p_new = p_new->next) {
2652 EVCardAttributeParam *param = p_new->data;
2653 const char *param_name1 = e_vcard_attribute_param_get_name (param);
2655 if (!g_ascii_strcasecmp (param_name1, EVC_X_DEST_CONTACT_UID)) {
2656 gboolean found = FALSE;
2657 GList *v = e_vcard_attribute_param_get_values (param);
2658 dn_new = v ? v->data : NULL;
2660 for (l2 = members_cur; l2 != NULL; l2 = g_list_next (l2)) {
2661 EVCardAttribute *attr_cur = l2->data;
2662 char *dn_cur = NULL;
2664 for (p_cur = e_vcard_attribute_get_params (attr_cur); p_cur; p_cur = p_cur->next) {
2665 EVCardAttributeParam *param2 = p_cur->data;
2666 const char *param_name2 = e_vcard_attribute_param_get_name (param2);
2668 if (!g_ascii_strcasecmp (param_name2, EVC_X_DEST_CONTACT_UID)) {
2669 GList *v2 = e_vcard_attribute_param_get_values (param2);
2670 dn_cur = v2 ? v2->data : NULL;
2673 if (!g_ascii_strcasecmp (dn_new, dn_cur)) {
2675 members_cur = g_list_remove (members_cur, attr_cur);
2695 homephone_populate(EContact *contact, char **values)
2698 e_contact_set (contact, E_CONTACT_PHONE_HOME, values[0]);
2700 e_contact_set (contact, E_CONTACT_PHONE_HOME_2, values[1]);
2704 static struct berval**
2705 homephone_ber(EContact *contact)
2707 struct berval** result;
2708 const char *homephones[3];
2712 if ((homephones[0] = e_contact_get (contact, E_CONTACT_PHONE_HOME)))
2714 if ((homephones[1] = e_contact_get (contact, E_CONTACT_PHONE_HOME_2)))
2720 result = g_new (struct berval*, num + 1);
2722 for (i = 0; i < num; i ++)
2723 result[i] = g_new (struct berval, 1);
2726 for (i = 0; i < 2; i ++) {
2727 if (homephones[i]) {
2728 result[j]->bv_val = g_strdup (homephones[i]);
2729 result[j++]->bv_len = strlen (homephones[i]);
2739 homephone_compare (EContact *contact1, EContact *contact2)
2741 int phone_ids[2] = { E_CONTACT_PHONE_HOME, E_CONTACT_PHONE_HOME_2 };
2742 const char *phone1, *phone2;
2745 for (i = 0; i < 2; i ++) {
2747 phone1 = e_contact_get (contact1, phone_ids[i]);
2748 phone2 = e_contact_get (contact2, phone_ids[i]);
2750 if (phone1 && phone2)
2751 equal = !strcmp (phone1, phone2);
2753 equal = (!!phone1 == !!phone2);
2763 business_populate(EContact *contact, char **values)
2766 e_contact_set (contact, E_CONTACT_PHONE_BUSINESS, values[0]);
2768 e_contact_set (contact, E_CONTACT_PHONE_BUSINESS_2, values[1]);
2772 static struct berval**
2773 business_ber(EContact *contact)
2775 struct berval** result;
2776 const char *business_phones[3];
2780 if ((business_phones[0] = e_contact_get (contact, E_CONTACT_PHONE_BUSINESS)))
2782 if ((business_phones[1] = e_contact_get (contact, E_CONTACT_PHONE_BUSINESS_2)))
2788 result = g_new (struct berval*, num + 1);
2790 for (i = 0; i < num; i ++)
2791 result[i] = g_new (struct berval, 1);
2794 for (i = 0; i < 2; i ++) {
2795 if (business_phones[i]) {
2796 result[j]->bv_val = g_strdup (business_phones[i]);
2797 result[j++]->bv_len = strlen (business_phones[i]);
2807 business_compare (EContact *contact1, EContact *contact2)
2809 int phone_ids[2] = { E_CONTACT_PHONE_BUSINESS, E_CONTACT_PHONE_BUSINESS_2 };
2810 const char *phone1, *phone2;
2813 for (i = 0; i < 2; i ++) {
2815 phone1 = e_contact_get (contact1, phone_ids[i]);
2816 phone2 = e_contact_get (contact2, phone_ids[i]);
2818 if (phone1 && phone2)
2819 equal = !strcmp (phone1, phone2);
2821 equal = (!!phone1 == !!phone2);
2831 anniversary_populate (EContact *contact, char **values)
2834 EContactDate *dt = e_contact_date_from_string (values[0]);
2835 e_contact_set (contact, E_CONTACT_ANNIVERSARY, dt);
2836 e_contact_date_free (dt);
2840 static struct berval**
2841 anniversary_ber (EContact *contact)
2844 struct berval** result = NULL;
2846 dt = e_contact_get (contact, E_CONTACT_ANNIVERSARY);
2851 anniversary = e_contact_date_to_string (dt);
2853 result = g_new (struct berval*, 2);
2854 result[0] = g_new (struct berval, 1);
2855 result[0]->bv_val = anniversary;
2856 result[0]->bv_len = strlen (anniversary);
2860 e_contact_date_free (dt);
2867 anniversary_compare (EContact *contact1, EContact *contact2)
2869 EContactDate *dt1, *dt2;
2872 dt1 = e_contact_get (contact1, E_CONTACT_ANNIVERSARY);
2873 dt2 = e_contact_get (contact2, E_CONTACT_ANNIVERSARY);
2875 equal = e_contact_date_equal (dt1, dt2);
2877 e_contact_date_free (dt1);
2878 e_contact_date_free (dt2);
2884 birthday_populate (EContact *contact, char **values)
2887 EContactDate *dt = e_contact_date_from_string (values[0]);
2888 e_contact_set (contact, E_CONTACT_BIRTH_DATE, dt);
2889 e_contact_date_free (dt);
2893 static struct berval**
2894 birthday_ber (EContact *contact)
2897 struct berval** result = NULL;
2899 dt = e_contact_get (contact, E_CONTACT_BIRTH_DATE);
2903 birthday = e_contact_date_to_string (dt);
2905 result = g_new (struct berval*, 2);
2906 result[0] = g_new (struct berval, 1);
2907 result[0]->bv_val = birthday;
2908 result[0]->bv_len = strlen (birthday);
2912 e_contact_date_free (dt);
2919 birthday_compare (EContact *contact1, EContact *contact2)
2921 EContactDate *dt1, *dt2;
2924 dt1 = e_contact_get (contact1, E_CONTACT_BIRTH_DATE);
2925 dt2 = e_contact_get (contact2, E_CONTACT_BIRTH_DATE);
2927 equal = e_contact_date_equal (dt1, dt2);
2929 e_contact_date_free (dt1);
2930 e_contact_date_free (dt2);
2936 category_populate (EContact *contact, char **values)
2939 GList *categories = NULL;
2941 for (i = 0; values[i]; i++)
2942 categories = g_list_append (categories, g_strdup (values[i]));
2944 e_contact_set (contact, E_CONTACT_CATEGORY_LIST, categories);
2946 g_list_foreach (categories, (GFunc)g_free, NULL);
2947 g_list_free (categories);
2950 static struct berval**
2951 category_ber (EContact *contact)
2953 struct berval** result = NULL;
2955 const char *category_string;
2957 category_string = e_contact_get (contact, E_CONTACT_CATEGORIES);
2958 if (!category_string || !*category_string)
2961 categories = e_contact_get (contact, E_CONTACT_CATEGORY_LIST);
2963 if (g_list_length (categories) != 0) {
2966 result = g_new0 (struct berval*, g_list_length (categories) + 1);
2968 for (iter = categories, i = 0; iter; iter = iter->next) {
2969 char *category = iter->data;
2971 if (category && *category) {
2972 result[i] = g_new (struct berval, 1);
2973 result[i]->bv_val = g_strdup (category);
2974 result[i]->bv_len = strlen (category);
2980 g_list_foreach (categories, (GFunc)g_free, NULL);
2981 g_list_free (categories);
2986 category_compare (EContact *contact1, EContact *contact2)
2988 const char *categories1, *categories2;
2991 categories1 = e_contact_get_const (contact1, E_CONTACT_CATEGORIES);
2992 categories2 = e_contact_get_const (contact2, E_CONTACT_CATEGORIES);
2994 if (categories1 && categories2)
2995 equal = !strcmp (categories1, categories2);
2997 equal = (categories1 == categories2);
3002 static EContactAddress * getormakeEContactAddress(EContact * card, EContactField field)
3004 EContactAddress *contact_addr = e_contact_get(card, field);
3006 contact_addr = g_new0(EContactAddress, 1);
3007 return contact_addr;
3013 address_populate(EContact * card, char **values, EContactField field, EContactField other_field)
3016 EContactAddress *contact_addr;
3017 char *temp = g_strdup(values[0]);
3019 for (i = temp; *i != '\0'; i++) {
3024 e_contact_set(card, field, temp);
3026 contact_addr = getormakeEContactAddress(card, other_field);
3027 contact_addr->street = g_strdup (temp);
3028 e_contact_set (card, other_field, contact_addr);
3029 e_contact_address_free (contact_addr);
3036 work_city_populate(EContact * card, char **values)
3038 EContactAddress *contact_addr = getormakeEContactAddress(card, E_CONTACT_ADDRESS_WORK);
3039 contact_addr->locality = g_strdup (values[0]);
3040 e_contact_set (card, E_CONTACT_ADDRESS_WORK, contact_addr);
3041 e_contact_address_free (contact_addr);
3045 work_state_populate(EContact * card, char **values)
3047 EContactAddress *contact_addr = getormakeEContactAddress(card, E_CONTACT_ADDRESS_WORK);
3048 contact_addr->region = g_strdup (values[0]);
3049 e_contact_set (card, E_CONTACT_ADDRESS_WORK, contact_addr);
3050 e_contact_address_free (contact_addr);
3054 work_po_populate(EContact * card, char **values)
3056 EContactAddress *contact_addr = getormakeEContactAddress(card, E_CONTACT_ADDRESS_WORK);
3057 contact_addr->po = g_strdup (values[0]);
3058 e_contact_set (card, E_CONTACT_ADDRESS_WORK, contact_addr);
3059 e_contact_address_free (contact_addr);
3063 work_zip_populate(EContact * card, char **values)
3065 EContactAddress *contact_addr = getormakeEContactAddress(card, E_CONTACT_ADDRESS_WORK);
3066 contact_addr->code = g_strdup (values[0]);
3067 e_contact_set (card, E_CONTACT_ADDRESS_WORK, contact_addr);
3068 e_contact_address_free (contact_addr);
3072 work_country_populate(EContact * card, char **values)
3074 EContactAddress *contact_addr = getormakeEContactAddress(card, E_CONTACT_ADDRESS_WORK);
3075 contact_addr->country = g_strdup (values[0]);
3076 e_contact_set (card, E_CONTACT_ADDRESS_WORK, contact_addr);
3077 e_contact_address_free (contact_addr);
3081 home_city_populate(EContact * card, char **values)
3083 EContactAddress *contact_addr = getormakeEContactAddress(card, E_CONTACT_ADDRESS_HOME);
3084 contact_addr->locality = g_strdup (values[0]);
3085 e_contact_set (card, E_CONTACT_ADDRESS_HOME, contact_addr);
3086 e_contact_address_free (contact_addr);
3090 home_state_populate(EContact * card, char **values)
3092 EContactAddress *contact_addr = getormakeEContactAddress(card, E_CONTACT_ADDRESS_HOME);
3093 contact_addr->region = g_strdup (values[0]);
3094 e_contact_set (card, E_CONTACT_ADDRESS_HOME, contact_addr);
3095 e_contact_address_free (contact_addr);
3099 home_zip_populate(EContact * card, char **values)
3101 EContactAddress *contact_addr = getormakeEContactAddress(card, E_CONTACT_ADDRESS_HOME);
3102 contact_addr->code = g_strdup (values[0]);
3103 e_contact_set (card, E_CONTACT_ADDRESS_HOME, contact_addr);
3104 e_contact_address_free (contact_addr);
3108 home_country_populate(EContact * card, char **values)
3110 EContactAddress *contact_addr = getormakeEContactAddress(card, E_CONTACT_ADDRESS_HOME);
3111 contact_addr->country = g_strdup (values[0]);
3112 e_contact_set (card, E_CONTACT_ADDRESS_HOME, contact_addr);
3113 e_contact_address_free (contact_addr);
3117 home_address_populate(EContact * card, char **values)
3119 address_populate(card, values, E_CONTACT_ADDRESS_LABEL_HOME, E_CONTACT_ADDRESS_HOME);
3123 work_address_populate(EContact * card, char **values)
3125 address_populate(card, values, E_CONTACT_ADDRESS_LABEL_WORK, E_CONTACT_ADDRESS_WORK);
3129 other_address_populate(EContact * card, char **values)
3131 address_populate(card, values, E_CONTACT_ADDRESS_LABEL_OTHER, E_CONTACT_ADDRESS_OTHER);
3134 static struct berval **
3135 address_ber(EContact * card, EContactField field)
3137 struct berval **result = NULL;
3140 address = e_contact_get(card, field);
3142 for (i = address; *i != '\0'; i++) {
3148 result = g_new(struct berval *, 2);
3149 result[0] = g_new(struct berval, 1);
3150 result[0]->bv_val = address;
3151 result[0]->bv_len = strlen(address);
3158 static struct berval **
3159 home_address_ber(EContact * card)
3161 return address_ber(card, E_CONTACT_ADDRESS_LABEL_HOME);
3164 static struct berval **
3165 work_address_ber(EContact * card)
3167 return address_ber(card, E_CONTACT_ADDRESS_LABEL_WORK);
3170 static struct berval **
3171 other_address_ber(EContact * card)
3173 return address_ber(card, E_CONTACT_ADDRESS_LABEL_OTHER);
3177 address_compare(EContact * ecard1, EContact * ecard2, EContactField field)
3179 const char *address1, *address2;
3182 address1 = e_contact_get_const(ecard1, field);
3183 address2 = e_contact_get_const(ecard2, field);
3185 if (address1 && address2)
3186 equal = !strcmp(address1, address2);
3188 equal = (!!address1 == !!address2);
3194 home_address_compare(EContact * ecard1, EContact * ecard2)
3196 return address_compare(ecard1, ecard2, E_CONTACT_ADDRESS_LABEL_HOME);
3200 work_address_compare(EContact * ecard1, EContact * ecard2)
3202 return address_compare(ecard1, ecard2, E_CONTACT_ADDRESS_LABEL_WORK);
3206 other_address_compare(EContact * ecard1, EContact * ecard2)
3208 return address_compare(ecard1, ecard2, E_CONTACT_ADDRESS_LABEL_OTHER);
3212 photo_populate (EContact *contact, struct berval **ber_values)
3214 if (ber_values && ber_values[0]) {
3215 EContactPhoto photo;
3216 photo.type = E_CONTACT_PHOTO_TYPE_INLINED;
3217 photo.data.inlined.mime_type = NULL;
3218 photo.data.inlined.data = (guchar*)ber_values[0]->bv_val;
3219 photo.data.inlined.length = ber_values[0]->bv_len;
3221 e_contact_set (contact, E_CONTACT_PHOTO, &photo);
3225 static struct berval **
3226 photo_ber (EContact *contact)
3228 struct berval **result = NULL;
3229 EContactPhoto *photo;
3231 photo = e_contact_get(contact, E_CONTACT_PHOTO);
3232 if (photo && photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
3234 result = g_new(struct berval *, 2);
3235 result[0] = g_new(struct berval, 1);
3236 result[0]->bv_len = photo->data.inlined.length;
3237 result[0]->bv_val = g_malloc (photo->data.inlined.length);
3238 memcpy (result[0]->bv_val, photo->data.inlined.data, photo->data.inlined.length);
3239 e_contact_photo_free (photo);
3248 photo_compare(EContact * ecard1, EContact * ecard2)
3250 EContactPhoto *photo1, *photo2;
3253 photo1 = e_contact_get(ecard1, E_CONTACT_PHOTO);
3254 photo2 = e_contact_get(ecard2, E_CONTACT_PHOTO);
3257 if (photo1 && photo2) {
3258 if (photo1->type == photo2->type && photo1->type == E_CONTACT_PHOTO_TYPE_INLINED) {
3259 equal = ((photo1->data.inlined.length == photo2->data.inlined.length)
3260 && !memcmp (photo1->data.inlined.data, photo2->data.inlined.data, photo1->data.inlined.length));
3261 } else if (photo1->type == photo2->type && photo1->type == E_CONTACT_PHOTO_TYPE_URI) {
3263 equal = !strcmp (photo1->data.uri, photo2->data.uri);
3270 equal = (!!photo1 == !!photo2);
3274 e_contact_photo_free (photo1);
3276 e_contact_photo_free (photo2);
3282 cert_populate (EContact *contact, struct berval **ber_values)
3284 if (ber_values && ber_values[0]) {
3286 cert.data = ber_values[0]->bv_val;
3287 cert.length = ber_values[0]->bv_len;
3289 e_contact_set (contact, E_CONTACT_X509_CERT, &cert);
3295 EBookBackendLDAP *bl;
3296 } EBookBackendLDAPSExpData;
3298 #define IS_RFC2254_CHAR(c) ((c) == '*' || (c) =='\\' || (c) == '(' || (c) == ')' || (c) == '\0')
3300 rfc2254_escape(char *str)
3303 int len = strlen(str);
3306 for (i = 0; i < len; i ++) {
3307 if (IS_RFC2254_CHAR(str[i]))
3313 if (len == newlen) {
3314 return g_strdup (str);
3317 char *newstr = g_malloc0 (newlen + 1);
3319 for (i = 0; i < len; i ++) {
3320 if (IS_RFC2254_CHAR(str[i])) {
3321 sprintf (newstr + j, "\\%02x", str[i]);
3325 newstr[j++] = str[i];
3332 static ESExpResult *
3333 func_and(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
3335 EBookBackendLDAPSExpData *ldap_data = data;
3342 strings = g_new0(char*, argc+3);
3343 strings[0] = g_strdup ("(&");
3344 strings[argc+3 - 2] = g_strdup (")");
3346 for (i = 0; i < argc; i ++) {
3347 GList *list_head = ldap_data->list;
3350 strings[argc - i] = list_head->data;
3351 ldap_data->list = g_list_remove_link(list_head, list_head);
3352 g_list_free_1(list_head);
3355 ldap_data->list = g_list_prepend(ldap_data->list, g_strjoinv(" ", strings));
3357 for (i = 0 ; i < argc + 2; i ++)
3358 g_free (strings[i]);
3363 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
3364 r->value.bool = FALSE;
3369 static ESExpResult *
3370 func_or(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
3372 EBookBackendLDAPSExpData *ldap_data = data;
3379 strings = g_new0(char*, argc+3);
3380 strings[0] = g_strdup ("(|");
3381 strings[argc+3 - 2] = g_strdup (")");
3383 for (i = 0; i < argc; i ++) {
3384 GList *list_head = ldap_data->list;
3387 strings[argc - i] = list_head->data;
3388 ldap_data->list = g_list_remove_link(list_head, list_head);
3389 g_list_free_1(list_head);
3392 ldap_data->list = g_list_prepend(ldap_data->list, g_strjoinv(" ", strings));
3394 for (i = 0 ; i < argc + 2; i ++)
3395 g_free (strings[i]);
3400 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
3401 r->value.bool = FALSE;
3406 static ESExpResult *
3407 func_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
3409 EBookBackendLDAPSExpData *ldap_data = data;
3412 /* just replace the head of the list with the NOT of it. */
3414 char *term = ldap_data->list->data;
3415 ldap_data->list->data = g_strdup_printf("(!%s)", term);
3419 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
3420 r->value.bool = FALSE;
3425 static ESExpResult *
3426 func_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
3428 EBookBackendLDAPSExpData *ldap_data = data;
3432 && argv[0]->type == ESEXP_RES_STRING
3433 && argv[1]->type == ESEXP_RES_STRING) {
3434 char *propname = argv[0]->value.string;
3435 char *str = rfc2254_escape(argv[1]->value.string);
3436 gboolean one_star = FALSE;
3438 if (strlen(str) == 0)
3441 if (!strcmp (propname, "x-evolution-any-field")) {
3447 /* ignore NULL query */
3448 r = e_sexp_result_new (f, ESEXP_RES_BOOL);
3449 r->value.bool = FALSE;
3453 match_str = g_strdup_printf ("=*%s*)", str);
3455 query_length = 3; /* strlen ("(|") + strlen (")") */
3457 for (i = 0; i < num_prop_infos; i ++) {
3458 query_length += 1 /* strlen ("(") */ + strlen(prop_info[i].ldap_attr) + strlen (match_str);
3461 big_query = g_malloc0(query_length + 1);
3462 strcat (big_query, "(|");
3463 for (i = 0; i < num_prop_infos; i ++) {
3464 strcat (big_query, "(");
3465 strcat (big_query, prop_info[i].ldap_attr);
3466 strcat (big_query, match_str);
3468 strcat (big_query, ")");
3470 ldap_data->list = g_list_prepend(ldap_data->list, big_query);
3475 char *ldap_attr = query_prop_to_ldap(propname);
3478 ldap_data->list = g_list_prepend(ldap_data->list,
3479 g_strdup_printf("(%s=*%s%s)",
3482 one_star ? "" : "*"));
3488 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
3489 r->value.bool = FALSE;
3494 static ESExpResult *
3495 func_is(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
3497 EBookBackendLDAPSExpData *ldap_data = data;
3501 && argv[0]->type == ESEXP_RES_STRING
3502 && argv[1]->type == ESEXP_RES_STRING) {
3503 char *propname = argv[0]->value.string;
3504 char *str = rfc2254_escape(argv[1]->value.string);
3505 char *ldap_attr = query_prop_to_ldap(propname);
3508 ldap_data->list = g_list_prepend(ldap_data->list,
3509 g_strdup_printf("(%s=%s)",
3512 g_warning ("unknown query property\n");
3513 /* we want something that'll always be false */
3514 ldap_data->list = g_list_prepend(ldap_data->list,
3515 g_strdup("objectClass=MyBarnIsBiggerThanYourBarn"));
3521 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
3522 r->value.bool = FALSE;
3527 static ESExpResult *
3528 func_beginswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
3530 EBookBackendLDAPSExpData *ldap_data = data;
3534 && argv[0]->type == ESEXP_RES_STRING
3535 && argv[1]->type == ESEXP_RES_STRING) {
3536 char *propname = argv[0]->value.string;
3537 char *str = rfc2254_escape(argv[1]->value.string);
3538 char *ldap_attr = query_prop_to_ldap(propname);
3540 if (strlen (str) == 0) {
3541 r = e_sexp_result_new (f, ESEXP_RES_BOOL);
3542 r->value.bool = FALSE;
3546 /* insert hack for fileAs queries, since we need to do
3547 the right thing if the server supports them or not,
3548 and for entries that have no fileAs attribute. */
3550 if (!strcmp (propname, "full_name")) {
3551 ldap_data->list = g_list_prepend(ldap_data->list,
3553 "(|(cn=%s*)(sn=%s*))",
3556 else if (!strcmp (ldap_attr, "fileAs")) {
3557 if (ldap_data->bl->priv->evolutionPersonSupported)
3558 ldap_data->list = g_list_prepend(ldap_data->list,
3559 g_strdup_printf("(|(fileAs=%s*)(&(!(fileAs=*))(sn=%s*)))",
3562 ldap_data->list = g_list_prepend(ldap_data->list,
3563 g_strdup_printf("(sn=%s*)", str));
3566 ldap_data->list = g_list_prepend(ldap_data->list,
3567 g_strdup_printf("(%s=%s*)",
3576 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
3577 r->value.bool = FALSE;
3582 static ESExpResult *
3583 func_endswith(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
3585 EBookBackendLDAPSExpData *ldap_data = data;
3589 && argv[0]->type == ESEXP_RES_STRING
3590 && argv[1]->type == ESEXP_RES_STRING) {
3591 char *propname = argv[0]->value.string;
3592 char *str = rfc2254_escape(argv[1]->value.string);
3593 char *ldap_attr = query_prop_to_ldap(propname);
3596 ldap_data->list = g_list_prepend(ldap_data->list,
3597 g_strdup_printf("(%s=*%s)",
3603 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
3604 r->value.bool = FALSE;
3609 static ESExpResult *
3610 func_exists(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
3612 EBookBackendLDAPSExpData *ldap_data = data;
3616 && argv[0]->type == ESEXP_RES_STRING) {
3617 char *propname = argv[0]->value.string;
3619 if (!strcmp (propname, "x-evolution-any-field")) {
3625 match_str = g_strdup("=*)");
3627 query_length = 3; /* strlen ("(|") + strlen (")") */
3629 for (i = 0; i < num_prop_infos; i ++) {
3630 query_length += 1 /* strlen ("(") */ + strlen(prop_info[i].ldap_attr) + strlen (match_str);
3633 big_query = g_malloc0(query_length + 1);
3634 strcat (big_query, "(|");
3635 for (i = 0; i < num_prop_infos; i ++) {
3636 strcat (big_query, "(");
3637 strcat (big_query, prop_info[i].ldap_attr);
3638 strcat (big_query, match_str);
3640 strcat (big_query, ")");
3642 ldap_data->list = g_list_prepend(ldap_data->list, big_query);
3647 char *ldap_attr = query_prop_to_ldap(propname);
3650 ldap_data->list = g_list_prepend(ldap_data->list,
3651 g_strdup_printf("(%s=*)", ldap_attr));
3655 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
3656 r->value.bool = FALSE;
3661 /* 'builtin' functions */
3665 int type; /* set to 1 if a function can perform shortcut evaluation, or
3666 doesn't execute everything, 0 otherwise */
3668 { "and", func_and, 0 },
3669 { "or", func_or, 0 },
3670 { "not", func_not, 0 },
3671 { "contains", func_contains, 0 },
3672 { "is", func_is, 0 },
3673 { "beginswith", func_beginswith, 0 },
3674 { "endswith", func_endswith, 0 },
3675 { "exists", func_exists, 0 },
3679 e_book_backend_ldap_build_query (EBookBackendLDAP *bl, const char *query)
3684 EBookBackendLDAPSExpData data;
3691 sexp = e_sexp_new();
3693 for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) {
3694 if (symbols[i].type == 1) {
3695 e_sexp_add_ifunction(sexp, 0, symbols[i].name,
3696 (ESExpIFunc *)symbols[i].func, &data);
3698 e_sexp_add_function(sexp, 0, symbols[i].name,
3699 symbols[i].func, &data);
3703 e_sexp_input_text(sexp, query, strlen(query));
3706 r = e_sexp_eval(sexp);
3708 e_sexp_result_free(sexp, r);
3709 e_sexp_unref (sexp);
3712 if (data.list->next) {
3713 g_warning ("conversion to ldap query string failed");
3715 g_list_foreach (data.list, (GFunc)g_free, NULL);
3718 if (bl->priv->ldap_search_filter && *bl->priv->ldap_search_filter) {
3719 strings = g_new0(char*, 5);
3720 strings[0] = g_strdup ("(&");
3721 strings[1] = g_strdup_printf ("%s", bl->priv->ldap_search_filter);
3722 strings[2] = data.list->data;
3723 strings[3] = g_strdup (")");
3724 retval = g_strjoinv (" ", strings);
3725 for (i = 0 ; i < 4; i ++)
3726 g_free (strings[i]);
3730 retval = g_strdup (data.list->data);
3735 g_warning ("conversion to ldap query string failed");
3739 g_list_free (data.list);
3744 query_prop_to_ldap(gchar *query_prop)
3748 for (i = 0; i < num_prop_infos; i ++)
3749 if (!strcmp (query_prop, e_contact_field_name (prop_info[i].field_id)))
3750 return prop_info[i].ldap_attr;
3757 EDataBookView *view;
3759 /* used to detect problems with start/stop_book_view racing */
3761 /* used by search_handler to only send the status messages once */
3762 gboolean notified_receiving_results;
3766 build_contact_from_entry (EBookBackendLDAP *bl,
3768 GList **existing_objectclasses)
3770 EContact *contact = e_contact_new ();
3773 BerElement *ber = NULL;
3776 ldap = bl->priv->ldap;
3777 dn = ldap_get_dn (ldap, e);
3778 e_contact_set (contact, E_CONTACT_UID, dn);
3781 for (attr = ldap_first_attribute (ldap, e, &ber); attr;
3782 attr = ldap_next_attribute (ldap, e, ber)) {
3784 struct prop_info *info = NULL;
3787 printf ("attr = %s \n", attr);
3788 if (!g_ascii_strcasecmp (attr, "objectclass")) {
3789 values = ldap_get_values (ldap, e, attr);
3790 for (i = 0; values[i]; i ++) {
3791 printf ("value = %s\n", values[i]);
3792 if (!g_ascii_strcasecmp (values[i], "groupOfNames")) {
3793 e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
3794 e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, GINT_TO_POINTER (TRUE));
3796 if (existing_objectclasses)
3797 *existing_objectclasses = g_list_append (*existing_objectclasses, g_strdup (values[i]));
3799 ldap_value_free (values);
3802 for (i = 0; i < num_prop_infos; i ++)
3803 if (!g_ascii_strcasecmp (attr, prop_info[i].ldap_attr)) {
3804 info = &prop_info[i];
3808 printf ("info = %p\n", info);
3811 if (info->prop_type & PROP_WRITE_ONLY)
3814 if (info->prop_type & PROP_TYPE_BINARY) {
3815 struct berval **ber_values = ldap_get_values_len (ldap, e, attr);
3818 info->binary_populate_contact_func (contact, ber_values);
3820 ldap_value_free_len (ber_values);
3824 values = ldap_get_values (ldap, e, attr);
3827 if (info->prop_type & PROP_TYPE_STRING) {
3828 printf ("value = %s\n", values[0]);
3829 /* if it's a normal property just set the string */
3831 e_contact_set (contact, info->field_id, values[0]);
3833 else if (info->prop_type & PROP_TYPE_COMPLEX) {
3834 /* if it's a list call the contact-populate function,
3835 which calls g_object_set to set the property */
3836 info->populate_contact_func(contact,
3839 else if (info->prop_type & PROP_TYPE_GROUP) {
3841 int j, view_limit = -1, ldap_error, count;
3842 EDataBookView *book_view;
3843 LDAPMessage *result;
3844 char **email_values, **cn_values, **member_info;
3847 grpattrs[1] = "mail";
3849 /* search for member attributes */
3850 /* get the e-mail id for each member and add them to the list */
3852 book_view = find_book_view (bl);
3854 view_limit = e_data_book_view_get_max_results (book_view);
3855 if (view_limit == -1 || view_limit > bl->priv->ldap_limit)
3856 view_limit = bl->priv->ldap_limit;
3858 count = ldap_count_values (values);
3859 member_info = g_new0 (gchar *, count+1);
3861 for (j = 0; values[j] ; j ++) {
3862 /* get the email id for the given dn */
3863 /* set base to DN and scope to base */
3864 printf ("value (dn) = %s \n", values [j]);
3866 if ((ldap_error = ldap_search_ext_s (bl->priv->ldap,
3875 &result)) == LDAP_SUCCESS) {
3876 /* find the e-mail ids of members */
3877 cn_values = ldap_get_values (ldap, result, "cn");
3878 email_values = ldap_get_values (ldap, result, "mail");
3881 printf ("email = %s \n", email_values[0]);
3882 *(member_info + j) =
3883 g_strdup_printf ("%s;%s;",
3884 email_values[0], values[j]);
3885 ldap_value_free (email_values);
3888 printf ("cn = %s \n", cn_values[0]);
3889 *(member_info + j) =
3890 g_strconcat (*(member_info + j),
3891 cn_values [0], NULL);
3892 ldap_value_free (cn_values);
3896 while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
3898 if (ldap_error != LDAP_SUCCESS) {
3899 book_view_notify_status (book_view,
3900 ldap_err2string(ldap_error));
3904 /* call populate function */
3905 info->populate_contact_func (contact, member_info);
3907 for (j = 0; j < count; j++) {
3908 g_free (*(member_info + j));
3910 g_free (member_info);
3913 ldap_value_free (values);
3919 ldap_memfree (attr);
3929 poll_ldap (EBookBackendLDAP *bl)
3934 struct timeval timeout;
3935 const char *ldap_timeout_string;
3937 ldap = bl->priv->ldap;
3939 bl->priv->poll_timeout = -1;
3943 if (!bl->priv->active_ops) {
3944 g_warning ("poll_ldap being called for backend with no active operations");
3945 bl->priv->poll_timeout = -1;
3950 ldap_timeout_string = g_getenv ("LDAP_TIMEOUT");
3951 if (ldap_timeout_string) {
3952 timeout.tv_usec = g_ascii_strtod (ldap_timeout_string, NULL) * 1000;
3955 timeout.tv_usec = LDAP_RESULT_TIMEOUT_MILLIS * 1000;
3957 rc = ldap_result (ldap, LDAP_RES_ANY, 0, &timeout, &res);
3958 if (rc != 0) {/* rc == 0 means timeout exceeded */
3960 EDataBookView *book_view = find_book_view (bl);
3961 g_warning ("ldap_result returned -1, restarting ops");
3963 e_book_backend_ldap_reconnect (bl, book_view, LDAP_SERVER_DOWN);
3965 if (bl->priv->connected)
3970 int msgid = ldap_msgid (res);
3973 g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
3974 op = g_hash_table_lookup (bl->priv->id_to_op, &msgid);
3976 d(printf ("looked up msgid %d, got op %p\n", msgid, op));
3978 if (op && op->handler)
3979 op->handler (op, res);
3981 g_warning ("unknown operation, msgid = %d", msgid);
3983 /* XXX should the call to op->handler be
3984 protected by the lock? */
3985 g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
3995 ldap_search_handler (LDAPOp *op, LDAPMessage *res)
3997 LDAPSearchOp *search_op = (LDAPSearchOp*)op;
3998 EDataBookView *view = search_op->view;
3999 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (op->backend);
4003 GTimeVal start, end;
4006 d(printf ("ldap_search_handler (%p)\n", view));
4008 g_get_current_time(&start);
4010 ldap = bl->priv->ldap;
4012 e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_OtherError);
4013 ldap_op_finished (op);
4015 printf ("ldap_search_handler... ldap handler is NULL \n");
4019 if (!search_op->notified_receiving_results) {
4020 search_op->notified_receiving_results = TRUE;
4021 book_view_notify_status (op->view, _("Receiving LDAP search results..."));
4024 msg_type = ldap_msgtype (res);
4025 if (msg_type == LDAP_RES_SEARCH_ENTRY) {
4026 e = ldap_first_entry (ldap, res);
4029 EContact *contact = build_contact_from_entry (bl, e, NULL);
4031 e_data_book_view_notify_update (view, contact);
4032 g_object_unref (contact);
4034 e = ldap_next_entry(ldap, e);
4037 else if (msg_type == LDAP_RES_SEARCH_RESULT) {
4038 char *ldap_error_msg;
4041 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
4042 ldap_parse_result (ldap, res, &ldap_error,
4043 NULL, &ldap_error_msg, NULL, NULL, 0);
4044 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
4045 if (ldap_error != LDAP_SUCCESS) {
4046 g_warning ("ldap_search_handler: %02X (%s), additional info: %s",
4048 ldap_err2string (ldap_error), ldap_error_msg);
4050 ldap_memfree (ldap_error_msg);
4052 if (ldap_error == LDAP_TIMELIMIT_EXCEEDED)
4053 e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_SearchTimeLimitExceeded);
4054 else if (ldap_error == LDAP_SIZELIMIT_EXCEEDED)
4055 e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_SearchSizeLimitExceeded);
4056 else if (ldap_error == LDAP_SUCCESS)
4057 e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_Success);
4059 e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_OtherError);
4061 ldap_op_finished (op);
4063 g_get_current_time (&end);
4064 diff = end.tv_sec * 1000 + end.tv_usec/1000;
4065 diff -= start.tv_sec * 1000 + start.tv_usec/1000;
4066 printf ("ldap_search_handler... completed with error code %d ", ldap_error);
4067 printf ("and took %ld.%03ld seconds\n", diff/1000, diff%1000);
4071 g_warning ("unhandled search result type %d returned", msg_type);
4072 //e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_OtherError);
4073 e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_InvalidQuery);
4074 ldap_op_finished (op);
4079 ldap_search_dtor (LDAPOp *op)
4081 LDAPSearchOp *search_op = (LDAPSearchOp*) op;
4083 d(printf ("ldap_search_dtor (%p)\n", search_op->view));
4085 /* unhook us from our EDataBookView */
4086 g_object_set_data (G_OBJECT (search_op->view), "EBookBackendLDAP.BookView::search_op", NULL);
4088 bonobo_object_unref (search_op->view);
4090 if (!search_op->aborted)
4095 e_book_backend_ldap_search (EBookBackendLDAP *bl,
4097 EDataBookView *view)
4102 GTimeVal start, end;
4106 printf ("e_book_backend_ldap_search ... \n");
4107 g_get_current_time (&start);
4110 switch (bl->priv->mode) {
4111 case GNOME_Evolution_Addressbook_MODE_LOCAL :
4112 if (!(bl->priv->marked_for_offline && bl->priv->cache)) {
4113 e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_RepositoryOffline);
4117 contacts = e_book_backend_cache_get_contacts (bl->priv->cache,
4118 e_data_book_view_get_card_query (view));
4120 for (l = contacts; l; l = g_list_next (l)) {
4121 EContact *contact = l->data;
4122 e_data_book_view_notify_update (view, contact);
4123 g_object_unref (contact);
4126 g_list_free (contacts);
4128 e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_Success);
4131 case GNOME_Evolution_Addressbook_MODE_REMOTE :
4132 ldap_query = e_book_backend_ldap_build_query (bl, e_data_book_view_get_card_query (view));
4134 if (ldap_query != NULL && bl->priv->ldap) {
4140 view_limit = e_data_book_view_get_max_results (view);
4141 if (view_limit == -1 || view_limit > bl->priv->ldap_limit)
4142 view_limit = bl->priv->ldap_limit;
4144 printf ("searching server using filter: %s (expecting max %d results)\n", ldap_query,
4147 ldap = bl->priv->ldap;
4150 book_view_notify_status (view, _("Searching..."));
4152 ldap_err = ldap_search_ext (ldap, bl->priv->ldap_rootdn,
4153 bl->priv->ldap_scope,
4158 NULL, /* XXX timeout */
4159 view_limit, &search_msgid);
4160 } while (e_book_backend_ldap_reconnect (bl, view, ldap_err));
4162 g_free (ldap_query);
4164 if (ldap_err != LDAP_SUCCESS) {
4165 book_view_notify_status (view, ldap_err2string(ldap_err));
4168 else if (search_msgid == -1) {
4169 book_view_notify_status (view,
4170 _("Error performing search"));
4174 LDAPSearchOp *op = g_new0 (LDAPSearchOp, 1);
4176 d(printf ("adding search_op (%p, %d)\n", view, search_msgid));
4179 op->aborted = FALSE;
4180 bonobo_object_ref (view);
4182 ldap_op_add ((LDAPOp*)op, E_BOOK_BACKEND(bl), book, view,
4184 ldap_search_handler, ldap_search_dtor);
4187 printf ("e_book_backend_ldap_search invoked ldap_search_handler ");
4188 g_get_current_time (&end);
4189 diff = end.tv_sec * 1000 + end.tv_usec/1000;
4190 diff -= start.tv_sec * 1000 + start.tv_usec/1000;
4191 printf("and took %ld.%03ld seconds\n", diff/1000,diff%1000);
4194 g_object_set_data (G_OBJECT (view), "EBookBackendLDAP.BookView::search_op", op);
4200 e_data_book_view_notify_complete (view,
4201 GNOME_Evolution_Addressbook_InvalidQuery);
4203 /* Ignore NULL query */
4204 e_data_book_view_notify_complete (view,
4205 GNOME_Evolution_Addressbook_Success);
4212 e_book_backend_ldap_start_book_view (EBookBackend *backend,
4213 EDataBookView *view)
4215 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
4217 d(printf ("start_book_view (%p)\n", view));
4219 /* we start at 1 so the user sees stuff as it appears and we
4220 aren't left waiting for more cards to show up, if the
4221 connection is slow. */
4222 e_data_book_view_set_thresholds (view, 1, 3000);
4224 e_book_backend_ldap_search (bl, NULL /* XXX ugh */, view);
4228 e_book_backend_ldap_stop_book_view (EBookBackend *backend,
4229 EDataBookView *view)
4233 d(printf ("stop_book_view (%p)\n", view));
4235 op = g_object_get_data (G_OBJECT (view), "EBookBackendLDAP.BookView::search_op");
4238 ldap_op_finished ((LDAPOp*)op);
4244 e_book_backend_ldap_get_changes (EBookBackend *backend,
4247 const char *change_id)
4249 /* FIXME: implement */
4252 #define LDAP_SIMPLE_PREFIX "ldap/simple-"
4253 #define SASL_PREFIX "sasl/"
4256 generate_cache_handler (LDAPOp *op, LDAPMessage *res)
4258 LDAPGetContactListOp *contact_list_op = (LDAPGetContactListOp *) op;
4259 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (op->backend);
4263 EDataBookView *book_view;
4264 GTimeVal start, end;
4268 printf ("generate_cache_handler ... \n");
4269 g_get_current_time (&start);
4271 ldap = bl->priv->ldap;
4273 ldap_op_finished (op);
4275 printf ("generate_cache_handler ... ldap handler is NULL \n");
4279 book_view = find_book_view (bl);
4281 msg_type = ldap_msgtype (res);
4282 if (msg_type == LDAP_RES_SEARCH_ENTRY) {
4283 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
4284 e = ldap_first_entry(ldap, res);
4285 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
4288 EContact *contact = build_contact_from_entry (bl, e, NULL);
4290 contact_list_op->contacts = g_list_prepend (contact_list_op->contacts, contact);
4292 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
4293 e = ldap_next_entry(ldap, e);
4294 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
4298 int contact_num = 0;
4301 e_file_cache_clean (E_FILE_CACHE (bl->priv->cache));
4303 e_file_cache_freeze_changes (E_FILE_CACHE (bl->priv->cache));
4304 for (l = contact_list_op->contacts; l; l = g_list_next (l)) {
4305 EContact *contact = l->data;
4309 status_msg = g_strdup_printf (_("Downloading contacts (%d)... "),
4311 e_data_book_view_notify_status_message (book_view, status_msg);
4312 g_free (status_msg);
4314 e_book_backend_cache_add_contact (bl->priv->cache, contact);
4316 e_book_backend_cache_set_populated (bl->priv->cache);
4317 e_file_cache_thaw_changes (E_FILE_CACHE (bl->priv->cache));
4319 e_data_book_view_notify_complete (book_view,
4320 GNOME_Evolution_Addressbook_Success);
4321 ldap_op_finished (op);
4323 g_get_current_time (&end);
4324 diff = end.tv_sec * 1000 + end.tv_usec/1000;
4325 diff -= start.tv_sec * 1000 + start.tv_usec/1000;
4326 printf ("generate_cache_handler ... completed in %ld.%03ld seconds\n",
4327 diff/1000,diff%1000);
4333 generate_cache_dtor (LDAPOp *op)
4335 LDAPGetContactListOp *contact_list_op = (LDAPGetContactListOp *) op;
4338 for (l = contact_list_op->contacts; l; l = g_list_next (l)) {
4339 g_object_unref (l->data);
4342 g_list_free (contact_list_op->contacts);
4343 g_free (contact_list_op);
4347 generate_cache (EBookBackendLDAP *book_backend_ldap)
4349 LDAPGetContactListOp *contact_list_op = g_new0 (LDAPGetContactListOp, 1);
4350 EBookBackendLDAPPrivate *priv;
4352 gint contact_list_msgid;
4354 GTimeVal start, end;
4358 printf ("generating offline cache ... \n");
4359 g_get_current_time (&start);
4362 priv = book_backend_ldap->priv;
4365 g_free (contact_list_op);
4367 printf ("generating offline cache failed ... ldap handler is NULL\n");
4371 ldap_query = e_book_backend_ldap_build_query (book_backend_ldap,
4372 "(beginswith \"file_as\" \"\")");
4375 ldap_error = ldap_search_ext (priv->ldap,
4379 NULL, 0, NULL, NULL,
4380 NULL, /* XXX timeout */
4381 LDAP_NO_LIMIT, &contact_list_msgid);
4382 } while (e_book_backend_ldap_reconnect (book_backend_ldap, NULL, ldap_error));
4384 g_free (ldap_query);
4386 if (ldap_error == LDAP_SUCCESS) {
4387 ldap_op_add ((LDAPOp*) contact_list_op, (EBookBackend *) book_backend_ldap, NULL /* book */,
4388 NULL /* book_view */, 0 /* opid */, contact_list_msgid,
4389 generate_cache_handler, generate_cache_dtor);
4391 printf ("generating offline cache invoked generate_cache_handler ");
4392 g_get_current_time (&end);
4393 diff = end.tv_sec * 1000 + end.tv_usec/1000;
4394 diff -= start.tv_sec * 1000 + start.tv_usec/1000;
4395 printf("and took %ld.%03ld seconds\n", diff/1000, diff%1000);
4398 generate_cache_dtor ((LDAPOp *) contact_list_op);
4403 e_book_backend_ldap_authenticate_user (EBookBackend *backend,
4408 const char *auth_method)
4410 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
4416 printf ("e_book_backend_ldap_authenticate_user ... \n");
4418 if (bl->priv->mode == GNOME_Evolution_Addressbook_MODE_LOCAL) {
4419 e_book_backend_notify_writable (backend, FALSE);
4420 e_book_backend_notify_connection_status (backend, FALSE);
4421 e_data_book_respond_authenticate_user (book,
4423 GNOME_Evolution_Addressbook_Success);
4427 if (!bl->priv->connected || !bl->priv->ldap) {
4429 status = e_book_backend_ldap_connect (bl);
4430 if (status != GNOME_Evolution_Addressbook_Success) {
4431 e_data_book_respond_authenticate_user (book,
4438 if (!g_ascii_strncasecmp (auth_method, LDAP_SIMPLE_PREFIX, strlen (LDAP_SIMPLE_PREFIX))) {
4440 if (!strcmp (auth_method, "ldap/simple-email")) {
4441 LDAPMessage *res, *e;
4442 char *query = g_strdup_printf ("(mail=%s)", user);
4444 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
4445 ldap_error = ldap_search_s (bl->priv->ldap,
4446 bl->priv->ldap_rootdn,
4447 bl->priv->ldap_scope,
4450 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
4453 if (ldap_error == LDAP_SUCCESS) {
4456 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
4457 e = ldap_first_entry (bl->priv->ldap, res);
4458 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
4460 g_warning ("Failed to get the DN for %s", user);
4462 e_data_book_respond_authenticate_user (book,
4464 GNOME_Evolution_Addressbook_AuthenticationFailed);
4468 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
4469 entry_dn = ldap_get_dn (bl->priv->ldap, e);
4470 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
4471 dn = g_strdup(entry_dn);
4473 ldap_memfree (entry_dn);
4477 e_data_book_respond_authenticate_user (book,
4479 GNOME_Evolution_Addressbook_PermissionDenied);
4483 else if (!strcmp (auth_method, "ldap/simple-binddn")) {
4484 dn = g_strdup (user);
4487 /* now authenticate against the DN we were either supplied or queried for */
4488 printf ("simple auth as %s\n", dn);
4489 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
4490 ldap_error = ldap_simple_bind_s(bl->priv->ldap,
4493 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
4494 /* Some ldap servers are returning (ex active directory ones) LDAP_SERVER_DOWN
4495 * when we try to do an ldap operation after being idle
4496 * for some time. This error is handled by poll_ldap in case of search operations
4497 * We need to handle it explicitly for this bind call. We call reconnect so that
4498 * we get a fresh ldap handle Fixes #67541 */
4500 if (ldap_error == LDAP_SERVER_DOWN) {
4501 EDataBookView *view = find_book_view (bl);
4503 if (e_book_backend_ldap_reconnect (bl, view, ldap_error)) {
4504 ldap_error = LDAP_SUCCESS;
4509 e_data_book_respond_authenticate_user (book,
4511 ldap_error_to_response (ldap_error));
4513 #ifdef ENABLE_SASL_BINDS
4514 else if (!g_ascii_strncasecmp (auth_method, SASL_PREFIX, strlen (SASL_PREFIX))) {
4515 g_print ("sasl bind (mech = %s) as %s", auth_method + strlen (SASL_PREFIX), user);
4516 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
4517 ldap_error = ldap_sasl_bind_s (bl->priv->ldap,
4519 auth_method + strlen (SASL_PREFIX),
4524 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
4526 if (ldap_error == LDAP_NOT_SUPPORTED)
4527 e_data_book_respond_authenticate_user (book,
4529 GNOME_Evolution_Addressbook_UnsupportedAuthenticationMethod);
4531 e_data_book_respond_authenticate_user (book,
4533 ldap_error_to_response (ldap_error));
4537 e_data_book_respond_authenticate_user (book,
4539 GNOME_Evolution_Addressbook_UnsupportedAuthenticationMethod);
4543 if (ldap_error == LDAP_SUCCESS) {
4544 bl->priv->auth_dn = dn;
4545 bl->priv->auth_passwd = g_strdup (passwd);
4547 e_book_backend_set_is_writable (backend, TRUE);
4549 /* force a requery on the root dse since some ldap
4550 servers are set up such that they don't report
4551 anything (including the schema DN) until the user
4553 if (!bl->priv->evolutionPersonChecked) {
4554 ldap_error = query_ldap_root_dse (bl);
4556 if (LDAP_SUCCESS == ldap_error) {
4557 if (!bl->priv->evolutionPersonChecked)
4558 check_schema_support (bl);
4561 g_warning ("Failed to perform root dse query after authenticating, (ldap_error 0x%02x)", ldap_error);
4564 e_data_book_report_writable (book, TRUE);
4566 if (bl->priv->marked_for_offline && bl->priv->cache)
4567 generate_cache (bl);
4572 e_book_backend_ldap_get_required_fields (EBookBackend *backend,
4577 GList *fields = NULL;
4580 /*FIMEME we should look at mandatory attributs in the schema
4581 and return all those fields here */
4582 fields = g_list_append (fields, (char *)e_contact_field_name (E_CONTACT_FILE_AS));
4583 fields = g_list_append (fields, (char *)e_contact_field_name (E_CONTACT_FULL_NAME));
4584 fields = g_list_append (fields, (char *)e_contact_field_name (E_CONTACT_FAMILY_NAME));
4587 e_data_book_respond_get_required_fields (book,
4589 GNOME_Evolution_Addressbook_Success,
4591 g_list_free (fields);
4596 e_book_backend_ldap_get_supported_fields (EBookBackend *backend,
4601 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
4603 e_data_book_respond_get_supported_fields (book,
4605 GNOME_Evolution_Addressbook_Success,
4606 bl->priv->supported_fields);
4610 e_book_backend_ldap_get_supported_auth_methods (EBookBackend *backend,
4615 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
4617 e_data_book_respond_get_supported_auth_methods (book,
4619 GNOME_Evolution_Addressbook_Success,
4620 bl->priv->supported_auth_methods);
4624 ldap_cancel_op(void *key, void *value, void *data)
4626 EBookBackendLDAP *bl = data;
4629 /* ignore errors, its only best effort? */
4630 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
4632 ldap_abandon (bl->priv->ldap, op->id);
4633 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
4636 static GNOME_Evolution_Addressbook_CallStatus
4637 e_book_backend_ldap_cancel_operation (EBookBackend *backend, EDataBook *book)
4639 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
4641 g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
4642 g_hash_table_foreach (bl->priv->id_to_op, ldap_cancel_op, bl);
4643 g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
4645 return GNOME_Evolution_Addressbook_Success;
4648 static GNOME_Evolution_Addressbook_CallStatus
4649 e_book_backend_ldap_load_source (EBookBackend *backend,
4651 gboolean only_if_exists)
4653 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
4657 int timeout = 60; /* 1 minute */
4660 const char *offline;
4663 g_assert (bl->priv->connected == FALSE);
4666 printf ("e_book_backend_ldap_load_source ... \n");
4668 uri = e_source_get_uri (source);
4670 offline = e_source_get_property (source, "offline_sync");
4671 if (offline && g_str_equal (offline, "1"))
4672 bl->priv->marked_for_offline = TRUE;
4673 str = e_source_get_property (source, "limit");
4677 str = e_source_get_property (source, "ssl");
4679 if (!strcmp (str, "always"))
4680 bl->priv->use_tls = E_BOOK_BACKEND_LDAP_TLS_ALWAYS;
4681 else if (!strcmp (str, "whenever_possible"))
4682 bl->priv->use_tls = E_BOOK_BACKEND_LDAP_TLS_WHEN_POSSIBLE;
4683 else if (strcmp (str, "never"))
4684 g_warning ("Unhandled value for 'ssl', not using it.");
4687 bl->priv->use_tls = E_BOOK_BACKEND_LDAP_TLS_NO;
4689 str = e_source_get_property (source, "timeout");
4691 timeout = atoi (str);
4693 ldap_error = ldap_url_parse ((char*) uri, &lud);
4695 if (ldap_error == LDAP_SUCCESS) {
4696 bl->priv->ldap_host = g_strdup(lud->lud_host);
4697 bl->priv->ldap_port = lud->lud_port;
4698 /* if a port wasn't specified, default to LDAP_PORT */
4699 if (bl->priv->ldap_port == 0)
4700 bl->priv->ldap_port = LDAP_PORT;
4701 bl->priv->ldap_rootdn = g_strdup(lud->lud_dn);
4702 /* in case of migration, filter will be set to NULL and hence the search will fail */
4703 if (lud->lud_filter)
4704 bl->priv->ldap_search_filter = g_strdup (lud->lud_filter);
4705 bl->priv->ldap_limit = limit;
4706 bl->priv->ldap_timeout = timeout;
4707 bl->priv->ldap_scope = lud->lud_scope;
4709 ldap_free_urldesc(lud);
4712 printf ("e_book_backend_ldap_load_source ... failed to parse the ldap URI %s\n", uri);
4714 return GNOME_Evolution_Addressbook_OtherError;
4717 if (bl->priv->cache) {
4718 g_object_unref (bl->priv->cache);
4719 bl->priv->cache = NULL;
4722 bl->priv->cache = e_book_backend_cache_new (uri);
4725 if (bl->priv->mode == GNOME_Evolution_Addressbook_MODE_LOCAL) {
4728 e_book_backend_set_is_loaded (backend, TRUE);
4729 e_book_backend_set_is_writable (backend, FALSE);
4730 e_book_backend_notify_writable (backend, FALSE);
4731 e_book_backend_notify_connection_status (backend, FALSE);
4733 if (!bl->priv->marked_for_offline)
4734 return GNOME_Evolution_Addressbook_OfflineUnavailable;
4737 if (!e_book_backend_cache_is_populated (bl->priv->cache))
4738 return GNOME_Evolution_Addressbook_OfflineUnavailable;
4741 return GNOME_Evolution_Addressbook_Success;
4744 e_book_backend_notify_connection_status (backend, TRUE);
4748 result = e_book_backend_ldap_connect (bl);
4749 if (result != GNOME_Evolution_Addressbook_Success) {
4751 printf ("e_book_backend_ldap_load_source ... failed to connect to server \n");
4755 if (bl->priv->marked_for_offline)
4756 generate_cache (bl);
4762 e_book_backend_ldap_remove (EBookBackend *backend, EDataBook *book, guint32 opid)
4764 /* if we ever add caching, we'll remove it here, but for now,
4765 just report back Success */
4767 e_data_book_respond_remove (book, opid, GNOME_Evolution_Addressbook_Success);
4771 e_book_backend_ldap_get_static_capabilities (EBookBackend *backend)
4773 return g_strdup("net,anon-access,do-initial-query,contact-lists");
4778 stop_views (EBookBackend *backend)
4783 book_views = e_book_backend_get_book_views (backend);
4784 iter = e_list_get_iterator (book_views);
4786 while (e_iterator_is_valid (iter)) {
4787 EDataBookView *data_book_view = (EDataBookView *) e_iterator_get (iter);
4788 e_book_backend_ldap_stop_book_view (backend, data_book_view);
4789 e_iterator_next (iter);
4792 g_object_unref (iter);
4793 g_object_unref (book_views);
4797 start_views (EBookBackend *backend)
4802 book_views = e_book_backend_get_book_views (backend);
4803 iter = e_list_get_iterator (book_views);
4805 while (e_iterator_is_valid (iter)) {
4806 EDataBookView *data_book_view = (EDataBookView *) e_iterator_get (iter);
4807 e_book_backend_ldap_start_book_view (backend, data_book_view);
4808 e_iterator_next (iter);
4811 g_object_unref (iter);
4812 g_object_unref (book_views);
4817 e_book_backend_ldap_set_mode (EBookBackend *backend, int mode)
4819 EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
4821 if (bl->priv->mode == mode)
4824 bl->priv->mode = mode;
4826 stop_views (backend);
4829 /* Cancel all running operations */
4830 e_book_backend_ldap_cancel_operation (backend, NULL);
4832 if (mode == GNOME_Evolution_Addressbook_MODE_LOCAL) {
4835 e_book_backend_set_is_writable (backend, FALSE);
4836 e_book_backend_notify_writable (backend, FALSE);
4837 e_book_backend_notify_connection_status (backend, FALSE);
4840 if (bl->priv->ldap) {
4841 ldap_unbind (bl->priv->ldap);
4842 bl->priv->ldap = NULL;
4846 bl->priv->connected = FALSE;
4849 if (e_book_backend_is_loaded (backend))
4850 start_views (backend);
4853 else if (mode == GNOME_Evolution_Addressbook_MODE_REMOTE) {
4856 e_book_backend_set_is_writable (backend, TRUE);
4857 e_book_backend_notify_writable (backend, TRUE);
4858 e_book_backend_notify_connection_status (backend, TRUE);
4860 if (e_book_backend_is_loaded (backend)) {
4861 e_book_backend_ldap_connect (bl);
4862 e_book_backend_notify_auth_required (backend);
4865 start_views (backend);
4868 if (bl->priv->marked_for_offline && bl->priv->cache)
4869 generate_cache (bl);
4875 e_book_backend_ldap_construct (EBookBackendLDAP *backend)
4877 g_assert (backend != NULL);
4878 g_assert (E_IS_BOOK_BACKEND_LDAP (backend));
4880 if (! e_book_backend_construct (E_BOOK_BACKEND (backend)))
4887 * e_book_backend_ldap_new:
4890 e_book_backend_ldap_new (void)
4892 EBookBackendLDAP *backend;
4894 backend = g_object_new (E_TYPE_BOOK_BACKEND_LDAP, NULL);
4896 if (! e_book_backend_ldap_construct (backend)) {
4897 g_object_unref (backend);
4901 return E_BOOK_BACKEND (backend);
4905 call_dtor (int msgid, LDAPOp *op, gpointer data)
4907 EBookBackendLDAP *bl;
4909 bl = E_BOOK_BACKEND_LDAP (op->backend);
4911 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
4913 ldap_abandon (bl->priv->ldap, op->id);
4914 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
4922 e_book_backend_ldap_dispose (GObject *object)
4924 EBookBackendLDAP *bl;
4926 bl = E_BOOK_BACKEND_LDAP (object);
4929 g_static_rec_mutex_lock (&bl->priv->op_hash_mutex);
4930 g_hash_table_foreach_remove (bl->priv->id_to_op, (GHRFunc)call_dtor, NULL);
4931 g_hash_table_destroy (bl->priv->id_to_op);
4932 g_static_rec_mutex_unlock (&bl->priv->op_hash_mutex);
4933 g_static_rec_mutex_free (&bl->priv->op_hash_mutex);
4935 g_static_rec_mutex_lock (&eds_ldap_handler_lock);
4937 ldap_unbind (bl->priv->ldap);
4938 g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
4940 if (bl->priv->poll_timeout != -1) {
4941 g_source_remove (bl->priv->poll_timeout);
4944 if (bl->priv->supported_fields) {
4945 g_list_foreach (bl->priv->supported_fields, (GFunc)g_free, NULL);
4946 g_list_free (bl->priv->supported_fields);
4949 if (bl->priv->supported_auth_methods) {
4950 g_list_foreach (bl->priv->supported_auth_methods, (GFunc)g_free, NULL);
4951 g_list_free (bl->priv->supported_auth_methods);
4953 if (bl->priv->summary_file_name) {
4954 g_free (bl->priv->summary_file_name);
4955 bl->priv->summary_file_name = NULL;
4957 if (bl->priv->summary) {
4958 e_book_backend_summary_save (bl->priv->summary);
4959 g_object_unref (bl->priv->summary);
4960 bl->priv->summary = NULL;
4963 g_free (bl->priv->ldap_host);
4964 g_free (bl->priv->ldap_rootdn);
4965 g_free (bl->priv->ldap_search_filter);
4966 g_free (bl->priv->schema_dn);
4971 if (G_OBJECT_CLASS (e_book_backend_ldap_parent_class)->dispose)
4972 G_OBJECT_CLASS (e_book_backend_ldap_parent_class)->dispose (object);
4976 e_book_backend_ldap_class_init (EBookBackendLDAPClass *klass)
4978 GObjectClass *object_class = G_OBJECT_CLASS (klass);
4979 EBookBackendClass *parent_class;
4982 /* get client side information (extensions present in the library) */
4983 get_ldap_library_info ();
4985 e_book_backend_ldap_parent_class = g_type_class_peek_parent (klass);
4987 parent_class = E_BOOK_BACKEND_CLASS (klass);
4989 /* Set the virtual methods. */
4990 parent_class->load_source = e_book_backend_ldap_load_source;
4991 parent_class->remove = e_book_backend_ldap_remove;
4992 parent_class->get_static_capabilities = e_book_backend_ldap_get_static_capabilities;
4994 parent_class->create_contact = e_book_backend_ldap_create_contact;
4995 parent_class->remove_contacts = e_book_backend_ldap_remove_contacts;
4996 parent_class->modify_contact = e_book_backend_ldap_modify_contact;
4997 parent_class->get_contact = e_book_backend_ldap_get_contact;
4998 parent_class->get_contact_list = e_book_backend_ldap_get_contact_list;
4999 parent_class->start_book_view = e_book_backend_ldap_start_book_view;
5000 parent_class->stop_book_view = e_book_backend_ldap_stop_book_view;
5001 parent_class->get_changes = e_book_backend_ldap_get_changes;
5002 parent_class->authenticate_user = e_book_backend_ldap_authenticate_user;
5003 parent_class->get_required_fields = e_book_backend_ldap_get_required_fields;
5004 parent_class->get_supported_fields = e_book_backend_ldap_get_supported_fields;
5005 parent_class->get_supported_auth_methods = e_book_backend_ldap_get_supported_auth_methods;
5006 parent_class->cancel_operation = e_book_backend_ldap_cancel_operation;
5007 parent_class->set_mode = e_book_backend_ldap_set_mode;
5009 object_class->dispose = e_book_backend_ldap_dispose;
5013 e_book_backend_ldap_init (EBookBackendLDAP *backend)
5015 EBookBackendLDAPPrivate *priv;
5017 priv = g_new0 (EBookBackendLDAPPrivate, 1);
5019 priv->supported_fields = NULL;
5020 priv->supported_auth_methods = NULL;
5021 priv->ldap_limit = 100;
5022 priv->id_to_op = g_hash_table_new (g_int_hash, g_int_equal);
5023 priv->poll_timeout = -1;
5024 priv->marked_for_offline = FALSE;
5025 priv->mode = GNOME_Evolution_Addressbook_MODE_REMOTE;
5026 priv->is_summary_ready = FALSE;
5027 priv->reserved1 = NULL;
5028 priv->reserved2 = NULL;
5029 priv->reserved3 = NULL;
5030 priv->reserved4 = NULL;
5031 g_static_rec_mutex_init (&priv->op_hash_mutex);
5033 backend->priv = priv;
5035 if (g_getenv ("LDAP_DEBUG"))
5036 enable_debug = TRUE;
5040 * e_book_backend_ldap_get_type:
5043 e_book_backend_ldap_get_type (void)
5045 static GType type = 0;
5049 sizeof (EBookBackendLDAPClass),
5050 NULL, /* base_class_init */
5051 NULL, /* base_class_finalize */
5052 (GClassInitFunc) e_book_backend_ldap_class_init,
5053 NULL, /* class_finalize */
5054 NULL, /* class_data */
5055 sizeof (EBookBackendLDAP),
5056 0, /* n_preallocs */
5057 (GInstanceInitFunc) e_book_backend_ldap_init
5060 type = g_type_register_static (E_TYPE_BOOK_BACKEND, "EBookBackendLDAP", &info, 0);