summaryrefslogtreecommitdiffstats
path: root/src/lib-storage/index/mbox/mbox-md5-apop3d.c
blob: 56f6f914b625d5967104f510eb407532dfedd09b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "md5.h"
#include "message-parser.h"
#include "mbox-md5.h"


struct mbox_md5_context {
	struct md5_context hdr_md5_ctx;
	bool seen_received_hdr;
};

struct mbox_md5_header_func {
	const char *header;
	bool (*func)(struct mbox_md5_context *ctx,
		     struct message_header_line *hdr);
};

static bool parse_date(struct mbox_md5_context *ctx,
		       struct message_header_line *hdr)
{
	if (!ctx->seen_received_hdr) {
		/* Received-header contains date too, and more trusted one */
		md5_update(&ctx->hdr_md5_ctx, hdr->value, hdr->value_len);
	}
	return TRUE;
}

static bool parse_delivered_to(struct mbox_md5_context *ctx,
			       struct message_header_line *hdr)
{
	md5_update(&ctx->hdr_md5_ctx, hdr->value, hdr->value_len);
	return TRUE;
}

static bool parse_message_id(struct mbox_md5_context *ctx,
			     struct message_header_line *hdr)
{
	if (!ctx->seen_received_hdr) {
		/* Received-header contains unique ID too,
		   and more trusted one */
		md5_update(&ctx->hdr_md5_ctx, hdr->value, hdr->value_len);
	}
	return TRUE;
}

static bool parse_received(struct mbox_md5_context *ctx,
			   struct message_header_line *hdr)
{
	if (!ctx->seen_received_hdr) {
		/* get only the first received-header */
		md5_update(&ctx->hdr_md5_ctx, hdr->value, hdr->value_len);
		if (!hdr->continues)
			ctx->seen_received_hdr = TRUE;
	}
	return TRUE;
}

static bool parse_x_delivery_id(struct mbox_md5_context *ctx,
				struct message_header_line *hdr)
{
	/* Let the local delivery agent help generate unique ID's but don't
	   blindly trust this header alone as it could just as easily come from
	   the remote. */
	md5_update(&ctx->hdr_md5_ctx, hdr->value, hdr->value_len);
	return TRUE;
}


static struct mbox_md5_header_func md5_header_funcs[] = {
	{ "Date", parse_date },
	{ "Delivered-To", parse_delivered_to },
	{ "Message-ID", parse_message_id },
	{ "Received", parse_received },
	{ "X-Delivery-ID", parse_x_delivery_id }
};

static int bsearch_header_func_cmp(const void *p1, const void *p2)
{
	const char *key = p1;
	const struct mbox_md5_header_func *func = p2;

	return strcasecmp(key, func->header);
}

static struct mbox_md5_context *mbox_md5_apop3d_init(void)
{
	struct mbox_md5_context *ctx;

	ctx = i_new(struct mbox_md5_context, 1);
	md5_init(&ctx->hdr_md5_ctx);
	return ctx;
}

static void mbox_md5_apop3d_more(struct mbox_md5_context *ctx,
				 struct message_header_line *hdr)
{
	struct mbox_md5_header_func *func;

	func = bsearch(hdr->name, md5_header_funcs,
		       N_ELEMENTS(md5_header_funcs), sizeof(*md5_header_funcs),
		       bsearch_header_func_cmp);
	if (func != NULL)
		(void)func->func(ctx, hdr);
}

static void mbox_md5_apop3d_finish(struct mbox_md5_context *ctx,
				   unsigned char result[STATIC_ARRAY 16])
{
	md5_final(&ctx->hdr_md5_ctx, result);
	i_free(ctx);
}

struct mbox_md5_vfuncs mbox_md5_apop3d = {
	mbox_md5_apop3d_init,
	mbox_md5_apop3d_more,
	mbox_md5_apop3d_finish
};