/* Copyright (C) 2007 Timo Sirainen, LGPLv2.1 */ /* export DOVECOT=~/src/dovecot-1.0.0 gcc -fPIC -g -shared -Wall -I$DOVECOT -I$DOVECOT/src/lib \ -I$DOVECOT/src/lib-storage -I$DOVECOT/src/lib-mail \ -I$DOVECOT/src/lib-imap -DHAVE_CONFIG_H \ listescape-plugin.c -o listescape_plugin.so */ #include "lib.h" #include "array.h" #include "str.h" #include "mail-storage-private.h" #include #define ESCAPE_CHAR '\\' #define REAL_SEP '.' #define VIRTUAL_SEP '/' #define LIST_ESCAPE_CONTEXT(obj) \ *((void **)array_idx_modifyable(&(obj)->module_contexts, \ listescape_storage_module_id)) struct listescape_mail_storage { struct mail_storage_vfuncs super; string_t *list_name; }; /* defined by imap, pop3, lda */ extern void (*hook_mail_storage_created)(struct mail_storage *storage); const char *listescape_plugin_version = PACKAGE_VERSION; static void (*listescape_next_hook_mail_storage_created) (struct mail_storage *storage); static unsigned int listescape_storage_module_id = 0; static bool listescape_storage_module_id_set = FALSE; static const char *list_escape(const char *str) { string_t *esc = t_str_new(64); if (*str == '~') { str_printfa(esc, "%c%02x", ESCAPE_CHAR, *str); str++; } for (; *str != '\0'; str++) { if (*str == REAL_SEP || *str == ESCAPE_CHAR) str_printfa(esc, "%c%02x", ESCAPE_CHAR, *str); else if (*str == VIRTUAL_SEP) str_append_c(esc, REAL_SEP); else str_append_c(esc, *str); } return str_c(esc); } static void list_unescape_str(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 == REAL_SEP) str_append_c(dest, VIRTUAL_SEP); else str_append_c(dest, *str); } } static struct mailbox_list_context * listescape_mailbox_list_init(struct mail_storage *storage, const char *ref, const char *mask, enum mailbox_list_flags flags) { struct listescape_mail_storage *mstorage = LIST_ESCAPE_CONTEXT(storage); ref = list_escape(ref); mask = list_escape(mask); return mstorage->super.mailbox_list_init(storage, ref, mask, flags); } static struct mailbox_list * listescape_mailbox_list_next(struct mailbox_list_context *ctx) { struct listescape_mail_storage *mstorage = LIST_ESCAPE_CONTEXT(ctx->storage); struct mailbox_list *list; list = mstorage->super.mailbox_list_next(ctx); if (list == NULL) return NULL; str_truncate(mstorage->list_name, 0); list_unescape_str(list->name, mstorage->list_name); list->name = str_c(mstorage->list_name); return list; } static int listescape_mailbox_list_deinit(struct mailbox_list_context *ctx) { struct listescape_mail_storage *mstorage = LIST_ESCAPE_CONTEXT(ctx->storage); return mstorage->super.mailbox_list_deinit(ctx); } 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); name = list_escape(name); return mstorage->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(name); return mstorage->super.mailbox_create(storage, name, directory); } static int listescape_mailbox_delete(struct mail_storage *storage, const char *name) { struct listescape_mail_storage *mstorage = LIST_ESCAPE_CONTEXT(storage); name = list_escape(name); return mstorage->super.mailbox_delete(storage, name); } static int listescape_mailbox_rename(struct mail_storage *storage, const char *oldname, const char *newname) { struct listescape_mail_storage *mstorage = LIST_ESCAPE_CONTEXT(storage); oldname = list_escape(oldname); newname = list_escape(newname); return mstorage->super.mailbox_rename(storage, oldname, newname); } static int listescape_set_subscribed(struct mail_storage *storage, const char *name, bool set) { struct listescape_mail_storage *mstorage = LIST_ESCAPE_CONTEXT(storage); name = list_escape(name); return mstorage->super.set_subscribed(storage, name, set); } static int listescape_get_mailbox_name_status(struct mail_storage *storage, const char *name, enum mailbox_name_status *status) { struct listescape_mail_storage *mstorage = LIST_ESCAPE_CONTEXT(storage); name = list_escape(name); return mstorage->super.get_mailbox_name_status(storage, name, status); } 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); mstorage = p_new(storage->pool, struct listescape_mail_storage, 1); mstorage->super = storage->v; mstorage->list_name = str_new(storage->pool, 256); storage->hierarchy_sep = VIRTUAL_SEP; storage->v.mailbox_list_init = listescape_mailbox_list_init; storage->v.mailbox_list_next = listescape_mailbox_list_next; storage->v.mailbox_list_deinit = listescape_mailbox_list_deinit; storage->v.mailbox_open = listescape_mailbox_open; storage->v.mailbox_create = listescape_mailbox_create; storage->v.mailbox_delete = listescape_mailbox_delete; storage->v.mailbox_rename = listescape_mailbox_rename; storage->v.set_subscribed = listescape_set_subscribed; storage->v.get_mailbox_name_status = listescape_get_mailbox_name_status; if (!listescape_storage_module_id_set) { listescape_storage_module_id = mail_storage_module_id++; listescape_storage_module_id_set = TRUE; } array_idx_set(&storage->module_contexts, listescape_storage_module_id, &mstorage); } void listescape_plugin_init(void); void listescape_plugin_deinit(void); void listescape_plugin_init(void) { listescape_next_hook_mail_storage_created = hook_mail_storage_created; hook_mail_storage_created = listescape_mail_storage_created; } void listescape_plugin_deinit(void) { hook_mail_storage_created = listescape_next_hook_mail_storage_created; }