1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2000-2012 Jeffrey Stedfast
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1
8 * of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
31 #include "internet-address.h"
32 #include "gmime-table-private.h"
33 #include "gmime-parse-utils.h"
34 #include "gmime-iconv-utils.h"
35 #include "gmime-events.h"
36 #include "gmime-utils.h"
40 #ifdef ENABLE_WARNINGS
44 #endif /* ENABLE_WARNINGS */
50 * SECTION: internet-address
51 * @title: InternetAddress
52 * @short_description: Internet addresses
53 * @see_also: #InternetAddressGroup, #InternetAddressMailbox
55 * An #InternetAddress is the base class for #InternetAddressGroup and
56 * #InternetAddressMailbox.
60 * SECTION: internet-address-group
61 * @title: InternetAddressGroup
62 * @short_description: rfc822 'group' address
63 * @see_also: #InternetAddress
65 * An #InternetAddressGroup represents an rfc822 'group' address.
69 * SECTION: internet-address-mailbox
70 * @title: InternetAddressMailbox
71 * @short_description: rfc822 'mailbox' address
72 * @see_also: #InternetAddress
74 * An #InternetAddressMailbox represents what is a typical "email
79 * SECTION: internet-address-list
80 * @title: InternetAddressList
81 * @short_description: A list of internet addresses
82 * @see_also: #InternetAddress
84 * An #InternetAddressList is a collection of #InternetAddress
90 INTERNET_ADDRESS_ENCODE = 1 << 0,
91 INTERNET_ADDRESS_FOLD = 1 << 1,
95 static void internet_address_class_init (InternetAddressClass *klass);
96 static void internet_address_init (InternetAddress *ia, InternetAddressClass *klass);
97 static void internet_address_finalize (GObject *object);
100 static GObjectClass *parent_class = NULL;
104 internet_address_get_type (void)
106 static GType type = 0;
109 static const GTypeInfo info = {
110 sizeof (InternetAddressClass),
111 NULL, /* base_class_init */
112 NULL, /* base_class_finalize */
113 (GClassInitFunc) internet_address_class_init,
114 NULL, /* class_finalize */
115 NULL, /* class_data */
116 sizeof (InternetAddress),
118 (GInstanceInitFunc) internet_address_init,
121 type = g_type_register_static (G_TYPE_OBJECT, "InternetAddress",
122 &info, G_TYPE_FLAG_ABSTRACT);
130 internet_address_class_init (InternetAddressClass *klass)
132 GObjectClass *object_class = G_OBJECT_CLASS (klass);
134 parent_class = g_type_class_ref (G_TYPE_OBJECT);
136 object_class->finalize = internet_address_finalize;
138 klass->to_string = NULL;
142 internet_address_init (InternetAddress *ia, InternetAddressClass *klass)
144 ia->priv = g_mime_event_new ((GObject *) ia);
149 internet_address_finalize (GObject *object)
151 InternetAddress *ia = (InternetAddress *) object;
153 g_mime_event_destroy (ia->priv);
156 G_OBJECT_CLASS (parent_class)->finalize (object);
161 _internet_address_set_name (InternetAddress *ia, const char *name)
165 buf = g_strdup (name);
171 * internet_address_set_name:
172 * @ia: a #InternetAddress
173 * @name: the display name for the address group or mailbox
175 * Set the display name of the #InternetAddress.
178 internet_address_set_name (InternetAddress *ia, const char *name)
180 g_return_if_fail (IS_INTERNET_ADDRESS (ia));
182 _internet_address_set_name (ia, name);
184 g_mime_event_emit (ia->priv, NULL);
189 * internet_address_get_name:
190 * @ia: a #InternetAddress
192 * Gets the display name of the #InternetAddress.
194 * Returns: the display name of @ia.
197 internet_address_get_name (InternetAddress *ia)
199 g_return_val_if_fail (IS_INTERNET_ADDRESS (ia), NULL);
206 * internet_address_to_string:
207 * @ia: Internet Address object
208 * @encode: %TRUE if the address should be rfc2047 encoded
210 * Allocates a string containing the contents of the #InternetAddress
213 * Returns: the #InternetAddress object as an allocated string in
217 internet_address_to_string (InternetAddress *ia, gboolean encode)
219 guint32 flags = encode ? INTERNET_ADDRESS_ENCODE : 0;
224 string = g_string_new ("");
225 INTERNET_ADDRESS_GET_CLASS (ia)->to_string (ia, flags, &linelen, string);
228 g_string_free (string, FALSE);
234 static void internet_address_mailbox_class_init (InternetAddressMailboxClass *klass);
235 static void internet_address_mailbox_init (InternetAddressMailbox *mailbox, InternetAddressMailboxClass *klass);
236 static void internet_address_mailbox_finalize (GObject *object);
238 static void mailbox_to_string (InternetAddress *ia, guint32 flags, size_t *linelen, GString *out);
241 static GObjectClass *mailbox_parent_class = NULL;
245 internet_address_mailbox_get_type (void)
247 static GType type = 0;
250 static const GTypeInfo info = {
251 sizeof (InternetAddressMailboxClass),
252 NULL, /* base_class_init */
253 NULL, /* base_class_finalize */
254 (GClassInitFunc) internet_address_mailbox_class_init,
255 NULL, /* class_finalize */
256 NULL, /* class_data */
257 sizeof (InternetAddressMailbox),
259 (GInstanceInitFunc) internet_address_mailbox_init,
262 type = g_type_register_static (INTERNET_ADDRESS_TYPE, "InternetAddressMailbox", &info, 0);
270 internet_address_mailbox_class_init (InternetAddressMailboxClass *klass)
272 InternetAddressClass *address_class = INTERNET_ADDRESS_CLASS (klass);
273 GObjectClass *object_class = G_OBJECT_CLASS (klass);
275 mailbox_parent_class = g_type_class_ref (INTERNET_ADDRESS_TYPE);
277 object_class->finalize = internet_address_mailbox_finalize;
279 address_class->to_string = mailbox_to_string;
283 internet_address_mailbox_init (InternetAddressMailbox *mailbox, InternetAddressMailboxClass *klass)
285 mailbox->addr = NULL;
289 internet_address_mailbox_finalize (GObject *object)
291 InternetAddressMailbox *mailbox = (InternetAddressMailbox *) object;
293 g_free (mailbox->addr);
295 G_OBJECT_CLASS (mailbox_parent_class)->finalize (object);
300 * internet_address_mailbox_new:
301 * @name: person's name
302 * @addr: person's address
304 * Creates a new #InternetAddress object with name @name and address
307 * Returns: a new #InternetAddressMailbox object.
310 internet_address_mailbox_new (const char *name, const char *addr)
312 InternetAddressMailbox *mailbox;
314 g_return_val_if_fail (addr != NULL, NULL);
316 mailbox = g_object_newv (INTERNET_ADDRESS_TYPE_MAILBOX, 0, NULL);
317 mailbox->addr = g_strdup (addr);
319 _internet_address_set_name ((InternetAddress *) mailbox, name);
321 return (InternetAddress *) mailbox;
326 * internet_address_mailbox_set_addr:
327 * @mailbox: a #InternetAddressMailbox
328 * @addr: contact's email address
330 * Set the mailbox address.
333 internet_address_mailbox_set_addr (InternetAddressMailbox *mailbox, const char *addr)
335 g_return_if_fail (INTERNET_ADDRESS_IS_MAILBOX (mailbox));
337 if (mailbox->addr == addr)
340 g_free (mailbox->addr);
341 mailbox->addr = g_strdup (addr);
343 g_mime_event_emit (((InternetAddress *) mailbox)->priv, NULL);
348 * internet_address_mailbox_get_addr:
349 * @mailbox: a #InternetAddressMailbox
351 * Gets the addr-spec of the internet address mailbox.
353 * Returns: the address of the mailbox.
356 internet_address_mailbox_get_addr (InternetAddressMailbox *mailbox)
358 g_return_val_if_fail (INTERNET_ADDRESS_IS_MAILBOX (mailbox), NULL);
360 return mailbox->addr;
364 static void internet_address_group_class_init (InternetAddressGroupClass *klass);
365 static void internet_address_group_init (InternetAddressGroup *group, InternetAddressGroupClass *klass);
366 static void internet_address_group_finalize (GObject *object);
368 static void group_to_string (InternetAddress *ia, guint32 flags, size_t *linelen, GString *out);
371 static GObjectClass *group_parent_class = NULL;
375 internet_address_group_get_type (void)
377 static GType type = 0;
380 static const GTypeInfo info = {
381 sizeof (InternetAddressGroupClass),
382 NULL, /* base_class_init */
383 NULL, /* base_class_finalize */
384 (GClassInitFunc) internet_address_group_class_init,
385 NULL, /* class_finalize */
386 NULL, /* class_data */
387 sizeof (InternetAddressGroup),
389 (GInstanceInitFunc) internet_address_group_init,
392 type = g_type_register_static (INTERNET_ADDRESS_TYPE, "InternetAddressGroup", &info, 0);
400 internet_address_group_class_init (InternetAddressGroupClass *klass)
402 InternetAddressClass *address_class = INTERNET_ADDRESS_CLASS (klass);
403 GObjectClass *object_class = G_OBJECT_CLASS (klass);
405 group_parent_class = g_type_class_ref (INTERNET_ADDRESS_TYPE);
407 object_class->finalize = internet_address_group_finalize;
409 address_class->to_string = group_to_string;
413 members_changed (InternetAddressList *members, gpointer args, InternetAddress *group)
415 g_mime_event_emit (((InternetAddress *) group)->priv, NULL);
419 internet_address_group_init (InternetAddressGroup *group, InternetAddressGroupClass *klass)
421 group->members = internet_address_list_new ();
423 g_mime_event_add (group->members->priv, (GMimeEventCallback) members_changed, group);
427 internet_address_group_finalize (GObject *object)
429 InternetAddressGroup *group = (InternetAddressGroup *) object;
431 g_mime_event_remove (group->members->priv, (GMimeEventCallback) members_changed, group);
433 g_object_unref (group->members);
435 G_OBJECT_CLASS (group_parent_class)->finalize (object);
440 * internet_address_group_new:
443 * Creates a new #InternetAddressGroup object with a display name of
446 * Returns: a new #InternetAddressGroup object.
449 internet_address_group_new (const char *name)
451 InternetAddress *group;
453 group = g_object_newv (INTERNET_ADDRESS_TYPE_GROUP, 0, NULL);
454 _internet_address_set_name (group, name);
461 * internet_address_group_set_members:
462 * @group: a #InternetAddressGroup
463 * @members: a #InternetAddressList
465 * Set the members of the internet address group.
468 internet_address_group_set_members (InternetAddressGroup *group, InternetAddressList *members)
470 g_return_if_fail (INTERNET_ADDRESS_IS_GROUP (group));
471 g_return_if_fail (IS_INTERNET_ADDRESS_LIST (members));
473 if (group->members == members)
476 if (group->members) {
477 g_mime_event_remove (group->members->priv, (GMimeEventCallback) members_changed, group);
478 g_object_unref (group->members);
482 g_mime_event_add (members->priv, (GMimeEventCallback) members_changed, group);
483 g_object_ref (members);
486 group->members = members;
488 g_mime_event_emit (((InternetAddress *) group)->priv, NULL);
493 * internet_address_group_get_members:
494 * @group: a #InternetAddressGroup
496 * Gets the #InternetAddressList containing the group members of an
497 * rfc822 group address.
499 * Returns: a #InternetAddressList containing the members of @group.
501 InternetAddressList *
502 internet_address_group_get_members (InternetAddressGroup *group)
504 g_return_val_if_fail (INTERNET_ADDRESS_IS_GROUP (group), NULL);
506 return group->members;
510 #define _internet_address_group_add_member(group,member) _internet_address_list_add (group->members, member)
513 * internet_address_group_add_member:
514 * @group: a #InternetAddressGroup
515 * @member: a #InternetAddress
517 * Add a contact to the internet address group.
519 * Returns: the index of the newly added member.
522 internet_address_group_add_member (InternetAddressGroup *group, InternetAddress *member)
524 g_return_val_if_fail (INTERNET_ADDRESS_IS_GROUP (group), -1);
525 g_return_val_if_fail (IS_INTERNET_ADDRESS (member), -1);
527 return internet_address_list_add (group->members, member);
531 static void internet_address_list_class_init (InternetAddressListClass *klass);
532 static void internet_address_list_init (InternetAddressList *list, InternetAddressListClass *klass);
533 static void internet_address_list_finalize (GObject *object);
536 static GObjectClass *list_parent_class = NULL;
540 internet_address_list_get_type (void)
542 static GType type = 0;
545 static const GTypeInfo info = {
546 sizeof (InternetAddressListClass),
547 NULL, /* base_class_init */
548 NULL, /* base_class_finalize */
549 (GClassInitFunc) internet_address_list_class_init,
550 NULL, /* class_finalize */
551 NULL, /* class_data */
552 sizeof (InternetAddressList),
554 (GInstanceInitFunc) internet_address_list_init,
557 type = g_type_register_static (G_TYPE_OBJECT, "InternetAddressList", &info, 0);
565 internet_address_list_class_init (InternetAddressListClass *klass)
567 GObjectClass *object_class = G_OBJECT_CLASS (klass);
569 list_parent_class = g_type_class_ref (G_TYPE_OBJECT);
571 object_class->finalize = internet_address_list_finalize;
575 internet_address_list_init (InternetAddressList *list, InternetAddressListClass *klass)
577 list->priv = g_mime_event_new ((GObject *) list);
578 list->array = g_ptr_array_new ();
582 address_changed (InternetAddress *ia, gpointer args, InternetAddressList *list)
584 g_mime_event_emit (list->priv, NULL);
588 internet_address_list_finalize (GObject *object)
590 InternetAddressList *list = (InternetAddressList *) object;
594 for (i = 0; i < list->array->len; i++) {
595 ia = (InternetAddress *) list->array->pdata[i];
596 g_mime_event_remove (ia->priv, (GMimeEventCallback) address_changed, list);
600 g_mime_event_destroy (list->priv);
602 g_ptr_array_free (list->array, TRUE);
604 G_OBJECT_CLASS (list_parent_class)->finalize (object);
609 * internet_address_list_new:
611 * Creates a new #InternetAddressList.
613 * Returns: a new #InternetAddressList.
615 InternetAddressList *
616 internet_address_list_new (void)
618 return g_object_newv (INTERNET_ADDRESS_LIST_TYPE, 0, NULL);
623 * internet_address_list_length:
624 * @list: a #InternetAddressList
626 * Gets the length of the list.
628 * Returns: the number of #InternetAddress objects in the list.
631 internet_address_list_length (InternetAddressList *list)
633 g_return_val_if_fail (IS_INTERNET_ADDRESS_LIST (list), -1);
635 return list->array->len;
640 * internet_address_list_clear:
641 * @list: a #InternetAddressList
643 * Clears the list of addresses.
646 internet_address_list_clear (InternetAddressList *list)
651 g_return_if_fail (IS_INTERNET_ADDRESS_LIST (list));
653 for (i = 0; i < list->array->len; i++) {
654 ia = (InternetAddress *) list->array->pdata[i];
655 g_mime_event_remove (ia->priv, (GMimeEventCallback) address_changed, list);
659 g_ptr_array_set_size (list->array, 0);
661 g_mime_event_emit (list->priv, NULL);
666 _internet_address_list_add (InternetAddressList *list, InternetAddress *ia)
670 g_mime_event_add (ia->priv, (GMimeEventCallback) address_changed, list);
672 index = list->array->len;
673 g_ptr_array_add (list->array, ia);
680 * internet_address_list_add:
681 * @list: a #InternetAddressList
682 * @ia: a #InternetAddress
684 * Adds an #InternetAddress to the #InternetAddressList.
686 * Returns: the index of the added #InternetAddress.
689 internet_address_list_add (InternetAddressList *list, InternetAddress *ia)
693 g_return_val_if_fail (IS_INTERNET_ADDRESS_LIST (list), -1);
694 g_return_val_if_fail (IS_INTERNET_ADDRESS (ia), -1);
696 index = _internet_address_list_add (list, ia);
699 g_mime_event_emit (list->priv, NULL);
706 * internet_address_list_prepend:
707 * @list: a #InternetAddressList
708 * @prepend: a #InternetAddressList
710 * Inserts all of the addresses in @prepend to the beginning of @list.
713 internet_address_list_prepend (InternetAddressList *list, InternetAddressList *prepend)
719 g_return_if_fail (IS_INTERNET_ADDRESS_LIST (prepend));
720 g_return_if_fail (IS_INTERNET_ADDRESS_LIST (list));
722 if (prepend->array->len == 0)
725 len = prepend->array->len;
726 g_ptr_array_set_size (list->array, list->array->len + len);
728 src = ((char *) list->array->pdata);
729 dest = src + (sizeof (void *) * len);
731 g_memmove (dest, src, (sizeof (void *) * list->array->len));
733 for (i = 0; i < prepend->array->len; i++) {
734 ia = (InternetAddress *) prepend->array->pdata[i];
735 g_mime_event_add (ia->priv, (GMimeEventCallback) address_changed, list);
736 list->array->pdata[i] = ia;
740 g_mime_event_emit (list->priv, NULL);
745 * internet_address_list_append:
746 * @list: a #InternetAddressList
747 * @append: a #InternetAddressList
749 * Adds all of the addresses in @append to @list.
752 internet_address_list_append (InternetAddressList *list, InternetAddressList *append)
757 g_return_if_fail (IS_INTERNET_ADDRESS_LIST (append));
758 g_return_if_fail (IS_INTERNET_ADDRESS_LIST (list));
760 len = list->array->len;
761 g_ptr_array_set_size (list->array, len + append->array->len);
763 for (i = 0; i < append->array->len; i++) {
764 ia = (InternetAddress *) append->array->pdata[i];
765 g_mime_event_add (ia->priv, (GMimeEventCallback) address_changed, list);
766 list->array->pdata[len + i] = ia;
770 g_mime_event_emit (list->priv, NULL);
775 * internet_address_list_insert:
776 * @list: a #InternetAddressList
777 * @index: index to insert at
778 * @ia: a #InternetAddress
780 * Inserts an #InternetAddress into the #InternetAddressList at the
784 internet_address_list_insert (InternetAddressList *list, int index, InternetAddress *ia)
789 g_return_if_fail (IS_INTERNET_ADDRESS_LIST (list));
790 g_return_if_fail (IS_INTERNET_ADDRESS (ia));
791 g_return_if_fail (index >= 0);
793 g_mime_event_add (ia->priv, (GMimeEventCallback) address_changed, list);
796 if ((guint) index < list->array->len) {
797 g_ptr_array_set_size (list->array, list->array->len + 1);
799 dest = ((char *) list->array->pdata) + (sizeof (void *) * (index + 1));
800 src = ((char *) list->array->pdata) + (sizeof (void *) * index);
801 n = list->array->len - index - 1;
803 g_memmove (dest, src, (sizeof (void *) * n));
804 list->array->pdata[index] = ia;
807 g_ptr_array_add (list->array, ia);
810 g_mime_event_emit (list->priv, NULL);
815 * internet_address_list_remove:
816 * @list: a #InternetAddressList
817 * @ia: a #InternetAddress
819 * Removes an #InternetAddress from the #InternetAddressList.
821 * Returns: %TRUE if the specified #InternetAddress was removed or
825 internet_address_list_remove (InternetAddressList *list, InternetAddress *ia)
829 g_return_val_if_fail (IS_INTERNET_ADDRESS_LIST (list), FALSE);
830 g_return_val_if_fail (IS_INTERNET_ADDRESS (ia), FALSE);
832 if ((index = internet_address_list_index_of (list, ia)) == -1)
835 internet_address_list_remove_at (list, index);
842 * internet_address_list_remove_at:
843 * @list: a #InternetAddressList
844 * @index: index to remove
846 * Removes an #InternetAddress from the #InternetAddressList at the
849 * Returns: %TRUE if an #InternetAddress was removed or %FALSE
853 internet_address_list_remove_at (InternetAddressList *list, int index)
857 g_return_val_if_fail (IS_INTERNET_ADDRESS_LIST (list), FALSE);
858 g_return_val_if_fail (index >= 0, FALSE);
860 if ((guint) index >= list->array->len)
863 ia = list->array->pdata[index];
864 g_mime_event_remove (ia->priv, (GMimeEventCallback) address_changed, list);
867 g_ptr_array_remove_index (list->array, index);
869 g_mime_event_emit (list->priv, NULL);
876 * internet_address_list_contains:
877 * @list: a #InternetAddressList
878 * @ia: a #InternetAddress
880 * Checks whether or not the specified #InternetAddress is contained
881 * within the #InternetAddressList.
883 * Returns: %TRUE if the specified #InternetAddress is contained
884 * within the specified #InternetAddressList or %FALSE otherwise.
887 internet_address_list_contains (InternetAddressList *list, InternetAddress *ia)
889 return internet_address_list_index_of (list, ia) != -1;
894 * internet_address_list_index_of:
895 * @list: a #InternetAddressList
896 * @ia: a #InternetAddress
898 * Gets the index of the specified #InternetAddress inside the
899 * #InternetAddressList.
901 * Returns: the index of the requested #InternetAddress within the
902 * #InternetAddressList or %-1 if it is not contained within the
903 * #InternetAddressList.
906 internet_address_list_index_of (InternetAddressList *list, InternetAddress *ia)
910 g_return_val_if_fail (IS_INTERNET_ADDRESS_LIST (list), -1);
911 g_return_val_if_fail (IS_INTERNET_ADDRESS (ia), -1);
913 for (i = 0; i < list->array->len; i++) {
914 if (list->array->pdata[i] == ia)
923 * internet_address_list_get_address:
924 * @list: a #InternetAddressList
925 * @index: index of #InternetAddress to get
927 * Gets the #InternetAddress at the specified index.
929 * Returns: the #InternetAddress at the specified index or %NULL if
930 * the index is out of range.
933 internet_address_list_get_address (InternetAddressList *list, int index)
935 g_return_val_if_fail (IS_INTERNET_ADDRESS_LIST (list), NULL);
936 g_return_val_if_fail (index >= 0, NULL);
938 if ((guint) index >= list->array->len)
941 return list->array->pdata[index];
946 * internet_address_list_set_address:
947 * @list: a #InternetAddressList
948 * @index: index of #InternetAddress to set
949 * @ia: a #InternetAddress
951 * Sets the #InternetAddress at the specified index to @ia.
954 internet_address_list_set_address (InternetAddressList *list, int index, InternetAddress *ia)
956 InternetAddress *old;
958 g_return_if_fail (IS_INTERNET_ADDRESS_LIST (list));
959 g_return_if_fail (IS_INTERNET_ADDRESS (ia));
960 g_return_if_fail (index >= 0);
962 if ((guint) index > list->array->len)
965 if ((guint) index == list->array->len) {
966 internet_address_list_add (list, ia);
970 if ((old = list->array->pdata[index]) == ia)
973 g_mime_event_remove (old->priv, (GMimeEventCallback) address_changed, list);
974 g_object_unref (old);
976 g_mime_event_add (ia->priv, (GMimeEventCallback) address_changed, list);
977 list->array->pdata[index] = ia;
980 g_mime_event_emit (list->priv, NULL);
985 encoded_name (const char *raw, gboolean rfc2047_encode)
989 g_return_val_if_fail (raw != NULL, NULL);
991 if (rfc2047_encode) {
992 name = g_mime_utils_header_encode_phrase (raw);
994 name = g_mime_utils_quote_string (raw);
1001 linewrap (GString *string)
1003 if (string->len > 0 && string->str[string->len - 1] == ' ') {
1004 string->str[string->len - 1] = '\n';
1005 g_string_append_c (string, '\t');
1007 g_string_append (string, "\n\t");
1012 append_folded_name (GString *string, size_t *linelen, const char *name)
1014 const char *word, *lwsp;
1023 /* quoted string, don't break these up */
1026 while (*lwsp && *lwsp != '"') {
1038 while (*lwsp && !is_lwsp (*lwsp))
1043 if (*linelen > 1 && (*linelen + len) > GMIME_FOLD_LEN) {
1048 g_string_append_len (string, word, len);
1052 while (*word && is_lwsp (*word))
1055 if (*word && is_lwsp (*lwsp)) {
1056 g_string_append_c (string, ' ');
1063 mailbox_to_string (InternetAddress *ia, guint32 flags, size_t *linelen, GString *string)
1065 InternetAddressMailbox *mailbox = (InternetAddressMailbox *) ia;
1066 gboolean encode = flags & INTERNET_ADDRESS_ENCODE;
1067 gboolean fold = flags & INTERNET_ADDRESS_FOLD;
1071 if (ia->name && *ia->name) {
1072 name = encoded_name (ia->name, encode);
1073 len = strlen (name);
1075 if (fold && (*linelen + len) > GMIME_FOLD_LEN) {
1076 if (len > GMIME_FOLD_LEN) {
1077 /* we need to break up the name */
1078 append_folded_name (string, linelen, name);
1080 /* the name itself is short enough to fit on a single
1081 * line, but only if we write it on a line by itself */
1087 g_string_append_len (string, name, len);
1091 /* we can safely fit the name on this line */
1092 g_string_append_len (string, name, len);
1098 len = strlen (mailbox->addr);
1100 if (fold && (*linelen + len + 3) >= GMIME_FOLD_LEN) {
1101 g_string_append_len (string, "\n\t<", 3);
1104 g_string_append_len (string, " <", 2);
1108 g_string_append_len (string, mailbox->addr, len);
1109 g_string_append_c (string, '>');
1110 *linelen += len + 1;
1112 len = strlen (mailbox->addr);
1114 if (fold && (*linelen + len) > GMIME_FOLD_LEN) {
1119 g_string_append_len (string, mailbox->addr, len);
1125 _internet_address_list_to_string (const InternetAddressList *list, guint32 flags, size_t *linelen, GString *string)
1127 InternetAddress *ia;
1130 for (i = 0; i < list->array->len; i++) {
1131 ia = (InternetAddress *) list->array->pdata[i];
1133 INTERNET_ADDRESS_GET_CLASS (ia)->to_string (ia, flags, linelen, string);
1135 if (i + 1 < list->array->len) {
1136 g_string_append (string, ", ");
1143 group_to_string (InternetAddress *ia, guint32 flags, size_t *linelen, GString *string)
1145 InternetAddressGroup *group = (InternetAddressGroup *) ia;
1146 gboolean encode = flags & INTERNET_ADDRESS_ENCODE;
1147 gboolean fold = flags & INTERNET_ADDRESS_FOLD;
1151 if (ia->name != NULL) {
1152 name = encoded_name (ia->name, encode);
1153 len = strlen (name);
1155 if (fold && *linelen > 1 && (*linelen + len + 1) > GMIME_FOLD_LEN) {
1160 g_string_append_len (string, name, len);
1163 g_string_append_len (string, ": ", 2);
1164 *linelen += len + 2;
1167 _internet_address_list_to_string (group->members, flags, linelen, string);
1168 g_string_append_c (string, ';');
1174 * internet_address_list_to_string:
1175 * @list: list of internet addresses
1176 * @encode: %TRUE if the address should be rfc2047 encoded
1178 * Allocates a string buffer containing the rfc822 formatted addresses
1181 * Returns: a string containing the list of addresses in rfc822 format
1182 * or %NULL if no addresses are contained in the list.
1185 internet_address_list_to_string (InternetAddressList *list, gboolean encode)
1187 guint32 flags = encode ? INTERNET_ADDRESS_ENCODE : 0;
1192 g_return_val_if_fail (IS_INTERNET_ADDRESS_LIST (list), NULL);
1194 if (list->array->len == 0)
1197 string = g_string_new ("");
1198 _internet_address_list_to_string (list, flags, &linelen, string);
1201 g_string_free (string, FALSE);
1208 * internet_address_list_writer:
1209 * @list: list of internet addresses
1210 * @str: string to write to
1212 * Writes the rfc2047-encoded rfc822 formatted addresses in @list to
1213 * @string, folding appropriately.
1216 internet_address_list_writer (InternetAddressList *list, GString *str)
1218 guint32 flags = INTERNET_ADDRESS_ENCODE | INTERNET_ADDRESS_FOLD;
1219 size_t linelen = str->len;
1221 g_return_if_fail (IS_INTERNET_ADDRESS_LIST (list));
1222 g_return_if_fail (str != NULL);
1224 _internet_address_list_to_string (list, flags, &linelen, str);
1228 _internet_address_decode_name (InternetAddress *ia, GString *name)
1230 char *value, *buf = NULL;
1233 if (!g_utf8_validate (name->str, name->len, NULL)) {
1234 /* A (broken) mailer has sent us raw 8bit/multibyte text data... */
1235 buf = g_mime_utils_decode_8bit (name->str, name->len);
1241 /* decode the phrase */
1242 g_mime_utils_unquote_string (phrase);
1243 value = g_mime_utils_header_decode_phrase (phrase);
1249 static InternetAddress *decode_address (const char **in);
1252 skip_lwsp (const char **in)
1254 register const char *inptr = *in;
1256 while (*inptr && is_lwsp (*inptr))
1262 static InternetAddress *
1263 decode_addrspec (const char **in)
1265 InternetAddress *mailbox = NULL;
1266 const char *start, *inptr, *word;
1267 gboolean got_local = FALSE;
1271 addr = g_string_new ("");
1274 decode_lwsp (&inptr);
1276 /* some spam bots set their addresses to stuff like: ).ORHH@em.ca */
1277 while (*inptr && !(*inptr == '"' || is_atom (*inptr)))
1282 /* extract the first word of the local-part */
1283 if ((word = decode_word (&inptr))) {
1284 g_string_append_len (addr, word, (size_t) (inptr - word));
1285 decode_lwsp (&inptr);
1289 /* extract the rest of the local-part */
1290 while (word && *inptr == '.') {
1291 /* Note: According to the spec, only a single '.' is
1292 * allowed between word tokens in the local-part of an
1293 * addr-spec token, but according to Evolution bug
1294 * #547969, some Japanese cellphones have email
1295 * addresses that look like x..y@somewhere.jp */
1298 decode_lwsp (&inptr);
1299 g_string_append_c (addr, '.');
1300 } while (*inptr == '.');
1302 if ((word = decode_word (&inptr)))
1303 g_string_append_len (addr, word, (size_t) (inptr - word));
1305 decode_lwsp (&inptr);
1308 if (*inptr == '@') {
1311 g_string_append_c (addr, '@');
1314 if (!decode_domain (&inptr, addr)) {
1315 /* drop the @domain and continue as if it weren't there */
1316 w(g_warning ("Missing domain in addr-spec: %.*s",
1317 inptr - start, start));
1318 g_string_truncate (addr, len);
1320 } else if (got_local) {
1321 w(g_warning ("Missing '@' and domain in addr-spec: %.*s",
1322 inptr - start, start));
1328 w(g_warning ("Invalid addr-spec, missing local-part: %.*s",
1329 inptr - start, start));
1330 g_string_free (addr, TRUE);
1334 mailbox = g_object_newv (INTERNET_ADDRESS_TYPE_MAILBOX, 0, NULL);
1335 ((InternetAddressMailbox *) mailbox)->addr = addr->str;
1336 g_string_free (addr, FALSE);
1341 static InternetAddress *
1342 decode_group (const char **in)
1344 InternetAddressGroup *group;
1345 InternetAddress *addr;
1350 addr = internet_address_group_new (NULL);
1351 group = (InternetAddressGroup *) addr;
1353 decode_lwsp (&inptr);
1354 while (*inptr && *inptr != ';') {
1355 InternetAddress *member;
1357 if ((member = decode_address (&inptr)))
1358 _internet_address_group_add_member (group, member);
1360 decode_lwsp (&inptr);
1361 while (*inptr == ',') {
1363 decode_lwsp (&inptr);
1364 if ((member = decode_address (&inptr)))
1365 _internet_address_group_add_member (group, member);
1367 decode_lwsp (&inptr);
1376 static InternetAddress *
1377 decode_address (const char **in)
1379 const char *inptr, *start, *word, *comment = NULL;
1380 InternetAddress *addr = NULL;
1381 gboolean has_lwsp = FALSE;
1386 start = inptr = *in;
1388 name = g_string_new ("");
1390 /* Both groups and mailboxes can begin with a phrase (denoting
1391 * the display name for the address). Collect all of the
1392 * tokens that make up this name phrase.
1395 if ((word = decode_word (&inptr))) {
1396 g_string_append_len (name, word, (size_t) (inptr - word));
1402 /* is the next token a word token? */
1403 is_word = *inptr == '"' || is_atom (*inptr);
1405 if (inptr > word && is_word) {
1406 g_string_append_c (name, ' ');
1414 /* specials = "(" / ")" / "<" / ">" / "@" ; Must be in quoted-
1415 * / "," / ";" / ":" / "\" / <"> ; string, to use
1416 * / "." / "[" / "]" ; within a word.
1418 if (*inptr == ':') {
1421 addr = decode_group (&inptr);
1422 decode_lwsp (&inptr);
1424 w(g_warning ("Invalid group spec, missing closing ';': %.*s",
1425 inptr - start, start));
1429 } else if (*inptr == '<') {
1430 /* mailbox route-addr */
1432 addr = decode_addrspec (&inptr);
1433 decode_lwsp (&inptr);
1434 if (*inptr != '>') {
1435 w(g_warning ("Invalid route-addr, missing closing '>': %.*s",
1436 inptr - start, start));
1438 while (*inptr && *inptr != '>' && *inptr != ',')
1446 /* if comment is non-NULL, we can check for a comment containing a name */
1449 } else if (*inptr == '(') {
1450 /* beginning of a comment, use decode_lwsp() to skip past it */
1451 decode_lwsp (&inptr);
1452 } else if (*inptr && strchr ("@,;", *inptr)) {
1453 if (name->len == 0) {
1454 if (*inptr == '@') {
1457 w(g_warning ("Unexpected address: %s: skipping.", start));
1459 /* skip over @domain? */
1461 domain = g_string_new ("");
1462 decode_domain (&inptr, domain);
1463 g_string_free (domain, TRUE);
1468 } else if (has_lwsp) {
1469 /* assume this is just an unquoted special that we should
1470 treat as part of the name */
1471 w(g_warning ("Unquoted '%c' in address name: %s: ignoring.", *inptr, start));
1472 g_string_append_c (name, *inptr);
1479 /* what we thought was a name was actually an addrspec? */
1480 g_string_truncate (name, 0);
1483 addr = decode_addrspec (&inptr);
1485 /* if comment is non-NULL, we can check for a comment containing a name */
1488 } else if (*inptr == '.') {
1489 /* This would normally signify that we are
1490 * decoding the local-part of an addr-spec,
1491 * but sadly, it is common for broken mailers
1492 * to forget to quote/encode .'s in the name
1494 g_string_append_c (name, *inptr);
1498 } else if (*inptr) {
1499 /* Technically, these are all invalid tokens
1500 * but in the interest of being liberal in
1501 * what we accept, we'll ignore them. */
1502 w(g_warning ("Unexpected char '%c' in address: %s: ignoring.", *inptr, start));
1503 g_string_append_c (name, *inptr);
1512 /* Note: will also skip over any comments */
1513 decode_lwsp (&inptr);
1515 if (name->len == 0 && comment && inptr > comment) {
1516 /* missing a name, look for a trailing comment */
1517 if ((comment = memchr (comment, '(', inptr - comment))) {
1520 /* find the end of the comment */
1522 while (cend > comment && is_lwsp (*cend))
1528 g_string_append_len (name, comment + 1, (size_t) (cend - comment));
1532 if (addr && name->len > 0)
1533 _internet_address_decode_name (addr, name);
1535 g_string_free (name, TRUE);
1544 * internet_address_list_parse_string:
1545 * @str: a string containing internet addresses
1547 * Construct a list of internet addresses from the given string.
1549 * Returns: a #InternetAddressList or %NULL if the input string does
1550 * not contain any addresses.
1552 InternetAddressList *
1553 internet_address_list_parse_string (const char *str)
1555 InternetAddressList *addrlist;
1556 const char *inptr = str;
1558 addrlist = internet_address_list_new ();
1560 while (inptr && *inptr) {
1561 InternetAddress *addr;
1566 if ((addr = decode_address (&inptr))) {
1567 _internet_address_list_add (addrlist, addr);
1569 w(g_warning ("Invalid or incomplete address: %.*s",
1570 inptr - start, start));
1573 decode_lwsp (&inptr);
1574 if (*inptr == ',') {
1576 } else if (*inptr) {
1577 w(g_warning ("Parse error at '%s': expected ','", inptr));
1578 /* try skipping to the next address */
1579 if ((inptr = strchr (inptr, ',')))
1584 if (addrlist->array->len == 0) {
1585 g_object_unref (addrlist);