Hi all, a while ago we introduced obfuscated message-id headers (see bugzilla #738155 and related messages in the balsa list). The message-id now is basically a base64-encoded hash value, which may contain the '+' and '/' characters explicitly allowed by RFC 5322. However, I noticed that if a DSN is requested, some MTA's seem to use this message-id verbatim as ENVID parameter (see RFC 3461). In this parameter, though, the '+' character is /not/ allowed and must be escaped. As a result, the receiving MTA /may/ reject the message if the ENVID contains an unescaped +. Although this is a bug in the sending MTA, IMO it would be better to adjust the way the message-id is created. The attached patch uses the first 240 bits (30 bytes) of the random hash to create a somewhat formatted, base32-encoded message-id (see e.g. in this message). Opinions? I wish you all a merry Christmas! Cheers, Albrecht.
diff --git a/libbalsa/send.c b/libbalsa/send.c index d38a00b..01487ce 100644 --- a/libbalsa/send.c +++ b/libbalsa/send.c @@ -1953,6 +1953,18 @@ libbalsa_message_postpone(LibBalsaMessage * message, } +static inline gchar +base32_char(guint8 val) +{ + val &= 0x1f; + if (val <= 25) { + return val + 'A'; + } else { + return val + '2' - 26; + } +} + + /* Create a message-id and set it on the mime message. */ static void @@ -1970,6 +1982,8 @@ libbalsa_set_message_id(GMimeMessage * mime_message) guint8 buffer[32]; gsize buflen; gchar *message_id; + guint8 *src; + gchar *dst; g_mutex_lock(&mutex); if (rand == NULL) { @@ -1994,15 +2008,28 @@ libbalsa_set_message_id(GMimeMessage * mime_message) g_hmac_unref(msg_id_hash); g_mutex_unlock(&mutex); - /* create a msg id string - * Note: RFC 5322, sect. 3.6.4 explicitly allows the form - * dot-atom-text "@" dot-atom-text - * where dot-atom-text may include all base64 (RFC 1421) chars, - * including '+' and '/' */ - message_id = g_base64_encode(buffer, buflen); - memmove(message_id + 23, message_id + 22, strlen(message_id) - 23); - message_id[22] = '@'; - + /* create a msg id string as base32-encoded string from the first + * 30 bytes of the hashed result, and separate the groups by '.' + * or '@' */ + message_id = dst = g_malloc0(54U); /* = (32 / 5) * 9 */ + src = buffer; + while (buflen >= 5U) { + *dst++ = base32_char(src[0] >> 3); + *dst++ = base32_char((src[0] << 2) + (src[1] >> 6)); + *dst++ = base32_char(src[1] >> 1); + *dst++ = base32_char((src[1] << 4) + (src[2] >> 4)); + *dst++ = base32_char((src[2] << 1) + (src[3] >> 7)); + *dst++ = base32_char(src[3] >> 2); + *dst++ = base32_char((src[3] << 3) + (src[4] >> 5)); + *dst++ = base32_char(src[4]); + src = &src[5]; + buflen -= 5U; + if (dst == &message_id[(54U / 2U) - 1U]) { + *dst++ = '@'; + } else if (buflen >= 5U) { + *dst++ = '.'; + } + } g_mime_message_set_message_id(mime_message, message_id); g_free(message_id); }
Attachment:
pgpJBEgiQDpj1.pgp
Description: PGP signature