X-Git-Url: https://git.hcoop.net/hcoop/debian/courier-authlib.git/blobdiff_plain/ac40fd9eb9d1980c90dc009d526a23ead1ec0f76..refs/tags/upstream/0.63.0:/rfc822/rfc2047u.c diff --git a/rfc822/rfc2047u.c b/rfc822/rfc2047u.c dissimilarity index 77% index 56e36d1..50d49fc 100644 --- a/rfc822/rfc2047u.c +++ b/rfc822/rfc2047u.c @@ -1,150 +1,1058 @@ -/* -** Copyright 1998 - 2000 Double Precision, Inc. See COPYING for -** distribution information. -*/ - - -#include -#include -#include -#include -#include - -#include "rfc822.h" -#include "rfc2047.h" - -static const char rcsid[]="$Id: rfc2047u.c,v 1.5 2004/05/23 14:28:24 mrsam Exp $"; - -#if HAVE_LIBUNICODE - -#include "../unicode/unicode.h" - -struct decode_unicode_s { - const struct unicode_info *mychset; - int options; - - char *bufptr; - size_t bufsize; -} ; - -static void save_unicode_text(const char *p, int l, struct decode_unicode_s *s) -{ - if (s->bufptr) - memcpy(s->bufptr+s->bufsize, p, l); - - s->bufsize += l; -} - -static int save_unicode(const char *txt, int len, const char *chset, - const char *lang, - void *arg) -{ - struct decode_unicode_s *p=(struct decode_unicode_s *)arg; - char *txts=malloc(len+1); - char *s; - int i; - - if (!txts) - return (-1); - memcpy(txts, txt, len); - txts[len]=0; - - if (!chset) - chset=unicode_ISO8859_1.chset; - - s=unicode_convert_fromchset(txts, chset, p->mychset); - if (!s && p->options & RFC2047_DECODE_REPLACE) - { - const struct unicode_info *uiptr=unicode_find(chset); - if (uiptr) - s=unicode_xconvert(txts, uiptr, p->mychset); - } - free(txts); - if (s) - { - save_unicode_text(s, strlen(s), p); - free(s); - return (0); - } - - if (p->options & RFC2047_DECODE_ABORT) - { - errno=EINVAL; - return (-1); - } - - if (p->options & RFC2047_DECODE_DISCARD) - return (0); - - if (!(p->options & RFC2047_DECODE_NOTAG)) - { - save_unicode_text(" [", 2, p); - save_unicode_text(chset, strlen(chset), p); - save_unicode_text("] ", 2, p); - if (!(p->options & RFC2047_DECODE_REPLACE)) - { - save_unicode_text(txt, len, p); - return (0); - } - } - - if (p->options & RFC2047_DECODE_REPLACE) - for (i=0; i < strlen(txt); i++) - save_unicode_text("?", 1, p); - - return (0); -} - -char *rfc2047_decode_unicode(const char *text, - const struct unicode_info *mychset, - int options) -{ - struct decode_unicode_s s; - char *p=0; - - s.mychset=mychset; - s.options=0; - - s.bufptr=0; - s.bufsize=1; - - - if (rfc2047_decode(text, &save_unicode, &s)) - return (0); - - s.bufptr=p=malloc(s.bufsize); - if (!s.bufptr) - return (0); - - s.bufsize=0; - if (rfc2047_decode(text, &save_unicode, &s)) - { - free(p); - return (0); - } - save_unicode_text("", 1, (void *)&s); - return (p); -} - - -static char *do_rfc2047_decode_enhanced(const char *text, const char *mychset) -{ - const struct unicode_info *u=unicode_find(mychset); - - if (!u) u=&unicode_ISO8859_1; - - return rfc2047_decode_unicode(text, u, 0); -} - -void rfc2047_print_unicode(const struct rfc822a *a, - const char *charset, - void (*print_func)(char, void *), - void (*print_separator)(const char *, void *), - void *ptr) -{ - rfc822_print_common(a, &do_rfc2047_decode_enhanced, charset, - print_func, print_separator, ptr); -} - - -#endif +/* +** Copyright 1998 - 2009 Double Precision, Inc. See COPYING for +** distribution information. +*/ + + +#include +#include +#include +#include +#include + +#include "rfc822.h" +#include "rfc822hdr.h" +#include "rfc2047.h" +#include "../unicode/unicode.h" + +#if LIBIDN +#include +#include +#endif + +static const char rcsid[]="$Id: rfc2047u.c,v 1.11 2009/11/22 19:39:52 mrsam Exp $"; + +static ssize_t rfc822_decode_rfc2047_atom(const char *str, + size_t cnt, + + void (*callback)(const char *, + const char *, + const char *, + size_t, + void *), + void *ptr); + +static int rfc2047_decode_unicode(const char *text, + const struct unicode_info *u, + void (*callback)(const char *, size_t, + void *), + void *ptr); + +struct decode_unicode_s { + const struct unicode_info *mychset; + + char *bufptr; + size_t bufsize; +} ; + +static void save_unicode_text(const char *p, size_t l, void *ptr) +{ + struct decode_unicode_s *s= + (struct decode_unicode_s *)ptr; + + if (s->bufptr) + memcpy(s->bufptr+s->bufsize, p, l); + + s->bufsize += l; +} + +struct rfc822_display_name_s { + const struct unicode_info *u; + void (*print_func)(const char *, size_t, void *); + void *ptr; +}; + +static void unknown_charset(const char *chset, + void (*print_func)(const char *, size_t, void *), + void *ptr) +{ + static const char unknown[]="[unknown character set: "; + + (*print_func)(unknown, sizeof(unknown)-1, ptr); + (*print_func)(chset, strlen(chset), ptr); + (*print_func)("]", 1, ptr); +} + +static void rfc822_display_addr_cb(const char *chset, + const char *lang, + const char *content, + size_t cnt, + void *dummy) +{ + const struct unicode_info *uchset=unicode_find(chset); + struct rfc822_display_name_s *s= + (struct rfc822_display_name_s *)dummy; + char *ptr; + char *buf; + + if (!uchset) + { + unknown_charset(chset, s->print_func, s->ptr); + return; + } + + buf=malloc(cnt+1); + + if (!buf) + return; + + memcpy(buf, content, cnt); + buf[cnt]=0; + + ptr=unicode_xconvert(buf, uchset, s->u); + free(buf); + + if (ptr) + { + (*s->print_func)(ptr, strlen(ptr), s->ptr); + free(ptr); + } +} + +static +int rfc822_display_name_int(const struct rfc822a *rfcp, int index, + const char *chset, + void (*print_func)(const char *, size_t, void *), + void *ptr) +{ + struct rfc822_display_name_s s; + const struct rfc822addr *addrs; + + struct rfc822token *i; + int prev_isatom=0; + int isatom=0; + ssize_t rc; + + if (index < 0 || index >= rfcp->naddrs) return 0; + + addrs=rfcp->addrs+index; + + if (!addrs->name) + return rfc822_display_addr(rfcp, index, chset, print_func, ptr); + + if (chset == NULL) + { + s.u=NULL; + } + else + { + s.u=unicode_find(chset); + + if (!s.u) + { + unknown_charset(chset, print_func, ptr); + return (0); + } + } + + s.print_func=print_func; + s.ptr=ptr; + + for (i=addrs->name; i; i=i->next, prev_isatom=isatom) + { + isatom=rfc822_is_atom(i->token); + if (isatom && prev_isatom) + (*print_func)(" ", 1, ptr); + + if (i->token == '"' || i->token == '(') + { + size_t l=i->len; + char *p, *q, *r; + + if (i->token == '(') + { + if (l > 2) + l -= 2; + else + l=0; + } + + p=malloc(l+1); + + if (!p) + return -1; + + if (l) + { + if (i->token == '(') + { + memcpy(p, i->ptr+1, l); + } + else + { + memcpy(p, i->ptr, l); + } + } + + + p[l]=0; + + for (q=r=p; *q; *r++ = *q++) + if (*q == '\\' && q[1]) + ++q; + + *r=0; + + if (chset == NULL) + { + (*print_func)(p, strlen(p), ptr); + } + else if (rfc822_display_hdrvalue("subject", + p, s.u->chset, + print_func, + NULL, ptr) < 0) + { + free(p); + return -1; + } + free(p); + continue; + } + + if (i->token) + { + char c= (char)i->token; + + (*print_func)(&c, 1, ptr); + continue; + } + + rc=chset ? rfc822_decode_rfc2047_atom(i->ptr, i->len, + rfc822_display_addr_cb, + &s):0; + + if (rc < 0) + return -1; + + if (rc == 0) + { + (*print_func)(i->ptr, i->len, ptr); + continue; + } + + if (i->next && i->next->token == 0) + { + rc=rfc822_decode_rfc2047_atom(i->next->ptr, + i->next->len, + NULL, NULL); + + if (rc < 0) + return -1; + + if (rc > 0) + isatom=0; /* Suppress the separating space */ + } + } + return 0; +} + +int rfc822_display_name(const struct rfc822a *rfcp, int index, + const char *chset, + void (*print_func)(const char *, size_t, void *), + void *ptr) +{ + const struct rfc822addr *addrs; + + if (index < 0 || index >= rfcp->naddrs) return 0; + + addrs=rfcp->addrs+index; + + if (!addrs->tokens) + return 0; + + return rfc822_display_name_int(rfcp, index, chset, + print_func, ptr); +} + +char *rfc822_display_name_tobuf(const struct rfc822a *rfcp, int index, + const char *chset) +{ + struct decode_unicode_s s; + char *p; + + s.bufptr=0; + s.bufsize=1; + + if (rfc822_display_name(rfcp, index, chset, save_unicode_text, &s) < 0) + return NULL; + s.bufptr=p=malloc(s.bufsize); + if (!p) + return (0); + + s.bufsize=0; + if (rfc822_display_name(rfcp, index, chset, save_unicode_text, &s) < 0) + { + free(s.bufptr); + return (0); + } + save_unicode_text("", 1, &s); + + return (p); +} + +int rfc822_display_namelist(const struct rfc822a *rfcp, + const char *chset, + void (*print_func)(const char *, size_t, void *), + void *ptr) +{ + int n; + + for (n=0; nnaddrs; n++) + { + if (rfcp->addrs[n].tokens) + { + int err=rfc822_display_name(rfcp, n, chset, + print_func, ptr); + + if (err < 0) + return err; + + (*print_func)("\n", 1, ptr); + } + } + return 0; +} + +int rfc822_display_addr_str(const char *tok, + const char *chset, + void (*print_func)(const char *, size_t, void *), + void *ptr) +{ + const char *p; + const struct unicode_info *uiptr; + + p=strchr(tok,'@'); + + if (!p) + p=tok; + else + ++p; + + if (chset != NULL && (uiptr=unicode_find(chset)) != NULL) + { + int err; + char *utf8_ptr; + + if (p > tok) + (*print_func)(tok, p-tok, ptr); + +#if LIBIDN + err=idna_to_unicode_8z8z(p, &utf8_ptr, 0); + if (err != IDNA_SUCCESS) + utf8_ptr=0; +#else + utf8_ptr=0; +#endif + + if (utf8_ptr == 0) + (*print_func)(p, strlen(p), ptr); + else + { + char *q=unicode_xconvert(utf8_ptr, &unicode_UTF8, + uiptr); + + if (q) + { + (*print_func)(q, strlen(q), ptr); + free(q); + } + else + { + (*print_func)(p, strlen(p), ptr); + } + free(utf8_ptr); + } + } + else + { + (*print_func)(tok, strlen(tok), ptr); + } + return 0; +} + +int rfc822_display_addr(const struct rfc822a *rfcp, int index, + const char *chset, + void (*print_func)(const char *, size_t, void *), + void *ptr) +{ + const struct rfc822addr *addrs; + char *tok; + int rc; + + if (index < 0 || index >= rfcp->naddrs) return 0; + + addrs=rfcp->addrs+index; + + if (!addrs->tokens) + return 0; + + tok=rfc822_gettok(addrs->tokens); + + if (!tok) + return 0; + + rc=rfc822_display_addr_str(tok, chset, print_func, ptr); + free(tok); + return rc; +} + +int rfc2047_print_unicodeaddr(const struct rfc822a *a, + const char *charset, + void (*print_func)(char, void *), + void (*print_separator)(const char *, void *), + void *ptr) +{ + const char *sep=NULL; + int n; + const struct unicode_info *charsetu=unicode_find(charset); + + for (n=0; nnaddrs; ++n) + { + struct decode_unicode_s nbuf; + const struct rfc822addr *addrs; + size_t i=0; + char *cpbuf; + int need_braces=0; + + addrs=a->addrs+n; + + nbuf.bufptr=0; + nbuf.bufsize=1; + + if (rfc822_display_name_int(a, n, charset, + save_unicode_text, &nbuf) < 0) + return -1; + + nbuf.bufptr=malloc(nbuf.bufsize); + nbuf.bufsize=0; + if (!nbuf.bufptr) + return -1; + + if (rfc822_display_name_int(a, n, charset, + save_unicode_text, &nbuf) < 0) + { + free(nbuf.bufptr); + return -1; + } + nbuf.bufptr[nbuf.bufsize]=0; + + if (addrs->tokens == 0) + { + size_t i; + + if (nbuf.bufsize == 1) /* ; */ + sep=0; + + if (sep) + (*print_separator)(sep, ptr); + + for (i=0; i 1) + (*print_separator)(" ", ptr); + sep=NULL; + continue; + } + if (sep) + (*print_separator)(sep, ptr); + + if (!addrs->name) + { + nbuf.bufsize=0; + nbuf.bufptr[0]=0; + } + + for (i=0; i', ptr); + sep=", "; + } + + return 0; +} + +static int rfc2047_print_unicode_addrstr(const char *addrheader, + const char *charset, + void (*print_func)(char, void *), + void (*print_separator)(const char *, void *), + void (*err_func)(const char *, int, void *), + void *ptr) +{ + struct rfc822t *t; + struct rfc822a *a; + int rc; + + t=rfc822t_alloc_new(addrheader, err_func, ptr); + + if (!t) + return -1; + + a=rfc822a_alloc(t); + + if (!a) + { + rfc822t_free(t); + return -1; + } + rc=rfc2047_print_unicodeaddr(a, charset, print_func, print_separator, + ptr); + rfc822a_free(a); + rfc822t_free(t); + return (rc); +} + +struct rfc822_display_hdrvalue_s { + + const struct unicode_info *u; + void (*display_func)(const char *, size_t, void *); + void *ptr; +}; + +static void rfc822_display_hdrvalue_print_func(char c, void *ptr) +{ + struct rfc822_display_hdrvalue_s *s= + (struct rfc822_display_hdrvalue_s *)ptr; + + (*s->display_func)(&c, 1, s->ptr); +} + +static void rfc822_display_hdrvalue_print_separator(const char *cp, void *ptr) +{ + struct rfc822_display_hdrvalue_s *s= + (struct rfc822_display_hdrvalue_s *)ptr; + + (*s->display_func)(cp, strlen(cp), s->ptr); + (*s->display_func)("", 0, s->ptr); /* Signal wrap point */ +} + +int rfc822_display_hdrvalue(const char *hdrname, + const char *hdrvalue, + const char *charset, + void (*display_func)(const char *, size_t, + void *), + void (*err_func)(const char *, int, void *), + void *ptr) +{ + struct rfc822_display_hdrvalue_s s; + + s.display_func=display_func; + s.ptr=ptr; + + if (rfc822hdr_is_addr(hdrname)) + { + return rfc2047_print_unicode_addrstr(hdrvalue, + charset, + rfc822_display_hdrvalue_print_func, + rfc822_display_hdrvalue_print_separator, + NULL, + &s); + } + + s.u=unicode_find(charset); + + if (!s.u) + { + unknown_charset(charset, display_func, ptr); + return (0); + } + + return rfc2047_decode_unicode(hdrvalue, s.u, display_func, ptr); +} + +struct rfc822_display_hdrvalue_tobuf_s { + void (*orig_err_func)(const char *, int, void *); + void *orig_ptr; + + size_t cnt; + char *buf; +}; + +static void rfc822_display_hdrvalue_tobuf_cnt(const char *ptr, size_t cnt, + void *s) +{ + ((struct rfc822_display_hdrvalue_tobuf_s *)s)->cnt += cnt; +} + +static void rfc822_display_hdrvalue_tobuf_save(const char *ptr, size_t cnt, + void *s) +{ + if (cnt) + memcpy(((struct rfc822_display_hdrvalue_tobuf_s *)s)->buf, + ptr, cnt); + + ((struct rfc822_display_hdrvalue_tobuf_s *)s)->buf += cnt; +} + +static void rfc822_display_hdrvalue_tobuf_errfunc(const char *ptr, int index, + void *s) +{ + void (*f)(const char *, int, void *)= + ((struct rfc822_display_hdrvalue_tobuf_s *)s)->orig_err_func; + + if (f) + f(ptr, index, + ((struct rfc822_display_hdrvalue_tobuf_s *)s)->orig_ptr); +} + +char *rfc822_display_addr_tobuf(const struct rfc822a *rfcp, int index, + const char *chset) +{ + struct rfc822_display_hdrvalue_tobuf_s nbuf; + int errcode; + char *ptr; + + nbuf.buf=0; + nbuf.cnt=1; + + errcode=rfc822_display_addr(rfcp, index, chset, + rfc822_display_hdrvalue_tobuf_cnt, &nbuf); + + if (errcode < 0) + return NULL; + + ptr=nbuf.buf=malloc(nbuf.cnt); + nbuf.cnt=0; + if (!ptr) + return NULL; + + errcode=rfc822_display_addr(rfcp, index, chset, + rfc822_display_hdrvalue_tobuf_save, &nbuf); + + if (errcode < 0) + { + free(nbuf.buf); + return NULL; + } + *nbuf.buf=0; + return ptr; +} + +char *rfc822_display_hdrvalue_tobuf(const char *hdrname, + const char *hdrvalue, + const char *charset, + void (*err_func)(const char *, int, + void *), + void *ptr) +{ + struct rfc822_display_hdrvalue_tobuf_s s; + int errcode; + char *bufptr; + + s.orig_err_func=err_func; + s.orig_ptr=ptr; + s.cnt=1; + + errcode=rfc822_display_hdrvalue(hdrname, hdrvalue, charset, + rfc822_display_hdrvalue_tobuf_cnt, + rfc822_display_hdrvalue_tobuf_errfunc, + &s); + + if (errcode < 0) + return NULL; + + bufptr=s.buf=malloc(s.cnt); + + if (!bufptr) + return NULL; + + errcode=rfc822_display_hdrvalue(hdrname, hdrvalue, charset, + rfc822_display_hdrvalue_tobuf_save, + rfc822_display_hdrvalue_tobuf_errfunc, + &s); + if (errcode) + { + free(bufptr); + return NULL; + } + *s.buf=0; + return bufptr; +} + +char *rfc822_display_addr_str_tobuf(const char *tok, const char *chset) +{ + struct rfc822_display_hdrvalue_tobuf_s s; + int errcode; + char *bufptr; + + s.cnt=1; + + errcode=rfc822_display_addr_str(tok, chset, + rfc822_display_hdrvalue_tobuf_cnt, + &s); + + if (errcode < 0) + return NULL; + + bufptr=s.buf=malloc(s.cnt); + + if (!bufptr) + return NULL; + + errcode=rfc822_display_addr_str(tok, chset, + rfc822_display_hdrvalue_tobuf_save, + &s); + if (errcode < 0) + { + free(bufptr); + return NULL; + } + *s.buf=0; + return bufptr; +} + + +static const char xdigit[]="0123456789ABCDEFabcdef"; + +static const unsigned char decode64tab[]={ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 99, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static int nyb(int c) +{ + const char *p; + int n; + + p=strchr(xdigit, c); + + if (!p) + return 0; + + n=p-xdigit; + + if (n > 15) + n -= 6; + + return n; +} + +static size_t decodebase64(const char *ptr, size_t cnt, + char *dec_buf) +{ + size_t i, j; + char a,b,c; + size_t k; + + i=cnt / 4; + i=i*4; + k=0; + for (j=0; j> 4); + b= (x << 4) | (y >> 2); + c= (y << 6) | z; + dec_buf[k++]=a; + if ( ptr[j+2] != '=') + dec_buf[k++]=b; + if ( ptr[j+3] != '=') + dec_buf[k++]=c; + } + return (k); +} + + +static ssize_t rfc822_decode_rfc2047_atom(const char *str, + size_t cnt, + + void (*callback)(const char *, + const char *, + const char *, + size_t, + void *), + void *ptr) +{ + const char *chset_str; + const char *enc_str; + const char *content_str; + + char *chset; + char *lang; + + char *content; + + size_t i; + size_t j; + size_t k; + + size_t content_len; + + if (cnt < 2 || str[0] != '=' || str[1] != '?') + return 0; + + chset_str=str+2; + + for (i=2; i= cnt) + return 0; + + enc_str= str + ++i; + + for (; i < cnt; i++) + if (str[i] == '?') + break; + + if (i >= cnt) + return 0; + + content_str= str + ++i; + + while (1) + { + if (cnt-i < 2) + return 0; + + if (str[i] == '?' && str[i+1] == '=') + break; + ++i; + } + + for (j=0; chset_str[j] != '?'; ++j) + ; + + chset=malloc(j+1); + + if (!chset) + return -1; + + memcpy(chset, chset_str, j); + chset[j]=0; + + lang=strchr(chset, '*'); /* RFC 2231 */ + + if (lang) + *lang++ = 0; + else + lang=""; + + content_len=str + i - content_str; + + content=malloc(content_len+1); + + if (!content) + { + free(chset); + return -1; + } + + switch (*enc_str) { + case 'q': + case 'Q': + + k=0; + for (j=0; j 0) + text += i; + } + + return 0; +} + +static int rfc2047_decode_unicode(const char *text, + const struct unicode_info *u, + void (*callback)(const char *, size_t, + void *), + void *ptr) +{ + struct rfc822_display_name_s s; + + s.u=u; + s.print_func=callback; + s.ptr=ptr; + + return rfc2047_decoder(text, rfc822_display_addr_cb, &s); +}