2 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4 * Authors: Michael Zucchi <notzed@ximian.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU Lesser General Public
8 * License as published by the Free Software Foundation.
10 * This program 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 * General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
24 #include "camel-internet-address.h"
25 #include "camel-mime-utils.h"
34 G_DEFINE_TYPE (CamelInternetAddress, camel_internet_address, CAMEL_TYPE_ADDRESS)
37 internet_address_decode (CamelAddress *a,
40 struct _camel_header_address *ha, *n;
41 gint count = a->addresses->len;
43 /* Should probably use its own decoder or something */
44 ha = camel_header_address_decode (raw, NULL);
48 if (n->type == CAMEL_HEADER_ADDRESS_NAME) {
49 camel_internet_address_add ((CamelInternetAddress *) a, n->name, n->v.addr);
50 } else if (n->type == CAMEL_HEADER_ADDRESS_GROUP) {
51 struct _camel_header_address *g = n->v.members;
53 if (g->type == CAMEL_HEADER_ADDRESS_NAME)
54 camel_internet_address_add ((CamelInternetAddress *) a, g->name, g->v.addr);
55 /* otherwise, it's an error, infact */
61 camel_header_address_list_clear (&ha);
64 return a->addresses->len - count;
68 internet_address_encode (CamelAddress *a)
73 gint len = 6; /* "From: ", assume longer of the address headers */
75 if (a->addresses->len == 0)
78 out = g_string_new ("");
80 for (i = 0; i < a->addresses->len; i++) {
81 struct _address *addr = g_ptr_array_index (a->addresses, i);
85 g_string_append (out, ", ");
87 enc = camel_internet_address_encode_address (&len, addr->name, addr->address);
88 g_string_append (out, enc);
93 g_string_free (out, FALSE);
99 internet_address_unformat (CamelAddress *a,
102 gchar *buffer, *p, *name, *addr;
104 gint count = a->addresses->len;
109 d (printf ("unformatting address: %s\n", raw));
111 /* we copy, so we can modify as we go */
112 buffer = g_strdup (raw);
114 /* this can be simpler than decode, since there are much fewer rules */
121 /* removes quotes, they should only be around the total name anyway */
137 while (*p && *p != '>')
148 name = g_strstrip (name);
149 addr = g_strstrip (addr);
151 d (printf ("found address: '%s' <%s>\n", name, addr));
152 camel_internet_address_add ((CamelInternetAddress *) a, name, addr);
162 return a->addresses->len - count;
166 internet_address_format (CamelAddress *a)
172 if (a->addresses->len == 0)
175 out = g_string_new ("");
177 for (i = 0; i < a->addresses->len; i++) {
178 struct _address *addr = g_ptr_array_index (a->addresses, i);
182 g_string_append (out, ", ");
184 enc = camel_internet_address_format_address (addr->name, addr->address);
185 g_string_append (out, enc);
190 g_string_free (out, FALSE);
196 internet_address_remove (CamelAddress *a,
199 struct _address *addr;
201 if (index < 0 || index >= a->addresses->len)
204 addr = g_ptr_array_index (a->addresses, index);
206 g_free (addr->address);
208 g_ptr_array_remove_index (a->addresses, index);
212 internet_address_cat (CamelAddress *dest,
213 CamelAddress *source)
217 g_assert (CAMEL_IS_INTERNET_ADDRESS (source));
219 for (i = 0; i < source->addresses->len; i++) {
220 struct _address *addr = g_ptr_array_index (source->addresses, i);
221 camel_internet_address_add ((CamelInternetAddress *) dest, addr->name, addr->address);
228 camel_internet_address_class_init (CamelInternetAddressClass *class)
230 CamelAddressClass *address_class;
232 address_class = CAMEL_ADDRESS_CLASS (class);
233 address_class->decode = internet_address_decode;
234 address_class->encode = internet_address_encode;
235 address_class->unformat = internet_address_unformat;
236 address_class->format = internet_address_format;
237 address_class->remove = internet_address_remove;
238 address_class->cat = internet_address_cat;
242 camel_internet_address_init (CamelInternetAddress *internet_address)
247 * camel_internet_address_new:
249 * Create a new #CamelInternetAddress object.
251 * Returns: a new #CamelInternetAddress object
253 CamelInternetAddress *
254 camel_internet_address_new (void)
256 return g_object_new (CAMEL_TYPE_INTERNET_ADDRESS, NULL);
260 * camel_internet_address_add:
261 * @addr: a #CamelInternetAddress object
262 * @name: name associated with the new address
263 * @address: routing address associated with the new address
265 * Add a new internet address to @addr.
267 * Returns: the index of added entry
270 camel_internet_address_add (CamelInternetAddress *addr,
272 const gchar *address)
274 struct _address *new;
277 g_assert (CAMEL_IS_INTERNET_ADDRESS (addr));
279 new = g_malloc (sizeof (*new));
280 new->name = g_strdup (name);
281 new->address = g_strdup (address);
282 index = ((CamelAddress *) addr)->addresses->len;
283 g_ptr_array_add (((CamelAddress *) addr)->addresses, new);
289 * camel_internet_address_get:
290 * @addr: a #CamelInternetAddress object
291 * @index: address's array index
292 * @namep: holder for the returned name, or %NULL, if not required.
293 * @addressp: holder for the returned address, or %NULL, if not required.
295 * Get the address at @index.
297 * Returns: %TRUE if such an address exists, or %FALSE otherwise
300 camel_internet_address_get (CamelInternetAddress *addr,
303 const gchar **addressp)
307 g_assert (CAMEL_IS_INTERNET_ADDRESS (addr));
309 if (index < 0 || index >= ((CamelAddress *) addr)->addresses->len)
312 a = g_ptr_array_index (((CamelAddress *) addr)->addresses, index);
316 *addressp = a->address;
321 * camel_internet_address_find_name:
322 * @addr: a #CamelInternetAddress object
323 * @name: name to lookup
324 * @addressp: holder for address part, or %NULL, if not required.
326 * Find address by real name.
328 * Returns: the index of the address matching the name, or %-1 if no
332 camel_internet_address_find_name (CamelInternetAddress *addr,
334 const gchar **addressp)
339 g_assert (CAMEL_IS_INTERNET_ADDRESS (addr));
341 len = ((CamelAddress *) addr)->addresses->len;
342 for (i = 0; i < len; i++) {
343 a = g_ptr_array_index (((CamelAddress *) addr)->addresses, i);
344 if (a->name && !strcmp (a->name, name)) {
346 *addressp = a->address;
354 * camel_internet_address_find_address:
355 * @addr: a #CamelInternetAddress object
356 * @address: address to lookup
357 * @namep: holder for the matching name, or %NULL, if not required.
359 * Find an address by address.
361 * Returns: the index of the address, or %-1 if not found
364 camel_internet_address_find_address (CamelInternetAddress *addr,
365 const gchar *address,
371 g_assert (CAMEL_IS_INTERNET_ADDRESS (addr));
373 len = ((CamelAddress *) addr)->addresses->len;
374 for (i = 0; i < len; i++) {
375 a = g_ptr_array_index (((CamelAddress *) addr)->addresses, i);
376 if (!strcmp (a->address, address)) {
386 cia_encode_addrspec (GString *out,
391 at = strchr (addr, '@');
399 /* strictly by rfc, we should split local parts on dots.
400 * however i think 2822 changes this, and not many clients grok it, so
401 * just quote the whole local part if need be */
402 if (!(camel_mime_is_atom (c) || c == '.')) {
403 g_string_append_c (out, '"');
408 if (c == '"' || c == '\\')
409 g_string_append_c (out, '\\');
410 g_string_append_c (out, c);
412 g_string_append_c (out, '"');
413 g_string_append (out, p);
420 g_string_append (out, addr);
424 * camel_internet_address_encode_address:
425 * @len: the length of the line the address is being appended to
426 * @name: the unencoded real name associated with the address
427 * @addr: the routing address
429 * Encode a single address ready for internet usage. Header folding
430 * as per rfc822 is also performed, based on the length *@len. If @len
431 * is %NULL, then no folding will occur.
433 * Note: The value at *@in will be updated based on any linewrapping done
435 * Returns: the encoded address
438 camel_internet_address_encode_address (gint *inlen,
442 gchar *name = camel_header_encode_phrase ((const guchar *) real);
445 GString *out = g_string_new ("");
452 if (name && name[0]) {
453 if (inlen != NULL && (strlen (name) + len) > CAMEL_FOLD_SIZE) {
454 gchar *folded = camel_header_address_fold (name, len);
456 g_string_append (out, folded);
458 last = strrchr (out->str, '\n');
460 len = last - (out->str + out->len);
464 g_string_append (out, name);
465 len += strlen (name);
469 /* NOTE: Strictly speaking, we could and should split the
470 * internal address up if we need to, on atom or specials
471 * boundaries - however, to aid interoperability with mailers
472 * that will probably not handle this case, we will just move
473 * the whole address to its own line. */
474 if (inlen != NULL && (strlen (addr) + len) > CAMEL_FOLD_SIZE) {
475 g_string_append (out, "\n\t");
482 g_string_append_printf (out, " <");
483 cia_encode_addrspec (out, addr);
485 g_string_append_printf (out, ">");
495 g_string_free (out, FALSE);
501 * camel_internet_address_format_address:
502 * @name: a name, quotes may be stripped from it
503 * @addr: an rfc822 routing address
505 * Function to format a single address, suitable for display.
507 * Returns: a nicely formatted string containing the rfc822 address
510 camel_internet_address_format_address (const gchar *name,
517 if (name && name[0]) {
518 const gchar *p = name;
522 if (c == '\"' || c == ',') {
523 o = ret = g_malloc (strlen (name) + 3 + strlen (addr) + 3 + 1);
530 sprintf (o, " <%s>", addr);
531 d (printf ("encoded '%s' => '%s'\n", name, ret));
535 ret = g_strdup_printf ("%s <%s>", name, addr);
537 ret = g_strdup (addr);