evolution-3.6.4/addressbook/importers/evolution-ldif-importer.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 16  */
 17 
 18 /*
 19  * LDIF importer.  LDIF is the file format of an exported Netscape
 20  * addressbook.
 21  *
 22  * Framework copied from evolution-gnomecard-importer.c
 23  *
 24  * Michael M. Morrison (mmorrison@kqcorp.com)
 25  *
 26  * Multi-line value support, mailing list support, base64 support, and
 27  * various fixups: Chris Toshok (toshok@ximian.com)
 28  *
 29  * Made re-entrant, converted to eplugin, Michael Zucchi <notzed@ximian.com>
 30  */
 31 
 32 #ifdef HAVE_CONFIG_H
 33 #include <config.h>
 34 #endif
 35 
 36 #include <stdio.h>
 37 #include <ctype.h>
 38 #include <string.h>
 39 
 40 #include <gtk/gtk.h>
 41 #include <glib/gi18n.h>
 42 #include <glib/gstdio.h>
 43 
 44 #include <libebook/libebook.h>
 45 #include <libedataserverui/libedataserverui.h>
 46 
 47 #include <shell/e-shell.h>
 48 #include <e-util/e-import.h>
 49 
 50 #include "evolution-addressbook-importers.h"
 51 
 52 typedef struct {
 53 	EImport *import;
 54 	EImportTarget *target;
 55 
 56 	guint idle_id;
 57 
 58 	GHashTable *dn_contact_hash;
 59 
 60 	gint state;		/* 0 - initial scan, 1 - list cards, 2 - cancelled/complete */
 61 	FILE *file;
 62 	gulong size;
 63 
 64 	EBookClient *book_client;
 65 
 66 	GSList *contacts;
 67 	GSList *list_contacts;
 68 	GSList *list_iterator;
 69 } LDIFImporter;
 70 
 71 static void ldif_import_done (LDIFImporter *gci);
 72 
 73 static struct {
 74 	const gchar *ldif_attribute;
 75 	EContactField contact_field;
 76 #define FLAG_HOME_ADDRESS	0x01
 77 #define FLAG_WORK_ADDRESS	0x02
 78 #define FLAG_LIST		0x04
 79 #define FLAG_BOOLEAN		0x08
 80 	gint flags;
 81 }
 82 ldif_fields[] = {
 83 	{ "cn", E_CONTACT_FULL_NAME },
 84 	{ "mail", E_CONTACT_EMAIL, FLAG_LIST },
 85 	{ "mozillaSecondEmail", E_CONTACT_EMAIL_2},
 86 #if 0
 87 	{ "givenname", E_CONTACT_GIVEN_NAME },
 88 #endif
 89 	{ "sn", E_CONTACT_FAMILY_NAME },
 90 	{ "xmozillanickname", E_CONTACT_NICKNAME },
 91 
 92 	{ "o", E_CONTACT_ORG },
 93 	{ "ou", E_CONTACT_ORG_UNIT },
 94 	{ "title", E_CONTACT_TITLE },
 95 
 96 	{ "locality", 0, FLAG_WORK_ADDRESS },
 97 	{ "l", 0, FLAG_WORK_ADDRESS },
 98 	{ "mozillahomelocalityname", 0, FLAG_HOME_ADDRESS },
 99 	{ "st", 0, FLAG_WORK_ADDRESS },
100 	{ "mozillaHomeState", 0, FLAG_HOME_ADDRESS },
101 	{ "streetaddress", 0, FLAG_WORK_ADDRESS },
102 	{ "postalcode", 0, FLAG_WORK_ADDRESS },
103 	{ "mozillaHomePostalCode", 0, FLAG_HOME_ADDRESS },
104 	{ "countryname", 0, FLAG_WORK_ADDRESS },
105 	{ "c", 0, FLAG_WORK_ADDRESS },
106 	{ "mozillaHomeCountryName", 0, FLAG_HOME_ADDRESS },
107 	{ "postalAddress", 0, FLAG_WORK_ADDRESS },
108 	{ "homePostalAddress", 0, FLAG_HOME_ADDRESS },
109 	{ "mozillaPostalAddress2", 0, FLAG_WORK_ADDRESS },
110 	{ "mozillaHomePostalAddress2", 0, FLAG_HOME_ADDRESS },
111 
112 	{ "telephonenumber", E_CONTACT_PHONE_BUSINESS},
113 	{ "homephone", E_CONTACT_PHONE_HOME },
114 	{ "facsimiletelephonenumber", E_CONTACT_PHONE_BUSINESS_FAX },
115 	{ "pagerphone", E_CONTACT_PHONE_PAGER },
116 	{ "cellphone", E_CONTACT_PHONE_MOBILE },
117 	{ "mobile", E_CONTACT_PHONE_MOBILE },
118 
119 	{ "homeurl", E_CONTACT_HOMEPAGE_URL },
120 	{ "mozillaHomeUrl", E_CONTACT_HOMEPAGE_URL },
121 
122 	{ "description", E_CONTACT_NOTE },
123 
124 	{ "xmozillausehtmlmail", E_CONTACT_WANTS_HTML, FLAG_BOOLEAN },
125 
126 	{ "nsAIMid", E_CONTACT_IM_AIM, FLAG_LIST },
127 	{ "mozilla_AimScreenName", E_CONTACT_IM_AIM, FLAG_LIST }
128 };
129 
130 static GString *
131 getValue (gchar **src)
132 {
133 	GString *dest = g_string_new ("");
134 	gchar *s = *src;
135 	gboolean need_base64 = (*s == ':');
136 
137  copy_line:
138 	while (*s != 0 && *s != '\n' && *s != '\r')
139 		dest = g_string_append_c (dest, *s++);
140 
141 	if (*s == '\r') s++;
142 	if (*s == '\n')	s++;
143 
144 	/* check for continuation here */
145 	if (*s == ' ') {
146 		s++;
147 		goto copy_line;
148 	}
149 
150 	if (need_base64) {
151 		guchar *data;
152 		gsize length;
153 
154 		/* XXX g_string_assign_len() would be nice here */
155 		data = g_base64_decode (dest->str + 2, &length);
156 		g_string_truncate (dest, 0);
157 		g_string_append_len (dest, (gchar *) data, length);
158 		g_free (data);
159 	}
160 
161 	*src = s;
162 
163 	return dest;
164 }
165 
166 static void
167 populate_contact_address (EContactAddress *address,
168                           gchar *attr,
169                           gchar *value)
170 {
171 	if (!g_ascii_strcasecmp (attr, "locality") ||
172 	    !g_ascii_strcasecmp (attr, "l") ||
173 	    !g_ascii_strcasecmp (attr, "mozillaHomeLocalityName"))
174 		address->locality = g_strdup (value);
175 	else if (!g_ascii_strcasecmp (attr, "countryname") ||
176 		 !g_ascii_strcasecmp (attr, "c") ||
177 		 !g_ascii_strcasecmp (attr, "mozillaHomeCountryName"))
178 		address->country = g_strdup (value);
179 	else if (!g_ascii_strcasecmp (attr, "postalcode") ||
180 		 !g_ascii_strcasecmp (attr, "mozillaHomePostalCode"))
181 		address->code = g_strdup (value);
182 	else if (!g_ascii_strcasecmp (attr, "st") ||
183 		 !g_ascii_strcasecmp (attr, "mozillaHomeState"))
184 		address->region = g_strdup (value);
185 	else if (!g_ascii_strcasecmp (attr, "streetaddress"))
186 		address->street = g_strdup (value);
187 	else if (!g_ascii_strcasecmp (attr, "mozillaPostalAddress2") ||
188 		 !g_ascii_strcasecmp (attr, "mozillaHomePostalAddress2")) {
189 		if (address->ext && *address->ext) {
190 			gchar *temp = g_strdup (address->ext);
191 			g_free (address->ext);
192 			address->ext = g_strconcat (temp, ",\n", value, NULL);
193 			g_free (temp);
194 		}
195 		else {
196 			address->ext = g_strdup (value);
197 		}
198 	}
199 	else if (!g_ascii_strcasecmp (attr, "postalAddress") ||
200 		 !g_ascii_strcasecmp (attr, "homepostalAddress")) {
201 		gchar *c, *i, *addr_field;
202 
203 		addr_field =  g_strdup (value);
204 		i = addr_field;
205 		for (c = addr_field; *c != '\0'; c++) {
206 			i++;
207 			if (*c == ',' &&  *i != '\0' && *i == ' ') {
208 				*i = '\n';
209 			}
210 		}
211 		if (address->ext && *address->ext) {
212 			gchar *temp = g_strdup (address->ext);
213 			g_free (address->ext);
214 			address->ext = g_strconcat (addr_field, ",\n", temp, NULL);
215 			g_free (temp);
216 			g_free (addr_field);
217 		}
218 		else {
219 			address->ext = addr_field;
220 		}
221 	}
222 }
223 
224 static gboolean
225 parseLine (GHashTable *dn_contact_hash,
226            EContact *contact,
227            EContactAddress *work_address,
228            EContactAddress *home_address,
229            gchar **buf)
230 {
231 	gchar *ptr;
232 	gchar *colon, *value;
233 	gboolean field_handled;
234 	GString *ldif_value;
235 
236 	ptr = *buf;
237 
238 	/* if the string is empty, return */
239 	if (*ptr == '\0') {
240 		*buf = NULL;
241 		return TRUE;
242 	}
243 
244 	/* skip comment lines */
245 	if (*ptr == '#') {
246 		ptr = strchr (ptr, '\n');
247 		if (!ptr)
248 			*buf = NULL;
249 		else
250 			*buf = ptr + 1;
251 		return TRUE;
252 	}
253 
254 	/* first, check for a 'continuation' line */
255 	if (ptr[0] == ' ' && ptr[1] != '\n') {
256 		g_warning ("unexpected continuation line");
257 		return FALSE;
258 	}
259 
260 	colon = (gchar *) strchr (ptr, ':');
261 	if (colon) {
262 		gint i;
263 
264 		*colon = 0;
265 		value = colon + 1;
266 		while (isspace (*value))
267 			value++;
268 
269 		ldif_value = getValue (&value);
270 
271 		field_handled = FALSE;
272 		for (i = 0; i < G_N_ELEMENTS (ldif_fields); i++) {
273 			if (!g_ascii_strcasecmp (ptr, ldif_fields[i].ldif_attribute)) {
274 				if (ldif_fields[i].flags & FLAG_WORK_ADDRESS) {
275 					populate_contact_address (work_address, ptr, ldif_value->str);
276 				}
277 				else if (ldif_fields[i].flags & FLAG_HOME_ADDRESS) {
278 					populate_contact_address (home_address, ptr, ldif_value->str);
279 				}
280 				else if (ldif_fields[i].flags & FLAG_LIST) {
281 					GList *list;
282 
283 					list = e_contact_get (contact, ldif_fields[i].contact_field);
284 					list = g_list_append (list, g_strdup (ldif_value->str));
285 					e_contact_set (contact, ldif_fields[i].contact_field, list);
286 
287 					g_list_foreach (list, (GFunc) g_free, NULL);
288 					g_list_free (list);
289 				}
290 				else if (ldif_fields[i].flags & FLAG_BOOLEAN) {
291 					if (!g_ascii_strcasecmp (ldif_value->str, "true")) {
292 						e_contact_set (
293 							contact,
294 							ldif_fields[i].contact_field,
295 							GINT_TO_POINTER (TRUE));
296 					}
297 					else {
298 						e_contact_set (
299 							contact,
300 							ldif_fields[i].contact_field,
301 							GINT_TO_POINTER (FALSE));
302 					}
303 					g_message ("set %s to %s", ptr, ldif_value->str);
304 				}
305 				else {
306 					/* FIXME is everything a string? */
307 					e_contact_set (
308 						contact,
309 						ldif_fields[i].contact_field,
310 						ldif_value->str);
311 					g_message ("set %s to %s", ptr, ldif_value->str);
312 				}
313 				field_handled = TRUE;
314 				break;
315 			}
316 		}
317 
318 		/* handle objectclass/dn/member out here */
319 		if (!field_handled) {
320 			if (!g_ascii_strcasecmp (ptr, "dn"))
321 				g_hash_table_insert (
322 					dn_contact_hash,
323 					g_strdup (ldif_value->str), contact);
324 			else if (!g_ascii_strcasecmp (ptr, "objectclass") &&
325 				!g_ascii_strcasecmp (ldif_value->str, "groupofnames")) {
326 				e_contact_set (
327 					contact, E_CONTACT_IS_LIST,
328 					GINT_TO_POINTER (TRUE));
329 			} else if (!g_ascii_strcasecmp (ptr, "member")) {
330 				GList *email;
331 
332 				email = e_contact_get (contact, E_CONTACT_EMAIL);
333 				email = g_list_append (email, g_strdup (ldif_value->str));
334 				e_contact_set (contact, E_CONTACT_EMAIL, email);
335 
336 				g_list_foreach (email, (GFunc) g_free, NULL);
337 				g_list_free (email);
338 			}
339 		}
340 
341 		/* put the colon back the way it was, just for kicks */
342 		*colon = ':';
343 
344 		g_string_free (ldif_value, TRUE);
345 
346 	} else {
347 		g_warning ("unrecognized entry %s", ptr);
348 		return FALSE;
349 	}
350 
351 	*buf = value;
352 
353 	return TRUE;
354 }
355 
356 static EContact *
357 getNextLDIFEntry (GHashTable *dn_contact_hash,
358                   FILE *f)
359 {
360 	EContact *contact;
361 	EContactAddress *work_address, *home_address;
362 	GString *str;
363 	gchar line[1024];
364 	gchar *buf;
365 
366 	str = g_string_new ("");
367 	/* read from the file until we get to a blank line (or eof) */
368 	while (!feof (f)) {
369 		if (!fgets (line, sizeof (line), f))
370 			break;
371 		if (line[0] == '\n' || (line[0] == '\r' && line[1] == '\n'))
372 			break;
373 		str = g_string_append (str, line);
374 	}
375 
376 	if (strlen (str->str) == 0) {
377 		g_string_free (str, TRUE);
378 		return NULL;
379 	}
380 
381 	/* now parse that entry */
382 	contact = e_contact_new ();
383 	work_address = g_new0 (EContactAddress, 1);
384 	home_address = g_new0 (EContactAddress, 1);
385 
386 	buf = str->str;
387 	while (buf) {
388 		if (!parseLine (dn_contact_hash, contact, work_address, home_address, &buf)) {
389 			/* parsing error */
390 			g_string_free (str, TRUE);
391 			e_contact_address_free (work_address);
392 			e_contact_address_free (home_address);
393 			g_object_unref (contact);
394 			return NULL;
395 		}
396 	}
397 
398 	/* fill in the address */
399 	if (work_address->locality || work_address->country || work_address->ext ||
400 	    work_address->code || work_address->region || work_address->street) {
401 		e_contact_set (contact, E_CONTACT_ADDRESS_WORK, work_address);
402 	}
403 	if (home_address->locality || home_address->country || home_address->ext ||
404 	    home_address->code || home_address->region || home_address->street) {
405 		e_contact_set (contact, E_CONTACT_ADDRESS_HOME, home_address);
406 	}
407 	e_contact_address_free (work_address);
408 	e_contact_address_free (home_address);
409 
410 	g_string_free (str, TRUE);
411 
412 	return contact;
413 }
414 
415 static void
416 resolve_list_card (LDIFImporter *gci,
417                    EContact *contact)
418 {
419 	GList *email, *l;
420 	GList *email_attrs = NULL;
421 	gchar *full_name;
422 
423 	/* set file_as to full_name so we don't later try and figure
424 	 * out a first/last name for the list. */
425 	full_name = e_contact_get (contact, E_CONTACT_FULL_NAME);
426 	if (full_name)
427 		e_contact_set (contact, E_CONTACT_FILE_AS, full_name);
428 	g_free (full_name);
429 
430 	/* FIMXE getting might not be implemented in ebook */
431 	email = e_contact_get (contact, E_CONTACT_EMAIL);
432 	for (l = email; l; l = l->next) {
433 		/* mozilla stuffs dn's in the EMAIL list for contact lists */
434 		gchar *dn = l->data;
435 		EContact *dn_contact = g_hash_table_lookup (gci->dn_contact_hash, dn);
436 
437 		/* break list chains here, since we don't support them just yet */
438 		if (dn_contact && !e_contact_get (dn_contact, E_CONTACT_IS_LIST)) {
439 			EDestination *dest;
440 			EVCardAttribute *attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
441 
442 			/* Hard-wired for default e-mail, since
443 			 * netscape only exports 1 email address. */
444 			dest = e_destination_new ();
445 			e_destination_set_contact (dest, dn_contact, 0);
446 
447 			e_destination_export_to_vcard_attribute (dest, attr);
448 
449 			g_object_unref (dest);
450 
451 			email_attrs = g_list_append (email_attrs, attr);
452 		}
453 	}
454 	e_contact_set_attributes (contact, E_CONTACT_EMAIL, email_attrs);
455 
456 	g_list_foreach (email, (GFunc) g_free, NULL);
457 	g_list_free (email);
458 	g_list_foreach (email_attrs, (GFunc) e_vcard_attribute_free, NULL);
459 	g_list_free (email_attrs);
460 }
461 
462 static void
463 add_to_notes (EContact *contact,
464               EContactField field)
465 {
466 	const gchar *old_text;
467 	const gchar *field_text;
468 	gchar       *new_text;
469 
470 	old_text = e_contact_get_const (contact, E_CONTACT_NOTE);
471 	if (old_text && strstr (old_text, e_contact_pretty_name (field)))
472 		return;
473 
474 	field_text = e_contact_get_const (contact, field);
475 	if (!field_text || !*field_text)
476 		return;
477 
478 	new_text = g_strdup_printf (
479 		"%s%s%s: %s",
480 		old_text ? old_text : "",
481 		old_text && *old_text &&
482 		*(old_text + strlen (old_text) - 1) != '\n' ? "\n" : "",
483 		e_contact_pretty_name (field), field_text);
484 	e_contact_set (contact, E_CONTACT_NOTE, new_text);
485 	g_free (new_text);
486 }
487 
488 static gboolean
489 ldif_import_contacts (gpointer d)
490 {
491 	LDIFImporter *gci = d;
492 	EContact *contact;
493 	GSList *iter;
494 	gint count = 0;
495 
496 	/* We process all normal cards immediately and keep the list
497 	 * ones till the end */
498 
499 	if (gci->state == 0) {
500 		while (count < 50 && (contact = getNextLDIFEntry (
501 			gci->dn_contact_hash, gci->file))) {
502 			if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
503 				gci->list_contacts = g_slist_prepend (
504 					gci->list_contacts, contact);
505 			} else {
506 				gchar *uid = NULL;
507 
508 				add_to_notes (contact, E_CONTACT_OFFICE);
509 				add_to_notes (contact, E_CONTACT_SPOUSE);
510 				add_to_notes (contact, E_CONTACT_BLOG_URL);
511 				if (e_book_client_add_contact_sync (gci->book_client, contact, &uid, NULL, NULL) && uid) {
512 					e_contact_set (contact, E_CONTACT_UID, uid);
513 					g_free (uid);
514 				}
515 				gci->contacts = g_slist_prepend (gci->contacts, contact);
516 			}
517 			count++;
518 		}
519 		if (contact == NULL) {
520 			gci->state = 1;
521 			gci->list_iterator = gci->list_contacts;
522 		}
523 	}
524 	if (gci->state == 1) {
525 		for (iter = gci->list_iterator; count < 50 && iter; iter = iter->next) {
526 			gchar *uid = NULL;
527 
528 			contact = iter->data;
529 			resolve_list_card (gci, contact);
530 			if (e_book_client_add_contact_sync (gci->book_client, contact, &uid, NULL, NULL) && uid) {
531 				e_contact_set (contact, E_CONTACT_UID, uid);
532 				g_free (uid);
533 			}
534 			count++;
535 		}
536 		gci->list_iterator = iter;
537 		if (iter == NULL)
538 			gci->state = 2;
539 	}
540 	if (gci->state == 2) {
541 		ldif_import_done (gci);
542 		return FALSE;
543 	} else {
544 		e_import_status (
545 			gci->import, gci->target, _("Importing..."),
546 			ftell (gci->file) * 100 / gci->size);
547 		return TRUE;
548 	}
549 }
550 
551 static void
552 primary_selection_changed_cb (ESourceSelector *selector,
553                               EImportTarget *target)
554 {
555 	ESource *source;
556 
557 	source = e_source_selector_ref_primary_selection (selector);
558 	g_return_if_fail (source != NULL);
559 
560 	g_datalist_set_data_full (
561 		&target->data, "ldif-source",
562 		source, (GDestroyNotify) g_object_unref);
563 }
564 
565 static GtkWidget *
566 ldif_getwidget (EImport *ei,
567                 EImportTarget *target,
568                 EImportImporter *im)
569 {
570 	EShell *shell;
571 	GtkWidget *vbox, *selector;
572 	ESourceRegistry *registry;
573 	ESource *primary;
574 	const gchar *extension_name;
575 
576 	vbox = gtk_vbox_new (FALSE, FALSE);
577 
578 	shell = e_shell_get_default ();
579 	registry = e_shell_get_registry (shell);
580 	extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
581 	selector = e_source_selector_new (registry, extension_name);
582 	e_source_selector_set_show_toggles (
583 		E_SOURCE_SELECTOR (selector), FALSE);
584 	gtk_box_pack_start (GTK_BOX (vbox), selector, FALSE, TRUE, 6);
585 
586 	primary = g_datalist_get_data (&target->data, "ldif-source");
587 	if (primary == NULL) {
588 		GList *list;
589 
590 		list = e_source_registry_list_sources (registry, extension_name);
591 		if (list != NULL) {
592 			primary = g_object_ref (list->data);
593 			g_datalist_set_data_full (
594 				&target->data, "ldif-source", primary,
595 				(GDestroyNotify) g_object_unref);
596 		}
597 
598 		g_list_free_full (list, (GDestroyNotify) g_object_unref);
599 	}
600 	e_source_selector_set_primary_selection (
601 		E_SOURCE_SELECTOR (selector), primary);
602 
603 	g_signal_connect (
604 		selector, "primary_selection_changed",
605 		G_CALLBACK (primary_selection_changed_cb), target);
606 
607 	gtk_widget_show_all (vbox);
608 
609 	return vbox;
610 }
611 
612 static const gchar *supported_extensions[3] = {
613 	".ldif", ".ldi", NULL
614 };
615 
616 static gboolean
617 ldif_supported (EImport *ei,
618                 EImportTarget *target,
619                 EImportImporter *im)
620 {
621 	gchar *ext;
622 	gint i;
623 	EImportTargetURI *s;
624 
625 	if (target->type != E_IMPORT_TARGET_URI)
626 		return FALSE;
627 
628 	s = (EImportTargetURI *) target;
629 	if (s->uri_src == NULL)
630 		return TRUE;
631 
632 	if (strncmp (s->uri_src, "file:///", 8) != 0)
633 		return FALSE;
634 
635 	ext = strrchr (s->uri_src, '.');
636 	if (ext == NULL)
637 		return FALSE;
638 
639 	for (i = 0; supported_extensions[i] != NULL; i++) {
640 		if (g_ascii_strcasecmp (supported_extensions[i], ext) == 0)
641 			return TRUE;
642 	}
643 
644 	return FALSE;
645 }
646 
647 static void
648 ldif_import_done (LDIFImporter *gci)
649 {
650 	if (gci->idle_id)
651 		g_source_remove (gci->idle_id);
652 
653 	fclose (gci->file);
654 	g_object_unref (gci->book_client);
655 	g_slist_foreach (gci->contacts, (GFunc) g_object_unref, NULL);
656 	g_slist_foreach (gci->list_contacts, (GFunc) g_object_unref, NULL);
657 	g_slist_free (gci->contacts);
658 	g_slist_free (gci->list_contacts);
659 	g_hash_table_destroy (gci->dn_contact_hash);
660 
661 	e_import_complete (gci->import, gci->target);
662 	g_object_unref (gci->import);
663 
664 	g_free (gci);
665 }
666 
667 static void
668 book_loaded_cb (GObject *source_object,
669                 GAsyncResult *result,
670                 gpointer user_data)
671 {
672 	ESource *source = E_SOURCE (source_object);
673 	LDIFImporter *gci = user_data;
674 	EClient *client = NULL;
675 
676 	e_client_utils_open_new_finish (source, result, &client, NULL);
677 
678 	if (client == NULL) {
679 		ldif_import_done (gci);
680 		return;
681 	}
682 
683 	gci->book_client = E_BOOK_CLIENT (client);
684 	gci->idle_id = g_idle_add (ldif_import_contacts, gci);
685 }
686 
687 static void
688 ldif_import (EImport *ei,
689              EImportTarget *target,
690              EImportImporter *im)
691 {
692 	LDIFImporter *gci;
693 	ESource *source;
694 	FILE *file = NULL;
695 	EImportTargetURI *s = (EImportTargetURI *) target;
696 	gchar *filename;
697 
698 	filename = g_filename_from_uri (s->uri_src, NULL, NULL);
699 	if (filename != NULL) {
700 		file = g_fopen (filename, "r");
701 		g_free (filename);
702 	}
703 	if (file == NULL) {
704 		g_message (G_STRLOC ":Can't open .ldif file");
705 		e_import_complete (ei, target);
706 		return;
707 	}
708 
709 	gci = g_malloc0 (sizeof (*gci));
710 	g_datalist_set_data (&target->data, "ldif-data", gci);
711 	gci->import = g_object_ref (ei);
712 	gci->target = target;
713 	gci->file = file;
714 	fseek (file, 0, SEEK_END);
715 	gci->size = ftell (file);
716 	fseek (file, 0, SEEK_SET);
717 	gci->dn_contact_hash = g_hash_table_new_full (
718 		g_str_hash, g_str_equal,
719 		(GDestroyNotify) g_free,
720 		(GDestroyNotify) NULL);
721 
722 	source = g_datalist_get_data (&target->data, "ldif-source");
723 
724 	e_client_utils_open_new (
725 		source, E_CLIENT_SOURCE_TYPE_CONTACTS, FALSE, NULL,
726 		book_loaded_cb, gci);
727 }
728 
729 static void
730 ldif_cancel (EImport *ei,
731              EImportTarget *target,
732              EImportImporter *im)
733 {
734 	LDIFImporter *gci = g_datalist_get_data (&target->data, "ldif-data");
735 
736 	if (gci)
737 		gci->state = 2;
738 }
739 
740 static GtkWidget *
741 ldif_get_preview (EImport *ei,
742                   EImportTarget *target,
743                   EImportImporter *im)
744 {
745 	GtkWidget *preview;
746 	GSList *contacts = NULL;
747 	EContact *contact;
748 	EImportTargetURI *s = (EImportTargetURI *) target;
749 	gchar *filename;
750 	GHashTable *dn_contact_hash;
751 	FILE *file;
752 
753 	filename = g_filename_from_uri (s->uri_src, NULL, NULL);
754 	if (filename == NULL) {
755 		g_message (G_STRLOC ": Couldn't get filename from URI '%s'", s->uri_src);
756 		return NULL;
757 	}
758 
759 	file = g_fopen (filename, "r");
760 	g_free (filename);
761 
762 	if (file == NULL) {
763 		g_message (G_STRLOC ": Can't open .ldif file");
764 		return NULL;
765 	}
766 
767 	dn_contact_hash = g_hash_table_new_full (
768 		g_str_hash, g_str_equal,
769 		(GDestroyNotify) g_free,
770 		(GDestroyNotify) NULL);
771 
772 	while (contact = getNextLDIFEntry (dn_contact_hash, file), contact != NULL) {
773 		if (!e_contact_get (contact, E_CONTACT_IS_LIST)) {
774 			add_to_notes (contact, E_CONTACT_OFFICE);
775 			add_to_notes (contact, E_CONTACT_SPOUSE);
776 			add_to_notes (contact, E_CONTACT_BLOG_URL);
777 		}
778 
779 		contacts = g_slist_prepend (contacts, contact);
780 	}
781 
782 	g_hash_table_destroy (dn_contact_hash);
783 
784 	contacts = g_slist_reverse (contacts);
785 	preview = evolution_contact_importer_get_preview_widget (contacts);
786 
787 	e_client_util_free_object_slist (contacts);
788 	fclose (file);
789 
790 	return preview;
791 }
792 
793 static EImportImporter ldif_importer = {
794 	E_IMPORT_TARGET_URI,
795 	0,
796 	ldif_supported,
797 	ldif_getwidget,
798 	ldif_import,
799 	ldif_cancel,
800 	ldif_get_preview,
801 };
802 
803 EImportImporter *
804 evolution_ldif_importer_peek (void)
805 {
806 	ldif_importer.name = _("LDAP Data Interchange Format (.ldif)");
807 	ldif_importer.description = _("Evolution LDIF importer");
808 
809 	return &ldif_importer;
810 }