1 /*
2  * This program is free software; you can redistribute it and/or modify it
3  * under the terms of the GNU Lesser General Public License as published by
4  * the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful, but
7  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
9  * for more details.
10  *
11  * You should have received a copy of the GNU Lesser General Public License
12  * along with this program; if not, see <http://www.gnu.org/licenses/>.
13  *
14  *
15  * Authors:
16  *		Jon Trowbridge <trow@ximian.com>
17  *
18  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19  *
20  */
21 
22 #include "evolution-config.h"
23 
24 #include <ctype.h>
25 #include <string.h>
26 #include <gtk/gtk.h>
27 #include <glib/gi18n.h>
28 
29 #include <addressbook/util/eab-book-util.h>
30 #include "e-contact-editor.h"
31 #include "e-contact-quick-add.h"
32 #include "eab-contact-merging.h"
33 
34 typedef struct _QuickAdd QuickAdd;
35 struct _QuickAdd {
36 	gchar *name;
37 	gchar *email;
38 	gchar *vcard;
39 	EContact *contact;
40 	GCancellable *cancellable;
41 	EClientCache *client_cache;
42 	ESource *source;
43 
44 	EContactQuickAddCallback cb;
45 	gpointer closure;
46 
47 	GtkWidget *dialog;
48 	GtkWidget *name_entry;
49 	GtkWidget *email_entry;
50 	GtkWidget *combo_box;
51 
52 	gint refs;
53 
54 };
55 
56 static QuickAdd *
quick_add_new(EClientCache * client_cache)57 quick_add_new (EClientCache *client_cache)
58 {
59 	QuickAdd *qa = g_slice_new0 (QuickAdd);
60 	qa->contact = e_contact_new ();
61 	qa->client_cache = g_object_ref (client_cache);
62 	qa->refs = 1;
63 	return qa;
64 }
65 
66 static void
quick_add_unref(QuickAdd * qa)67 quick_add_unref (QuickAdd *qa)
68 {
69 	if (qa) {
70 		--qa->refs;
71 		if (qa->refs == 0) {
72 			if (qa->cancellable != NULL) {
73 				g_cancellable_cancel (qa->cancellable);
74 				g_object_unref (qa->cancellable);
75 			}
76 			g_free (qa->name);
77 			g_free (qa->email);
78 			g_free (qa->vcard);
79 			g_object_unref (qa->contact);
80 			g_object_unref (qa->client_cache);
81 			g_slice_free (QuickAdd, qa);
82 		}
83 	}
84 }
85 
86 static void
quick_add_set_name(QuickAdd * qa,const gchar * name)87 quick_add_set_name (QuickAdd *qa,
88                     const gchar *name)
89 {
90 	if (name == qa->name)
91 		return;
92 
93 	g_free (qa->name);
94 	qa->name = g_strdup (name);
95 }
96 
97 static void
quick_add_set_email(QuickAdd * qa,const gchar * email)98 quick_add_set_email (QuickAdd *qa,
99                      const gchar *email)
100 {
101 	if (email == qa->email)
102 		return;
103 
104 	g_free (qa->email);
105 	qa->email = g_strdup (email);
106 }
107 
108 static void
quick_add_set_vcard(QuickAdd * qa,const gchar * vcard)109 quick_add_set_vcard (QuickAdd *qa,
110                      const gchar *vcard)
111 {
112 	if (vcard == qa->vcard)
113 		return;
114 
115 	g_free (qa->vcard);
116 	qa->vcard = g_strdup (vcard);
117 }
118 
119 static void
merge_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)120 merge_cb (GObject *source_object,
121           GAsyncResult *result,
122           gpointer user_data)
123 {
124 	QuickAdd *qa = user_data;
125 	EClient *client;
126 	GError *error = NULL;
127 
128 	client = e_client_cache_get_client_finish (
129 		E_CLIENT_CACHE (source_object), result, &error);
130 
131 	/* Sanity check. */
132 	g_return_if_fail (
133 		((client != NULL) && (error == NULL)) ||
134 		((client == NULL) && (error != NULL)));
135 
136 	/* Ignore cancellations. */
137 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
138 		g_warn_if_fail (client == NULL);
139 		g_error_free (error);
140 		return;
141 	}
142 
143 	if (error != NULL) {
144 		if (qa->cb)
145 			qa->cb (NULL, qa->closure);
146 		g_error_free (error);
147 		quick_add_unref (qa);
148 		return;
149 	}
150 
151 	if (!e_client_is_readonly (client)) {
152 		ESourceRegistry *registry;
153 
154 		registry = e_client_cache_ref_registry (qa->client_cache);
155 
156 		eab_merging_book_add_contact (
157 			registry, E_BOOK_CLIENT (client),
158 			qa->contact, NULL, NULL);
159 
160 		g_object_unref (registry);
161 	} else {
162 		ESource *source = e_client_get_source (client);
163 
164 		e_alert_run_dialog_for_args (
165 			e_shell_get_active_window (NULL),
166 			"addressbook:error-read-only",
167 			e_source_get_display_name (source),
168 			NULL);
169 	}
170 
171 	if (qa->cb)
172 		qa->cb (qa->contact, qa->closure);
173 
174 	g_object_unref (client);
175 
176 	quick_add_unref (qa);
177 }
178 
179 static void
quick_add_merge_contact(QuickAdd * qa)180 quick_add_merge_contact (QuickAdd *qa)
181 {
182 	if (qa->cancellable != NULL) {
183 		g_cancellable_cancel (qa->cancellable);
184 		g_object_unref (qa->cancellable);
185 	}
186 
187 	qa->cancellable = g_cancellable_new ();
188 
189 	e_client_cache_get_client (
190 		qa->client_cache, qa->source,
191 		E_SOURCE_EXTENSION_ADDRESS_BOOK, 30,
192 		qa->cancellable, merge_cb, qa);
193 }
194 
195 /* Raise a contact editor with all fields editable,
196  * and hook up all signals accordingly. */
197 
198 static void
contact_added_cb(EContactEditor * ce,const GError * error,EContact * contact,gpointer closure)199 contact_added_cb (EContactEditor *ce,
200                   const GError *error,
201                   EContact *contact,
202                   gpointer closure)
203 {
204 	QuickAdd *qa;
205 
206 	qa = g_object_get_data (G_OBJECT (ce), "quick_add");
207 
208 	if (qa) {
209 		if (qa->cb)
210 			qa->cb (qa->contact, qa->closure);
211 
212 		/* We don't need to unref qa because we set_data_full below */
213 		g_object_set_data (G_OBJECT (ce), "quick_add", NULL);
214 	}
215 }
216 
217 static void
editor_closed_cb(GtkWidget * w,gpointer closure)218 editor_closed_cb (GtkWidget *w,
219                   gpointer closure)
220 {
221 	QuickAdd *qa;
222 
223 	qa = g_object_get_data (G_OBJECT (w), "quick_add");
224 
225 	if (qa)
226 		/* We don't need to unref qa because we set_data_full below */
227 		g_object_set_data (G_OBJECT (w), "quick_add", NULL);
228 }
229 
230 static void
ce_have_contact(EBookClient * book_client,const GError * error,EContact * contact,gpointer closure)231 ce_have_contact (EBookClient *book_client,
232                  const GError *error,
233                  EContact *contact,
234                  gpointer closure)
235 {
236 	QuickAdd *qa = (QuickAdd *) closure;
237 
238 	if (error != NULL) {
239 		if (book_client)
240 			g_object_unref (book_client);
241 		g_warning (
242 			"Failed to find contact, status %d (%s).",
243 			error->code, error->message);
244 		quick_add_unref (qa);
245 	} else {
246 		EShell *shell;
247 		EABEditor *contact_editor;
248 
249 		if (contact) {
250 			/* use found contact */
251 			if (qa->contact)
252 				g_object_unref (qa->contact);
253 			qa->contact = g_object_ref (contact);
254 		}
255 
256 		shell = e_shell_get_default ();
257 		contact_editor = e_contact_editor_new (
258 			shell, book_client, qa->contact, TRUE, TRUE /* XXX */);
259 
260 		/* Mark it as changed so the Save buttons are
261 		 * enabled when we bring up the dialog. */
262 		g_object_set (
263 			contact_editor, "changed", contact != NULL, NULL);
264 
265 		/* We pass this via object data, so that we don't get a
266 		 * dangling pointer referenced if both the "contact_added"
267 		 * and "editor_closed" get emitted.  (Which, based on a
268 		 * backtrace in bugzilla, I think can happen and cause a
269 		 * crash. */
270 		g_object_set_data_full (
271 			G_OBJECT (contact_editor), "quick_add", qa,
272 			(GDestroyNotify) quick_add_unref);
273 
274 		g_signal_connect (
275 			contact_editor, "contact_added",
276 			G_CALLBACK (contact_added_cb), NULL);
277 		g_signal_connect (
278 			contact_editor, "editor_closed",
279 			G_CALLBACK (editor_closed_cb), NULL);
280 
281 		g_object_unref (book_client);
282 	}
283 }
284 
285 static void
ce_have_book(GObject * source_object,GAsyncResult * result,gpointer user_data)286 ce_have_book (GObject *source_object,
287               GAsyncResult *result,
288               gpointer user_data)
289 {
290 	QuickAdd *qa = user_data;
291 	EClient *client;
292 	ESourceRegistry *registry;
293 	GError *error = NULL;
294 
295 	client = e_client_cache_get_client_finish (
296 		E_CLIENT_CACHE (source_object), result, &error);
297 
298 	/* Sanity check. */
299 	g_return_if_fail (
300 		((client != NULL) && (error == NULL)) ||
301 		((client == NULL) && (error != NULL)));
302 
303 	/* Ignore cancellations. */
304 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
305 		g_warn_if_fail (client == NULL);
306 		g_error_free (error);
307 		return;
308 	}
309 
310 	if (error != NULL) {
311 		g_warning ("%s", error->message);
312 		quick_add_unref (qa);
313 		g_error_free (error);
314 		return;
315 	}
316 
317 	registry = e_client_cache_ref_registry (qa->client_cache);
318 
319 	eab_merging_book_find_contact (
320 		registry, E_BOOK_CLIENT (client),
321 		qa->contact, ce_have_contact, qa);
322 
323 	g_object_unref (registry);
324 }
325 
326 static void
edit_contact(QuickAdd * qa)327 edit_contact (QuickAdd *qa)
328 {
329 	if (qa->cancellable != NULL) {
330 		g_cancellable_cancel (qa->cancellable);
331 		g_object_unref (qa->cancellable);
332 	}
333 
334 	qa->cancellable = g_cancellable_new ();
335 
336 	e_client_cache_get_client (
337 		qa->client_cache, qa->source,
338 		E_SOURCE_EXTENSION_ADDRESS_BOOK, 30,
339 		qa->cancellable, ce_have_book, qa);
340 }
341 
342 #define QUICK_ADD_RESPONSE_EDIT_FULL 2
343 
344 static void
clicked_cb(GtkWidget * w,gint button,gpointer closure)345 clicked_cb (GtkWidget *w,
346             gint button,
347             gpointer closure)
348 {
349 	QuickAdd *qa = (QuickAdd *) closure;
350 
351 	/* Get data out of entries. */
352 	if (!qa->vcard && (button == GTK_RESPONSE_OK ||
353 			button == QUICK_ADD_RESPONSE_EDIT_FULL)) {
354 		gchar *name = NULL;
355 		gchar *email = NULL;
356 
357 		if (qa->name_entry)
358 			name = gtk_editable_get_chars (
359 				GTK_EDITABLE (qa->name_entry), 0, -1);
360 
361 		if (qa->email_entry)
362 			email = gtk_editable_get_chars (
363 				GTK_EDITABLE (qa->email_entry), 0, -1);
364 
365 		e_contact_set (
366 			qa->contact, E_CONTACT_FULL_NAME,
367 			(name != NULL) ? name : "");
368 
369 		e_contact_set (
370 			qa->contact, E_CONTACT_EMAIL_1,
371 			(email != NULL) ? email : "");
372 
373 		g_free (name);
374 		g_free (email);
375 	}
376 
377 	gtk_widget_destroy (w);
378 
379 	if (button == GTK_RESPONSE_OK) {
380 
381 		/* OK */
382 		quick_add_merge_contact (qa);
383 
384 	} else if (button == QUICK_ADD_RESPONSE_EDIT_FULL) {
385 
386 		/* EDIT FULL */
387 		edit_contact (qa);
388 
389 	} else {
390 		/* CANCEL */
391 		quick_add_unref (qa);
392 	}
393 
394 }
395 
396 static void
sanitize_widgets(QuickAdd * qa)397 sanitize_widgets (QuickAdd *qa)
398 {
399 	GtkComboBox *combo_box;
400 	const gchar *active_id;
401 	gboolean enabled = TRUE;
402 
403 	g_return_if_fail (qa != NULL);
404 	g_return_if_fail (qa->dialog != NULL);
405 
406 	combo_box = GTK_COMBO_BOX (qa->combo_box);
407 	active_id = gtk_combo_box_get_active_id (combo_box);
408 	enabled = (active_id != NULL);
409 
410 	gtk_dialog_set_response_sensitive (
411 		GTK_DIALOG (qa->dialog),
412 		QUICK_ADD_RESPONSE_EDIT_FULL, enabled);
413 	gtk_dialog_set_response_sensitive (
414 		GTK_DIALOG (qa->dialog), GTK_RESPONSE_OK, enabled);
415 }
416 
417 static void
source_changed(ESourceComboBox * source_combo_box,QuickAdd * qa)418 source_changed (ESourceComboBox *source_combo_box,
419                 QuickAdd *qa)
420 {
421 	ESource *source;
422 
423 	source = e_source_combo_box_ref_active (source_combo_box);
424 
425 	if (source != NULL) {
426 		if (qa->source != NULL)
427 			g_object_unref (qa->source);
428 		qa->source = source;  /* takes reference */
429 	}
430 
431 	sanitize_widgets (qa);
432 }
433 
434 static GtkWidget *
build_quick_add_dialog(QuickAdd * qa)435 build_quick_add_dialog (QuickAdd *qa)
436 {
437 	GtkWidget *container;
438 	GtkWidget *dialog;
439 	GtkWidget *label;
440 	GtkTable *table;
441 	ESource *source;
442 	ESourceRegistry *registry;
443 	const gchar *extension_name;
444 	const gint xpad = 0, ypad = 0;
445 
446 	g_return_val_if_fail (qa != NULL, NULL);
447 
448 	dialog = gtk_dialog_new_with_buttons (
449 		_("Contact Quick-Add"),
450 		e_shell_get_active_window (NULL),
451 		0,
452 		_("_Edit Full"), QUICK_ADD_RESPONSE_EDIT_FULL,
453 		_("_Cancel"), GTK_RESPONSE_CANCEL,
454 		_("_OK"), GTK_RESPONSE_OK,
455 		NULL);
456 
457 	container = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
458 	gtk_container_set_border_width (GTK_CONTAINER (container), 12);
459 	container = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
460 	gtk_container_set_border_width (GTK_CONTAINER (container), 0);
461 
462 	g_signal_connect (
463 		dialog, "response",
464 		G_CALLBACK (clicked_cb), qa);
465 
466 	qa->dialog = dialog;
467 
468 	qa->name_entry = gtk_entry_new ();
469 	if (qa->name)
470 		gtk_entry_set_text (GTK_ENTRY (qa->name_entry), qa->name);
471 
472 	qa->email_entry = gtk_entry_new ();
473 	if (qa->email)
474 		gtk_entry_set_text (GTK_ENTRY (qa->email_entry), qa->email);
475 
476 	if (qa->vcard) {
477 		/* when adding vCard, then do not allow change name or email */
478 		gtk_widget_set_sensitive (qa->name_entry, FALSE);
479 		gtk_widget_set_sensitive (qa->email_entry, FALSE);
480 	}
481 
482 	extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
483 	registry = e_client_cache_ref_registry (qa->client_cache);
484 	source = e_source_registry_ref_default_address_book (registry);
485 	g_object_unref (registry);
486 
487 	qa->combo_box = e_client_combo_box_new (
488 		qa->client_cache, extension_name);
489 	e_source_combo_box_set_active (
490 		E_SOURCE_COMBO_BOX (qa->combo_box), source);
491 
492 	g_object_unref (source);
493 
494 	source_changed (E_SOURCE_COMBO_BOX (qa->combo_box), qa);
495 	g_signal_connect (
496 		qa->combo_box, "changed",
497 		G_CALLBACK (source_changed), qa);
498 
499 	table = GTK_TABLE (gtk_table_new (3, 2, FALSE));
500 	gtk_table_set_row_spacings (table, 6);
501 	gtk_table_set_col_spacings (table, 12);
502 
503 	label = gtk_label_new_with_mnemonic (_("_Full name"));
504 	gtk_label_set_mnemonic_widget ((GtkLabel *) label, qa->name_entry);
505 	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
506 
507 	gtk_table_attach (
508 		table, label,
509 		0, 1, 0, 1,
510 		GTK_FILL, 0, xpad, ypad);
511 	gtk_table_attach (
512 		table, qa->name_entry,
513 		1, 2, 0, 1,
514 		GTK_EXPAND | GTK_FILL, 0, xpad, ypad);
515 
516 	label = gtk_label_new_with_mnemonic (_("E_mail"));
517 	gtk_label_set_mnemonic_widget ((GtkLabel *) label, qa->email_entry);
518 	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
519 
520 	gtk_table_attach (
521 		table, label,
522 		0, 1, 1, 2,
523 		GTK_FILL, 0, xpad, ypad);
524 	gtk_table_attach (
525 		table, qa->email_entry,
526 		1, 2, 1, 2,
527 		GTK_EXPAND | GTK_FILL, 0, xpad, ypad);
528 
529 	label = gtk_label_new_with_mnemonic (_("_Select Address Book"));
530 	gtk_label_set_mnemonic_widget ((GtkLabel *) label, qa->combo_box);
531 	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
532 
533 	gtk_table_attach (
534 		table, label,
535 		0, 1, 2, 3,
536 		GTK_FILL, 0, xpad, ypad);
537 	gtk_table_attach (
538 		table, qa->combo_box,
539 		1, 2, 2, 3,
540 		GTK_EXPAND | GTK_FILL, 0, xpad, ypad);
541 
542 	gtk_container_set_border_width (GTK_CONTAINER (table), 12);
543 	container = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
544 	gtk_box_pack_start (
545 		GTK_BOX (container), GTK_WIDGET (table), FALSE, FALSE, 0);
546 	gtk_widget_show_all (GTK_WIDGET (table));
547 
548 	return dialog;
549 }
550 
551 void
e_contact_quick_add(EClientCache * client_cache,const gchar * in_name,const gchar * email,EContactQuickAddCallback cb,gpointer closure)552 e_contact_quick_add (EClientCache *client_cache,
553                      const gchar *in_name,
554                      const gchar *email,
555                      EContactQuickAddCallback cb,
556                      gpointer closure)
557 {
558 	QuickAdd *qa;
559 	GtkWidget *dialog;
560 	gchar *name = NULL;
561 	gint len;
562 
563 	g_return_if_fail (E_IS_CLIENT_CACHE (client_cache));
564 
565 	/* We need to have *something* to work with. */
566 	if (in_name == NULL && email == NULL) {
567 		if (cb)
568 			cb (NULL, closure);
569 		return;
570 	}
571 
572 	if (in_name) {
573 		name = g_strdup (in_name);
574 
575 		/* Remove extra whitespace and the quotes some mailers put around names. */
576 		g_strstrip (name);
577 		len = strlen (name);
578 		if ((name[0] == '\'' && name[len - 1] == '\'') ||
579 			(name[0] == '"' && name[len - 1] == '"')) {
580 			name[0] = ' ';
581 			name[len - 1] = ' ';
582 		}
583 		g_strstrip (name);
584 	}
585 
586 	qa = quick_add_new (client_cache);
587 	qa->cb = cb;
588 	qa->closure = closure;
589 	if (name)
590 		quick_add_set_name (qa, name);
591 	if (email)
592 		quick_add_set_email (qa, email);
593 
594 	dialog = build_quick_add_dialog (qa);
595 	gtk_widget_show_all (dialog);
596 
597 	g_free (name);
598 }
599 
600 void
e_contact_quick_add_free_form(EClientCache * client_cache,const gchar * text,EContactQuickAddCallback cb,gpointer closure)601 e_contact_quick_add_free_form (EClientCache *client_cache,
602                                const gchar *text,
603                                EContactQuickAddCallback cb,
604                                gpointer closure)
605 {
606 	gchar *name = NULL, *email = NULL;
607 	const gchar *last_at, *s;
608 	gboolean in_quote;
609 
610 	g_return_if_fail (E_IS_CLIENT_CACHE (client_cache));
611 
612 	if (text == NULL) {
613 		e_contact_quick_add (client_cache, NULL, NULL, cb, closure);
614 		return;
615 	}
616 
617 	/* Look for things that look like e-mail addresses embedded in text */
618 	in_quote = FALSE;
619 	last_at = NULL;
620 	for (s = text; *s; ++s) {
621 		if (*s == '@' && !in_quote)
622 			last_at = s;
623 		else if (*s == '"')
624 			in_quote = !in_quote;
625 	}
626 
627 	if (last_at == NULL) {
628 		/* No at sign, so we treat it all as the name */
629 		name = g_strdup (text);
630 	} else {
631 		gboolean bad_char = FALSE;
632 
633 		/* walk backwards to whitespace or a < or a quote... */
634 		while (last_at >= text && !bad_char
635 		       && !(isspace ((gint) *last_at) ||
636 			  *last_at == '<' ||
637 			  *last_at == '"')) {
638 			/* Check for some stuff that can't appear in a legal e-mail address. */
639 			if (*last_at == '['
640 			    || *last_at == ']'
641 			    || *last_at == '('
642 			    || *last_at == ')')
643 				bad_char = TRUE;
644 			--last_at;
645 		}
646 		if (last_at < text)
647 			last_at = text;
648 
649 		/* ...and then split the text there */
650 		if (!bad_char) {
651 			if (text < last_at)
652 				name = g_strndup (text, last_at - text);
653 			email = g_strdup (last_at);
654 		}
655 	}
656 
657 	/* If all else has failed, make it the name. */
658 	if (name == NULL && email == NULL)
659 		name = g_strdup (text);
660 
661 	/* Clean up email, remove bracketing <>s */
662 	if (email && *email) {
663 		gboolean changed = FALSE;
664 		g_strstrip (email);
665 		if (*email == '<') {
666 			*email = ' ';
667 			changed = TRUE;
668 		}
669 		if (email[strlen (email) - 1] == '>') {
670 			email[strlen (email) - 1] = ' ';
671 			changed = TRUE;
672 		}
673 		if (changed)
674 			g_strstrip (email);
675 	}
676 
677 	e_contact_quick_add (client_cache, name, email, cb, closure);
678 
679 	g_free (name);
680 	g_free (email);
681 }
682 
683 void
e_contact_quick_add_email(EClientCache * client_cache,const gchar * email,EContactQuickAddCallback cb,gpointer closure)684 e_contact_quick_add_email (EClientCache *client_cache,
685                            const gchar *email,
686                            EContactQuickAddCallback cb,
687                            gpointer closure)
688 {
689 	gchar *name = NULL;
690 	gchar *addr = NULL;
691 	gchar *lt, *gt;
692 
693 	/* Handle something of the form "Foo <foo@bar.com>".  This is more
694 	 * more forgiving than the free-form parser, allowing for unquoted
695 	 * whitespace since we know the whole string is an email address. */
696 
697 	lt = (email != NULL) ? strchr (email, '<') : NULL;
698 	gt = (lt != NULL) ? strchr (email, '>') : NULL;
699 
700 	if (lt != NULL && gt != NULL && (gt - lt) > 0) {
701 		name = g_strndup (email, lt - email);
702 		addr = g_strndup (lt + 1, gt - lt - 1);
703 	} else {
704 		addr = g_strdup (email);
705 	}
706 
707 	e_contact_quick_add (client_cache, name, addr, cb, closure);
708 
709 	g_free (name);
710 	g_free (addr);
711 }
712 
713 void
e_contact_quick_add_vcard(EClientCache * client_cache,const gchar * vcard,EContactQuickAddCallback cb,gpointer closure)714 e_contact_quick_add_vcard (EClientCache *client_cache,
715                            const gchar *vcard,
716                            EContactQuickAddCallback cb,
717                            gpointer closure)
718 {
719 	QuickAdd *qa;
720 	GtkWidget *dialog;
721 	EContact *contact;
722 
723 	g_return_if_fail (E_IS_CLIENT_CACHE (client_cache));
724 
725 	/* We need to have *something* to work with. */
726 	if (vcard == NULL) {
727 		if (cb)
728 			cb (NULL, closure);
729 		return;
730 	}
731 
732 	qa = quick_add_new (client_cache);
733 	qa->cb = cb;
734 	qa->closure = closure;
735 	quick_add_set_vcard (qa, vcard);
736 
737 	contact = e_contact_new_from_vcard (qa->vcard);
738 
739 	if (contact) {
740 		GList *emails;
741 		gchar *name;
742 		EContactName *contact_name;
743 
744 		g_object_unref (qa->contact);
745 		qa->contact = contact;
746 
747 		contact_name = e_contact_get (qa->contact, E_CONTACT_NAME);
748 		name = e_contact_name_to_string (contact_name);
749 		quick_add_set_name (qa, name);
750 		g_free (name);
751 		e_contact_name_free (contact_name);
752 
753 		emails = e_contact_get (qa->contact, E_CONTACT_EMAIL);
754 		if (emails) {
755 			quick_add_set_email (qa, emails->data);
756 
757 			g_list_foreach (emails, (GFunc) g_free, NULL);
758 			g_list_free (emails);
759 		}
760 	} else {
761 		if (cb)
762 			cb (NULL, closure);
763 
764 		quick_add_unref (qa);
765 		g_warning ("Contact's vCard parsing failed!");
766 		return;
767 	}
768 
769 	dialog = build_quick_add_dialog (qa);
770 	gtk_widget_show_all (dialog);
771 }
772