summaryrefslogtreecommitdiff
path: root/pith/addrstring.c
diff options
context:
space:
mode:
authorEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
committerEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
commit094ca96844842928810f14844413109fc6cdd890 (patch)
treee60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /pith/addrstring.c
downloadalpine-094ca96844842928810f14844413109fc6cdd890.tar.xz
Initial Alpine Version
Diffstat (limited to 'pith/addrstring.c')
-rw-r--r--pith/addrstring.c452
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(&copy);
+}
+
+
+/*
+ * 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';
+}