dovecot-2.2: pop3-migration: Truncate header if there's line con...
dovecot at dovecot.org
dovecot at dovecot.org
Thu Jul 16 15:08:53 UTC 2015
details: http://hg.dovecot.org/dovecot-2.2/rev/ab441df52e86
changeset: 18909:ab441df52e86
user: Timo Sirainen <tss at iki.fi>
date: Thu Jul 16 18:08:40 2015 +0300
description:
pop3-migration: Truncate header if there's line containing only CR(s).
This fixes matching IMAP <-> POP3 messages when the servers behave
differently.
diffstat:
src/plugins/pop3-migration/Makefile.am | 22 ++++++
src/plugins/pop3-migration/pop3-migration-plugin.c | 58 ++++++++++++----
src/plugins/pop3-migration/pop3-migration-plugin.h | 7 ++
src/plugins/pop3-migration/test-pop3-migration-plugin.c | 50 ++++++++++++++
4 files changed, 123 insertions(+), 14 deletions(-)
diffs (226 lines):
diff -r b51dfee18fd2 -r ab441df52e86 src/plugins/pop3-migration/Makefile.am
--- a/src/plugins/pop3-migration/Makefile.am Tue Jul 14 15:08:24 2015 +0200
+++ b/src/plugins/pop3-migration/Makefile.am Thu Jul 16 18:08:40 2015 +0300
@@ -1,5 +1,6 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-test \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-storage
@@ -15,3 +16,24 @@
noinst_HEADERS = \
pop3-migration-plugin.h
+
+noinst_PROGRAMS = $(test_programs)
+
+test_programs = \
+ test-pop3-migration-plugin
+
+test_libs = \
+ ../../lib-storage/libstorage.la \
+ ../../lib-test/libtest.la \
+ ../../lib/liblib.la
+test_deps = $(module_LTLIBRARIES) $(test_libs)
+
+test_pop3_migration_plugin_SOURCES = test-pop3-migration-plugin.c
+test_pop3_migration_plugin_LDADD = pop3-migration-plugin.lo $(test_libs)
+test_pop3_migration_plugin_DEPENDENCIES = $(test_deps)
+
+check: check-am check-test
+check-test: all-am
+ for bin in $(test_programs); do \
+ if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
+ done
diff -r b51dfee18fd2 -r ab441df52e86 src/plugins/pop3-migration/pop3-migration-plugin.c
--- a/src/plugins/pop3-migration/pop3-migration-plugin.c Tue Jul 14 15:08:24 2015 +0200
+++ b/src/plugins/pop3-migration/pop3-migration-plugin.c Thu Jul 16 18:08:40 2015 +0300
@@ -112,33 +112,56 @@
return memcmp(map1->hdr_sha1, map2->hdr_sha1, sizeof(map1->hdr_sha1));
}
+struct pop3_hdr_context {
+ bool have_eoh;
+ bool stop;
+};
+
static void
pop3_header_filter_callback(struct header_filter_istream *input ATTR_UNUSED,
struct message_header_line *hdr,
- bool *matched ATTR_UNUSED, bool *have_eoh)
+ bool *matched, struct pop3_hdr_context *ctx)
{
- if (hdr != NULL && hdr->eoh)
- *have_eoh = TRUE;
+ if (hdr == NULL)
+ return;
+ if (hdr->eoh) {
+ ctx->have_eoh = TRUE;
+ if (ctx->stop) {
+ /* matched is handled differently for eoh by
+ istream-header-filter. a design bug I guess.. */
+ *matched = FALSE;
+ }
+ } else {
+ if (strspn(hdr->name, "\r") == hdr->name_len) {
+ /* CR+CR+LF - some servers stop the header processing
+ here while others don't. To make sure they can be
+ matched correctly we want to stop here entirely. */
+ ctx->stop = TRUE;
+ }
+ if (ctx->stop)
+ *matched = TRUE;
+ }
}
-static int
-get_hdr_sha1_stream(struct mail *mail, struct istream *input, uoff_t hdr_size,
- unsigned char sha1_r[SHA1_RESULTLEN], bool *have_eoh_r)
+int pop3_migration_get_hdr_sha1(uint32_t mail_seq, struct istream *input,
+ uoff_t hdr_size,
+ unsigned char sha1_r[SHA1_RESULTLEN],
+ bool *have_eoh_r)
{
struct istream *input2;
const unsigned char *data, *p;
size_t size, idx;
struct sha1_ctxt sha1_ctx;
+ struct pop3_hdr_context hdr_ctx;
- *have_eoh_r = FALSE;
-
+ memset(&hdr_ctx, 0, sizeof(hdr_ctx));
input2 = i_stream_create_limit(input, hdr_size);
/* hide headers that might change or be different in IMAP vs. POP3 */
input = i_stream_create_header_filter(input2,
HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR,
hdr_hash_skip_headers,
N_ELEMENTS(hdr_hash_skip_headers),
- pop3_header_filter_callback, have_eoh_r);
+ pop3_header_filter_callback, &hdr_ctx);
i_stream_unref(&input2);
sha1_init(&sha1_ctx);
@@ -159,12 +182,14 @@
}
if (input->stream_errno != 0) {
i_error("pop3_migration: Failed to read header for msg %u: %s",
- mail->seq, i_stream_get_error(input));
+ mail_seq, i_stream_get_error(input));
i_stream_unref(&input);
return -1;
}
sha1_result(&sha1_ctx, sha1_r);
i_stream_unref(&input);
+
+ *have_eoh_r = hdr_ctx.have_eoh;
return 0;
}
@@ -180,8 +205,9 @@
mail->seq, mailbox_get_last_error(mail->box, NULL));
return -1;
}
- if (get_hdr_sha1_stream(mail, input, hdr_size.physical_size,
- sha1_r, &have_eoh) < 0)
+ if (pop3_migration_get_hdr_sha1(mail->seq, input,
+ hdr_size.physical_size,
+ sha1_r, &have_eoh) < 0)
return -1;
if (have_eoh)
return 0;
@@ -199,6 +225,9 @@
truncating the rest. POP3 TOP instead returns the entire header.
This causes the IMAP and POP3 hashes not to match.
+ If there's LF+CR+CR+LF in the middle of headers, Courier IMAP's
+ FETCH BODY[HEADER] stops after that, but Courier POP3's TOP doesn't.
+
So we'll try to avoid this by falling back to full FETCH BODY[]
(and/or RETR) and we'll parse the header ourself from it. This
should work around any similar bugs in all IMAP/POP3 servers. */
@@ -207,8 +236,9 @@
mail->seq, mailbox_get_last_error(mail->box, NULL));
return -1;
}
- return get_hdr_sha1_stream(mail, input, hdr_size.physical_size,
- sha1_r, &have_eoh);
+ return pop3_migration_get_hdr_sha1(mail->seq, input,
+ hdr_size.physical_size,
+ sha1_r, &have_eoh);
}
diff -r b51dfee18fd2 -r ab441df52e86 src/plugins/pop3-migration/pop3-migration-plugin.h
--- a/src/plugins/pop3-migration/pop3-migration-plugin.h Tue Jul 14 15:08:24 2015 +0200
+++ b/src/plugins/pop3-migration/pop3-migration-plugin.h Thu Jul 16 18:08:40 2015 +0300
@@ -1,7 +1,14 @@
#ifndef POP3_MIGRATION_PLUGIN_H
#define POP3_MIGRATION_PLUGIN_H
+struct module;
+
void pop3_migration_plugin_init(struct module *module);
void pop3_migration_plugin_deinit(void);
+int pop3_migration_get_hdr_sha1(uint32_t mail_seq, struct istream *input,
+ uoff_t hdr_size,
+ unsigned char sha1_r[SHA1_RESULTLEN],
+ bool *have_eoh_r);
+
#endif
diff -r b51dfee18fd2 -r ab441df52e86 src/plugins/pop3-migration/test-pop3-migration-plugin.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/pop3-migration/test-pop3-migration-plugin.c Thu Jul 16 18:08:40 2015 +0300
@@ -0,0 +1,50 @@
+/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "sha1.h"
+#include "hex-binary.h"
+#include "istream.h"
+#include "test-common.h"
+#include "pop3-migration-plugin.h"
+
+static void test_pop3_migration_get_hdr_sha1(void)
+{
+ struct {
+ const char *input;
+ const char *sha1;
+ bool have_eoh;
+ } tests[] = {
+ { "", "da39a3ee5e6b4b0d3255bfef95601890afd80709", FALSE },
+ { "\n", "adc83b19e793491b1c6ea0fd8b46cd9f32e592fc", TRUE },
+ { "a: b\r\n", "3edb5ce145cf1d1e2413e02b8bed70f1ae3ed105", FALSE },
+ { "a: b\r\n\r\n", "d14841695e1d9e2de6625d9222abd149ec821b0d", TRUE },
+ { "a: b\r\n\r\r\n", "3edb5ce145cf1d1e2413e02b8bed70f1ae3ed105", FALSE },
+ { "a: b\r\n\r\r\nc: d\r\n\r\n", "3edb5ce145cf1d1e2413e02b8bed70f1ae3ed105", TRUE }
+ };
+ struct istream *input;
+ unsigned char digest[SHA1_RESULTLEN];
+ unsigned int i;
+ bool have_eoh;
+
+ test_begin("pop3 migration get hdr sha1");
+
+ for (i = 0; i < N_ELEMENTS(tests); i++) {
+ input = i_stream_create_from_data(tests[i].input,
+ strlen(tests[i].input));
+ test_assert_idx(pop3_migration_get_hdr_sha1(1, input, strlen(tests[i].input),
+ digest, &have_eoh) == 0, i);
+ test_assert_idx(strcasecmp(binary_to_hex(digest, sizeof(digest)), tests[i].sha1) == 0, i);
+ test_assert_idx(tests[i].have_eoh == have_eoh, i);
+ }
+
+ test_end();
+}
+
+int main(void)
+{
+ static void (*test_functions[])(void) = {
+ test_pop3_migration_get_hdr_sha1,
+ NULL
+ };
+ return test_run(test_functions);
+}
More information about the dovecot-cvs
mailing list