When citing URLs for messages in public mail archives,
the YYYYmmddHHMMSS provides crucial information to readers
which can be useful without having to open the cited URL.

Since these messages are cited by others from a public mail
archive (e.g. in commit messages), they are likely legitimate
and a faked timestamp is not something to worry about.

YYYYmmddHHMMSS doesn't require reading the mutt source
code to understand, and it can be used for prefix filtering
for some messages in the absence of other header information.

It's also worthwhile to use URL-safe Base64-encoding
given the prevalance of Message-IDs being used in HTTP(S)
and NNTP URLs.  URLs with Message-IDs are favored by git
and Linux kernel hackers nowadays to ensure URLs remain
useful in case a particular archive host goes down.
---
  Sent from my iP^H^H^H^Hutt with this patch applied and
  not git-send-email :)

  Side note: I left random_bytes at 8, but maybe 5 is enough.
  In any case, there's only one place to change now if somebody
  wants a different size.

 sendlib.c | 33 ++++++++++++++++++++++-----------
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/sendlib.c b/sendlib.c
index ac91dc94..cb27db9e 100644
--- a/sendlib.c
+++ b/sendlib.c
@@ -2410,31 +2410,42 @@ const char *mutt_fqdn(short may_hide_host)
   return p;
 }
 
+/* Base64 encoded length of @n;  + 1 for "\0" */
+#define B64_CAPA(n) (n*2 - n/2 + 1)
+
 char *mutt_gen_msgid (void)
 {
   char buf[SHORT_STRING];
   time_t now = time (NULL);
+  struct tm *tm = gmtime (&now);
   char random_bytes[8];
-  char localpart[12]; /* = 32 bit timestamp, plus 64 bit randomness */
-  unsigned char localpart_B64[16+1]; /* = Base64 encoded value of localpart 
plus
-                                        terminating \0 */
+  unsigned char random_B64[B64_CAPA(sizeof(random_bytes))];
   const char *fqdn;
+  char *c;
 
   mutt_random_bytes (random_bytes, sizeof(random_bytes));
 
-  /* Convert the four least significant bytes of our timestamp and put it in
-     localpart, with proper endianness (for humans) taken into account. */
-  for (int i = 0; i < 4; i++)
-    localpart[i] = (uint8_t) (now >> (3-i)*8u);
-
-  memcpy (&localpart[4], &random_bytes, 8);
+  mutt_to_base64 (random_B64, (unsigned char *) random_bytes,
+                 sizeof(random_bytes), sizeof(random_B64));
 
-  mutt_to_base64 (localpart_B64, (unsigned char *) localpart, 12, 17);
+  /* RFC 4648 "base64url" for HTTP(S) mail archives with Message-IDs in URLs
+   * echo $random_B64 | tr '+/=' '-_' # drop '=' padding byte
+   */
+  for (c = random_B64; *c != '\0'; c++) {
+    switch (*c)
+    {
+      case '+': *c = '-'; break;
+      case '/': *c = '_'; break;
+      case '=': *c = '\0'; break;
+    }
+  }
 
   if (!(fqdn = mutt_fqdn (0)))
     fqdn = NONULL (Hostname);
 
-  snprintf (buf, sizeof (buf), "<%s@%s>", localpart_B64, fqdn);
+  snprintf (buf, sizeof (buf), "<%d%02d%02d%02d%02d%02d.%s@%s>",
+           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
+           tm->tm_min, tm->tm_sec, random_B64, fqdn);
   return (safe_strdup (buf));
 }
 

base-commit: 00b70ff0a5ed86104b880d3974321bf77942320c

Reply via email to