/* Copyright (C) 2010 Timo Sirainen, LGPLv2.1 */

/*
   Note: a pretty evil way to change the header value, but should work.

   export DOVECOT=~/cvs/dovecot-2.0
   gcc -fPIC -shared -g -Wall -I$DOVECOT -I$DOVECOT/src/lib \
     -I$DOVECOT/src/lib-storage -I$DOVECOT/src/lib-mail \
     -I$DOVECOT/src/lib-imap -I$DOVECOT/src/lib-index -DHAVE_CONFIG_H \
     modify-plugin.c -o modify_plugin.so
*/

#include "lib.h"
#include "str.h"
#include "istream.h"
#include "istream-header-filter.h"
#include "message-header-parser.h"
#include "mail-storage-private.h"

#define MODIFY_CONTEXT(obj) \
	MODULE_CONTEXT(obj, modify_storage_module)

static MODULE_CONTEXT_DEFINE_INIT(modify_storage_module,
				  &mail_storage_module_register);

static int modify_mailbox_open(struct mailbox *box)
{
	union mailbox_module_context *zbox = MODIFY_CONTEXT(box);

	if (zbox->super.open(box) < 0)
		return -1;

	if (strcmp(box->name, "spam") == 0) {
		/* force copying to go through mail_save_begin() */
		box->disable_reflink_copy_to = TRUE;
	}
	return 0;
}

static void filter_callback(struct message_header_line *hdr,
			    bool *matched, void *context)
{
	string_t *str;

	if (hdr == NULL || strcasecmp(hdr->name, "subject") != 0)
		return;

	str = t_str_new(128);
	str_append_n(str, hdr->value, hdr->value_len);
	str_append(str, " (hello world)");

	hdr->value = str_data(str);
	hdr->value_len = str_len(str);
}

struct istream *create_modifier_stream(struct istream *input)
{
	return i_stream_create_header_filter(input, HEADER_FILTER_EXCLUDE,
					     NULL, 0, filter_callback, NULL);

}

static int
modify_mail_save_begin(struct mail_save_context *ctx, struct istream *input)
{
	struct mailbox_transaction_context *t = ctx->transaction;
	union mailbox_module_context *zbox = MODIFY_CONTEXT(t->box);
	struct istream *new_input;

	if (strcmp(t->box->name, "spam") == 0) {
		new_input = create_modifier_stream(input);
		i_stream_unref(&input);
		input = new_input;
	}
	return zbox->super.save_begin(ctx, input);
}

static void modify_mailbox_allocated(struct mailbox *box)
{
	struct mailbox_vfuncs *v = box->vlast;
	union mailbox_module_context *zbox;

	zbox = p_new(box->pool, union mailbox_module_context, 1);
	zbox->super = *v;
	box->vlast = &zbox->super;
	v->open = modify_mailbox_open;
	v->save_begin = modify_mail_save_begin;

	MODULE_CONTEXT_SET_SELF(box, modify_storage_module, zbox);
}

static struct mail_storage_hooks modify_mail_storage_hooks = {
	.mailbox_allocated = modify_mailbox_allocated
};

void modify_plugin_init(struct module *module);
void modify_plugin_deinit(void);

void modify_plugin_init(struct module *module)
{
	mail_storage_hooks_add(module, &modify_mail_storage_hooks);
}

void modify_plugin_deinit(void)
{
	mail_storage_hooks_remove(&modify_mail_storage_hooks);
}
