]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added imap-zlib plugin for enabling COMPRESS=DEFLATE extension.
authorTimo Sirainen <tss@iki.fi>
Sat, 13 Feb 2010 03:46:17 +0000 (05:46 +0200)
committerTimo Sirainen <tss@iki.fi>
Sat, 13 Feb 2010 03:46:17 +0000 (05:46 +0200)
--HG--
branch : HEAD

configure.in
src/plugins/Makefile.am
src/plugins/imap-zlib/Makefile.am [new file with mode: 0644]
src/plugins/imap-zlib/imap-zlib-plugin.c [new file with mode: 0644]
src/plugins/imap-zlib/imap-zlib-plugin.h [new file with mode: 0644]
src/plugins/zlib/zlib-plugin.c
src/plugins/zlib/zlib-plugin.h

index 6deeeabb96fb17f99811296cce3807ac6507ad05..cfdbc44d68983359931eeb3ff6c551ff431687dd 100644 (file)
@@ -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])
 
index ceaa072f58191680c2c3a2917329715e12cae14c..fb8d63166edfcecd22d1a64e87564be6311d3c81 100644 (file)
@@ -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 (file)
index 0000000..d379f8f
--- /dev/null
@@ -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 (file)
index 0000000..c7d709a
--- /dev/null
@@ -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 <stdlib.h>
+
+#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;
+
+       /* <mechanism> */
+       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 (file)
index 0000000..1fb39eb
--- /dev/null
@@ -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
index 0bede3aa1daf8c0d8466c912d69b502c684e76ec..03a2182ffb5d830a5ee085b31cc23c8b5dd8edfc 100644 (file)
 
 #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 }
+};
index 98f520d9b789d370cbe2894d0983a5d2b8e4df4e..079060794a3d724761bce0564c7cf0c290bd0318 100644 (file)
@@ -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);