Download raw body.
For those interested, know that I'll keep correcting, updating and
uploading my patches on the same link:
https://en.roquesor.com/Downloads/mail_patches.tar.gz
Yesterday I debugged the function I wrote to encode headers in base64.
An update of the program I wrote to test it is pasted below. Stressing
it with large and UTF-8-dense files, ktrace (and valgring under Linux)
showed me zero errors, zero memory leaks.
/*
* Program to test the base64 headers encode_word function and wrap_header
* functions included in id.diff
*/
#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>
static int newline_at_end = 0;
void encode_word(char **p);
static void filecopy(FILE *, FILE *);
void usage(void);
void base64(char **p);
unsigned b64len(unsigned len);
void wrap_header(char **p, size_t name_len);
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;
size_t i = 0;
size_t n = 0;
size_t size = 0;
size_t word_len = 0;
char otag[] = "=?UTF-8?B?";
char ctag[] = "?=";
size_t tags_len = strlen(otag) + strlen(ctag);
int utf8word = 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') {
/* We are at the first character of a word */
if ((n == 0 || (isspace(r[n - 1]) || r[n - 1] == '\n')) &&
!isspace(r[n]) && r[n] != '\n') {
/* Load the size of the word in a variable */
word_len = strcspn(&r[n], "\t\n ");
/*
* If we are not at the first character of the
* string count one more character[1].
*/
if (n > 0 && utf8word)
word_len++;
word = malloc(word_len + 1);
if (word == NULL)
err(1, NULL);
/*
* (1) If the pervious word was encoded we need
* to include the previous space or tab in the
* encoded word.
*/
if (n > 0 && utf8word) {
if (r[n - 1] == '\n')
r[n - 1] = ' ';
snprintf(word, word_len + 1, "%s", &r[n - 1]);
} else
snprintf(word, word_len + 1, "%s", &r[n]);
/* Check if the word contains UTF-8 characters */
if (word_len > mbstowcs(NULL, word, 0) ) {
s = realloc(s, size + tags_len +
(b64len(word_len) - word_len) + 1);
if (s == NULL)
err(1, NULL);
size += tags_len +
(b64len(word_len) - word_len) + 1;
/* Encode the word */
base64(&word);
/* Append the encoded word to the string */
snprintf(&s[i], i + b64len(word_len) +
tags_len + 1, "%s%s%s", otag, word, ctag);
i += b64len(word_len) + tags_len;
n += word_len;
/*
* If we included the last space or tab in
* the encoded word shift the count to
* prevent the last caracter of the word
* be loaded twice in the destination
* string.
*/
if (n > 0 && utf8word)
n--;
utf8word = 1;
} else
utf8word = 0;
free(word);
}
s[i++] = r[n++];
}
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
base64(char **p)
{
size_t len, olen, i, j;
uint32_t a, b, c, triple;
char *enc = NULL;
unsigned char *in = NULL;
const char b64table[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int b64mod[] = { 0, 2, 1 };
in = (unsigned char*)*p;
i = 0;
while (in[i] != '\0') {
/* Replace control characters by spaces */
if (iscntrl(in[i])) {
/* ---- Remove from mail(1) patch ----- */
if (in[i] == '\n' && in[i + 1] == '\0')
newline_at_end = 1;
/* ------------------------------------ */
in[i] = ' ';
}
i++;
}
len = strlen(*p);
enc = malloc(b64len(len));
if (enc == NULL)
err(1, NULL);
olen = b64len(len);
i = j = 0;
while (in[i] != '\0') {
a = i < len ? in[i++] : 0;
b = i < len ? in[i++] : 0;
c = i < len ? in[i++] : 0;
triple = (a << 0x10) + (b << 0x08) + c;
enc[j++] = b64table[(triple >> 3 * 6) & 0x3F];
enc[j++] = b64table[(triple >> 2 * 6) & 0x3F];
enc[j++] = b64table[(triple >> 1 * 6) & 0x3F];
enc[j++] = b64table[(triple >> 0 * 6) & 0x3F];
}
i = 0;
while (i < b64mod[len % 3])
enc[olen - 1 - i++] = '=';
if (olen == j) {
enc = realloc(enc, olen + 1);
if (enc == NULL)
err(1, NULL);
}
enc[j] = '\0';
*p = enc;
/* Remove from mail(1) patch */
free(in);
}
unsigned
b64len(unsigned len)
{
return (len + 2) / 3 * 4;
}
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