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