Download raw body.
After reading an article by Todd C. Miller, I realized that I was
misusing snprintf(). Following Todd's advice I changed it to strndup()
and the testing program below gained performance significantly. Because
of this and some annoying bug that took me a while to fix, I rewrote my
encode_word() function.
Updated in my patches:
https://en.roquesor.com/Downloads/mail_patches.tar.gz
/*
* Little testing program.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <errno.h>
#include <stdint.h>
#include <unistd.h>
#include <ctype.h>
#include <locale.h>
#define b64enc __b64_ntop
static int newline_at_end = 0;
void encode_word(char **p);
static void filecopy(FILE *, FILE *);
int b64enc(unsigned char const *src, size_t srclength,
char *target, size_t targsize);
void wrap_header(char **p, size_t name_len);
void usage(void);
int
main(int argc, char *argv[])
{
FILE *fp;
int option;
while ((option = getopt(argc, argv, "h")) != -1)
switch (option) {
case 'h':
usage();
break;
default:
usage();
}
argc -= optind;
argv += optind;
if (argc > 0)
while (argc-- > 0)
if ((fp = fopen(*argv++, "r")) == NULL)
warn("%s", *(argv - 1));
else {
filecopy(fp, stdout);
fclose(fp);
}
else
filecopy(stdin, stdout);
return errno;
}
void
filecopy(FILE * ifp, FILE * ofp)
{
char *p = NULL;
size_t size = 0;
size_t i = 0;
int c;
while ((c = getc(ifp)) != EOF) {
if (i == size) {
p = realloc(p, size + 100);
if (p == NULL)
err(1, NULL);
size += 100;
}
/* Strip control characters */
if (!iscntrl(c) || c == '\t' || c == '\n')
p[i++] = c;
}
if (i == size) {
p = realloc(p, size + 1);
if (p == NULL)
err(1, NULL);
}
p[i] = '\0';
encode_word(&p);
wrap_header(&p, 0);
printf("%s", p);
free(p);
}
void
encode_word(char **p)
{
char *s = NULL;
char *r = NULL;
char *word = NULL;
char *eword = NULL;
size_t i = 0;
size_t n = 0;
size_t size = 0;
size_t ck = 0;
size_t sp = 0;
size_t wlen = 0;
size_t elen = 0;
char ftag[] = "=?UTF-8?B?";
char otag[] = " =?UTF-8?B?";
char ctag[] = "?=";
size_t flen = strlen(ftag);
size_t olen = strlen(otag);
size_t clen = strlen(ctag);
int encoded = 0;
setlocale(LC_CTYPE, "en_US.UTF-8");
size = strlen(*p);
s = malloc(size);
if (s == NULL)
err(1, NULL);
r = *p;
while (r[n] != '\0') {
if (encoded == 0 && isspace(r[n]))
s[i++] = r[n++];
sp = strspn(&r[n], "\t\n ");
wlen = strcspn(&r[n + sp], "\t\n ");
wlen += sp;
word = strndup(&r[n], wlen);
if (word == NULL)
err(1, NULL);
/* Check if the word contains UTF-8 characters */
if (wlen > mbstowcs(NULL, word, 0)) {
elen = (wlen + 2) / 3 * 4;
eword = malloc(elen + 1);
if (eword == NULL)
err(1, NULL);
b64enc(word, wlen, eword, elen);
eword[elen] = '\0';
if (encoded > 0) {
s = realloc(s, size + olen + clen +
(elen - wlen) + 1);
if (s == NULL)
err(1, NULL);
size += olen + clen + (elen - wlen) + 1;
ck = snprintf(&s[i], elen + olen + clen + 1,
"%s%s%s", otag, eword, ctag);
if (ck >= elen + olen + clen + 1)
errx(1, "snprint: toolong");
i += elen + olen + clen;
} else {
s = realloc(s, size + flen + clen +
(elen - wlen) + 1);
if (s == NULL)
err(1, NULL);
size += flen + clen + (elen - wlen) + 1;
ck = snprintf(&s[i], elen + flen + clen + 1,
"%s%s%s", ftag, eword, ctag);
if (ck >= elen + flen + clen + 1)
errx(1, "snprint: toolong");
i += elen + flen + clen;
}
free(eword);
n += wlen;
encoded++;
} else {
ck = snprintf(&s[i], wlen + 1,
"%s", word);
if (ck >= wlen + 1)
errx(1, "snprint: toolong");
i += wlen;
n += wlen;
encoded = 0;
}
free(word);
}
if (i == size) {
s = realloc(s, size + 1);
if (s == NULL)
err(1, NULL);
}
s[i] = '\0';
/* Remove from mail patch */
free(r);
*p = s;
}
void
wrap_header(char **p, size_t name_len)
{
char *s = NULL;
char *r = NULL;
size_t i = 0;
size_t n = 0;
size_t size = 0;
int col = name_len; /* let room for header name */
int wrap = 72;
size = strlen(*p);
s = malloc(size);
if (s == NULL)
err(1, NULL);
r = *p;
while (r[n] != '\0') {
/* Replace newlines by spaces */
if (r[n] == '\n' && r[n + 1] != '\0')
r[n] = ' ';
if (n != 0 && isspace(r[n]) &&
col + strcspn(&r[n + 1], "\t\n ") >= wrap) {
s = realloc(s, size + 1);
if (s == NULL)
err(1, NULL);
size++;
if (r[n + 1] != '\0')
s[i++] = '\n';
while (isspace(r[n + 1]))
n++;
col = 0;
if (r[n] == '\t')
col += 7;
}
s[i++] = r[n++];
if (r[n] == '\t')
col += 7;
col++;
}
if (i == size) {
s = realloc(s, size + 1);
if (s == NULL)
err(1, NULL);
}
s[i] = '\0';
/* Remove this free from mail patch */
free(r);
*p = s;
}
void
usage(void)
{
extern char *__progname;
fprintf(stderr,
"Usage: %s [-bhlnp] [-w width] [file ...]\n"
" -h print this help\n",
__progname);
exit(1);
}
--
Walter