tHandle quoted-printable transfer encoding - scribo - Email-based phlog generator
HTML git clone git://git.z3bra.org/scribo.git
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
DIR commit e52aa889d2cdd9d9cbb0af4fd60d0e23109cc2ce
DIR parent f03f0be08b98eb5096d147a398c8ffe2a0cd0c77
HTML Author: Willy Goiffon <dev@z3bra.org>
Date: Wed, 9 Sep 2020 22:44:31 +0200
Handle quoted-printable transfer encoding
Diffstat:
M makefile | 4 ++--
A qp.c | 120 +++++++++++++++++++++++++++++++
A qp.h | 2 ++
M scribo.c | 33 +++++++++++++++++++++++++++++++
4 files changed, 157 insertions(+), 2 deletions(-)
---
DIR diff --git a/makefile b/makefile
t@@ -2,8 +2,8 @@ include config.mk
.SUFFIXES: .h .def.h
-scribo: scribo.o base64.o rfc5322.o strlcpy.o strlcat.o
- ${CC} ${LDFLAGS} -o $@ scribo.o base64.o rfc5322.o strlcpy.o strlcat.o
+scribo: scribo.o base64.o qp.o rfc5322.o strlcpy.o strlcat.o
+ ${CC} ${LDFLAGS} -o $@ scribo.o base64.o qp.o rfc5322.o strlcpy.o strlcat.o
scribo.o: config.h
DIR diff --git a/qp.c b/qp.c
t@@ -0,0 +1,120 @@
+#include <ctype.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "qp.h"
+
+#define QP_FOLD 76
+
+static char *
+qp_bin2hex(const int in, char *out)
+{
+ char hex[] = "0123456789ABCDEF";
+
+ out[0] = hex[(unsigned char)in >> 4];
+ out[1] = hex[(unsigned char)in & 15];
+
+ return out;
+}
+
+static char
+qp_hex2bin(const unsigned char *in)
+{
+ int out;
+
+ if (*in == '=')
+ in++;
+
+ if ('A' <= in[0] && in[0] <= 'F') out = 16 * (in[0] - 'A' + 10);
+ if ('0' <= in[0] && in[0] <= '9') out = 16 * (in[0] - '0');
+
+ if ('A' <= in[1] && in[1] <= 'F') out += (in[1] - 'A' + 10);
+ if ('0' <= in[1] && in[1] <= '9') out += (in[1] - '0');
+
+ return out;
+}
+
+/*
+ * Encode the given message in qp, allocate memory to store the encoded
+ * message, and return the size allocated.
+ */
+size_t
+qp_encode(char **buf, const unsigned char *msg, size_t len)
+{
+ size_t i, n;
+ char *p;
+
+ /* maximum size the encoded message can have */
+ *buf = malloc(len * 3);
+ if (!*buf)
+ return 0;
+
+ p = *buf;
+ memset(*buf, 0, len * 3);
+
+ for (i = 0; i < len; i++) {
+ if (isascii(msg[i]) && msg[i] != '=') {
+ *(p++) = msg[i];
+ n++;
+ } else if (msg[i] == '=') {
+ strcpy(p, "==");
+ p += 2;
+ n += 2;
+ } else {
+ if (n > 72) {
+ strcpy(p, "=\n");
+ p += 2;
+ n = 0;
+ }
+ qp_bin2hex(msg[i], p);
+ p += 3;
+ n += 3;
+ }
+ if (n > 74) {
+ *(p++) = '=';
+ *(p++) = '\n';
+ n = 0;
+ }
+ }
+
+ return strnlen(*buf, len * 3);;
+}
+
+/*
+ * Allocate size to decode a qp message, decode it in the buffer and
+ * return the allocated size.
+ */
+size_t
+qp_decode(char **buf, const unsigned char *msg, size_t len)
+{
+ size_t i;
+ char *p;
+
+ /* maximum size the encoded message can have */
+ *buf = malloc(len);
+ if (!*buf)
+ return 0;
+
+ p = *buf;
+ memset(*buf, 0, len);
+
+ for (i = 0; i < len && msg[i]; i++) {
+ if (msg[i] == '=') {
+ switch (msg[i+1]) {
+ case '\r': i++; /* FALLTHROUGH */
+ case '\n': i++; break;
+ default:
+ *(p++) = qp_hex2bin(&msg[i]);
+ i += 2;
+ }
+ } else {
+ *(p++) = msg[i];
+ }
+ }
+
+ return strnlen(*buf, len);
+}
DIR diff --git a/qp.h b/qp.h
t@@ -0,0 +1,2 @@
+size_t qp_encode(char **buf, const unsigned char *msg, size_t len);
+size_t qp_decode(char **buf, const unsigned char *msg, size_t len);
DIR diff --git a/scribo.c b/scribo.c
t@@ -13,6 +13,7 @@
#include "arg.h"
#include "base64.h"
#include "config.h"
+#include "qp.h"
#include "rfc5322.h"
/* header field */
t@@ -41,6 +42,7 @@ int parseheaders(FILE *, struct headers *);
int verifyheaders(struct headers *);
int write_8bit(FILE *, FILE *);
int write_base64(FILE *, FILE *);
+int write_qp(FILE *, FILE *);
int writeentry(FILE *, const char *, char *, struct headers *);
int writeindex(FILE *, char *);
t@@ -243,6 +245,35 @@ write_base64(FILE *in, FILE *out)
}
int
+write_qp(FILE *in, FILE *out)
+{
+ size_t n, bufsiz;
+ ssize_t len;
+ char *msg, *line, *qp;
+
+ qp = NULL;
+ bufsiz = 0;
+
+ line = NULL;
+ n = 0;
+
+ while ((len = getline(&line, &n, in)) > 0) {
+ qp = realloc(qp, bufsiz + len + 1);
+ strlcat(qp, line, bufsiz + len + 1);
+ bufsiz += len + 1;
+ }
+
+ len = qp_decode(&msg, (unsigned char *)qp, bufsiz);
+
+ fwrite(msg, 1, len, out);
+
+ free(qp);
+ free(msg);
+
+ return 0;
+}
+
+int
writeentry(FILE *in, const char *cmd, char *dir, struct headers *head)
{
FILE *out;
t@@ -277,6 +308,8 @@ writeentry(FILE *in, const char *cmd, char *dir, struct headers *head)
if (transfer && !strncmp(transfer, "base64", 6))
write_base64(in, out);
+ if (transfer && !strncmp(transfer, "quoted-printable", 16))
+ write_qp(in, out);
else
write_8bit(in, out);