/* 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
};