/* * Copyright (C) 2000 Ximian Inc. * * Authors: Michael Zucchi * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include "camel-mime-utils.h" #include "camel-internet-address.h" #define d(x) static int internet_decode (CamelAddress *, const char *raw); static char * internet_encode (CamelAddress *); static int internet_unformat (CamelAddress *, const char *raw); static char * internet_format (CamelAddress *); static int internet_cat (CamelAddress *dest, const CamelAddress *source); static void internet_remove (CamelAddress *, int index); static void camel_internet_address_class_init (CamelInternetAddressClass *klass); static void camel_internet_address_init (CamelInternetAddress *obj); static CamelAddressClass *camel_internet_address_parent; struct _address { char *name; char *address; }; static void camel_internet_address_class_init(CamelInternetAddressClass *klass) { CamelAddressClass *address = (CamelAddressClass *) klass; camel_internet_address_parent = CAMEL_ADDRESS_CLASS(camel_type_get_global_classfuncs(camel_address_get_type())); address->decode = internet_decode; address->encode = internet_encode; address->unformat = internet_unformat; address->format = internet_format; address->remove = internet_remove; address->cat = internet_cat; } static void camel_internet_address_init(CamelInternetAddress *obj) { } CamelType camel_internet_address_get_type(void) { static CamelType type = CAMEL_INVALID_TYPE; if (type == CAMEL_INVALID_TYPE) { type = camel_type_register(camel_address_get_type(), "CamelInternetAddress", sizeof (CamelInternetAddress), sizeof (CamelInternetAddressClass), (CamelObjectClassInitFunc) camel_internet_address_class_init, NULL, (CamelObjectInitFunc) camel_internet_address_init, NULL); } return type; } static int internet_decode (CamelAddress *a, const char *raw) { struct _header_address *ha, *n; int count = a->addresses->len; /* Should probably use its own decoder or something */ ha = header_address_decode(raw); if (ha) { n = ha; while (n) { if (n->type == HEADER_ADDRESS_NAME) { camel_internet_address_add((CamelInternetAddress *)a, n->name, n->v.addr); } else if (n->type == HEADER_ADDRESS_GROUP) { struct _header_address *g = n->v.members; while (g) { if (g->type == HEADER_ADDRESS_NAME) camel_internet_address_add((CamelInternetAddress *)a, g->name, g->v.addr); /* otherwise, it's an error, infact */ g = g->next; } } n = n->next; } header_address_list_clear(&ha); } return a->addresses->len - count; } static char * internet_encode (CamelAddress *a) { int i; GString *out; char *ret; int len = 6; /* "From: ", assume longer of the address headers */ if (a->addresses->len == 0) return NULL; out = g_string_new(""); for (i = 0;i < a->addresses->len; i++) { struct _address *addr = g_ptr_array_index(a->addresses, i); char *enc; if (i != 0) g_string_append(out, ", "); enc = camel_internet_address_encode_address(&len, addr->name, addr->address); g_string_append(out, enc); g_free(enc); } ret = out->str; g_string_free(out, FALSE); return ret; } static int internet_unformat(CamelAddress *a, const char *raw) { char *buffer, *p, *name, *addr; int c; int count = a->addresses->len; if (raw == NULL) return 0; d(printf("unformatting address: %s\n", raw)); /* we copy, so we can modify as we go */ buffer = g_strdup(raw); /* this can be simpler than decode, since there are much fewer rules */ p = buffer; name = NULL; addr = p; do { c = (unsigned char)*p++; switch (c) { /* removes quotes, they should only be around the total name anyway */ case '"': p[-1] = ' '; while (*p) if (*p == '"') { *p++ = ' '; break; } else { p++; } break; case '<': if (name == NULL) name = addr; addr = p; addr[-1] = 0; while (*p && *p != '>') p++; if (*p == 0) break; p++; /* falls through */ case ',': p[-1] = 0; /* falls through */ case 0: if (name) name = g_strstrip(name); addr = g_strstrip(addr); if (addr[0]) { d(printf("found address: '%s' <%s>\n", name, addr)); camel_internet_address_add((CamelInternetAddress *)a, name, addr); } name = NULL; addr = p; break; } } while (c); g_free(buffer); return a->addresses->len - count; } static char * internet_format (CamelAddress *a) { int i; GString *out; char *ret; if (a->addresses->len == 0) return NULL; out = g_string_new(""); for (i = 0;i < a->addresses->len; i++) { struct _address *addr = g_ptr_array_index(a->addresses, i); char *enc; if (i != 0) g_string_append(out, ", "); enc = camel_internet_address_format_address(addr->name, addr->address); g_string_append(out, enc); g_free(enc); } ret = out->str; g_string_free(out, FALSE); return ret; } static int internet_cat (CamelAddress *dest, const CamelAddress *source) { int i; g_assert(CAMEL_IS_INTERNET_ADDRESS(source)); for (i=0;iaddresses->len;i++) { struct _address *addr = g_ptr_array_index(source->addresses, i); camel_internet_address_add((CamelInternetAddress *)dest, addr->name, addr->address); } return i; } static void internet_remove (CamelAddress *a, int index) { struct _address *addr; if (index < 0 || index >= a->addresses->len) return; addr = g_ptr_array_index(a->addresses, index); g_free(addr->name); g_free(addr->address); g_free(addr); g_ptr_array_remove_index(a->addresses, index); } /** * camel_internet_address_new: * * Create a new CamelInternetAddress object. * * Return value: A new CamelInternetAddress object. **/ CamelInternetAddress * camel_internet_address_new (void) { CamelInternetAddress *new = CAMEL_INTERNET_ADDRESS(camel_object_new(camel_internet_address_get_type())); return new; } /** * camel_internet_address_add: * @a: internet address object * @name: * @address: * * Add a new internet address to the address object. * * Return value: Index of added entry. **/ int camel_internet_address_add (CamelInternetAddress *a, const char *name, const char *address) { struct _address *new; int index; g_assert(CAMEL_IS_INTERNET_ADDRESS(a)); new = g_malloc(sizeof(*new)); new->name = g_strdup(name); new->address = g_strdup(address); index = ((CamelAddress *)a)->addresses->len; g_ptr_array_add(((CamelAddress *)a)->addresses, new); return index; } /** * camel_internet_address_get: * @a: internet address object * @index: address's array index * @namep: Holder for the returned name, or NULL, if not required. * @addressp: Holder for the returned address, or NULL, if not required. * * Get the address at @index. * * Return value: TRUE if such an address exists, or FALSE otherwise. **/ gboolean camel_internet_address_get (const CamelInternetAddress *a, int index, const char **namep, const char **addressp) { struct _address *addr; g_assert(CAMEL_IS_INTERNET_ADDRESS(a)); if (index < 0 || index >= ((CamelAddress *)a)->addresses->len) return FALSE; addr = g_ptr_array_index( ((CamelAddress *)a)->addresses, index); if (namep) *namep = addr->name; if (addressp) *addressp = addr->address; return TRUE; } /** * camel_internet_address_find_name: * @a: * @name: * @addressp: Holder for address part, or NULL, if not required. * * Find address by real name. * * Return value: The index of the address matching the name, or -1 * if no match was found. **/ int camel_internet_address_find_name(CamelInternetAddress *a, const char *name, const char **addressp) { struct _address *addr; int i, len; g_assert(CAMEL_IS_INTERNET_ADDRESS(a)); len = ((CamelAddress *)a)->addresses->len; for (i=0;iaddresses, i ); if (!strcmp(addr->name, name)) { if (addressp) *addressp = addr->address; return i; } } return -1; } /** * camel_internet_address_find_address: * @a: * @address: * @namep: Return for the matching name, or NULL, if not required. * * Find an address by address. * * Return value: The index of the address, or -1 if not found. **/ int camel_internet_address_find_address(CamelInternetAddress *a, const char *address, const char **namep) { struct _address *addr; int i, len; g_assert(CAMEL_IS_INTERNET_ADDRESS(a)); len = ((CamelAddress *)a)->addresses->len; for (i=0;iaddresses, i ); if (!strcmp(addr->address, address)) { if (namep) *namep = addr->name; return i; } } return -1; } /** * camel_internet_address_encode_address: * @len: The encoded length so far, of this line * @name: * @addr: * * Encode a single address ready for internet usage. Header folding * as per rfc 822 is also performed, based on the length in len. * * Return value: The encoded address. **/ char * camel_internet_address_encode_address(int *inlen, const char *real, const char *addr) { char *name = header_encode_phrase(real); char *ret = NULL, *addra = NULL; int len = *inlen; GString *out = g_string_new(""); g_assert(addr); if (name && name[0]) { if (strlen(name) + len > CAMEL_FOLD_SIZE) { char *folded = header_address_fold(name, len); char *last; g_string_append(out, folded); g_free(folded); last = strrchr(out->str, '\n'); if (last) len = last-(out->str+out->len); else len = out->len; } else { g_string_append(out, name); len += strlen(name); } addr = addra = g_strdup_printf(" <%s>", addr); } /* NOTE: Strictly speaking, we could and should split the * internal address up if we need to, on atom or specials * boundaries - however, to aid interoperability with mailers * that will probably not handle this case, we will just move * the whole address to its own line */ if (strlen(addr) + len > CAMEL_FOLD_SIZE) { g_string_append(out, "\n\t"); g_string_append(out, addr); len = strlen(addr)+1; } else { g_string_append(out, addr); len += strlen(addr); } *inlen = len; #if 0 if (name && name[0]) ret = g_strdup_printf("%s <%s>", name, addr); else ret = g_strdup_printf("%s", addr); #endif g_free(name); g_free(addra); ret = out->str; g_string_free(out, FALSE); return ret; } /** * camel_internet_address_format_address: * @name: A name, quotes may be stripped from it. * @addr: Assumes a valid rfc822 email address. * * Function to format a single address, suitable for display. * * Return value: **/ char * camel_internet_address_format_address(const char *name, const char *addr) { char *ret = NULL; g_assert(addr); if (name && name[0]) { const char *p = name; char *o, c; while ((c = *p++)) { if (c == '\"' || c == ',') { o = ret = g_malloc(strlen(name)+3+strlen(addr)+3 + 1); p = name; *o++ = '\"'; while ((c = *p++)) if (c != '\"') *o++ = c; *o++ = '\"'; sprintf(o, " <%s>", addr); d(printf("encoded '%s' => '%s'\n", name, ret)); return ret; } } ret = g_strdup_printf("%s <%s>", name, addr); } else ret = g_strdup(addr); return ret; } as C. Berner2020-06-131-3/+3 * Add missing dependency on kinitTobias C. Berner2020-05-181-1/+1 * Update KDE's Applications to 20.04.1Tobias C. Berner2020-05-161-3/+3 * Update KDE Applications (release-service) to 20.04Tobias C. Berner2020-04-242-3/+5 * KDE Applications: update to 19.12.3Tobias C. Berner2020-03-071-3/+3 * Update KDE's Applications to 19.12.2Tobias C. Berner2020-02-071-3/+3 * Update KDE's App Bundle to 19.12.1Tobias C. Berner2020-01-101-3/+3 * KDE's December 2019 Apps UpdateTobias C. Berner2019-12-132-4/+3 * devel/boost-*: update to 1.72.0Jan Beich2019-12-121-0/+1 * KDE Applications: update to 19.08.3Tobias C. Berner2019-11-091-3/+3 * KDE Applications: update to 19.08.2Tobias C. Berner2019-10-162-4/+3 * KDE Applications: update to 19.08.1Tobias C. Berner2019-09-061-3/+3 * devel/umbrello: Drop nop CMAKE_BOOLTobias Kortkamp2019-08-311-3/+0 * devel/boost-*: update to 1.71.0Jan Beich2019-08-191-0/+1 * Update KDE Applications to latest upstream release, 19.08Adriaan de Groot2019-08-153-4/+6 * Bump PORTREVISION for ports depending on the canonical version of GCCGerald Pfeifer2019-07-271-1/+1 * KDE Applications: update to 19.04.3Tobias C. Berner2019-07-122-3/+12 * KDE Applications: complete dependency listsTobias C. Berner2019-06-231-2/+3 * Update KDE Applications to 19.04.2Tobias C. Berner2019-06-071-3/+3 * Update KDE Applications to 19.04.1Tobias C. Berner2019-05-102-3/+4 * Update KDE Applications to 19.04.0Tobias C. Berner2019-04-193-4/+4 * devel/boost-*: update to 1.70.0Jan Beich2019-04-121-0/+1 * Update KDE Applications to 18.12.3Tobias C. Berner2019-03-082-3/+4 * Update KDE Applications to 18.12.2Tobias C. Berner2019-02-082-4/+3 * Fix Qt5 symbol version scripts to put the catch-all clause first. WhenTijl Coosemans2019-01-161-0/+1 * Update KDE Applications to 18.12.1Tobias C. Berner2019-01-112-3/+4 * Change cmake default behaviour to outsource.Tobias C. Berner2018-12-261-1/+1 * Update KDE Applications to 18.12.0Tobias C. Berner2018-12-143-7/+3 * Bump PORTREVISION for ports depending on the canonical version of GCCGerald Pfeifer2018-12-121-1/+1 * devel/boost-*: update to 1.69.0Jan Beich2018-12-121-0/+1 * Fix build for some more kde@ ports on GCC-architecturesTobias C. Berner2018-11-101-1/+1 * Update KDE Applications to 18.09.3Tobias C. Berner2018-11-101-3/+3 * - Update WWWDmitry Marakasov2018-11-071-1/+1 * Update KDE Applications to 18.08.2Tobias C. Berner2018-10-121-3/+3 * Add DOCS options to ports that should have one.Mathieu Arnold2018-09-101-0/+2 * Update the current KDE Applications to 18.08.1, the latest release.Adriaan de Groot2018-09-071-3/+3 * Update KDE Applications to 18.08Tobias C. Berner2018-08-253-35/+38 * devel/boost-*: update to 1.68.0Jan Beich2018-08-091-0/+1 * Update KDE Applications to 18.04.3Tobias C. Berner2018-07-141-3/+3 * Replace bsd.qt.mk by Uses/qt.mk and Uses/qt-dist.mkTobias C. Berner2018-06-291-2/+2 * Update KDE Applications to 18.04.2Tobias C. Berner2018-06-101-3/+3 * Update KDE Applications to 18.04.1Tobias C. Berner2018-05-111-3/+3 * Update KDE Applications to 18.04.0Tobias C. Berner2018-04-293-9/+49 * devel/boost-*: update to 1.67.0Jan Beich2018-04-181-0/+1 * New ports: KDE Applications devel/Tobias C. Berner2018-04-104-0/+151 * Give the KDE SC4 applications ports a -kde4 suffixTobias C. Berner2018-02-234-264/+0 * Rename KDE4 meta portsTobias C. Berner2018-02-101-1/+1 * devel/boost-*: update to 1.66.0Jan Beich2018-01-181-1/+1 * devel/boost-*: update to 1.65.1Jan Beich2017-09-251-1/+1 * devel/boost-*: enable C++11 featuresJan Beich2017-09-251-1/+1 * devel/boost-*: update to 1.64.0Jan Beich2017-05-021-1/+1 * Chase ffmpeg 3.3 update (ABI changes)Thomas Zander2017-04-251-1/+1 * devel/boost-*: update to 1.63.0Jan Beich2017-01-061-1/+1 * devel/boost-*: update to 1.62.0Jan Beich2016-11-231-0/+1 * Introduce new extensible virtual categories for KDETobias C. Berner2016-10-191-3/+1 * Replace Mk/bsd.kde4.mk by Mk/Uses/kde.mk in preparation for KDE Frameworks andTobias C. Berner2016-08-241-2/+2 * Remove expired misc/kdehier4 and update all of its consumers to not reference...Rene Ladan2016-05-261-1/+1 * Remove ${PORTSDIR}/ from dependencies, categories d, e, f, and g.Mathieu Arnold2016-04-011-1/+1 * Update KDE SC to 4.14.3Alonso Schaich2015-03-12