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