On Sun Oct 1 15:19:12 2023, Walter wrote > I decided to add another header, "Message-ID". Sending mails from my > patched mail(1) I realized that it's convenient the MUA itself add the > Message-ID (the one in this message was generated by my patch), if you > relegate this to the MTA, your MUA will save the local copy without that > header, then if more late you wish to read your mail with a > thread-capable MUA (eg Mutt), those messages won't be in the right > place. >
To not break threads, one last detail was needed. Now mail(1) adds a In-Reply-To: header. Index: cmd3.c =================================================================== RCS file: /cvs/src/usr.bin/mail/cmd3.c,v retrieving revision 1.30 diff -u -p -r1.30 cmd3.c --- cmd3.c 8 Mar 2023 04:43:11 -0000 1.30 +++ cmd3.c 2 Oct 2023 12:59:49 -0000 @@ -238,6 +238,7 @@ _respond(int *msgvec) head.h_cc = np; } else head.h_cc = NULL; + head.h_msgid = hfield("message-id", mp); head.h_bcc = NULL; head.h_smopts = NULL; mail1(&head, 1); @@ -617,6 +618,7 @@ _Respond(int *msgvec) if ((head.h_subject = hfield("subject", mp)) == NULL) head.h_subject = hfield("subj", mp); head.h_subject = reedit(head.h_subject); + head.h_msgid = hfield("message-id", mp); head.h_from = NULL; head.h_cc = NULL; head.h_bcc = NULL; Index: collect.c =================================================================== RCS file: /cvs/src/usr.bin/mail/collect.c,v retrieving revision 1.34 diff -u -p -r1.34 collect.c --- collect.c 17 Jan 2014 18:42:30 -0000 1.34 +++ collect.c 2 Oct 2023 12:59:49 -0000 @@ -87,7 +87,7 @@ collect(struct header *hp, int printhead * refrain from printing a newline after * the headers (since some people mind). */ - t = GTO|GSUBJECT|GCC|GNL; + t = GTO|GSUBJECT|GMID|GCC|GNL; getsub = 0; if (hp->h_subject == NULL && value("interactive") != NULL && (value("ask") != NULL || value("asksub") != NULL)) @@ -208,7 +208,7 @@ cont: /* * Grab a bunch of headers. */ - grabh(hp, GTO|GSUBJECT|GCC|GBCC); + grabh(hp, GTO|GSUBJECT|GMID|GCC|GBCC); goto cont; case 't': /* @@ -328,7 +328,7 @@ cont: */ rewind(collf); puts("-------\nMessage contains:"); - puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); + puthead(hp, stdout, GTO|GSUBJECT|GMID|GCC|GBCC|GNL); while ((t = getc(collf)) != EOF) (void)putchar(t); goto cont; Index: def.h =================================================================== RCS file: /cvs/src/usr.bin/mail/def.h,v retrieving revision 1.17 diff -u -p -r1.17 def.h --- def.h 28 Jan 2022 06:18:41 -0000 1.17 +++ def.h 2 Oct 2023 12:59:49 -0000 @@ -156,14 +156,15 @@ struct headline { #define GTO 1 /* Grab To: line */ #define GSUBJECT 2 /* Likewise, Subject: line */ -#define GCC 4 /* And the Cc: line */ -#define GBCC 8 /* And also the Bcc: line */ -#define GMASK (GTO|GSUBJECT|GCC|GBCC) +#define GMID 4 /* Message-ID: line */ +#define GCC 8 /* And the Cc: line */ +#define GBCC 16 /* And also the Bcc: line */ +#define GMASK (GTO|GSUBJECT|GMID|GCC|GBCC) /* Mask of places from whence */ -#define GNL 16 /* Print blank line after */ -#define GDEL 32 /* Entity removed from list */ -#define GCOMMA 64 /* detract puts in commas */ +#define GNL 32 /* Print blank line after */ +#define GDEL 64 /* Entity removed from list */ +#define GCOMMA 128 /* detract puts in commas */ /* * Structure used to pass about the current @@ -173,6 +174,7 @@ struct header { struct name *h_to; /* Dynamic "To:" string */ char *h_from; /* User-specified "From:" string */ char *h_subject; /* Subject string */ + char *h_msgid; /* Message-ID string */ struct name *h_cc; /* Carbon copies string */ struct name *h_bcc; /* Blind carbon copies */ struct name *h_smopts; /* Sendmail options */ Index: extern.h =================================================================== RCS file: /cvs/src/usr.bin/mail/extern.h,v retrieving revision 1.29 diff -u -p -r1.29 extern.h --- extern.h 16 Sep 2018 02:38:57 -0000 1.29 +++ extern.h 2 Oct 2023 12:59:49 -0000 @@ -163,7 +163,7 @@ void load(char *); struct var * lookup(char *); int mail(struct name *, struct name *, struct name *, struct name *, - char *, char *); + char *, char *, char *); void mail1(struct header *, int); void makemessage(FILE *, int); void mark(int); Index: main.c =================================================================== RCS file: /cvs/src/usr.bin/mail/main.c,v retrieving revision 1.35 diff -u -p -r1.35 main.c --- main.c 26 Jan 2021 18:21:47 -0000 1.35 +++ main.c 2 Oct 2023 12:59:49 -0000 @@ -103,6 +103,7 @@ main(int argc, char **argv) struct name *to, *cc, *bcc, *smopts; char *fromaddr; char *subject; + char *msgid; char *ef; char nosrc = 0; char *rc; @@ -136,6 +137,7 @@ main(int argc, char **argv) smopts = NULL; fromaddr = NULL; subject = NULL; + msgid = NULL; while ((i = getopt(argc, argv, "EINb:c:dfinr:s:u:v")) != -1) { switch (i) { case 'u': @@ -269,7 +271,7 @@ main(int argc, char **argv) rc = "~/.mailrc"; load(expand(rc)); if (!rcvmode) { - mail(to, cc, bcc, smopts, fromaddr, subject); + mail(to, cc, bcc, smopts, fromaddr, subject, msgid); /* * why wait? */ Index: send.c =================================================================== RCS file: /cvs/src/usr.bin/mail/send.c,v retrieving revision 1.26 diff -u -p -r1.26 send.c --- send.c 8 Mar 2023 04:43:11 -0000 1.26 +++ send.c 2 Oct 2023 12:59:49 -0000 @@ -32,7 +32,10 @@ #include "rcv.h" #include "extern.h" +#include "locale.h" +static int utf8body; +static int isutf8(FILE *s); /* UTF-8 check */ static volatile sig_atomic_t sendsignal; /* Interrupted by a signal? */ /* @@ -279,13 +282,14 @@ statusput(struct message *mp, FILE *obuf */ int mail(struct name *to, struct name *cc, struct name *bcc, struct name *smopts, - char *fromaddr, char *subject) + char *fromaddr, char *subject, char *msgid) { struct header head; head.h_to = to; head.h_from = fromaddr; head.h_subject = subject; + head.h_msgid = msgid; head.h_cc = cc; head.h_bcc = bcc; head.h_smopts = smopts; @@ -306,6 +310,7 @@ sendmail(void *v) head.h_to = extract(str, GTO); head.h_from = NULL; head.h_subject = NULL; + head.h_msgid = NULL; head.h_cc = NULL; head.h_bcc = NULL; head.h_smopts = NULL; @@ -341,6 +346,14 @@ mail1(struct header *hp, int printheader else puts("Null message body; hope that's ok"); } + + /* UTF-8 check */ + setlocale(LC_CTYPE, "en_US.UTF-8"); + if (fsize(mtf) != 0) { + utf8body = isutf8(mtf); + rewind(mtf); + } + /* * Now, take the user names from the combined * to and cc lists and do all the alias @@ -482,7 +495,7 @@ infix(struct header *hp, FILE *fi) return(fi); } (void)rm(tempname); - (void)puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA); + (void)puthead(hp, nfo, GTO|GSUBJECT|GMID|GCC|GBCC|GNL|GCOMMA); c = getc(fi); while (c != EOF) { (void)putc(c, nfo); @@ -516,19 +529,48 @@ puthead(struct header *hp, FILE *fo, int { int gotcha; char *from; + char *inrepto; + time_t t = time(NULL); + struct tm tm = *localtime(&t); + char hostname[1024]; + gethostname(hostname, 1023); gotcha = 0; from = hp->h_from ? hp->h_from : value("from"); if (from != NULL) - fprintf(fo, "From: %s\n", from), gotcha++; + fprintf(fo, "From: %s\n", from), + gotcha++; if (hp->h_to != NULL && w & GTO) - fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; + fmt("To:", hp->h_to, fo, w&GCOMMA), + gotcha++; + fprintf(fo, "User-Agent: OpenBSD mail(1)\n"), + gotcha++; if (hp->h_subject != NULL && w & GSUBJECT) - fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; + fprintf(fo, "Subject: %s\n", hp->h_subject), + gotcha++; + fprintf(fo, "Message-ID: <%d%02d%02d.%02d%02d%02d@%s>\n", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, hostname), + gotcha++; + if (hp->h_msgid != NULL && w & GMID) + fprintf(fo, "In-Reply-To: %s\n", hp->h_msgid), + gotcha++; + if (utf8body > 0) + fprintf(fo, "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=utf-8\n" + "Content-Transfer-Encoding: 8bit\n"), + gotcha++; + else if (utf8body == 0) + fprintf(fo, "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=us-ascii\n" + "Content-Transfer-Encoding: 7bit\n"), + gotcha++; if (hp->h_cc != NULL && w & GCC) - fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; + fmt("Cc:", hp->h_cc, fo, w&GCOMMA), + gotcha++; if (hp->h_bcc != NULL && w & GBCC) - fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; + fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), + gotcha++; if (gotcha && w & GNL) (void)putc('\n', fo); return(0); @@ -607,6 +649,44 @@ savemail(char *name, FILE *fi) void sendint(int s) { - sendsignal = s; +} + +/* UTF-8 check */ +static int +isutf8(FILE *fp) +{ + unsigned char *p = NULL; + size_t size = 0; + size_t i = 0; + int c, n, len; + + setlocale(LC_CTYPE, "en_US.UTF-8"); + + while ((c = getc(fp)) != 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'; + + len = mbstowcs(NULL, p, 0); + if (len == i) + n = 0; /* ASCII */ + else if (len < i) + n = 1; /* UTF-8 */ + if (len < 0) + n = len; /* Invalid UTF-8 */ + + free(p); + return n; }