Thorsten Glaser wrote: > >> Mind you, I am also open to reviewing his proposal of >> adding those headers even with -a (letting -a override the >> auto-generated ones when there is a conflict).
I was thinking how to implement this functionality, and during that I realized that it actually would nice not to add the headers if the mail content is 7-bit only. I even tried to write some code for this, but it would require too many changes, so I gave up the idea for now. Anyway after a few attempts I ended with the attached patch. It allows user to override the headers, however it touches different parts of code than your original patch, mostly because of my failed attempt of 7 vs 8 bit mail content detection. It potentially has slightly worse performance due to parsing of the user-provider headers after they have been already joined by "\n" chars, but on the other hand it does not allocate additional memory via asprintf(). What do you think about it? > > Robert, Niels, what do you think about the attached patch? The patch looks OK. The addition of -D_GNU_SOURCE flag causes warnings during compilation of files that already #define _GNU_SOURCE, but this is easy to fix by using #define in main.c. I would like to prepare an upload tomorrow. Could you please let me know which patch you prefer: the original one or the one attached to this mail? Regards, robert
From: Robert Luberda <rob...@debian.org> Date: Thu, 13 Apr 2017 23:39:39 +0200 Subject: Add MIME headers unless set by user Generate the three following headers by default: MIME-Version: 1.0 Content-Type: text/plain; charset="<current charset from $LC_CTYPE>" Content-Transfer-Encoding: 8bit However allow a user to override each of them with the -a flag. Example: bsd-mailx -a "Content-Type: text/html; charset=UTF-8" uses the above user-provided Content-Type, but still adds the default MIME-Version and Content-Transfer-Encoding headers. Bugs-Debian: https://bugs.debian.org/859935 --- main.c | 4 ++++ send.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/main.c b/main.c index 07ad856..4cba833 100644 --- a/main.c +++ b/main.c @@ -34,6 +34,7 @@ #include <fcntl.h> #include <sys/ioctl.h> #include "extern.h" +#include <locale.h> static void usage(void); int main(int, char **); @@ -70,6 +71,9 @@ main(int argc, char **argv) err(1, "setuid"); } + /* Set the current user locale's charset. */ + setlocale(LC_CTYPE, ""); + /* * Set up a reasonable environment. * Figure out whether we are being run interactively, diff --git a/send.c b/send.c index cc75f49..771ecc9 100644 --- a/send.c +++ b/send.c @@ -30,6 +30,7 @@ * SUCH DAMAGE. */ +#include <langinfo.h> #include <time.h> #include "rcv.h" #include "extern.h" @@ -558,6 +559,36 @@ infix(struct header *hp, FILE *fi) rewind(nfi); return(nfi); } +/* + * Check if headers (a list separated by new line characters) contains a header + * which name is given in the headername argument of length given in headernamelen. + */ +static int hasheader(const char* headers, const char* const headername, const size_t headernamelen) +{ + while (headers) { + /* Skip leading white spaces, including '\n' from + * the previous iteration of the loop + */ + while (isspace(*headers)) + ++headers; + + if (strncasecmp(headers, headername, headernamelen) == 0) { + /* Found a match, check if it is followed by ':' */ + const char* end = headers + headernamelen; + /* Permit optional white spaces before ':' */ + while (isspace(*end) && *end != '\n') + ++end; + + if (*end == ':') + return 1; + + headers = end; /* Small optimization for the following strchr() call */ + } + + headers = strchr(headers, '\n'); /* Find start of the next header */ + } + return 0; +} /* * Dump the to, subject, cc header on the @@ -583,6 +614,18 @@ puthead(struct header *hp, FILE *fo, int w) fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; if (hp->h_header != NULL && w) fprintf(fo, "%s\n", hp->h_header), gotcha++; + if (w) + { +#define ADDHEADER(name, value, ...) if (!hasheader(hp->h_header, name, sizeof(name) - 1)) \ + fprintf(fo, name ": " value "\n", ##__VA_ARGS__), gotcha++ + + const char* const cs = nl_langinfo(CODESET); + ADDHEADER("MIME-Version", "1.0"); + ADDHEADER("Content-Type", "text/plain; charset=\"%s\"", + cs && *cs ? cs : "ANSI_X3.4-1968"); + ADDHEADER("Content-Transfer-Encoding", "8bit"); +#undef ADDHEADER + } if (hp->h_replyto != NULL && w & GREPLYTO) fprintf(fo, "Reply-To: %s\n", hp->h_replyto), gotcha++; if (hp->h_inreplyto != NULL && w & GINREPLYTO)