zlib-plugin.c revision 5d202fa7788e500f5b2bab2aa6f6327c8c7461dc
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "array.h"
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen#include "istream.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "ostream.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "mail-user.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "index-storage.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "index-mail.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "istream-zlib.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "ostream-zlib.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "zlib-plugin.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <stdlib.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <fcntl.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#define ZLIB_PLUGIN_DEFAULT_LEVEL 6
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#define ZLIB_CONTEXT(obj) \
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen MODULE_CONTEXT(obj, zlib_storage_module)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#define ZLIB_MAIL_CONTEXT(obj) \
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen MODULE_CONTEXT(obj, zlib_mail_module)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#define ZLIB_USER_CONTEXT(obj) \
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen MODULE_CONTEXT(obj, zlib_user_module)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen#ifndef HAVE_ZLIB
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen# define i_stream_create_gz NULL
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen# define o_stream_create_gz NULL
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen#endif
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen#ifndef HAVE_BZLIB
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen# define i_stream_create_bz2 NULL
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen# define o_stream_create_bz2 NULL
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen#endif
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen#define MAX_INBUF_SIZE (1024*1024)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenstruct zlib_transaction_context {
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen union mailbox_transaction_module_context module_ctx;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct mail *tmp_mail;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen};
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct zlib_user {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen union mail_user_module_context module_ctx;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const struct zlib_handler *save_handler;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen unsigned int save_level;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen};
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenconst char *zlib_plugin_version = DOVECOT_VERSION;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(zlib_user_module,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen &mail_user_module_register);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(zlib_storage_module,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen &mail_storage_module_register);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(zlib_mail_module, &mail_module_register);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenstatic bool is_compressed_zlib(struct istream *input)
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen{
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen const unsigned char *data;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen size_t size;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen /* Peek in to the stream and see if it looks like it's compressed
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen (based on its header). This also means that users can try to exploit
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen security holes in the uncompression library by APPENDing a specially
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen crafted mail. So let's hope zlib is free of holes. */
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (i_stream_read_data(input, &data, &size, 1) <= 0)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return FALSE;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen i_assert(size >= 2);
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return data[0] == 31 && data[1] == 139;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen}
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainenstatic bool is_compressed_bzlib(struct istream *input)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen{
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen const unsigned char *data;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen size_t size;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (i_stream_read_data(input, &data, &size, 4+6 - 1) <= 0)
df831edaa3b3aa22e03bc5fd416a0553c5600a69Phil Carmody return FALSE;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (data[0] != 'B' || data[1] != 'Z')
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return FALSE;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (data[2] != 'h' && data[2] != '0')
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return FALSE;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (data[3] < '1' || data[3] > '9')
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen return FALSE;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen return memcmp(data + 4, "\x31\x41\x59\x26\x53\x59", 6) == 0;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenconst struct zlib_handler *zlib_find_zlib_handler(const char *name)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int i;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (i = 0; zlib_handlers[i].name != NULL; i++) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (strcmp(name, zlib_handlers[i].name) == 0)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return &zlib_handlers[i];
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return NULL;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen}
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstatic const struct zlib_handler *zlib_get_zlib_handler(struct istream *input)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen unsigned int i;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen for (i = 0; zlib_handlers[i].name != NULL; i++) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (zlib_handlers[i].is_compressed != NULL &&
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen zlib_handlers[i].is_compressed(input))
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return &zlib_handlers[i];
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return NULL;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen}
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic const struct zlib_handler *zlib_get_zlib_handler_ext(const char *name)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen unsigned int i, len, name_len = strlen(name);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (i = 0; zlib_handlers[i].name != NULL; i++) {
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen if (zlib_handlers[i].ext == NULL)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen continue;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen len = strlen(zlib_handlers[i].ext);
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen if (name_len > len &&
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen strcmp(name + name_len - len, zlib_handlers[i].ext) == 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return &zlib_handlers[i];
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainenstatic int zlib_permail_get_stream(struct mail *_mail,
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen struct message_size *hdr_size,
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen struct message_size *body_size,
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen struct istream **stream_r)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen struct zlib_user *zuser = ZLIB_USER_CONTEXT(_mail->box->storage->user);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen struct index_mail *imail = (struct index_mail *)mail;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen union mail_module_context *zmail = ZLIB_MAIL_CONTEXT(mail);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct istream *input;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen const struct zlib_handler *handler;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* don't uncompress input when we are reading a mail that we're just
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen in the middle of saving, and we didn't do the compression ourself.
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen in such situation we're probably checking if the user-given input
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen looks compressed */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (imail->data.stream != NULL ||
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen (_mail->uid == 0 && zuser->save_handler == NULL)) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return zmail->super.get_stream(_mail, hdr_size, body_size,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen stream_r);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (zmail->super.get_stream(_mail, NULL, NULL, &input) < 0)
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen return -1;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_assert(input == imail->data.stream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
a2738cdb6d2733fb3e186331d68009421a19ea00Timo Sirainen handler = zlib_get_zlib_handler(imail->data.stream);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen if (handler != NULL) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (handler->create_istream == NULL) {
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen mail_storage_set_critical(_mail->box->storage,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen "zlib plugin: Detected %s compression "
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen "but support not compiled in", handler->ext);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return -1;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen input = imail->data.stream;
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen imail->data.stream = handler->create_istream(input, TRUE);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_stream_unref(&input);
7af4788b402346c94496095dd819f95ce03fe431Timo Sirainen }
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen return index_mail_init_stream(imail, hdr_size, body_size, stream_r);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen}
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainenstatic struct mail *
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainenzlib_permail_mail_alloc(struct mailbox_transaction_context *t,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen enum mail_fetch_field wanted_fields,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen{
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen union mailbox_module_context *zbox = ZLIB_CONTEXT(t->box);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen union mail_module_context *zmail;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen struct mail *_mail;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen struct mail_private *mail;
c24ef531ca58abad996482f5c2e8992be9ae8981Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen _mail = zbox->super.mail_alloc(t, wanted_fields, wanted_headers);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen mail = (struct mail_private *)_mail;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen zmail = p_new(mail->pool, union mail_module_context, 1);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen zmail->super = mail->v;
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen mail->v.get_stream = zlib_permail_get_stream;
2524ef7b34965a1b1895d6140fd8296bf57c78d2Timo Sirainen MODULE_CONTEXT_SET_SELF(mail, zlib_mail_module, zmail);
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen return _mail;
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen}
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic struct mailbox_transaction_context *
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenzlib_mailbox_transaction_begin(struct mailbox *box,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen enum mailbox_transaction_flags flags)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen union mailbox_module_context *zbox = ZLIB_CONTEXT(box);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct mailbox_transaction_context *t;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct zlib_transaction_context *zt;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen t = zbox->super.transaction_begin(box, flags);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen zt = i_new(struct zlib_transaction_context, 1);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen MODULE_CONTEXT_SET(t, zlib_storage_module, zt);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return t;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenstatic void
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenzlib_mailbox_transaction_rollback(struct mailbox_transaction_context *t)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen{
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen union mailbox_module_context *zbox = ZLIB_CONTEXT(t->box);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct zlib_transaction_context *zt = ZLIB_CONTEXT(t);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (zt->tmp_mail != NULL)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mail_free(&zt->tmp_mail);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen zbox->super.transaction_rollback(t);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen i_free(zt);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenstatic int
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenzlib_mailbox_transaction_commit(struct mailbox_transaction_context *t,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct mail_transaction_commit_changes *changes_r)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen{
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen union mailbox_module_context *zbox = ZLIB_CONTEXT(t->box);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct zlib_transaction_context *zt = ZLIB_CONTEXT(t);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen int ret;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (zt->tmp_mail != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_free(&zt->tmp_mail);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = zbox->super.transaction_commit(t, changes_r);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_free(zt);
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen return ret;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenzlib_mail_save_begin(struct mail_save_context *ctx, struct istream *input)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mailbox_transaction_context *t = ctx->transaction;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct zlib_transaction_context *zt = ZLIB_CONTEXT(t);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen union mailbox_module_context *zbox = ZLIB_CONTEXT(t->box);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen if (ctx->dest_mail == NULL) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (zt->tmp_mail == NULL) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen zt->tmp_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE,
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen NULL);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ctx->dest_mail = zt->tmp_mail;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return zbox->super.save_begin(ctx, input);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainenstatic int zlib_mail_save_finish(struct mail_save_context *ctx)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen struct mailbox *box = ctx->transaction->box;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen union mailbox_module_context *zbox = ZLIB_CONTEXT(box);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct istream *input;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (zbox->super.save_finish(ctx) < 0)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return -1;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (mail_get_stream(ctx->dest_mail, NULL, NULL, &input) < 0)
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return -1;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (zlib_get_zlib_handler(input) != NULL) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen "Saving mails compressed by client isn't supported");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return 0;
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic int
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenzlib_mail_save_compress_begin(struct mail_save_context *ctx,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct istream *input)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct mailbox *box = ctx->transaction->box;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct zlib_user *zuser = ZLIB_USER_CONTEXT(box->storage->user);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen union mailbox_module_context *zbox = ZLIB_CONTEXT(box);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen struct ostream *output;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen if (zbox->super.save_begin(ctx, input) < 0)
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen return -1;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen output = zuser->save_handler->create_ostream(ctx->output,
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen zuser->save_level);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen o_stream_unref(&ctx->output);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen ctx->output = output;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen o_stream_cork(ctx->output);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen return 0;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void zlib_permail_alloc_init(struct mailbox *box)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct zlib_user *zuser = ZLIB_USER_CONTEXT(box->storage->user);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen box->v.mail_alloc = zlib_permail_mail_alloc;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen box->v.transaction_begin = zlib_mailbox_transaction_begin;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen box->v.transaction_rollback = zlib_mailbox_transaction_rollback;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen box->v.transaction_commit = zlib_mailbox_transaction_commit;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (zuser->save_handler == NULL) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen box->v.save_begin = zlib_mail_save_begin;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen box->v.save_finish = zlib_mail_save_finish;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen } else {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen box->v.save_begin = zlib_mail_save_compress_begin;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic int zlib_mailbox_open_input(struct mailbox *box)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen const struct zlib_handler *handler;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen struct istream *input;
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen int fd;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen handler = zlib_get_zlib_handler_ext(box->name);
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (handler == NULL || handler->create_istream == NULL)
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (mail_storage_is_mailbox_file(box->storage)) {
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* looks like a compressed single file mailbox. we should be
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen able to handle this. */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen fd = open(box->path, O_RDONLY);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (fd == -1) {
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen mail_storage_set_critical(box->storage,
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen "open(%s) failed: %m", box->path);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return -1;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen }
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen i_stream_set_name(input, box->path);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen box->input = handler->create_istream(input, TRUE);
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen i_stream_unref(&input);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen box->flags |= MAILBOX_FLAG_READONLY;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen }
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen return 0;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen}
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainenstatic int zlib_mailbox_open(struct mailbox *box)
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen{
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen union mailbox_module_context *zbox = ZLIB_CONTEXT(box);
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen if (box->input == NULL &&
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen (box->storage->class_flags &
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS) != 0) {
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen if (zlib_mailbox_open_input(box) < 0)
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen return -1;
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen }
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen return zbox->super.open(box);
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen}
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void zlib_mailbox_allocated(struct mailbox *box)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen union mailbox_module_context *zbox;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen zbox = p_new(box->pool, union mailbox_module_context, 1);
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen zbox->super = box->v;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen box->v.open = zlib_mailbox_open;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen MODULE_CONTEXT_SET_SELF(box, zlib_storage_module, zbox);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen if (strcmp(box->storage->name, "maildir") == 0 ||
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen strcmp(box->storage->name, "mdbox") == 0 ||
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen strcmp(box->storage->name, "dbox") == 0)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen zlib_permail_alloc_init(box);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenstatic void zlib_mail_user_created(struct mail_user *user)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen struct zlib_user *zuser;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen const char *name;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen zuser = p_new(user->pool, struct zlib_user, 1);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen zuser->module_ctx.super = user->v;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen name = mail_user_plugin_getenv(user, "zlib_save");
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (name != NULL && *name != '\0') {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen zuser->save_handler = zlib_find_zlib_handler(name);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (zuser->save_handler == NULL)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen i_error("zlib_save: Unknown handler: %s", name);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen name = mail_user_plugin_getenv(user, "zlib_save_level");
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (name != NULL) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (str_to_uint(name, &zuser->save_level) < 0 ||
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen zuser->save_level < 1 || zuser->save_level > 9) {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen i_error("zlib_save_level: Level must be between 1..9");
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen zuser->save_level = 0;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen }
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen }
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (zuser->save_level == 0)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen zuser->save_level = ZLIB_PLUGIN_DEFAULT_LEVEL;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen MODULE_CONTEXT_SET(user, zlib_user_module, zuser);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenstatic struct mail_storage_hooks zlib_mail_storage_hooks = {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen .mail_user_created = zlib_mail_user_created,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen .mailbox_allocated = zlib_mailbox_allocated
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen};
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid zlib_plugin_init(struct module *module)
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen{
df16c7e87511fed827e6890a2a47d13ca48716deTimo Sirainen mail_storage_hooks_add(module, &zlib_mail_storage_hooks);
df16c7e87511fed827e6890a2a47d13ca48716deTimo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainenvoid zlib_plugin_deinit(void)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen mail_storage_hooks_remove(&zlib_mail_storage_hooks);
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen}
b7651d283ca261015ef3c445f1f27f340f0864e2Timo Sirainen
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainenconst struct zlib_handler zlib_handlers[] = {
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen { "gz", ".gz", is_compressed_zlib,
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen i_stream_create_gz, o_stream_create_gz },
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen { "bz2", ".bz2", is_compressed_bzlib,
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen i_stream_create_bz2, o_stream_create_bz2 },
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen { "deflate", NULL, NULL,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_stream_create_deflate, o_stream_create_deflate },
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen { NULL, NULL, NULL, NULL, NULL }
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen};
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen