]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-mail: message_header_hash_more() - add v3 that strips spaces
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 23 Jun 2017 08:00:37 +0000 (11:00 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 26 Jun 2017 08:51:39 +0000 (11:51 +0300)
This helps with Zimbra, which strips away trailing whitespaces in
BODY[HEADER].

src/lib-mail/message-header-hash.c
src/lib-mail/message-header-hash.h
src/lib-mail/test-message-header-hash.c

index 80dfea47460b6e8962550d6868db00d53811294f..d4265d5ba9a7c7ed888949274f20235bdda10b99 100644 (file)
@@ -11,7 +11,7 @@ void message_header_hash_more(struct message_header_hash_context *ctx,
 {
        size_t i, start;
 
-       i_assert(version == 1 || version == 2);
+       i_assert(version >= 1 && version <= MESSAGE_HEADER_HASH_MAX_VERSION);
 
        if (version == 1) {
                method->loop(context, data, size);
@@ -28,24 +28,39 @@ void message_header_hash_more(struct message_header_hash_context *ctx,
 
           So we'll just replace all control and 8bit chars with '?' and
           remove any repeated '?', which hopefully will satisfy everybody.
+
+          Also:
+          - Zimbra removes trailing spaces from IMAP BODY[HEADER], but not
+          IMAP BODY[] or POP3 TOP. Just strip away all spaces with version 3.
+
        */
        for (i = start = 0; i < size; i++) {
+               bool cur_is_questionmark = FALSE;
+
                switch (data[i]) {
+               case ' ':
+                       if (version == 3) {
+                               /* strip away spaces */
+                               method->loop(context, data + start, i-start);
+                               start = i+1;
+                       }
+                       break;
                case '\t':
                case '\n':
                        break;
                default:
                        if (data[i] < 0x20 || data[i] >= 0x7f || data[i] == '?') {
                                /* remove repeated '?' */
-                               if (start < i || (i == 0 && !ctx->prev_was_questionmark)) {
+                               if (start < i || !ctx->prev_was_questionmark) {
                                        method->loop(context, data + start, i-start);
                                        method->loop(context, "?", 1);
                                }
                                start = i+1;
+                               cur_is_questionmark = TRUE;
                        }
                        break;
                }
+               ctx->prev_was_questionmark = cur_is_questionmark;
        }
-       ctx->prev_was_questionmark = start == i;
        method->loop(context, data + start, i-start);
 }
index cfedd83fdadee95710faaa507ce47381276423da..4183ed2f9e8ee5fc145e07a5c1d19f64fd3b0f6e 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef MESSAGE_HEADER_HASH_H
 #define MESSAGE_HEADER_HASH_H
 
+#define MESSAGE_HEADER_HASH_MAX_VERSION 3
+
 struct hash_method;
 
 struct message_header_hash_context {
index b90de76b1a671efa24928e76ed32b2f58424c1bb..1bcc5ecfd9039c506677f97f3a6bdc3c4bdbd44c 100644 (file)
@@ -25,6 +25,18 @@ static const struct {
        { "\x01?hi??\x01", 2, "?hi?" },
        { "?\t?hi?\t?", 2, "?\t?hi?\t?" },
        { "\n\nhi\n\n", 2, "\n\nhi\n\n" },
+       { "", 2, "" },
+       { " ", 2, " " },
+       { "   ", 2, "   " },
+       { "? ? ? hi \x01\x02   \x03   ", 2, "? ? ? hi ?   ?   " },
+
+       { test_input_with_nuls, 3, "?\t\n?!?x?yz?-plop?" },
+       { "\n\nhi\n\n", 2, "\n\nhi\n\n" },
+       { "", 3, "" },
+       { " ", 3, "" },
+       { "   ", 3, "" },
+       { " ? ", 3, "?" },
+       { "? ? ? hi \x01\x02   \x03   ", 3, "???hi??" },
 };
 
 static void test_message_header_hash_more(void)