/* ** Copyright 2018 Double Precision, Inc. See COPYING for ** distribution information. */ /* */ #if HAVE_CONFIG_H #include "rfc2045_config.h" #endif #include "rfc2045.h" #include #include #include static const char xdigit[]="0123456789ABCDEF"; static void count(const char *s, size_t n, void *ptr) { (*(size_t *)ptr) += n; } static void save(const char *s, size_t n, void *ptr) { char **p=(char **)ptr; memcpy(*p, s, n); *p += n; } static void encode_rfc822(const char *address, void (*callback)(const char *, size_t, void *), void *arg) { callback("rfc822;", 7, arg); while (*address) { size_t i; for (i=0; address[i]; ++i) { if (address[i] < '!' || address[i] > '~') break; if (address[i] == '+' || address[i] == '=') break; } if (i == 0) { (*callback)("+", 1, arg); (*callback)(xdigit + ((*address >> 4) & 15), 1, arg); (*callback)(xdigit + (*address & 15), 1, arg); ++address; continue; } (*callback)(address, i, arg); address += i; } (*callback)("", 1, arg); } static void encode_rfc6533(const char *address, void (*callback)(const char *, size_t, void *), void *arg) { callback("utf-8;", 6, arg); while (*address) { size_t i; for (i=0; address[i]; ++i) { if ((unsigned char)address[i] <= ' ') break; if (address[i] == '\\' || address[i] == '+' || address[i] == '=' || address[i] == 0x7f) break; } if (i == 0) { static const char xdigit[]="0123456789ABCDEF"; (*callback)("\\x{", 3, arg); (*callback)(xdigit + ((*address >> 4) & 15), 1, arg); (*callback)(xdigit + (*address & 15), 1, arg); (*callback)("}", 1, arg); ++address; continue; } (*callback)(address, i, arg); address += i; } (*callback)("", 1, arg); } char *rfc6533_encode(const char *address, int use_rfc822) { size_t l=0; char *buffer; char *p; const char *cp; for (cp=address; *cp; ++cp) if (*cp & 0x80) break; if (!*cp || use_rfc822) { encode_rfc822(address, count, &l); if ((buffer=malloc(l)) == NULL) abort(); p=buffer; encode_rfc822(address, save, &p); return buffer; } encode_rfc6533(address, count, &l); if ((buffer=malloc(l)) == NULL) abort(); p=buffer; encode_rfc6533(address, save, &p); return buffer; } static int decode_rfc6533(const char *address, void (*callback)(const char *, size_t, void *), void *arg) { while (*address) { size_t i; char32_t c; char *p; size_t ignore1; int err; for (i=0; address[i]; ++i) { if (address[i] == '\\') break; } if (i) { (*callback)(address, i, arg); address += i; continue; } if (address[1] != 'x' || address[2] != '{') return -1; c=0; address += 3; while (*address != '}') { const char *p; if (!*address) return -1; p=strchr(xdigit, *address); if (!p) return -1; c <<= 4; c |= (p-xdigit); ++address; } ++address; if (c == 0) return -1; err=0; if (unicode_convert_fromu_tobuf(&c, 1, "utf-8", &p, &ignore1, &err)) return 0; if (err) { free(p); return 0; } (*callback)(p, strlen(p), arg); free(p); } (*callback)("", 1, arg); return 0; } char *rfc6533_decode(const char *address) { size_t l; char *buf; char *p; if (strncasecmp(address, "rfc822;", 7) == 0) { buf=malloc(strlen(address)); if (!buf) abort(); p=buf; address += 7; while (*address) { const char *hi, *lo; if (*address != '+') { *p++ = *address++; continue; } ++address; if (*address) { hi=strchr(xdigit, *address); ++address; if (*address) { lo=strchr(xdigit, *address); ++address; if (hi && lo) { char n= (char) ((hi-xdigit) * 16 +(lo-xdigit)); if (n) *p++=n; } } } } *p=0; } else { if (strncasecmp(address, "utf-8;", 6)) return NULL; l=0; if (decode_rfc6533(address+6, count, &l)) return NULL; if ((buf=malloc(l)) == NULL) abort(); p=buf; decode_rfc6533(address+6, save, &p); } for (p=buf; *p; ++p) if ((unsigned char)*p <= ' ') { free(buf); return NULL; } return buf; }