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