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;
 }

Reply via email to