From: Timo Sirainen Date: Sat, 13 Feb 2010 03:46:17 +0000 (+0200) Subject: Added imap-zlib plugin for enabling COMPRESS=DEFLATE extension. X-Git-Tag: 2.0.beta3~99 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=383395aee82283b15d9ea8ea0ad55d1d8c988b60;p=thirdparty%2Fdovecot%2Fcore.git Added imap-zlib plugin for enabling COMPRESS=DEFLATE extension. --HG-- branch : HEAD --- diff --git a/configure.in b/configure.in index 6deeeabb96..cfdbc44d68 100644 --- a/configure.in +++ b/configure.in @@ -2669,6 +2669,7 @@ src/plugins/imap-quota/Makefile src/plugins/trash/Makefile src/plugins/virtual/Makefile src/plugins/zlib/Makefile +src/plugins/imap-zlib/Makefile stamp.h dovecot-config.in]) diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index ceaa072f58..fb8d63166e 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -1,5 +1,5 @@ if BUILD_ZLIB_PLUGIN -ZLIB = zlib +ZLIB = zlib imap-zlib endif if BUILD_LUCENE diff --git a/src/plugins/imap-zlib/Makefile.am b/src/plugins/imap-zlib/Makefile.am new file mode 100644 index 0000000000..d379f8f765 --- /dev/null +++ b/src/plugins/imap-zlib/Makefile.am @@ -0,0 +1,26 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-mail \ + -I$(top_srcdir)/src/lib-imap \ + -I$(top_srcdir)/src/lib-index \ + -I$(top_srcdir)/src/lib-storage \ + -I$(top_srcdir)/src/imap \ + -I$(top_srcdir)/src/plugins/zlib + +imap_moduledir = $(moduledir) + +lib30_imap_zlib_plugin_la_LDFLAGS = -module -avoid-version + +imap_module_LTLIBRARIES = \ + lib30_imap_zlib_plugin.la + +if PLUGIN_DEPS +lib30_imap_zlib_plugin_la_LIBADD = \ + ../zlib/lib20_zlib_plugin.la +endif + +lib30_imap_zlib_plugin_la_SOURCES = \ + imap-zlib-plugin.c + +noinst_HEADERS = \ + imap-zlib-plugin.h diff --git a/src/plugins/imap-zlib/imap-zlib-plugin.c b/src/plugins/imap-zlib/imap-zlib-plugin.c new file mode 100644 index 0000000000..c7d709ad6c --- /dev/null +++ b/src/plugins/imap-zlib/imap-zlib-plugin.c @@ -0,0 +1,157 @@ +/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */ + +#include "imap-common.h" +#include "str.h" +#include "istream.h" +#include "ostream.h" +#include "module-context.h" +#include "imap-commands.h" +#include "zlib-plugin.h" +#include "imap-zlib-plugin.h" + +#include + +#define IMAP_COMPRESS_DEFAULT_LEVEL 6 + +#define IMAP_ZLIB_IMAP_CONTEXT(obj) \ + MODULE_CONTEXT(obj, imap_zlib_imap_module) + +struct zlib_client { + union imap_module_context module_ctx; + + const struct zlib_handler *handler; +}; + +const char *imap_zlib_plugin_version = DOVECOT_VERSION; + +static struct module *imap_zlib_module; +static void (*next_hook_client_created)(struct client **client); + +static MODULE_CONTEXT_DEFINE_INIT(imap_zlib_imap_module, + &imap_module_register); + +static void client_skip_line(struct client *client) +{ + const unsigned char *data; + size_t data_size; + + data = i_stream_get_data(client->input, &data_size); + i_assert(data_size > 0); + if (data[0] == '\n') + i_stream_skip(client->input, 1); + else if (data[0] == '\r' && data_size > 1 && data[1] == '\n') + i_stream_skip(client->input, 2); + else + i_unreached(); + client->input_skip_line = FALSE; +} + +static void client_update_imap_parser_streams(struct client *client) +{ + struct client_command_context *cmd; + + if (client->free_parser != NULL) { + imap_parser_set_streams(client->free_parser, + client->input, client->output); + } + + for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) { + imap_parser_set_streams(cmd->parser, + client->input, client->output); + } +} + +static bool cmd_compress(struct client_command_context *cmd) +{ + struct client *client = cmd->client; + struct zlib_client *zclient = IMAP_ZLIB_IMAP_CONTEXT(client); + const struct zlib_handler *handler; + const struct imap_arg *args; + struct istream *old_input; + struct ostream *old_output; + const char *mechanism, *value; + int level; + + /* */ + if (!client_read_args(cmd, 0, 0, &args)) + return FALSE; + + mechanism = imap_arg_string(&args[0]); + if (mechanism == NULL || args[1].type != IMAP_ARG_EOL) { + client_send_command_error(cmd, "Invalid arguments."); + return TRUE; + } + if (zclient->handler != NULL) { + client_send_tagline(cmd, t_strdup_printf( + "NO [COMPRESSIONACTIVE] COMPRESSION=%s already enabled.", + t_str_ucase(zclient->handler->name))); + return TRUE; + } + if (client->tls_compression) { + client_send_tagline(cmd, + "NO [COMPRESSIONACTIVE] TLS compression already enabled."); + return TRUE; + } + + + handler = zlib_find_zlib_handler(t_str_lcase(mechanism)); + if (handler == NULL || handler->create_istream == NULL) { + client_send_tagline(cmd, "NO Unknown compression mechanism."); + return TRUE; + } + + client_skip_line(client); + client_send_tagline(cmd, "OK Begin compression."); + + value = mail_user_plugin_getenv(client->user, + "imap_zlib_compress_level"); + level = value == NULL ? 0 : atoi(value); + if (level <= 0 || level > 9) + level = IMAP_COMPRESS_DEFAULT_LEVEL; + + old_input = client->input; + old_output = client->output; + client->input = handler->create_istream(old_input); + client->output = handler->create_ostream(old_output, level); + i_stream_unref(&old_input); + o_stream_unref(&old_output); + + client_update_imap_parser_streams(client); + zclient->handler = handler; + return TRUE; +} + +static void imap_zlib_client_created(struct client **clientp) +{ + struct client *client = *clientp; + struct zlib_client *zclient; + + if (mail_user_is_plugin_loaded(client->user, imap_zlib_module) && + zlib_find_zlib_handler("deflate") != NULL) { + zclient = p_new(client->pool, struct zlib_client, 1); + MODULE_CONTEXT_SET(client, imap_zlib_imap_module, zclient); + + str_append(client->capability_string, " COMPRESS=DEFLATE"); + } + + if (next_hook_client_created != NULL) + next_hook_client_created(clientp); +} + +void imap_zlib_plugin_init(struct module *module) +{ + command_register("COMPRESS", cmd_compress, 0); + + imap_zlib_module = module; + next_hook_client_created = hook_client_created; + hook_client_created = imap_zlib_client_created; +} + +void imap_zlib_plugin_deinit(void) +{ + command_unregister("COMPRESS"); + + hook_client_created = next_hook_client_created; +} + +const char *imap_zlib_plugin_dependencies[] = { "zlib", NULL }; diff --git a/src/plugins/imap-zlib/imap-zlib-plugin.h b/src/plugins/imap-zlib/imap-zlib-plugin.h new file mode 100644 index 0000000000..1fb39eb4a2 --- /dev/null +++ b/src/plugins/imap-zlib/imap-zlib-plugin.h @@ -0,0 +1,11 @@ +#ifndef IMAP_ZLIB_PLUGIN_H +#define IMAP_ZLIB_PLUGIN_H + +struct module; + +extern const char *imap_zlib_plugin_dependencies[]; + +void imap_zlib_plugin_init(struct module *module); +void imap_zlib_plugin_deinit(void); + +#endif diff --git a/src/plugins/zlib/zlib-plugin.c b/src/plugins/zlib/zlib-plugin.c index 0bede3aa1d..03a2182ffb 100644 --- a/src/plugins/zlib/zlib-plugin.c +++ b/src/plugins/zlib/zlib-plugin.c @@ -34,14 +34,6 @@ #define MAX_INBUF_SIZE (1024*1024) -struct zlib_handler { - const char *name; - const char *ext; - bool (*is_compressed)(struct istream *input); - struct istream *(*create_istream)(struct istream *input); - struct ostream *(*create_ostream)(struct ostream *output, int level); -}; - struct zlib_transaction_context { union mailbox_transaction_module_context module_ctx; @@ -51,7 +43,7 @@ struct zlib_transaction_context { struct zlib_user { union mail_user_module_context module_ctx; - struct zlib_handler *save_handler; + const struct zlib_handler *save_handler; int save_level; }; @@ -95,40 +87,37 @@ static bool is_compressed_bzlib(struct istream *input) return memcmp(data + 4, "\x31\x41\x59\x26\x53\x59", 6) == 0; } -static struct zlib_handler zlib_handlers[] = { - { "gz", ".gz", is_compressed_zlib, - i_stream_create_gz, o_stream_create_gz }, - { "bz2", ".bz2", is_compressed_bzlib, - i_stream_create_bz2, o_stream_create_bz2 } -}; - -static struct zlib_handler *zlib_find_zlib_handler(const char *name) +const struct zlib_handler *zlib_find_zlib_handler(const char *name) { unsigned int i; - for (i = 0; i < N_ELEMENTS(zlib_handlers); i++) { + for (i = 0; zlib_handlers[i].name != NULL; i++) { if (strcmp(name, zlib_handlers[i].name) == 0) return &zlib_handlers[i]; } return NULL; } -static struct zlib_handler *zlib_get_zlib_handler(struct istream *input) +static const struct zlib_handler *zlib_get_zlib_handler(struct istream *input) { unsigned int i; - for (i = 0; i < N_ELEMENTS(zlib_handlers); i++) { - if (zlib_handlers[i].is_compressed(input)) + for (i = 0; zlib_handlers[i].name != NULL; i++) { + if (zlib_handlers[i].is_compressed != NULL && + zlib_handlers[i].is_compressed(input)) return &zlib_handlers[i]; } return NULL; } -static struct zlib_handler *zlib_get_zlib_handler_ext(const char *name) +static const struct zlib_handler *zlib_get_zlib_handler_ext(const char *name) { unsigned int i, len, name_len = strlen(name); - for (i = 0; i < N_ELEMENTS(zlib_handlers); i++) { + for (i = 0; zlib_handlers[i].name != NULL; i++) { + if (zlib_handlers[i].ext == NULL) + continue; + len = strlen(zlib_handlers[i].ext); if (name_len > len && strcmp(name + name_len - len, zlib_handlers[i].ext) == 0) @@ -146,7 +135,7 @@ static int zlib_maildir_get_stream(struct mail *_mail, struct index_mail *imail = (struct index_mail *)mail; union mail_module_context *zmail = ZLIB_MAIL_CONTEXT(mail); struct istream *input; - struct zlib_handler *handler; + const struct zlib_handler *handler; if (imail->data.stream != NULL) { return zmail->super.get_stream(_mail, hdr_size, body_size, @@ -262,7 +251,6 @@ static int zlib_mail_save_finish(struct mail_save_context *ctx) struct mailbox *box = ctx->transaction->box; union mailbox_module_context *zbox = ZLIB_CONTEXT(box); struct istream *input; - unsigned int i; if (zbox->super.save_finish(ctx) < 0) return -1; @@ -270,13 +258,10 @@ static int zlib_mail_save_finish(struct mail_save_context *ctx) if (mail_get_stream(ctx->dest_mail, NULL, NULL, &input) < 0) return -1; - for (i = 0; i < N_ELEMENTS(zlib_handlers); i++) { - if (zlib_handlers[i].is_compressed(input)) { - mail_storage_set_error(box->storage, - MAIL_ERROR_NOTPOSSIBLE, - "Saving mails compressed by client isn't supported"); - return -1; - } + if (zlib_get_zlib_handler(input) != NULL) { + mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE, + "Saving mails compressed by client isn't supported"); + return -1; } return 0; } @@ -319,7 +304,7 @@ static void zlib_maildir_alloc_init(struct mailbox *box) static int zlib_mailbox_open_input(struct mailbox *box) { - struct zlib_handler *handler; + const struct zlib_handler *handler; struct istream *input; int fd; @@ -413,3 +398,13 @@ void zlib_plugin_deinit(void) { mail_storage_hooks_remove(&zlib_mail_storage_hooks); } + +const struct zlib_handler zlib_handlers[] = { + { "gz", ".gz", is_compressed_zlib, + i_stream_create_gz, o_stream_create_gz }, + { "bz2", ".bz2", is_compressed_bzlib, + i_stream_create_bz2, o_stream_create_bz2 }, + { "deflate", NULL, NULL, + i_stream_create_deflate, o_stream_create_deflate }, + { NULL, NULL, NULL, NULL, NULL } +}; diff --git a/src/plugins/zlib/zlib-plugin.h b/src/plugins/zlib/zlib-plugin.h index 98f520d9b7..079060794a 100644 --- a/src/plugins/zlib/zlib-plugin.h +++ b/src/plugins/zlib/zlib-plugin.h @@ -1,6 +1,18 @@ #ifndef ZLIB_PLUGIN_H #define ZLIB_PLUGIN_H +struct zlib_handler { + const char *name; + const char *ext; + bool (*is_compressed)(struct istream *input); + struct istream *(*create_istream)(struct istream *input); + struct ostream *(*create_ostream)(struct ostream *output, int level); +}; + +extern const struct zlib_handler zlib_handlers[]; + +const struct zlib_handler *zlib_find_zlib_handler(const char *name); + void zlib_plugin_init(struct module *module); void zlib_plugin_deinit(void);