# HG changeset patch # User Timo Sirainen # Date 1224362741 -10800 # Node ID 0d1bd98a6387e93d410e8aea9658e861e30dbc58 # Parent 698fca0d8b0a211d11ae7bffb03b4a8db0060355 Added listescape plugin. diff -r 698fca0d8b0a -r 0d1bd98a6387 configure.in --- a/configure.in Sat Oct 18 22:51:20 2008 +0300 +++ b/configure.in Sat Oct 18 23:45:41 2008 +0300 @@ -2448,6 +2448,7 @@ src/plugins/fts-solr/Makefile src/plugins/fts-squat/Makefile src/plugins/lazy-expunge/Makefile +src/plugins/listescape/Makefile src/plugins/mail-log/Makefile src/plugins/mbox-snarf/Makefile src/plugins/quota/Makefile diff -r 698fca0d8b0a -r 0d1bd98a6387 src/plugins/Makefile.am --- a/src/plugins/Makefile.am Sat Oct 18 22:51:20 2008 +0300 +++ b/src/plugins/Makefile.am Sat Oct 18 23:45:41 2008 +0300 @@ -18,6 +18,7 @@ fts \ fts-squat \ lazy-expunge \ + listescape \ mail-log \ mbox-snarf \ quota \ diff -r 698fca0d8b0a -r 0d1bd98a6387 src/plugins/listescape/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/listescape/Makefile.am Sat Oct 18 23:45:41 2008 +0300 @@ -0,0 +1,25 @@ +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 + +lib20_listescape_plugin_la_LDFLAGS = -module -avoid-version + +module_LTLIBRARIES = \ + lib20_listescape_plugin.la + +lib20_listescape_plugin_la_SOURCES = \ + listescape-plugin.c + +noinst_HEADERS = \ + listescape-plugin.h + +install-exec-local: + for d in imap pop3 lda; do \ + $(mkdir_p) $(DESTDIR)$(moduledir)/$$d; \ + rm -f $(DESTDIR)$(moduledir)/$$d/lib20_listescape_plugin$(MODULE_SUFFIX); \ + $(LN_S) ../lib20_listescape_plugin$(MODULE_SUFFIX) $(DESTDIR)$(moduledir)/$$d; \ + done + diff -r 698fca0d8b0a -r 0d1bd98a6387 src/plugins/listescape/listescape-plugin.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/listescape/listescape-plugin.c Sat Oct 18 23:45:41 2008 +0300 @@ -0,0 +1,329 @@ +/* Copyright (C) 2007-2008 Timo Sirainen, LGPLv2.1 */ + +#include "lib.h" +#include "array.h" +#include "str.h" +#include "module-context.h" +#include "mail-storage-private.h" +#include "mailbox-list-private.h" +#include "listescape-plugin.h" + +#include +#include + +#define DEFAULT_ESCAPE_CHAR '\\' + +#define LIST_ESCAPE_CONTEXT(obj) \ + MODULE_CONTEXT(obj, listescape_storage_module) +#define LIST_ESCAPE_LIST_CONTEXT(obj) \ + MODULE_CONTEXT(obj, listescape_list_module) + +struct listescape_mail_storage { + union mail_storage_module_context module_ctx; +}; + +struct listescape_mailbox_list { + union mailbox_list_module_context module_ctx; + struct mailbox_info info; + string_t *list_name; + bool name_escaped; +}; + +const char *listescape_plugin_version = PACKAGE_VERSION; + +static void (*listescape_next_hook_mail_storage_created) + (struct mail_storage *storage); +static void (*listescape_next_hook_mailbox_list_created) + (struct mailbox_list *list); +static void (*listescape_next_hook_mail_namespaces_created) + (struct mail_namespace *namespaces); +static char escape_char = DEFAULT_ESCAPE_CHAR; + +static MODULE_CONTEXT_DEFINE_INIT(listescape_storage_module, + &mail_storage_module_register); +static MODULE_CONTEXT_DEFINE_INIT(listescape_list_module, + &mailbox_list_module_register); + +static const char *list_escape(struct mail_namespace *ns, + const char *str, bool change_sep) +{ + string_t *esc = t_str_new(64); + + if (*str == '~') { + str_printfa(esc, "%c%02x", escape_char, *str); + str++; + } + for (; *str != '\0'; str++) { + if (*str == ns->sep && change_sep) + str_append_c(esc, ns->list->hierarchy_sep); + else if (*str == ns->list->hierarchy_sep || + *str == escape_char || *str == '/') + str_printfa(esc, "%c%02x", escape_char, *str); + else + str_append_c(esc, *str); + } + return str_c(esc); +} + +static void list_unescape_str(struct mail_namespace *ns, + const char *str, string_t *dest) +{ + unsigned int num; + + for (; *str != '\0'; str++) { + if (*str == escape_char && + i_isxdigit(str[1]) && i_isxdigit(str[2])) { + if (str[1] >= '0' && str[1] <= '9') + num = str[1] - '0'; + else + num = i_toupper(str[1]) - 'A' + 10; + num *= 16; + if (str[2] >= '0' && str[2] <= '9') + num += str[2] - '0'; + else + num += i_toupper(str[2]) - 'A' + 10; + + str_append_c(dest, num); + str += 2; + } else if (*str == ns->list->hierarchy_sep) + str_append_c(dest, ns->sep); + else + str_append_c(dest, *str); + } +} + +static struct mailbox_list_iterate_context * +listescape_mailbox_list_iter_init(struct mailbox_list *list, + const char *const *patterns, + enum mailbox_list_iter_flags flags) +{ + struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list); + struct mailbox_list_iterate_context *ctx; + const char **escaped_patterns; + unsigned int i; + + t_push(); + if ((flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0) { + escaped_patterns = t_new(const char *, + str_array_length(patterns) + 1); + for (i = 0; patterns[i] != NULL; i++) { + escaped_patterns[i] = + list_escape(list->ns, patterns[i], FALSE); + } + patterns = escaped_patterns; + } + + /* Listing breaks if ns->real_sep isn't correct, but with everything + else we need real_sep == virtual_sep. maybe some day lib-storage + API gets changed so that it sees only virtual mailbox names and + convers them internally and we don't have this problem. */ + list->ns->real_sep = list->hierarchy_sep; + ctx = mlist->module_ctx.super.iter_init(list, patterns, flags); + list->ns->real_sep = list->ns->sep; + t_pop(); + return ctx; +} + +static const struct mailbox_info * +listescape_mailbox_list_iter_next(struct mailbox_list_iterate_context *ctx) +{ + struct listescape_mailbox_list *mlist = + LIST_ESCAPE_LIST_CONTEXT(ctx->list); + const struct mailbox_info *info; + + ctx->list->ns->real_sep = ctx->list->hierarchy_sep; + info = mlist->module_ctx.super.iter_next(ctx); + ctx->list->ns->real_sep = ctx->list->ns->sep; + if (info == NULL || (ctx->flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) == 0) + return info; + + str_truncate(mlist->list_name, 0); + list_unescape_str(ctx->list->ns, info->name, mlist->list_name); + mlist->info = *info; + mlist->info.name = str_c(mlist->list_name); + return &mlist->info; +} + +static int +listescape_mailbox_list_iter_deinit(struct mailbox_list_iterate_context *ctx) +{ + struct mailbox_list *list = ctx->list; + struct listescape_mailbox_list *mlist = + LIST_ESCAPE_LIST_CONTEXT(ctx->list); + int ret; + + list->ns->real_sep = list->hierarchy_sep; + ret = mlist->module_ctx.super.iter_deinit(ctx); + list->ns->real_sep = list->ns->sep; + return ret; +} + +static struct mailbox * +listescape_mailbox_open(struct mail_storage *storage, const char *name, + struct istream *input, enum mailbox_open_flags flags) +{ + struct listescape_mail_storage *mstorage = + LIST_ESCAPE_CONTEXT(storage); + struct listescape_mailbox_list *mlist = + LIST_ESCAPE_LIST_CONTEXT(storage->list); + + if (!mlist->name_escaped) + name = list_escape(storage->ns, name, TRUE); + return mstorage->module_ctx.super. + mailbox_open(storage, name, input, flags); +} + +static int +listescape_mailbox_create(struct mail_storage *storage, const char *name, + bool directory) +{ + struct listescape_mail_storage *mstorage = + LIST_ESCAPE_CONTEXT(storage); + + name = list_escape(storage->ns, name, TRUE); + return mstorage->module_ctx.super. + mailbox_create(storage, name, directory); +} + +static int +listescape_delete_mailbox(struct mailbox_list *list, const char *name) +{ + struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list); + int ret; + + /* at least quota plugin opens the mailbox when deleting it */ + name = list_escape(list->ns, name, TRUE); + mlist->name_escaped = TRUE; + ret = mlist->module_ctx.super.delete_mailbox(list, name); + mlist->name_escaped = FALSE; + return ret; +} + +static int +listescape_rename_mailbox(struct mailbox_list *list, const char *oldname, + const char *newname) +{ + struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list); + + oldname = list_escape(list->ns, oldname, TRUE); + newname = list_escape(list->ns, newname, TRUE); + return mlist->module_ctx.super.rename_mailbox(list, oldname, newname); +} + +static int listescape_set_subscribed(struct mailbox_list *list, + const char *name, bool set) +{ + struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list); + + name = list_escape(list->ns, name, TRUE); + return mlist->module_ctx.super.set_subscribed(list, name, set); +} + +static int listescape_get_mailbox_name_status(struct mailbox_list *list, + const char *name, + enum mailbox_name_status *status) +{ + struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list); + + name = list_escape(list->ns, name, TRUE); + return mlist->module_ctx.super. + get_mailbox_name_status(list, name, status); +} + +static bool listescape_is_valid_existing_name(struct mailbox_list *list, + const char *name) +{ + struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list); + + name = list_escape(list->ns, name, TRUE); + return mlist->module_ctx.super.is_valid_existing_name(list, name); +} + +static bool listescape_is_valid_create_name(struct mailbox_list *list, + const char *name) +{ + struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list); + + name = list_escape(list->ns, name, TRUE); + return mlist->module_ctx.super.is_valid_create_name(list, name); +} + +static void listescape_mail_storage_created(struct mail_storage *storage) +{ + struct listescape_mail_storage *mstorage; + + if (listescape_next_hook_mail_storage_created != NULL) + listescape_next_hook_mail_storage_created(storage); + + if (storage->list->hierarchy_sep == storage->ns->sep) + return; + + mstorage = p_new(storage->pool, struct listescape_mail_storage, 1); + mstorage->module_ctx.super = storage->v; + storage->v.mailbox_open = listescape_mailbox_open; + storage->v.mailbox_create = listescape_mailbox_create; + + MODULE_CONTEXT_SET(storage, listescape_storage_module, mstorage); +} + +static void listescape_mailbox_list_created(struct mailbox_list *list) +{ + struct listescape_mailbox_list *mlist; + + if (listescape_next_hook_mailbox_list_created != NULL) + listescape_next_hook_mailbox_list_created(list); + + if (list->hierarchy_sep == list->ns->sep) + return; + + mlist = p_new(list->pool, struct listescape_mailbox_list, 1); + mlist->module_ctx.super = list->v; + mlist->list_name = str_new(list->pool, 256); + list->v.iter_init = listescape_mailbox_list_iter_init; + list->v.iter_next = listescape_mailbox_list_iter_next; + list->v.iter_deinit = listescape_mailbox_list_iter_deinit; + list->v.delete_mailbox = listescape_delete_mailbox; + list->v.rename_mailbox = listescape_rename_mailbox; + list->v.set_subscribed = listescape_set_subscribed; + list->v.get_mailbox_name_status = listescape_get_mailbox_name_status; + list->v.is_valid_existing_name = listescape_is_valid_existing_name; + list->v.is_valid_create_name = listescape_is_valid_create_name; + + MODULE_CONTEXT_SET(list, listescape_list_module, mlist); +} + +static void +listescape_mail_namespaces_created(struct mail_namespace *namespaces) +{ + for (; namespaces != NULL; namespaces = namespaces->next) { + if (namespaces->real_sep != namespaces->sep) + namespaces->real_sep = namespaces->sep; + } +} + +void listescape_plugin_init(void) +{ + const char *env; + + env = getenv("LISTESCAPE_CHAR"); + if (env != NULL && *env != '\0') + escape_char = env[0]; + + listescape_next_hook_mail_storage_created = hook_mail_storage_created; + hook_mail_storage_created = listescape_mail_storage_created; + + listescape_next_hook_mailbox_list_created = hook_mailbox_list_created; + hook_mailbox_list_created = listescape_mailbox_list_created; + + listescape_next_hook_mail_namespaces_created = + hook_mail_namespaces_created; + hook_mail_namespaces_created = listescape_mail_namespaces_created; +} + +void listescape_plugin_deinit(void) +{ + hook_mail_storage_created = listescape_next_hook_mail_storage_created; + hook_mailbox_list_created = listescape_next_hook_mailbox_list_created; + hook_mail_namespaces_created = + listescape_next_hook_mail_namespaces_created; +} diff -r 698fca0d8b0a -r 0d1bd98a6387 src/plugins/listescape/listescape-plugin.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/listescape/listescape-plugin.h Sat Oct 18 23:45:41 2008 +0300 @@ -0,0 +1,7 @@ +#ifndef LISTESCAPE_PLUGIN_H +#define LISTESCAPE_PLUGIN_H + +void listescape_plugin_init(void); +void listescape_plugin_deinit(void); + +#endif