2 * Copyright (C) 2000 Ximian Inc.
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"
29 static int internet_decode (CamelAddress *, const char *raw);
30 static char * internet_encode (CamelAddress *);
31 static int internet_unformat (CamelAddress *, const char *raw);
32 static char * internet_format (CamelAddress *);
33 static int internet_cat (CamelAddress *dest, const CamelAddress *source);
34 static void internet_remove (CamelAddress *, int index);
36 static void camel_internet_address_class_init (CamelInternetAddressClass *klass);
37 static void camel_internet_address_init (CamelInternetAddress *obj);
39 static CamelAddressClass *camel_internet_address_parent;
47 camel_internet_address_class_init(CamelInternetAddressClass *klass)
49 CamelAddressClass *address = (CamelAddressClass *) klass;
51 camel_internet_address_parent = CAMEL_ADDRESS_CLASS(camel_type_get_global_classfuncs(camel_address_get_type()));
53 address->decode = internet_decode;
54 address->encode = internet_encode;
55 address->unformat = internet_unformat;
56 address->format = internet_format;
57 address->remove = internet_remove;
58 address->cat = internet_cat;
62 camel_internet_address_init(CamelInternetAddress *obj)
67 camel_internet_address_get_type(void)
69 static CamelType type = CAMEL_INVALID_TYPE;
71 if (type == CAMEL_INVALID_TYPE) {
72 type = camel_type_register(camel_address_get_type(), "CamelInternetAddress",
73 sizeof (CamelInternetAddress),
74 sizeof (CamelInternetAddressClass),
75 (CamelObjectClassInitFunc) camel_internet_address_class_init,
77 (CamelObjectInitFunc) camel_internet_address_init,
85 internet_decode (CamelAddress *a, const char *raw)
87 struct _camel_header_address *ha, *n;
88 int count = a->addresses->len;
90 /* Should probably use its own decoder or something */
91 ha = camel_header_address_decode(raw, NULL);
95 if (n->type == CAMEL_HEADER_ADDRESS_NAME) {
96 camel_internet_address_add((CamelInternetAddress *)a, n->name, n->v.addr);
97 } else if (n->type == CAMEL_HEADER_ADDRESS_GROUP) {
98 struct _camel_header_address *g = n->v.members;
100 if (g->type == CAMEL_HEADER_ADDRESS_NAME)
101 camel_internet_address_add((CamelInternetAddress *)a, g->name, g->v.addr);
102 /* otherwise, it's an error, infact */
108 camel_header_address_list_clear(&ha);
111 return a->addresses->len - count;
115 internet_encode (CamelAddress *a)
120 int len = 6; /* "From: ", assume longer of the address headers */
122 if (a->addresses->len == 0)
125 out = g_string_new("");
127 for (i = 0;i < a->addresses->len; i++) {
128 struct _address *addr = g_ptr_array_index(a->addresses, i);
132 g_string_append(out, ", ");
134 enc = camel_internet_address_encode_address(&len, addr->name, addr->address);
135 g_string_append(out, enc);
140 g_string_free(out, FALSE);
146 internet_unformat(CamelAddress *a, const char *raw)
148 char *buffer, *p, *name, *addr;
150 int count = a->addresses->len;
155 d(printf("unformatting address: %s\n", raw));
157 /* we copy, so we can modify as we go */
158 buffer = g_strdup(raw);
160 /* this can be simpler than decode, since there are much fewer rules */
165 c = (unsigned char)*p++;
167 /* removes quotes, they should only be around the total name anyway */
183 while (*p && *p != '>')
194 name = g_strstrip(name);
195 addr = g_strstrip(addr);
197 d(printf("found address: '%s' <%s>\n", name, addr));
198 camel_internet_address_add((CamelInternetAddress *)a, name, addr);
208 return a->addresses->len - count;
212 internet_format (CamelAddress *a)
218 if (a->addresses->len == 0)
221 out = g_string_new("");
223 for (i = 0;i < a->addresses->len; i++) {
224 struct _address *addr = g_ptr_array_index(a->addresses, i);
228 g_string_append(out, ", ");
230 enc = camel_internet_address_format_address(addr->name, addr->address);
231 g_string_append(out, enc);
236 g_string_free(out, FALSE);
242 internet_cat (CamelAddress *dest, const CamelAddress *source)
246 g_assert(CAMEL_IS_INTERNET_ADDRESS(source));
248 for (i=0;i<source->addresses->len;i++) {
249 struct _address *addr = g_ptr_array_index(source->addresses, i);
250 camel_internet_address_add((CamelInternetAddress *)dest, addr->name, addr->address);
257 internet_remove (CamelAddress *a, int index)
259 struct _address *addr;
261 if (index < 0 || index >= a->addresses->len)
264 addr = g_ptr_array_index(a->addresses, index);
266 g_free(addr->address);
268 g_ptr_array_remove_index(a->addresses, index);
273 * camel_internet_address_new:
275 * Create a new #CamelInternetAddress object.
277 * Returns a new #CamelInternetAddress object
279 CamelInternetAddress *
280 camel_internet_address_new (void)
282 CamelInternetAddress *new = CAMEL_INTERNET_ADDRESS(camel_object_new(camel_internet_address_get_type()));
288 * camel_internet_address_add:
289 * @addr: a #CamelInternetAddress object
290 * @name: name associated with the new address
291 * @address: routing address associated with the new address
293 * Add a new internet address to @addr.
295 * Returns the index of added entry
298 camel_internet_address_add (CamelInternetAddress *addr, const char *name, const char *address)
300 struct _address *new;
303 g_assert(CAMEL_IS_INTERNET_ADDRESS(addr));
305 new = g_malloc(sizeof(*new));
306 new->name = g_strdup(name);
307 new->address = g_strdup(address);
308 index = ((CamelAddress *)addr)->addresses->len;
309 g_ptr_array_add(((CamelAddress *)addr)->addresses, new);
316 * camel_internet_address_get:
317 * @addr: a #CamelInternetAddress object
318 * @index: address's array index
319 * @namep: holder for the returned name, or %NULL, if not required.
320 * @addressp: holder for the returned address, or %NULL, if not required.
322 * Get the address at @index.
324 * Returns %TRUE if such an address exists, or %FALSE otherwise
327 camel_internet_address_get (const CamelInternetAddress *addr, int index, const char **namep, const char **addressp)
331 g_assert(CAMEL_IS_INTERNET_ADDRESS(addr));
333 if (index < 0 || index >= ((CamelAddress *)addr)->addresses->len)
336 a = g_ptr_array_index (((CamelAddress *)addr)->addresses, index);
340 *addressp = a->address;
346 * camel_internet_address_find_name:
347 * @addr: a #CamelInternetAddress object
348 * @name: name to lookup
349 * @addressp: holder for address part, or %NULL, if not required.
351 * Find address by real name.
353 * Returns the index of the address matching the name, or %-1 if no
357 camel_internet_address_find_name(CamelInternetAddress *addr, const char *name, const char **addressp)
362 g_assert(CAMEL_IS_INTERNET_ADDRESS(addr));
364 len = ((CamelAddress *)addr)->addresses->len;
365 for (i=0;i<len;i++) {
366 a = g_ptr_array_index (((CamelAddress *)addr)->addresses, i);
367 if (a->name && !strcmp(a->name, name)) {
369 *addressp = a->address;
378 * camel_internet_address_find_address:
379 * @addr: a #CamelInternetAddress object
380 * @address: address to lookup
381 * @namep: holder for the matching name, or %NULL, if not required.
383 * Find an address by address.
385 * Returns the index of the address, or %-1 if not found
388 camel_internet_address_find_address(CamelInternetAddress *addr, const char *address, const char **namep)
393 g_assert(CAMEL_IS_INTERNET_ADDRESS(addr));
395 len = ((CamelAddress *)addr)->addresses->len;
396 for (i=0;i<len;i++) {
397 a = g_ptr_array_index (((CamelAddress *)addr)->addresses, i);
398 if (!strcmp(a->address, address)) {
408 cia_encode_addrspec(GString *out, const char *addr)
412 at = strchr(addr, '@');
420 /* strictly by rfc, we should split local parts on dots.
421 however i think 2822 changes this, and not many clients grok it, so
422 just quote the whole local part if need be */
423 if (!(camel_mime_is_atom(c) || c=='.')) {
424 g_string_append_c(out, '"');
429 if (c == '"' || c == '\\')
430 g_string_append_c(out, '\\');
431 g_string_append_c(out, c);
433 g_string_append_c(out, '"');
434 g_string_append(out, p);
441 g_string_append(out, addr);
446 * camel_internet_address_encode_address:
447 * @len: the length of the line the address is being appended to
448 * @name: the unencoded real name associated with the address
449 * @addr: the routing address
451 * Encode a single address ready for internet usage. Header folding
452 * as per rfc822 is also performed, based on the length *@len. If @len
453 * is %NULL, then no folding will occur.
455 * Note: The value at *@in will be updated based on any linewrapping done
457 * Returns the encoded address
460 camel_internet_address_encode_address(int *inlen, const char *real, const char *addr)
462 char *name = camel_header_encode_phrase ((const unsigned char *) real);
465 GString *out = g_string_new("");
472 if (name && name[0]) {
473 if (inlen != NULL && (strlen(name) + len) > CAMEL_FOLD_SIZE) {
474 char *folded = camel_header_address_fold(name, len);
476 g_string_append(out, folded);
478 last = strrchr(out->str, '\n');
480 len = last-(out->str+out->len);
484 g_string_append(out, name);
489 /* NOTE: Strictly speaking, we could and should split the
490 * internal address up if we need to, on atom or specials
491 * boundaries - however, to aid interoperability with mailers
492 * that will probably not handle this case, we will just move
493 * the whole address to its own line. */
494 if (inlen != NULL && (strlen(addr) + len) > CAMEL_FOLD_SIZE) {
495 g_string_append(out, "\n\t");
502 g_string_append_printf(out, " <");
503 cia_encode_addrspec(out, addr);
505 g_string_append_printf(out, ">");
515 g_string_free(out, FALSE);
522 * camel_internet_address_format_address:
523 * @name: a name, quotes may be stripped from it
524 * @addr: an rfc822 routing address
526 * Function to format a single address, suitable for display.
528 * Returns a nicely formatted string containing the rfc822 address
531 camel_internet_address_format_address(const char *name, const char *addr)
537 if (name && name[0]) {
538 const char *p = name;
542 if (c == '\"' || c == ',') {
543 o = ret = g_malloc(strlen(name)+3+strlen(addr)+3 + 1);
550 sprintf(o, " <%s>", addr);
551 d(printf("encoded '%s' => '%s'\n", name, ret));
555 ret = g_strdup_printf("%s <%s>", name, addr);
557 ret = g_strdup(addr);