aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2017-04-06 20:59:41 +0200
committerLeah Neukirchen <leah@vuxu.org>2017-04-06 21:02:16 +0200
commitc6480f4785987aa97db25e7baa5adb394f8007a8 (patch)
treea5df0ae828dbfcad9ce99b2d14d9f6db586758a3
parentda907f0045cc26c2c7b066ddaa1b1df462dab5ed (diff)
downloadmblaze-c6480f4785987aa97db25e7baa5adb394f8007a8.tar.gz
rfc2231: add RFC 2231 mime parameter parsing
-rw-r--r--blaze822.h4
-rw-r--r--rfc2231.c127
2 files changed, 131 insertions, 0 deletions
diff --git a/blaze822.h b/blaze822.h
index e767114..4dfd8f5 100644
--- a/blaze822.h
+++ b/blaze822.h
@@ -45,6 +45,10 @@ typedef enum { MIME_CONTINUE, MIME_STOP, MIME_PRUNE } blaze822_mime_action;
typedef blaze822_mime_action (*blaze822_mime_callback)(int, struct message *, char *, size_t);
blaze822_mime_action blaze822_walk_mime(struct message *, int, blaze822_mime_callback);
+// rfc2231.c
+
+int blaze822_mime2231_parameter(char *, char *, char *, size_t, char *);
+
// seq.c
char *blaze822_seq_open(char *file);
diff --git a/rfc2231.c b/rfc2231.c
new file mode 100644
index 0000000..5a05f86
--- /dev/null
+++ b/rfc2231.c
@@ -0,0 +1,127 @@
+#include <iconv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "blaze822.h"
+
+int
+blaze822_mime2231_parameter(char *s, char *name,
+ char *dst, size_t dlen, char *tgtenc)
+{
+ static signed char hex[] = {
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
+ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
+ };
+
+ int i = 0;
+ char namenum[64];
+
+ char *srcenc = 0;
+
+ char *dststart = dst;
+ char *dstend = dst + dlen;
+
+ char *sbuf, *ebuf;
+
+ snprintf(namenum, sizeof namenum, "%s*", name, i);
+ if (blaze822_mime_parameter(s, namenum, &sbuf, &ebuf)) {
+ i = 100;
+ goto found_extended;
+ }
+ if (blaze822_mime_parameter(s, namenum, &sbuf, &ebuf)) {
+ i = 100;
+ goto found_plain;
+ }
+
+ while (i < 100) {
+ snprintf(namenum, sizeof namenum, "%s*%d*", name, i);
+ if (blaze822_mime_parameter(s, namenum, &sbuf, &ebuf)) {
+found_extended:
+ // decode extended
+ if (i == 0) { // extended-initial-value
+ char *encstart = sbuf;
+ sbuf = strchr(sbuf, '\'');
+ if (!sbuf)
+ return 0;
+ srcenc = strndup(encstart, sbuf - encstart);
+ if (!srcenc)
+ return 0;
+ sbuf = strchr(sbuf+1, '\'');
+ if (!sbuf)
+ return 0;
+ sbuf++;
+ }
+ while (sbuf < ebuf && dst < dstend) {
+ if (sbuf[0] == '%') {
+ unsigned char c1 = sbuf[1];
+ unsigned char c2 = sbuf[2];
+ if (c1 < 127 && c2 < 127 &&
+ hex[c1] > -1 && hex[c2] > -1) {
+ *dst++ = (hex[c1] << 4) | hex[c2];
+ sbuf += 3;
+ } else {
+ *dst++ = *sbuf++;
+ }
+ } else {
+ *dst++ = *sbuf++;
+ }
+ }
+ *dst = 0;
+ } else {
+ namenum[strlen(namenum) - 1] = 0;
+ if (blaze822_mime_parameter(s, namenum, &sbuf, &ebuf)) {
+found_plain:
+ // copy plain
+ if (dstend - dst < ebuf - sbuf) {
+ memcpy(dst, sbuf, ebuf - sbuf);
+ dst += ebuf - sbuf;
+ }
+ } else {
+ break;
+ }
+ }
+ i++;
+ }
+
+ if (i <= 0)
+ return 0;
+
+ if (!srcenc)
+ return 1;
+
+ iconv_t ic = iconv_open(tgtenc, srcenc);
+ free(srcenc);
+ if (ic == (iconv_t)-1)
+ return 1;
+
+ size_t tmplen = dlen;
+ char *tmp = malloc(tmplen);
+ if (!tmp)
+ return 1;
+ char *tmpend = tmp;
+
+ size_t dstlen = dst - dststart;
+ dst = dststart;
+
+ int r = iconv(ic, &dst, &dstlen, &tmpend, &tmplen);
+ if (r < 0) {
+ free(tmp);
+ return 1;
+ }
+
+ iconv_close(ic);
+
+ // copy back
+ memcpy(dststart, tmp, tmpend - tmp);
+ dststart[tmpend - tmp] = 0;
+ free(tmp);
+
+ return 1;
+}