about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--decode.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/decode.c b/decode.c
index abee7f5..a106c9c 100644
--- a/decode.c
+++ b/decode.c
@@ -17,6 +17,7 @@
 #include <err.h>
 #include <errno.h>
 #include <iconv.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -85,6 +86,28 @@ static void convertCharset(
 	iconv_close(conv);
 }
 
+static uint8_t unbase64(char ch) {
+	static const char Base64[64] = {
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+	};
+	const char *ptr = strchr(Base64, ch);
+	return (ptr ? ptr - Base64 : 0);
+}
+
+static void decodeBase64(struct Buffer *dst, const char *src) {
+	while (src[0] && src[1] && src[2] && src[3]) {
+		uint32_t bits = 0;
+		for (int i = 0; i < 4; ++i) {
+			bits <<= 6;
+			bits |= unbase64(src[i]);
+		}
+		*bufferDest(dst, 1) = bits >> 16;
+		if (src[2] != '=') *bufferDest(dst, 1) = bits >> 8;
+		if (src[3] != '=') *bufferDest(dst, 1) = bits;
+		src += 4;
+	}
+}
+
 static char unhex(char ch) {
 	if (ch <= '9') return ch - '0';
 	if (ch <= 'F') return 0xA + ch - 'A';
@@ -149,7 +172,9 @@ static void decode8Bit(struct Buffer *dst, const char *src) {
 
 static void
 decodeEncoding(struct Buffer *dst, const char *encoding, const char *src) {
-	if (!strcasecmp(encoding, "Q")) {
+	if (!strcasecmp(encoding, "base64") || !strcasecmp(encoding, "B")) {
+		decodeBase64(dst, src);
+	} else if (!strcasecmp(encoding, "Q")) {
 		decodeQ(dst, src);
 	} else if (!strcasecmp(encoding, "quoted-printable")) {
 		decodeQuotedPrintable(dst, src);