diff options
Diffstat (limited to 'pith/addrstring.c')
-rw-r--r-- | pith/addrstring.c | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/pith/addrstring.c b/pith/addrstring.c new file mode 100644 index 00000000..928de43e --- /dev/null +++ b/pith/addrstring.c @@ -0,0 +1,452 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: addrstring.c 770 2007-10-24 00:23:09Z hubert@u.washington.edu $"; +#endif + +/* + * ======================================================================== + * Copyright 2006-2007 University of Washington + * Copyright 2013 Eduardo Chappa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include "../pith/headers.h" +#include "../pith/addrstring.h" +#include "../pith/state.h" +#include "../pith/copyaddr.h" +#include "../pith/charset.h" +#include "../pith/stream.h" + + +/* + * Internal prototypes + */ +void rfc822_write_address_decode(char *, size_t, ADDRESS *, int); + + +/* + * Format an address structure into a string + * + * Args: addr -- Single ADDRESS structure to turn into a string + * + * Result: Fills in buf and returns pointer to it. + * Just uses the c-client call to do this. + * (the address is not rfc1522 decoded) + */ +char * +addr_string(struct mail_address *addr, char *buf, size_t buflen) +{ + ADDRESS *next_addr; + RFC822BUFFER rbuf; + + *buf = '\0'; + next_addr = addr->next; + addr->next = NULL; + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = buf; + rbuf.cur = buf; + rbuf.end = buf+buflen-1; + rfc822_output_address_list(&rbuf, addr, 0L, NULL); + *rbuf.cur = '\0'; + addr->next = next_addr; + return(buf); +} + + +/* + * Same as addr_string only it doesn't have to be a + * single address. + */ +char * +addr_string_mult(struct mail_address *addr, char *buf, size_t buflen) +{ + RFC822BUFFER rbuf; + + *buf = '\0'; + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = buf; + rbuf.cur = buf; + rbuf.end = buf+buflen-1; + rfc822_output_address_list(&rbuf, addr, 0L, NULL); + *rbuf.cur = '\0'; + return(buf); +} + + +/* + * Format an address structure into a simple string: "mailbox@host" + * + * Args: addr -- Single ADDRESS structure to turn into a string + * buf -- buffer to write address in; + * + * Result: Returns pointer to buf; + */ +char * +simple_addr_string(struct mail_address *addr, char *buf, size_t buflen) +{ + RFC822BUFFER rbuf; + + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = buf; + rbuf.cur = buf; + rbuf.end = buf+buflen-1; + rfc822_output_address(&rbuf, addr); + *rbuf.cur = '\0'; + + return(buf); +} + + +/* + * Format an address structure into a simple string: "mailbox@host" + * Like simple_addr_string but can be multiple addresses. + * + * Args: addr -- ADDRESS structure to turn into a string + * buf -- buffer to write address in; + * buflen -- length of buffer + * sep -- separator string + * + * Result: Returns pointer to internal static formatted string. + * Just uses the c-client call to do this. + */ +char * +simple_mult_addr_string(struct mail_address *addr, char *buf, size_t buflen, char *sep) +{ + ADDRESS *a; + char *dest = buf; + size_t seplen = 0; + + if(sep) + seplen = strlen(sep); + + *dest = '\0'; + for(a = addr; a; a = a->next){ + if(dest > buf && seplen > 0 && buflen-1-(dest-buf) >= seplen){ + strncpy(dest, sep, seplen); + dest += seplen; + *dest = '\0'; + } + + simple_addr_string(a, dest, buflen-(dest-buf)); + dest += strlen(dest); + } + + buf[buflen-1] = '\0'; + + return(buf); +} + + +/* + * 1522 encode the personal name portion of addr and return an allocated + * copy of the resulting address string. + */ +char * +encode_fullname_of_addrstring(char *addr, char *charset) +{ + char *pers_encoded, + *tmp_a_string, + *ret = NULL; + ADDRESS *adr; + static char *fakedomain = "@"; + RFC822BUFFER rbuf; + size_t len; + + tmp_a_string = cpystr(addr ? addr : ""); + adr = NULL; + rfc822_parse_adrlist(&adr, tmp_a_string, fakedomain); + fs_give((void **)&tmp_a_string); + + if(!adr) + return(cpystr("")); + + if(adr->personal && adr->personal[0]){ + pers_encoded = cpystr(rfc1522_encode(tmp_20k_buf, SIZEOF_20KBUF, + (unsigned char *)adr->personal, + charset)); + fs_give((void **)&adr->personal); + adr->personal = pers_encoded; + } + + len = est_size(adr); + ret = (char *) fs_get(len * sizeof(char)); + ret[0] = '\0'; + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = ret; + rbuf.cur = ret; + rbuf.end = ret+len-1; + rfc822_output_address_list(&rbuf, adr, 0L, NULL); + *rbuf.cur = '\0'; + mail_free_address(&adr); + return(ret); +} + + +/* + * 1522 decode the personal name portion of addr and return an allocated + * copy of the resulting address string. + */ +char * +decode_fullname_of_addrstring(char *addr, int verbose) +{ + char *pers_decoded, + *tmp_a_string, + *ret = NULL; + ADDRESS *adr; + static char *fakedomain = "@"; + RFC822BUFFER rbuf; + size_t len; + + tmp_a_string = cpystr(addr ? addr : ""); + adr = NULL; + rfc822_parse_adrlist(&adr, tmp_a_string, fakedomain); + fs_give((void **)&tmp_a_string); + + if(!adr) + return(cpystr("")); + + if(adr->personal && adr->personal[0]){ + pers_decoded + = cpystr((char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf, + SIZEOF_20KBUF, adr->personal)); + fs_give((void **)&adr->personal); + adr->personal = pers_decoded; + } + + len = est_size(adr); + ret = (char *) fs_get(len * sizeof(char)); + ret[0] = '\0'; + rbuf.f = dummy_soutr; + rbuf.s = NULL; + rbuf.beg = ret; + rbuf.cur = ret; + rbuf.end = ret+len-1; + rfc822_output_address_list(&rbuf, adr, 0L, NULL); + *rbuf.cur = '\0'; + mail_free_address(&adr); + return(ret); +} + + +/* + * Turn a list of address structures into a formatted string + * + * Args: adrlist -- An adrlist + * f -- Function to use to print one address in list. If NULL, + * use rfc822_write_address_decode to print whole list. + * do_quote -- Quote quotes and dots (only used if f == NULL). + * Result: comma separated list of addresses which is + * malloced here and returned + * (the list is rfc1522 decoded unless f is *not* NULL) + */ +char * +addr_list_string(struct mail_address *adrlist, + char *(*f)(struct mail_address *, char *, size_t), + int do_quote) +{ + size_t len; + char *list, *s, string[MAX_ADDR_EXPN+1]; + register ADDRESS *a; + + if(!adrlist) + return(cpystr("")); + + if(f){ + len = 0; + for(a = adrlist; a; a = a->next) + len += (strlen((*f)(a, string, sizeof(string))) + 2); + + list = (char *) fs_get((len+1) * sizeof(char)); + s = list; + s[0] = '\0'; + + for(a = adrlist; a; a = a->next){ + sstrncpy(&s, (*f)(a, string, sizeof(string)), len-(s-list)); + if(a->next && len-(s-list) > 2){ + *s++ = ','; + *s++ = SPACE; + } + } + } + else{ + len = est_size(adrlist); + list = (char *) fs_get((len+1) * sizeof(char)); + list[0] = '\0'; + rfc822_write_address_decode(list, len+1, adrlist, do_quote); + removing_leading_and_trailing_white_space(list); + } + + list[len] = '\0'; + return(list); +} + + +static long rfc822_dummy_soutr (void *stream, char *string) +{ + return LONGT; +} + +/* + * Copied from c-client/rfc822.c buf with dot and double quote removed. + */ +static const char *rspecials_minus_quote_and_dot = "()<>@,;:\\[]\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177"; + +/* Write RFC822 address with 1522 decoding of personal name + * and optional quoting. + * + * The idea is that there are some places where we'd just like to display + * the personal name as is before applying confusing quoting. However, + * we do want to be careful not to break things that should be quoted so + * we'll only use this where we are sure. Quoting may look ugly but it + * doesn't usually break anything. + */ +void +rfc822_write_address_decode(char *dest, size_t destlen, struct mail_address *adr, int do_quote) +{ + RFC822BUFFER buf; + extern const char *rspecials; + ADDRESS *copy, *a; + + /* + * We want to print the adr list after decoding it. C-client knows + * how to parse and print, so we want to use that. But c-client + * doesn't decode. So we make a copy of the address list, decode + * things there, and let c-client print that. + */ + copy = copyaddrlist(adr); + for(a = copy; a; a = a->next){ + if(a->host){ /* ordinary address? */ + if(a->personal && *a->personal){ + unsigned char *p; + + p = rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, + SIZEOF_20KBUF, a->personal); + + if(p && (char *) p != a->personal){ + fs_give((void **) &a->personal); + a->personal = cpystr((char *) p); + } + } + } + else if(a->mailbox && *a->mailbox){ /* start of group? */ + unsigned char *p; + + p = rfc1522_decode_to_utf8((unsigned char *) tmp_20k_buf, SIZEOF_20KBUF, a->mailbox); + + if(p && (char *) p != a->mailbox){ + fs_give((void **) &a->mailbox); + a->mailbox = cpystr((char *) p); + } + } + } + + buf.end = (buf.beg = buf.cur = dest) + destlen; + buf.f = rfc822_dummy_soutr; + *buf.cur = '\0'; + buf.s = NIL; + + (void) rfc822_output_address_list(&buf, copy, 0, + do_quote ? rspecials : rspecials_minus_quote_and_dot); + + *buf.cur = '\0'; + + if(copy) + mail_free_address(©); +} + + +/* + * Compute an upper bound on the size of the array required by + * rfc822_write_address for this list of addresses. + * + * Args: adrlist -- The address list. + * + * Returns -- an integer giving the upper bound + */ +int +est_size(struct mail_address *a) +{ + int cnt = 0; + + for(; a; a = a->next){ + + /* two times personal for possible quoting */ + cnt += 2 * (a->personal ? (strlen(a->personal)+1) : 0); + cnt += 2 * (a->mailbox ? (strlen(a->mailbox)+1) : 0); + cnt += (a->adl ? strlen(a->adl) : 0); + cnt += (a->host ? strlen(a->host) : 0); + + /* + * add room for: + * possible single space between fullname and addr + * left and right brackets + * @ sign + * possible : for route addr + * , <space> + * + * So I really think that adding 7 is enough. Instead, I'll add 10. + */ + cnt += 10; + } + + return(MAX(cnt, 50)); /* just making sure */ +} + + +/* + * Returns the number of addresses in the list. + */ +int +count_addrs(struct mail_address *adrlist) +{ + int cnt = 0; + + while(adrlist){ + if(adrlist->mailbox && adrlist->mailbox[0]) + cnt++; + + adrlist = adrlist->next; + } + + return(cnt); +} + + +/* + * Buf is at least size maxlen+1 + */ +void +a_little_addr_string(struct mail_address *addr, char *buf, size_t maxlen) +{ + buf[0] = '\0'; + if(addr){ + if(addr->personal && addr->personal[0]){ + char tmp[MAILTMPLEN]; + + snprintf(tmp, sizeof(tmp), "%s", addr->personal); + iutf8ncpy(buf, (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf, + SIZEOF_20KBUF, tmp), + maxlen); + } + else if(addr->mailbox && addr->mailbox[0]){ + strncpy(buf, addr->mailbox, maxlen); + buf[maxlen] = '\0'; + if(addr->host && addr->host[0] && addr->host[0] != '.'){ + strncat(buf, "@", maxlen+1-1-strlen(buf)); + strncat(buf, addr->host, maxlen+1-1-strlen(buf)); + } + } + } + + buf[maxlen] = '\0'; +} |