URI:
       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);