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