summaryrefslogtreecommitdiffstats
path: root/src/lib-mail/message-header-hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib-mail/message-header-hash.c')
-rw-r--r--src/lib-mail/message-header-hash.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/lib-mail/message-header-hash.c b/src/lib-mail/message-header-hash.c
new file mode 100644
index 0000000..05eb791
--- /dev/null
+++ b/src/lib-mail/message-header-hash.c
@@ -0,0 +1,72 @@
+/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "hash-method.h"
+#include "message-header-hash.h"
+
+void message_header_hash_more(struct message_header_hash_context *ctx,
+ const struct hash_method *method, void *context,
+ unsigned int version,
+ const unsigned char *data, size_t size)
+{
+ size_t i, start;
+
+ i_assert(version >= 1 && version <= MESSAGE_HEADER_HASH_MAX_VERSION);
+
+ if (version == 1) {
+ method->loop(context, data, size);
+ return;
+ }
+ /* - Dovecot IMAP replaces NULs with 0x80 character.
+ - Dovecot POP3 with outlook-no-nuls workaround replaces NULs
+ with 0x80 character.
+ - Zimbra replaces 8bit chars with '?' in header fetches,
+ but not body fetches.
+ - Yahoo replaces 8bit chars with '?' in partial header
+ fetches, but not POP3 TOP. UTF-8 character sequence writes only a
+ single '?'
+
+ 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 and tabs from IMAP BODY[HEADER],
+ but not IMAP BODY[] or POP3 TOP. Just strip away all spaces with
+ version 3 and tabs also with version 4.
+ */
+ 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':
+ if (version >= 4) {
+ /* strip away tabs */
+ method->loop(context, data + start, i-start);
+ start = i+1;
+ }
+ break;
+ case '\n':
+ break;
+ default:
+ if (data[i] < 0x20 || data[i] >= 0x7f || data[i] == '?') {
+ /* remove repeated '?' */
+ 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;
+ }
+ method->loop(context, data + start, i-start);
+}