mblaze

Unix utilities to deal with Maildir - my mirror
git clone https://pi.duncano.de/git/mblaze.git
Log | Files | Refs | README | COPYING

commit c6480f4785987aa97db25e7baa5adb394f8007a8
parent da907f0045cc26c2c7b066ddaa1b1df462dab5ed
Author: Leah Neukirchen <leah@vuxu.org>
Date:   Thu,  6 Apr 2017 20:59:41 +0200

rfc2231: add RFC 2231 mime parameter parsing

Diffstat:
blaze822.h | 4++++
rfc2231.c | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 131 insertions(+), 0 deletions(-)

diff --git 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 @@ -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; +}