diff options
Diffstat (limited to 'rfc2045/rfc6533.c')
| -rw-r--r-- | rfc2045/rfc6533.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/rfc2045/rfc6533.c b/rfc2045/rfc6533.c new file mode 100644 index 0000000..529da45 --- /dev/null +++ b/rfc2045/rfc6533.c @@ -0,0 +1,283 @@ +/* +** Copyright 2018 Double Precision, Inc. See COPYING for +** distribution information. +*/ + +/* +*/ + +#if HAVE_CONFIG_H +#include "rfc2045_config.h" +#endif +#include "rfc2045.h" +#include <courier-unicode.h> +#include <string.h> +#include <stdlib.h> + +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 NULL; + + if (err) + { + free(p); + return NULL; + } + (*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; +} |
