summaryrefslogtreecommitdiffstats
path: root/rfc2045/rfc6533.c
diff options
context:
space:
mode:
Diffstat (limited to 'rfc2045/rfc6533.c')
-rw-r--r--rfc2045/rfc6533.c283
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;
+}