1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 * Copyright (C) 2001-2004 Ximian, Inc.
8 * Authors: Jon Trowbridge <trow@ximian.com>
9 * Chris Toshok <toshok@ximian.com>
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of version 2 of the GNU Lesser General Public
15 * License as published by the Free Software Foundation.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
29 We should probably make most of the functions in this file a little
30 stupider.. all the work extracting useful info from the
31 EContact/raw text/etc should happen in e_destination_set_contact
32 (and the other setters), not in a bunch of if's in the respective
37 #include "e-destination.h"
42 #include <libebook/e-book.h>
45 #include <libxml/xmlmemory.h>
46 #include <glib/gi18n-lib.h>
47 #include <camel/camel-internet-address.h>
51 struct _EDestinationPrivate {
69 guint html_mail_override : 1;
70 guint wants_html_mail : 1;
72 guint show_addresses : 1;
74 guint auto_recipient : 1;
77 static gboolean e_destination_from_contact (const EDestination *);
78 static xmlNodePtr e_destination_xml_encode (const EDestination *dest);
79 static gboolean e_destination_xml_decode (EDestination *dest, xmlNodePtr node);
80 static void e_destination_clear (EDestination *dest);
89 static guint signals [LAST_SIGNAL] = { 0 };
91 static GObjectClass *parent_class;
93 /* Copied from eab-book-util.c. The name selector also keeps its own copy... */
95 utf8_casefold_collate_len (const gchar *str1, const gchar *str2, gint len)
97 gchar *s1 = g_utf8_casefold(str1, len);
98 gchar *s2 = g_utf8_casefold(str2, len);
101 rv = g_utf8_collate (s1, s2);
109 /* Copied from eab-book-util.c. The name selector also keeps its own copy... */
111 utf8_casefold_collate (const gchar *str1, const gchar *str2)
113 return utf8_casefold_collate_len (str1, str2, -1);
117 e_destination_dispose (GObject *obj)
119 EDestination *dest = E_DESTINATION (obj);
122 e_destination_clear (dest);
128 if (G_OBJECT_CLASS (parent_class)->dispose)
129 (* G_OBJECT_CLASS (parent_class)->dispose) (obj);
133 e_destination_class_init (EDestinationClass *klass)
135 GObjectClass *object_class = G_OBJECT_CLASS (klass);
137 parent_class = g_type_class_ref (G_TYPE_OBJECT);
140 g_signal_new ("changed",
141 G_OBJECT_CLASS_TYPE (object_class),
143 G_STRUCT_OFFSET (EDestinationClass, changed),
145 g_cclosure_marshal_VOID__VOID,
148 object_class->dispose = e_destination_dispose;
152 e_destination_init (EDestination *dest)
154 dest->priv = g_new0 (struct _EDestinationPrivate, 1);
156 dest->priv->auto_recipient = FALSE;
157 dest->priv->ignored = FALSE;
161 e_destination_get_type (void)
163 static GType dest_type = 0;
166 GTypeInfo dest_info = {
167 sizeof (EDestinationClass),
168 NULL, /* base_class_init */
169 NULL, /* base_class_finalize */
170 (GClassInitFunc) e_destination_class_init,
171 NULL, /* class_finalize */
172 NULL, /* class_data */
173 sizeof (EDestination),
175 (GInstanceInitFunc) e_destination_init
178 dest_type = g_type_register_static (G_TYPE_OBJECT, "EDestination", &dest_info, 0);
187 * Creates a new #EDestination with blank values.
189 * Return value: A newly created #EDestination.
192 e_destination_new (void)
194 return g_object_new (E_TYPE_DESTINATION, NULL);
198 * e_destination_copy:
199 * @dest: an #EDestination
201 * Creates a new #EDestination identical to @dest.
203 * Return value: A newly created #EDestination, identical to @dest.
206 e_destination_copy (const EDestination *dest)
208 EDestination *new_dest;
211 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
213 new_dest = e_destination_new ();
215 new_dest->priv->source_uid = g_strdup (dest->priv->source_uid);
216 new_dest->priv->contact_uid = g_strdup (dest->priv->contact_uid);
217 new_dest->priv->name = g_strdup (dest->priv->name);
218 new_dest->priv->email = g_strdup (dest->priv->email);
219 new_dest->priv->addr = g_strdup (dest->priv->addr);
220 new_dest->priv->email_num = dest->priv->email_num;
221 new_dest->priv->ignored = dest->priv->ignored;
223 if (dest->priv->contact)
224 new_dest->priv->contact = g_object_ref (dest->priv->contact);
226 new_dest->priv->html_mail_override = dest->priv->html_mail_override;
227 new_dest->priv->wants_html_mail = dest->priv->wants_html_mail;
229 /* deep copy, recursively copy our children */
230 for (iter = dest->priv->list_dests; iter != NULL; iter = g_list_next (iter)) {
231 new_dest->priv->list_dests = g_list_append (new_dest->priv->list_dests,
232 e_destination_copy (E_DESTINATION (iter->data)));
235 /* XXX other settings? */
236 new_dest->priv->raw = g_strdup(dest->priv->raw);
242 e_destination_clear (EDestination *dest)
244 g_free (dest->priv->source_uid);
245 dest->priv->source_uid = NULL;
247 g_free (dest->priv->contact_uid);
248 dest->priv->contact_uid = NULL;
250 g_free (dest->priv->raw);
251 dest->priv->raw = NULL;
253 g_free (dest->priv->name);
254 dest->priv->name = NULL;
256 g_free (dest->priv->email);
257 dest->priv->email = NULL;
259 g_free (dest->priv->addr);
260 dest->priv->addr = NULL;
262 g_free (dest->priv->textrep);
263 dest->priv->textrep = NULL;
265 if (dest->priv->contact) {
266 g_object_unref (dest->priv->contact);
267 dest->priv->contact = NULL;
269 dest->priv->email_num = -1;
271 g_list_foreach (dest->priv->list_dests, (GFunc) g_object_unref, NULL);
272 g_list_free (dest->priv->list_dests);
273 dest->priv->list_dests = NULL;
277 nonempty (const char *s)
283 c = g_utf8_get_char (s);
284 if (!g_unichar_isspace (c))
286 s = g_utf8_next_char (s);
292 * e_destination_empty:
293 * @dest: an #EDestination
295 * Checks if @dest is blank.
297 * Return value: %TRUE if @dest is empty, %FALSE otherwise.
300 e_destination_empty (const EDestination *dest)
303 struct _EDestinationPrivate *p;
305 g_return_val_if_fail (E_IS_DESTINATION (dest), TRUE);
309 return !(p->contact != NULL
310 || (p->source_uid && *p->source_uid)
311 || (p->contact_uid && *p->contact_uid)
312 || (nonempty (p->raw))
313 || (nonempty (p->name))
314 || (nonempty (p->email))
315 || (nonempty (p->addr))
316 || (p->list_dests != NULL));
320 * e_destination_equal:
321 * @a: an #EDestination
322 * @b: an #EDestination
324 * Checks if @a and @b are equal.
326 * Return value: %TRUE if the destinations are equal, %FALSE otherwise.
329 e_destination_equal (const EDestination *a, const EDestination *b)
331 const struct _EDestinationPrivate *pa, *pb;
334 g_return_val_if_fail (E_IS_DESTINATION (a), FALSE);
335 g_return_val_if_fail (E_IS_DESTINATION (b), FALSE);
343 /* Check equality of contacts. */
344 if (pa->contact || pb->contact) {
345 if (! (pa->contact && pb->contact))
348 if (pa->contact == pb->contact || !strcmp (e_contact_get_const (pa->contact, E_CONTACT_UID),
349 e_contact_get_const (pb->contact, E_CONTACT_UID)))
355 /* Just in case name returns NULL */
356 na = e_destination_get_name (a);
357 nb = e_destination_get_name (b);
358 if ((na || nb) && !(na && nb && ! utf8_casefold_collate (na, nb)))
361 if (!g_ascii_strcasecmp (e_destination_get_email (a), e_destination_get_email (b)))
368 * e_destination_set_contact:
369 * @dest: an #EDestination
370 * @contact: an #EContact
371 * @email_num: an email index
373 * Sets @dest to point to one of @contact's e-mail addresses
374 * indicated by @email_num.
377 e_destination_set_contact (EDestination *dest, EContact *contact, gint email_num)
379 g_return_if_fail (dest && E_IS_DESTINATION (dest));
380 g_return_if_fail (contact && E_IS_CONTACT (contact));
382 if (dest->priv->contact != contact ) {
383 g_object_ref (contact);
385 e_destination_clear (dest);
387 dest->priv->contact = contact;
389 dest->priv->contact_uid = e_contact_get (dest->priv->contact, E_CONTACT_UID);
391 dest->priv->email_num = email_num;
393 dest->priv->ignored = FALSE;
395 /* handle the mailing list case */
396 if (e_contact_get (dest->priv->contact, E_CONTACT_IS_LIST)) {
397 GList *email = e_contact_get_attributes (dest->priv->contact, E_CONTACT_EMAIL);
402 for (iter = email; iter; iter = iter->next) {
403 EVCardAttribute *attr = iter->data;
405 EDestination *list_dest = e_destination_new ();
406 char *contact_uid = NULL;
407 char *email_addr = NULL;
410 gboolean html_pref = FALSE;
412 for (p = e_vcard_attribute_get_params (attr); p; p = p->next) {
413 EVCardAttributeParam *param = p->data;
414 const char *param_name = e_vcard_attribute_param_get_name (param);
415 if (!g_ascii_strcasecmp (param_name,
416 EVC_X_DEST_CONTACT_UID)) {
417 GList *v = e_vcard_attribute_param_get_values (param);
418 contact_uid = v ? g_strdup (v->data) : NULL;
420 else if (!g_ascii_strcasecmp (param_name,
421 EVC_X_DEST_EMAIL_NUM)) {
422 GList *v = e_vcard_attribute_param_get_values (param);
423 email_num = v ? atoi (v->data) : -1;
425 else if (!g_ascii_strcasecmp (param_name,
427 GList *v = e_vcard_attribute_param_get_values (param);
428 name = v ? v->data : NULL;
430 else if (!g_ascii_strcasecmp (param_name,
432 GList *v = e_vcard_attribute_param_get_values (param);
433 email_addr = v ? v->data : NULL;
435 else if (!g_ascii_strcasecmp (param_name,
436 EVC_X_DEST_HTML_MAIL)) {
437 GList *v = e_vcard_attribute_param_get_values (param);
438 html_pref = v ? !g_ascii_strcasecmp (v->data, "true") : FALSE;
442 if (contact_uid) e_destination_set_contact_uid (list_dest, contact_uid, email_num);
443 if (name) e_destination_set_name (list_dest, name);
444 if (email_addr) e_destination_set_email (list_dest, email_addr);
445 e_destination_set_html_mail_pref (list_dest, html_pref);
446 list_dest->priv->ignored = FALSE;
448 dest->priv->list_dests = g_list_append (dest->priv->list_dests, list_dest);
451 g_list_foreach (email, (GFunc) e_vcard_attribute_free, NULL);
456 /* handle the normal contact case */
457 /* is there anything to do here? */
460 g_signal_emit (dest, signals [CHANGED], 0);
461 } else if (dest->priv->email_num != email_num){
462 /* Splitting here would help the contact lists not rebuiding, so that it remembers ignored values */
463 g_object_ref (contact);
465 e_destination_clear (dest);
467 dest->priv->contact = contact;
469 dest->priv->contact_uid = e_contact_get (dest->priv->contact, E_CONTACT_UID);
471 dest->priv->email_num = email_num;
473 g_signal_emit (dest, signals [CHANGED], 0);
479 * e_destination_set_book:
480 * @dest: an #EDestination
483 * Specify the source @dest's contact comes from. This is useful
484 * if you need to update the contact later.
487 e_destination_set_book (EDestination *dest, EBook *book)
491 g_return_if_fail (dest && E_IS_DESTINATION (dest));
492 g_return_if_fail (book && E_IS_BOOK (book));
494 source = e_book_get_source (book);
496 if (!dest->priv->source_uid || strcmp (e_source_peek_uid (source), dest->priv->source_uid)) {
497 e_destination_clear (dest);
498 dest->priv->source_uid = g_strdup (e_source_peek_uid (source));
500 g_signal_emit (dest, signals [CHANGED], 0);
505 * e_destination_set_contact_uid:
506 * @dest: an #EDestination
507 * @uid: a unique contact ID
508 * @email_num: an email index
510 * Sets @dest to point to one of the contact specified by @uid's e-mail
511 * addresses indicated by @email_num.
514 e_destination_set_contact_uid (EDestination *dest, const char *uid, gint email_num)
516 g_return_if_fail (dest && E_IS_DESTINATION (dest));
517 g_return_if_fail (uid != NULL);
519 if (dest->priv->contact_uid == NULL
520 || strcmp (dest->priv->contact_uid, uid)
521 || dest->priv->email_num != email_num) {
523 g_free (dest->priv->contact_uid);
524 dest->priv->contact_uid = g_strdup (uid);
525 dest->priv->email_num = email_num;
527 /* If we already have a contact, remove it unless it's uid matches the one
529 if (dest->priv->contact && strcmp (uid,
530 e_contact_get_const (dest->priv->contact, E_CONTACT_UID))) {
531 g_object_unref (dest->priv->contact);
532 dest->priv->contact = NULL;
535 g_signal_emit (dest, signals [CHANGED], 0);
540 e_destination_set_source_uid (EDestination *dest, const char *uid)
542 g_return_if_fail (dest && E_IS_DESTINATION (dest));
543 g_return_if_fail (uid != NULL);
545 if (dest->priv->source_uid == NULL
546 || strcmp (dest->priv->source_uid, uid)) {
548 g_free (dest->priv->source_uid);
549 dest->priv->source_uid = g_strdup (uid);
551 g_signal_emit (dest, signals [CHANGED], 0);
556 * e_destination_set_name:
557 * @dest: an #EDestination
558 * @name: the destination's full name
560 * Sets the full name of @dest's addressee.
563 e_destination_set_name (EDestination *dest, const char *name)
565 gboolean changed = FALSE;
567 g_return_if_fail (E_IS_DESTINATION (dest));
570 if (dest->priv->name != NULL) {
571 g_free (dest->priv->name);
572 dest->priv->name = NULL;
575 } else if (dest->priv->name == NULL || strcmp (dest->priv->name, name)) {
576 g_free (dest->priv->name);
577 dest->priv->name = g_strdup (name);
582 g_free (dest->priv->addr);
583 dest->priv->addr = NULL;
584 g_free (dest->priv->textrep);
585 dest->priv->textrep = NULL;
587 g_signal_emit (dest, signals [CHANGED], 0);
592 * e_destination_set_email:
593 * @dest: an #EDestination
594 * @email: the destination's e-mail address
596 * Sets the e-mail address of @dest's addressee.
599 e_destination_set_email (EDestination *dest, const char *email)
601 gboolean changed = FALSE;
603 g_return_if_fail (E_IS_DESTINATION (dest));
606 if (dest->priv->email != NULL) {
607 g_free (dest->priv->addr);
608 dest->priv->addr = NULL;
611 } else if (dest->priv->email == NULL || strcmp (dest->priv->email, email)) {
612 g_free (dest->priv->email);
613 dest->priv->email = g_strdup (email);
618 g_free (dest->priv->addr);
619 dest->priv->addr = NULL;
620 g_free (dest->priv->textrep);
621 dest->priv->textrep = NULL;
623 g_signal_emit (dest, signals [CHANGED], 0);
628 e_destination_from_contact (const EDestination *dest)
630 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), FALSE);
631 return dest->priv->contact != NULL || dest->priv->source_uid != NULL || dest->priv->contact_uid != NULL;
635 * e_destination_is_auto_recipient:
636 * @dest: an #EDestination
638 * Checks if @dest is flagged as an automatic recipient, meaning
639 * it was not explicitly specified by the user. This can be used
640 * to hide it from some UI elements.
642 * Return value: %TRUE if destination is an auto recipient, %FALSE otherwise.
645 e_destination_is_auto_recipient (const EDestination *dest)
647 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), FALSE);
649 return dest->priv->auto_recipient;
653 * e_destination_set_auto_recipient:
654 * @dest: an #EDestination
655 * @value: the auto recipient flag
657 * Sets the flag indicating if @dest is an automatic recipient, meaning
658 * it was not explicitly specified by the user. This can be used
659 * to hide it from some UI elements.
662 e_destination_set_auto_recipient (EDestination *dest, gboolean value)
664 g_return_if_fail (dest && E_IS_DESTINATION (dest));
666 dest->priv->auto_recipient = value;
668 g_signal_emit (dest, signals [CHANGED], 0);
672 * e_destination_get_contact:
673 * @dest: an #EDestination
675 * Gets the contact @dest is pointing to, if any.
677 * Return value: An #EContact, or %NULL if none was set.
680 e_destination_get_contact (const EDestination *dest)
682 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
684 return dest->priv->contact;
688 * e_destination_get_contact_uid:
689 * @dest: an #EDestination
691 * Gets the unique contact ID @dest is pointing to, if any.
693 * Return value: A unique contact ID, or %NULL if none was set.
696 e_destination_get_contact_uid (const EDestination *dest)
698 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
700 return dest->priv->contact_uid;
704 * e_destination_get_source_uid:
705 * @dest: an #EDestination
707 * Gets the unique source ID @dest is pointing to, if any. The source
708 * ID specifies which address book @dest's contact came from.
710 * Return value: A unique source ID, or %NULL if none was set.
713 e_destination_get_source_uid (const EDestination *dest)
715 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
717 return dest->priv->source_uid;
721 * e_destination_get_email_num:
722 * @dest: an #EDestination
724 * Gets the index of the e-mail address of the contact that
725 * @dest is pointing to, if any.
727 * Return value: The e-mail index, or -1 if none was set.
730 e_destination_get_email_num (const EDestination *dest)
732 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), -1);
734 if (dest->priv->contact == NULL && (dest->priv->source_uid == NULL || dest->priv->contact_uid == NULL))
737 return dest->priv->email_num;
741 * e_destination_get_name:
742 * @dest: an #EDestination
744 * Gets the full name of @dest's addressee, or if the addressee is
745 * a contact list, the name the list was filed under.
747 * Return value: The full name of the addressee, or %NULL if none was set.
750 e_destination_get_name (const EDestination *dest)
752 struct _EDestinationPrivate *priv;
754 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
756 priv = (struct _EDestinationPrivate *)dest->priv; /* cast out const */
758 if (priv->name == NULL) {
759 if (priv->contact != NULL) {
760 priv->name = e_contact_get (priv->contact, E_CONTACT_FULL_NAME);
762 if (priv->name == NULL || *priv->name == '\0') {
764 priv->name = e_contact_get (priv->contact, E_CONTACT_FILE_AS);
767 if (priv->name == NULL || *priv->name == '\0') {
769 if (e_contact_get (priv->contact, E_CONTACT_IS_LIST))
770 priv->name = g_strdup (_("Unnamed List"));
772 priv->name = g_strdup (e_destination_get_email (dest));
775 else if (priv->raw != NULL) {
776 CamelInternetAddress *addr = camel_internet_address_new ();
778 if (camel_address_unformat (CAMEL_ADDRESS (addr), priv->raw)) {
779 const char *camel_name = NULL;
781 camel_internet_address_get (addr, 0, &camel_name, NULL);
782 priv->name = g_strdup (camel_name);
785 camel_object_unref (CAMEL_OBJECT (addr));
793 * e_destination_is_ignored:
794 * @dest: an #EDestination
796 * Check if @dest is to be ignored.
798 * Return value: #TRUE if this destination should be ignored, else #FALSE.
801 e_destination_is_ignored (const EDestination *dest)
803 return dest->priv->ignored;
807 * e_destination_set_ignored:
808 * @dest: an #EDestination
809 * @ignored: #TRUE if this #EDestination should be ignored.
811 * Set the ignore flag on a #EDestination.
814 e_destination_set_ignored (EDestination *dest, gboolean ignored)
816 dest->priv->ignored = ignored;
820 * e_destination_get_email:
821 * @dest: an #EDestination
823 * Gets the e-mail address of @dest's addressee.
825 * Return value: An e-mail address, or an empty string if none was set.
828 e_destination_get_email (const EDestination *dest)
830 struct _EDestinationPrivate *priv;
832 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
834 priv = (struct _EDestinationPrivate *)dest->priv; /* cast out const */
836 if (priv->email == NULL) {
837 if (priv->contact != NULL) {
838 /* Pull the address out of the card. */
839 GList *email = e_contact_get (priv->contact, E_CONTACT_EMAIL);
841 char *e = g_list_nth_data (email, priv->email_num);
844 priv->email = g_strdup (e);
847 g_list_foreach (email, (GFunc)g_free, NULL);
851 } else if (priv->raw != NULL) {
852 CamelInternetAddress *addr = camel_internet_address_new ();
854 if (camel_address_unformat (CAMEL_ADDRESS (addr), priv->raw)) {
855 const char *camel_email = NULL;
856 camel_internet_address_get (addr, 0, NULL, &camel_email);
857 priv->email = g_strdup (camel_email);
860 camel_object_unref (CAMEL_OBJECT (addr));
863 /* Force e-mail to be non-null... */
864 if (priv->email == NULL) {
865 priv->email = g_strdup ("");
873 * e_destination_get_address:
874 * @dest: an #EDestination
876 * Gets the formatted name and e-mail address, or in the case of
877 * lists, the formatted list of e-mail addresses, from @dest.
879 * Return value: A formatted destination string, or %NULL if the destination was empty.
882 e_destination_get_address (const EDestination *dest)
884 struct _EDestinationPrivate *priv;
886 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
888 priv = (struct _EDestinationPrivate *)dest->priv; /* cast out const */
890 if (priv->addr == NULL) {
891 CamelInternetAddress *addr = camel_internet_address_new ();
893 if (e_destination_is_evolution_list (dest)) {
894 GList *iter = dest->priv->list_dests;
897 EDestination *list_dest = E_DESTINATION (iter->data);
899 if (!e_destination_empty (list_dest) && !list_dest->priv->ignored) {
900 const char *name, *email;
901 name = e_destination_get_name (list_dest);
902 email = e_destination_get_email (list_dest);
904 if (nonempty (name) && nonempty (email))
905 camel_internet_address_add (addr, name, email);
906 else if (nonempty (email))
907 camel_address_decode (CAMEL_ADDRESS (addr), email);
908 else /* this case loses i suppose, but there's
909 nothing we can do here */
910 camel_address_decode (CAMEL_ADDRESS (addr), name);
912 iter = g_list_next (iter);
915 priv->addr = camel_address_encode (CAMEL_ADDRESS (addr));
916 } else if (priv->raw) {
918 if (camel_address_unformat (CAMEL_ADDRESS (addr), priv->raw)) {
919 priv->addr = camel_address_encode (CAMEL_ADDRESS (addr));
922 const char *name, *email;
923 name = e_destination_get_name (dest);
924 email = e_destination_get_email (dest);
926 if (nonempty (name) && nonempty (email))
927 camel_internet_address_add (addr, name, email);
928 else if (nonempty (email))
929 camel_address_decode (CAMEL_ADDRESS (addr), email);
930 else /* this case loses i suppose, but there's
931 nothing we can do here */
932 camel_address_decode (CAMEL_ADDRESS (addr), name);
934 priv->addr = camel_address_encode (CAMEL_ADDRESS (addr));
937 camel_object_unref (CAMEL_OBJECT (addr));
944 * e_destination_set_raw:
945 * @dest: an #EDestination
946 * @raw: an unparsed string
948 * Sets @dest to point to the name and e-mail address resulting from
949 * parsing the supplied string. Useful for user input.
952 e_destination_set_raw (EDestination *dest, const char *raw)
954 g_return_if_fail (E_IS_DESTINATION (dest));
955 g_return_if_fail (raw != NULL);
957 if (dest->priv->raw == NULL || strcmp (dest->priv->raw, raw)) {
959 e_destination_clear (dest);
960 dest->priv->raw = g_strdup (raw);
962 g_signal_emit (dest, signals [CHANGED], 0);
967 * e_destination_get_textrep:
968 * @dest: an #EDestination
969 * @include_email: whether to include the e-mail address
971 * Generates a textual representation of @dest, suitable for referring
972 * to the destination during user interaction.
974 * Return value: A textual representation of the destination.
977 e_destination_get_textrep (const EDestination *dest, gboolean include_email)
979 const char *name, *email;
981 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
984 return dest->priv->raw;
986 name = e_destination_get_name (dest);
987 email = e_destination_get_email (dest);
989 if (e_destination_from_contact (dest) && name != NULL && (!include_email || !email || !*email))
992 /* Make sure that our address gets quoted properly */
993 if (name && email && dest->priv->textrep == NULL) {
994 CamelInternetAddress *addr = camel_internet_address_new ();
996 camel_internet_address_add (addr, name, email);
997 g_free (dest->priv->textrep);
998 dest->priv->textrep = camel_address_format (CAMEL_ADDRESS (addr));
999 camel_object_unref (CAMEL_OBJECT (addr));
1002 if (dest->priv->textrep != NULL)
1003 return dest->priv->textrep;
1012 * e_destination_is_evolution_list:
1013 * @dest: an #EDestination
1015 * Checks if @dest is a list of addresses.
1017 * Return value: %TRUE if destination is a list, %FALSE if it is an individual.
1020 e_destination_is_evolution_list (const EDestination *dest)
1022 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), FALSE);
1024 return dest->priv->list_dests != NULL;
1028 * e_destination_list_show_addresses:
1029 * @dest: an #EDestination
1031 * If @dest is a list, checks if the addresses in the list
1032 * should be presented to the user during interaction.
1034 * Return value: %TRUE if addresses should be shown, %FALSE otherwise.
1037 e_destination_list_show_addresses (const EDestination *dest)
1039 g_return_val_if_fail (E_IS_DESTINATION (dest), FALSE);
1041 if (dest->priv->contact != NULL)
1042 return GPOINTER_TO_UINT (e_contact_get (dest->priv->contact, E_CONTACT_LIST_SHOW_ADDRESSES));
1044 return dest->priv->show_addresses;
1048 * e_destination_list_get_dests:
1049 * @dest: an #EDestination
1051 * If @dest is a list, gets the list of destinations. The list
1052 * and its elements belong to @dest, and should not be freed.
1054 * Return value: A list of elements of type #EDestination, or %NULL.
1057 e_destination_list_get_dests (const EDestination *dest)
1059 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
1061 if (!e_destination_is_evolution_list (dest))
1064 return dest->priv->list_dests;
1068 * e_destination_get_html_mail_pref:
1069 * @dest: an #EDestination
1071 * Check if @dest wants to get mail formatted as HTML.
1073 * Return value: %TRUE if destination wants HTML, %FALSE if not.
1076 e_destination_get_html_mail_pref (const EDestination *dest)
1078 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), FALSE);
1080 if (dest->priv->html_mail_override || dest->priv->contact == NULL)
1081 return dest->priv->wants_html_mail;
1083 return e_contact_get (dest->priv->contact, E_CONTACT_WANTS_HTML) ? TRUE : FALSE;
1087 * e_destination_set_html_mail_pref:
1088 * @dest: an #EDestination
1089 * @flag: whether the destination wants HTML mail
1091 * Specifies whether @dest wants to get mail formatted as HTML.
1094 e_destination_set_html_mail_pref (EDestination *dest, gboolean flag)
1096 g_return_if_fail (dest && E_IS_DESTINATION (dest));
1098 dest->priv->html_mail_override = TRUE;
1099 if (dest->priv->wants_html_mail != flag) {
1100 dest->priv->wants_html_mail = flag;
1102 g_signal_emit (dest, signals [CHANGED], 0);
1107 * Destination import/export
1111 * e_destination_get_textrepv:
1112 * @destv: %NULL-terminated array of pointers to #EDestination
1114 * Generates a joint text representation of all the #EDestination
1115 * elements in @destv.
1117 * Return value: The text representation of @destv.
1120 e_destination_get_textrepv (EDestination **destv)
1126 g_return_val_if_fail (destv, NULL);
1128 /* Q: Please tell me this is only for assertion
1129 reasons. If this is considered to be ok behavior then you
1130 shouldn't use g_return's. Just a reminder ;-)
1132 A: Yes, this is just an assertion. (Though it does find the
1133 length of the vector in the process...)
1135 while (destv[len]) {
1136 g_return_val_if_fail (E_IS_DESTINATION (destv[len]), NULL);
1140 strv = g_new0 (char *, len + 1);
1141 for (i = 0, j = 0; destv[i]; i++) {
1142 if (!e_destination_empty (destv[i])) {
1143 const char *addr = e_destination_get_address (destv[i]);
1144 strv[j++] = addr ? (char *) addr : "";
1148 str = g_strjoinv (", ", strv);
1156 * e_destination_xml_encode:
1157 * @dest: an #EDestination
1159 * Generates an XML tree from @dest.
1161 * Return value: Pointer to the root node of the XML tree.
1164 e_destination_xml_encode (const EDestination *dest)
1166 xmlNodePtr dest_node;
1169 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
1171 dest_node = xmlNewNode (NULL, (xmlChar*)"destination");
1173 str = e_destination_get_name (dest);
1175 xmlNewTextChild (dest_node, NULL, (xmlChar*)"name", (xmlChar*)str);
1177 if (!e_destination_is_evolution_list (dest)) {
1178 str = e_destination_get_email (dest);
1180 xmlNewTextChild (dest_node, NULL, (xmlChar*)"email", (xmlChar*)str);
1182 GList *iter = dest->priv->list_dests;
1185 EDestination *list_dest = E_DESTINATION (iter->data);
1186 xmlNodePtr list_node = xmlNewNode (NULL, (xmlChar*)"list_entry");
1188 str = e_destination_get_name (list_dest);
1190 xmlChar *escaped = xmlEncodeEntitiesReentrant (NULL, (xmlChar*)str);
1191 xmlNewTextChild (list_node, NULL, (xmlChar*)"name", escaped);
1195 str = e_destination_get_email (list_dest);
1197 xmlChar *escaped = xmlEncodeEntitiesReentrant (NULL, (xmlChar*)str);
1198 xmlNewTextChild (list_node, NULL, (xmlChar*)"email", escaped);
1202 xmlAddChild (dest_node, list_node);
1204 iter = g_list_next (iter);
1207 xmlNewProp (dest_node, (xmlChar*)"is_list", (xmlChar*)"yes");
1208 xmlNewProp (dest_node, (xmlChar*)"show_addresses",
1209 e_destination_list_show_addresses (dest) ? (xmlChar*)"yes" : (xmlChar*)"no");
1212 str = e_destination_get_source_uid (dest);
1214 xmlChar *escaped = xmlEncodeEntitiesReentrant (NULL, (xmlChar*)str);
1215 xmlNewTextChild (dest_node, NULL, (xmlChar*)"source_uid", escaped);
1219 str = e_destination_get_contact_uid (dest);
1223 xmlNodePtr uri_node = xmlNewTextChild (dest_node, NULL, (xmlChar*)"card_uid", (xmlChar*)str);
1224 g_snprintf (buf, 16, "%d", e_destination_get_email_num (dest));
1225 xmlNewProp (uri_node, (xmlChar*)"email_num", (xmlChar*)buf);
1228 xmlNewProp (dest_node, (xmlChar*)"html_mail", e_destination_get_html_mail_pref (dest) ? (xmlChar*)"yes" : (xmlChar*)"no");
1230 xmlNewProp (dest_node, (xmlChar*)"auto_recipient",
1231 e_destination_is_auto_recipient (dest) ? (xmlChar*)"yes" : (xmlChar*)"no");
1237 * e_destination_xml_decode:
1238 * @dest: an #EDestination
1239 * @node: the root node of an XML tree
1241 * Initializes @dest based on the information encoded in the
1242 * XML tree under @node.
1244 * Return value: %TRUE if the XML tree was well-formed, %FALSE otherwise.
1247 e_destination_xml_decode (EDestination *dest, xmlNodePtr node)
1249 char *name = NULL, *email = NULL, *source_uid = NULL, *card_uid = NULL;
1250 gboolean is_list = FALSE, show_addr = FALSE, auto_recip = FALSE;
1251 gboolean html_mail = FALSE;
1252 GList *list_dests = NULL;
1256 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), FALSE);
1257 g_return_val_if_fail (node != NULL, FALSE);
1259 if (strcmp ((char*)node->name, "destination"))
1262 tmp = (char*)xmlGetProp (node, (xmlChar*)"html_mail");
1264 html_mail = !strcmp (tmp, "yes");
1268 tmp = (char*)xmlGetProp (node, (xmlChar*)"is_list");
1270 is_list = !strcmp (tmp, "yes");
1274 tmp = (char*)xmlGetProp (node, (xmlChar*)"show_addresses");
1276 show_addr = !strcmp (tmp, "yes");
1280 tmp = (char*)xmlGetProp (node, (xmlChar*)"auto_recipient");
1282 auto_recip = !strcmp (tmp, "yes");
1286 node = node->xmlChildrenNode;
1288 if (!strcmp ((char*)node->name, "name")) {
1289 tmp = (char*)xmlNodeGetContent (node);
1291 name = g_strdup (tmp);
1293 } else if (!is_list && !strcmp ((char*)node->name, "email")) {
1294 tmp = (char*)xmlNodeGetContent (node);
1296 email = g_strdup (tmp);
1298 } else if (is_list && !strcmp ((char*)node->name, "list_entry")) {
1299 xmlNodePtr subnode = node->xmlChildrenNode;
1300 char *list_name = NULL, *list_email = NULL;
1303 if (!strcmp ((char*)subnode->name, "name")) {
1304 tmp = (char*)xmlNodeGetContent (subnode);
1306 list_name = g_strdup (tmp);
1308 } else if (!strcmp ((char*)subnode->name, "email")) {
1309 tmp = (char*)xmlNodeGetContent (subnode);
1310 g_free (list_email);
1311 list_email = g_strdup (tmp);
1315 subnode = subnode->next;
1318 if (list_name || list_email) {
1319 EDestination *list_dest = e_destination_new ();
1322 e_destination_set_name (list_dest, list_name);
1324 e_destination_set_email (list_dest, list_email);
1327 g_free (list_email);
1329 list_dests = g_list_append (list_dests, list_dest);
1331 } else if (!strcmp ((char*)node->name, "source_uid")) {
1332 tmp = (char*)xmlNodeGetContent (node);
1333 g_free (source_uid);
1334 source_uid = g_strdup (tmp);
1336 } else if (!strcmp ((char*)node->name, "card_uid")) {
1337 tmp = (char*)xmlNodeGetContent (node);
1339 card_uid = g_strdup (tmp);
1342 tmp = (char*)xmlGetProp (node, (xmlChar*)"email_num");
1343 email_num = atoi (tmp);
1350 e_destination_clear (dest);
1353 e_destination_set_name (dest, name);
1357 e_destination_set_email (dest, email);
1361 e_destination_set_source_uid (dest, source_uid);
1362 g_free (source_uid);
1365 e_destination_set_contact_uid (dest, card_uid, email_num);
1369 dest->priv->list_dests = list_dests;
1371 dest->priv->html_mail_override = TRUE;
1372 dest->priv->wants_html_mail = html_mail;
1374 dest->priv->show_addresses = show_addr;
1376 dest->priv->auto_recipient = auto_recip;
1382 null_terminate_and_remove_extra_whitespace (xmlChar *xml_in, gint size)
1384 gboolean skip_white = FALSE;
1387 if (xml_in == NULL || size <= 0)
1390 xml = g_strndup ((char*)xml_in, size);
1394 if (*r == '\n' || *r == '\r') {
1397 gunichar c = g_utf8_get_char (r);
1398 gboolean is_space = g_unichar_isspace (c);
1402 if (!(skip_white && is_space))
1407 r = g_utf8_next_char (r);
1416 * e_destination_export:
1417 * @dest: an #EDestination
1419 * Exports a destination to an XML document.
1421 * Return value: An XML string, allocated with g_malloc.
1424 e_destination_export (const EDestination *dest)
1426 xmlNodePtr dest_node;
1428 xmlChar *buffer = NULL;
1432 g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL);
1434 dest_node = e_destination_xml_encode (dest);
1435 if (dest_node == NULL)
1438 dest_doc = xmlNewDoc ((xmlChar*)XML_DEFAULT_VERSION);
1439 xmlDocSetRootElement (dest_doc, dest_node);
1441 xmlDocDumpMemory (dest_doc, &buffer, &size);
1442 xmlFreeDoc (dest_doc);
1444 str = null_terminate_and_remove_extra_whitespace (buffer, size);
1451 * e_destination_import
1452 * @str: an XML string
1454 * Creates an #EDestination from an XML document.
1456 * Return value: An #EDestination, or %NULL if the document was not well-formed.
1459 e_destination_import (const char *str)
1461 EDestination *dest = NULL;
1467 dest_doc = xmlParseMemory ((char *) str, strlen (str));
1468 if (dest_doc && dest_doc->xmlRootNode) {
1469 dest = e_destination_new ();
1470 if (! e_destination_xml_decode (dest, dest_doc->xmlRootNode)) {
1471 g_object_unref (dest);
1475 xmlFreeDoc (dest_doc);
1481 * e_destination_exportv:
1482 * @destv: a %NULL-terminated array of pointers to #EDestination
1484 * Exports multiple #EDestination elements to a single XML document.
1486 * Return value: An XML string, allocated with g_malloc.
1489 e_destination_exportv (EDestination **destv)
1491 xmlDocPtr destv_doc;
1492 xmlNodePtr destv_node;
1493 xmlChar *buffer = NULL;
1497 if (destv == NULL || *destv == NULL)
1500 destv_doc = xmlNewDoc ((xmlChar*)XML_DEFAULT_VERSION);
1501 destv_node = xmlNewNode (NULL, (xmlChar*)"destinations");
1502 xmlDocSetRootElement (destv_doc, destv_node);
1504 for (i = 0; destv[i]; i++) {
1505 if (! e_destination_empty (destv[i])) {
1506 xmlNodePtr dest_node = e_destination_xml_encode (destv[i]);
1508 xmlAddChild (destv_node, dest_node);
1512 xmlDocDumpMemory (destv_doc, &buffer, &size);
1513 xmlFreeDoc (destv_doc);
1515 str = null_terminate_and_remove_extra_whitespace (buffer, size);
1522 * e_destination_importv:
1523 * @str: an XML string
1525 * Creates an array of pointers to #EDestination elements
1526 * from an XML document.
1528 * Return value: A %NULL-terminated array of pointers to #EDestination elements.
1531 e_destination_importv (const char *str)
1533 GPtrArray *dest_array = NULL;
1534 xmlDocPtr destv_doc;
1536 EDestination **destv = NULL;
1541 destv_doc = xmlParseMemory ((char *)str, strlen (str));
1542 if (destv_doc == NULL)
1545 node = destv_doc->xmlRootNode;
1547 if (strcmp ((char*)node->name, "destinations"))
1550 node = node->xmlChildrenNode;
1552 dest_array = g_ptr_array_new ();
1557 dest = e_destination_new ();
1558 if (e_destination_xml_decode (dest, node) && !e_destination_empty (dest)) {
1559 g_ptr_array_add (dest_array, dest);
1561 g_object_unref (dest);
1567 /* we need destv to be NULL terminated */
1568 g_ptr_array_add (dest_array, NULL);
1570 destv = (EDestination **) dest_array->pdata;
1571 g_ptr_array_free (dest_array, FALSE);
1574 xmlFreeDoc (destv_doc);
1580 * e_destination_freev:
1581 * @destv: a %NULL-terminated array of pointers to #EDestination
1583 * Unrefs the elements of @destv and frees @destv itself.
1586 e_destination_freev (EDestination **destv)
1591 for (i = 0; destv[i] != NULL; ++i) {
1592 g_object_unref (destv[i]);
1600 * e_destination_export_to_vcard_attribute:
1601 * @dest: an #EDestination
1602 * @attr: an #EVCardAttribute
1604 * Exports the contact information from @dest to parameters
1605 * and values in @attr, suitable for an address book.
1608 e_destination_export_to_vcard_attribute (EDestination *dest, EVCardAttribute *attr)
1610 e_vcard_attribute_remove_values (attr);
1611 e_vcard_attribute_remove_params (attr);
1613 if (e_destination_get_contact_uid (dest))
1614 e_vcard_attribute_add_param_with_value (attr,
1615 e_vcard_attribute_param_new (EVC_X_DEST_CONTACT_UID),
1616 e_destination_get_contact_uid (dest));
1617 if (e_destination_get_source_uid (dest))
1618 e_vcard_attribute_add_param_with_value (attr,
1619 e_vcard_attribute_param_new (EVC_X_DEST_SOURCE_UID),
1620 e_destination_get_source_uid (dest));
1621 if (-1 != e_destination_get_email_num (dest)) {
1623 g_snprintf (buf, sizeof (buf), "%d", e_destination_get_email_num (dest));
1624 e_vcard_attribute_add_param_with_value (attr,
1625 e_vcard_attribute_param_new (EVC_X_DEST_EMAIL_NUM),
1628 if (e_destination_get_name (dest))
1629 e_vcard_attribute_add_param_with_value (attr,
1630 e_vcard_attribute_param_new (EVC_X_DEST_NAME),
1631 e_destination_get_name (dest));
1632 if (e_destination_get_email (dest))
1633 e_vcard_attribute_add_param_with_value (attr,
1634 e_vcard_attribute_param_new (EVC_X_DEST_EMAIL),
1635 e_destination_get_email (dest));
1636 e_vcard_attribute_add_param_with_value (attr,
1637 e_vcard_attribute_param_new (EVC_X_DEST_HTML_MAIL),
1638 e_destination_get_html_mail_pref (dest) ? "TRUE" : "FALSE");
1640 if (e_destination_get_address (dest))
1641 e_vcard_attribute_add_value (attr, e_destination_get_address (dest));