scribo

Email-based phlog generator
git clone git://git.z3bra.org/scribo.git
Log | Files | Refs

commit e52aa889d2cdd9d9cbb0af4fd60d0e23109cc2ce
parent f03f0be08b98eb5096d147a398c8ffe2a0cd0c77
Author: Willy Goiffon <dev@z3bra.org>
Date:   Wed,  9 Sep 2020 22:44:31 +0200

Handle quoted-printable transfer encoding

Diffstat:
Mmakefile | 4++--
Aqp.c | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aqp.h | 2++
Mscribo.c | 33+++++++++++++++++++++++++++++++++
4 files changed, 157 insertions(+), 2 deletions(-)

diff --git a/makefile b/makefile @@ -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 diff --git a/qp.c b/qp.c @@ -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); +} diff --git a/qp.h b/qp.h @@ -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); diff --git a/scribo.c b/scribo.c @@ -13,6 +13,7 @@ #include "arg.h" #include "base64.h" #include "config.h" +#include "qp.h" #include "rfc5322.h" /* header field */ @@ -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 *); @@ -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; @@ -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);