diff options
author | Leah Neukirchen <leah@vuxu.org> | 2017-04-06 20:59:41 +0200 |
---|---|---|
committer | Leah Neukirchen <leah@vuxu.org> | 2017-04-06 21:02:16 +0200 |
commit | c6480f4785987aa97db25e7baa5adb394f8007a8 (patch) | |
tree | a5df0ae828dbfcad9ce99b2d14d9f6db586758a3 | |
parent | da907f0045cc26c2c7b066ddaa1b1df462dab5ed (diff) | |
download | mblaze-c6480f4785987aa97db25e7baa5adb394f8007a8.tar.gz mblaze-c6480f4785987aa97db25e7baa5adb394f8007a8.tar.xz mblaze-c6480f4785987aa97db25e7baa5adb394f8007a8.zip |
rfc2231: add RFC 2231 mime parameter parsing
-rw-r--r-- | blaze822.h | 4 | ||||
-rw-r--r-- | rfc2231.c | 127 |
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; +} |