More changes:
- I changed my overpopulated Message-ID for the function used by
smtpd(8) (generate_uid()). Now the Message-ID generated by mail(1)
is identical to the one generated by smtpd(8).
- Added a conditional to skip adding the Message-ID if the machine
doesn't have hostname yet.
Also some clenage and ordering:
- Moved included libraries to def.h
- Moved function definitions to extern.h
- Moved isutf8() and generate_uid() funcions to util.c
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 11 Oct 2023 06:39:20 -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 11 Oct 2023 06:39:20 -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 11 Oct 2023 06:39:20 -0000
@@ -53,6 +53,8 @@
#include <termios.h>
#include <unistd.h>
#include <limits.h>
+#include <locale.h>
+#include <inttypes.h>
#include <vis.h>
#include "pathnames.h"
@@ -156,14 +158,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 +176,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 11 Oct 2023 06:39:20 -0000
@@ -129,6 +129,7 @@ int forward(char *, FILE *, char *, int
void free_child(pid_t);
int from(void *);
off_t fsize(FILE *);
+uint64_t generate_uid(void);
int getfold(char *, int);
int gethfield(FILE *, char *, int, char **);
int gethfromtty(struct header *, int);
@@ -157,13 +158,14 @@ int ishead(char *);
int isign(char *, struct ignoretab *);
int isprefix(char *, char *);
size_t istrlcpy(char *, const char *, size_t);
+int isutf8(FILE *s);
const struct cmd *
lex(char *);
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 11 Oct 2023 06:39:20 -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 11 Oct 2023 06:39:20 -0000
@@ -33,6 +33,8 @@
#include "rcv.h"
#include "extern.h"
+static int utf8body;
+
static volatile sig_atomic_t sendsignal; /* Interrupted by a signal? */
/*
@@ -279,13 +281,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 +309,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 +345,13 @@ mail1(struct header *hp, int printheader
else
puts("Null message body; hope that's ok");
}
+
+ /* UTF-8 check */
+ 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 +493,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 +527,48 @@ puthead(struct header *hp, FILE *fo, int
{
int gotcha;
char *from;
+ char *inrepto;
+
+ 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++;
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++;
+ if (fo != stdout) {
+ fprintf(fo, "User-Agent: OpenBSD mail(1)\n"),
+ gotcha++;
+ fprintf(fo, "Message-ID: <%016"PRIx64"@%s>\n",
+ generate_uid(), 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 +647,5 @@ savemail(char *name, FILE *fi)
void
sendint(int s)
{
-
sendsignal = s;
}
Index: util.c
===================================================================
RCS file: /cvs/src/usr.bin/mail/util.c,v
retrieving revision 1.2
diff -u -p -r1.2 util.c
--- util.c 26 Dec 2022 19:16:01 -0000 1.2
+++ util.c 11 Oct 2023 06:39:20 -0000
@@ -641,3 +641,58 @@ clearnew(void)
}
}
}
+
+uint64_t
+generate_uid(void)
+{
+ static uint32_t id;
+ static uint8_t inited;
+ uint64_t uid;
+
+ if (!inited) {
+ id = arc4random();
+ inited = 1;
+ }
+ while ((uid = ((uint64_t)(id++) << 32 | arc4random())) == 0)
+ ;
+
+ return (uid);
+}
+
+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;
+}