Download raw body.
[patch] Adding In-Reply-To: support to mail(1)
On Fri, Feb 02, 2024 at 07:57:43AM -0700, Theo de Raadt wrote:
> I would be happy to see improvements to mail(1), but past improvements have
> tried to do too much in one go. The work must be in small incremental steps,
> each on judged on their own. It is good that this is finally getting split
> up into pieces. But I think the steps are still too large.
>
If you read them carefully you'll notice that the modifications seem
larger than what they really are, the patches are noisy because I tried
to respect the way things are distributed in the code (adding variables
and functions in different files.)
Then you have the functions. Except the function to generate the
message-id, which I just cut and pasted from smptd code, the patches
include little functions I wrote, I can also write more little programs
like the one below to let you test them and judge if they're acceptable
(needless to say I'm no C expert.)
I'll see if I can split things even more.
/* b64.c */
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <locale.h>
static int newline_at_end = 0;
void filecopy(FILE *, FILE *);
/* ---- mail(1) ptach extern.h ------- */
void wrap_b64_subject(char **p);
void wrap_ascii_subject(char **p);
void base64(char **p);
unsigned b64len(unsigned 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;
int ulen;
while ((c = getc(ifp)) != EOF) {
if (i == size) {
p = realloc(p, size + 100);
if (p == NULL)
err(1, NULL);
size += 100;
}
p[i++] = c;
}
if (i == size) {
p = realloc(p, size + 1);
if (p == NULL)
err(1, NULL);
}
p[i] = '\0';
setlocale(LC_CTYPE, "en_US.UTF-8");
ulen = mbstowcs(NULL, p, 0);
printf("Subject: ");
if (ulen < i && ulen >= 0) {
p = realloc(p, b64len(i) + 1);
if (p == NULL)
err(1, NULL);
base64(&p);
wrap_b64_subject(&p);
printf("%s", p);
} else {
wrap_ascii_subject(&p);
printf("%s", p);
}
free(p);
}
/* -------------------- mail(1) patch util.c ------------------ */
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_b64_subject(char **p)
{
char *s = NULL;
char *r = NULL;
char otag[] = "=?UTF-8?B?";
char ctag[] = "?=";
char mtag[] = "?=\n =?UTF-8?B?";
size_t otag_len = 10;
size_t ctag_len = 2;
size_t mtag_len = 14;
size_t i, n, size, tmp;
int col = 0;
int wrap = 72;
/* Rest tags width to all lines */
wrap -= otag_len + ctag_len + 1;
/* ... and "Subject:" width to the first line */
col += 8;
/* Opening tag at the beginning of string */
s = malloc(strlen(*p) + otag_len);
if (s == NULL)
err(1, NULL);
size = strlen(*p) + otag_len;
i = tmp = 0;
while (tmp < otag_len)
s[i++] = otag[tmp++];
r = *p;
n = 0;
while (r[n] != '\0') {
if (col % 4 == 0 && col >= wrap) {
/* Closing tag / new line / space / opening tag */
s = realloc(s, size + mtag_len);
if (s == NULL)
err(1, NULL);
size += mtag_len;
tmp = 0;
while (tmp < mtag_len)
s[i++] = mtag[tmp++];
col = 0;
} else {
s[i++] = r[n++];
col++;
}
}
/* Closing tag at the end of string */
s = realloc(s, size + ctag_len);
if (s == NULL)
err(1, NULL);
size += ctag_len;
tmp = 0;
while (tmp < ctag_len)
s[i++] = ctag[tmp++];
/* -- Remove from mail(1) patch -- */
if (newline_at_end) {
s = realloc(s, size + 1);
if (s == NULL)
err(1, NULL);
size++;
s[i++] = '\n';
}
/* ------------------------------- */
if (i == size) {
s = realloc(s, size + 1);
if (s == NULL)
err(1, NULL);
}
s[i] = '\0';
*p = s;
/* Remove from mail(1) patch */
free(r);
}
void
wrap_ascii_subject(char **p)
{
char *s = NULL;
char *r = NULL;
size_t i = 0;
size_t n = 0;
size_t size = 0;
int col = 0;
int wrap = 72;
/* Rest Subject: width at first line */
col += 9;
s = malloc(strlen(*p));
if (s == NULL)
err(1, NULL);
size = strlen(*p);
r = *p;
while (r[n] != '\0') {
/* Skip control characters */
if (iscntrl(r[n]) && r[n] != '\t' && r[n] != '\r' &&
r[n] != '\n')
n++;
/* Replace newlines by spaces */
if (r[n] == '\n')
if (r[n + 1] != '\0')
r[n] = ' ';
if (n != 0 && r[n] == ' ' &&
col + strcspn(&r[n + 1], " ") >= wrap) {
s = realloc(s, size + 1);
if (s == NULL)
err(1, NULL);
size++;
s[i++] = '\n';
col = 0;
}
s[i++] = r[n++];
col++;
}
if (i == size) {
s = realloc(s, size + 1);
if (s == NULL)
err(1, NULL);
}
s[i] = '\0';
*p = s;
/* Remove from mail(1) patch */
free(r);
}
/* ------------------- end util.c mail(1) patch ------------------ */
void
usage(void)
{
extern char *__progname;
fprintf(stderr, "usage: %s [-h] [file ...]\n"
" -h print this help\n", __progname);
exit(1);
}
--
Walter
[patch] Adding In-Reply-To: support to mail(1)