Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-storage/index/shared/shared-storage.c @ 8319:8553bb4c53ad HEAD
Fixed shared mailboxes to work with plugins.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 23 Oct 2008 20:15:16 +0300 |
parents | 4296aa3fbb75 |
children | b46cf0979768 |
line wrap: on
line source
/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "array.h" #include "str.h" #include "var-expand.h" #include "shared-storage.h" #define SHARED_LIST_CONTEXT(obj) \ MODULE_CONTEXT(obj, shared_mailbox_list_module) extern struct mail_storage shared_storage; extern struct mailbox shared_mailbox; static MODULE_CONTEXT_DEFINE_INIT(shared_mailbox_list_module, &mailbox_list_module_register); static struct mail_storage *shared_alloc(void) { struct shared_storage *storage; pool_t pool; pool = pool_alloconly_create("shared storage", 256); storage = p_new(pool, struct shared_storage, 1); storage->storage = shared_storage; storage->storage.pool = pool; storage->storage.storage_class = &shared_storage; return &storage->storage; } static int shared_create(struct mail_storage *_storage, const char *data, const char **error_r) { struct shared_storage *storage = (struct shared_storage *)_storage; struct mailbox_list_settings list_set; const char *driver, *p; bool have_username; /* data must begin with the actual mailbox driver */ p = strchr(data, ':'); if (p == NULL) { *error_r = "Shared mailbox location not prefixed with driver"; return -1; } driver = t_strdup_until(data, p); storage->location = p_strdup(_storage->pool, data); storage->storage_class = mail_storage_find_class(driver); if (storage->storage_class == NULL) { *error_r = t_strconcat("Unknown shared storage driver: ", driver, NULL); return -1; } _storage->mailbox_is_file = storage->storage_class->mailbox_is_file; p = strchr(_storage->ns->prefix, '%'); if (p == NULL) { *error_r = "Shared namespace prefix doesn't contain %"; return -1; } storage->ns_prefix_pattern = p_strdup(_storage->pool, p); _storage->ns->prefix = p_strdup_until(_storage->ns->user->pool, _storage->ns->prefix, p); have_username = FALSE; for (p = storage->ns_prefix_pattern; *p != '\0'; p++) { if (*p != '%') continue; if (*++p == '\0') break; if (*p == 'u' || *p == 'n') have_username = TRUE; else if (*p != 'd') break; } if (*p != '\0') { *error_r = "Shared namespace prefix contains unknown variables"; return -1; } if (!have_username) { *error_r = "Shared namespace prefix doesn't contain %u or %n"; return -1; } if (mailbox_list_alloc("shared", &_storage->list, error_r) < 0) return -1; MODULE_CONTEXT_SET_FULL(_storage->list, shared_mailbox_list_module, storage, &storage->list_module_ctx); memset(&list_set, 0, sizeof(list_set)); list_set.mail_storage_flags = &_storage->flags; list_set.lock_method = &_storage->lock_method; mailbox_list_init(_storage->list, _storage->ns, &list_set, mail_storage_get_list_flags(_storage->flags)); return 0; } int shared_storage_get_namespace(struct mail_storage *_storage, const char **_name, struct mail_namespace **ns_r) { struct shared_storage *storage = (struct shared_storage *)_storage; struct mail_user *user = _storage->ns->user; static struct var_expand_table static_tab[] = { { 'u', NULL }, { 'n', NULL }, { 'd', NULL }, { '\0', NULL } }; struct var_expand_table *tab; struct mail_namespace *ns; const char *domain = NULL, *username = NULL, *userdomain = NULL; const char *name, *p, *next, **dest, *error; string_t *prefix, *location; p = storage->ns_prefix_pattern; for (name = *_name; *p != '\0';) { if (*p != '%') { if (*p != *name) return -1; p++; name++; continue; } switch (*++p) { case 'd': dest = &domain; break; case 'n': dest = &username; break; case 'u': dest = &userdomain; break; default: /* we checked this already above */ i_unreached(); } p++; next = strchr(name, *p != '\0' ? *p : _storage->ns->sep); if (next == NULL) return -1; *dest = t_strdup_until(name, next); name = next; } /* successfully matched the name. */ if (userdomain == NULL) { i_assert(username != NULL); userdomain = domain == NULL ? username : t_strconcat(username, "@", domain, NULL); } else { domain = strchr(userdomain, '@'); if (domain == NULL) username = userdomain; else { username = t_strdup_until(userdomain, domain); domain++; } } /* expand the namespace prefix and see if it already exists. this should normally happen only when the mailbox is being opened */ tab = t_malloc(sizeof(static_tab)); memcpy(tab, static_tab, sizeof(static_tab)); tab[0].value = userdomain; tab[1].value = username; tab[2].value = domain; prefix = t_str_new(128); str_append(prefix, _storage->ns->prefix); var_expand(prefix, storage->ns_prefix_pattern, tab); ns = mail_namespace_find_prefix(user->namespaces, str_c(prefix)); if (ns != NULL) { *_name = mail_namespace_fix_sep(ns, name); *ns_r = ns; return 0; } /* create the new namespace */ ns = p_new(user->pool, struct mail_namespace, 1); ns->type = NAMESPACE_SHARED; ns->user = user; ns->prefix = p_strdup(user->pool, str_c(prefix)); ns->flags = NAMESPACE_FLAG_LIST | NAMESPACE_FLAG_HIDDEN | NAMESPACE_FLAG_AUTOCREATED; ns->sep = _storage->ns->sep; location = t_str_new(256); var_expand(location, storage->location, tab); if (mail_storage_create(ns, NULL, str_c(location), _storage->flags, _storage->lock_method, &error) < 0) { i_error("Namespace '%s': %s", ns->prefix, error); return -1; } /* FIXME: we could remove namespaces here that don't have usable mailboxes. otherwise the memory usage could just keep growing. */ mail_user_add_namespace(user, ns); *_name = mail_namespace_fix_sep(ns, name); *ns_r = ns; return 0; } static void shared_mailbox_copy_error(struct mail_storage *shared_storage, struct mail_namespace *backend_ns) { const char *str; enum mail_error error; str = mail_storage_get_last_error(backend_ns->storage, &error); mail_storage_set_error(shared_storage, error, str); } static struct mailbox * shared_mailbox_open(struct mail_storage *storage, const char *name, struct istream *input, enum mailbox_open_flags flags) { struct mail_namespace *ns; struct mailbox *box; if (input != NULL) { mail_storage_set_critical(storage, "Shared storage doesn't support streamed mailboxes"); return NULL; } if (shared_storage_get_namespace(storage, &name, &ns) < 0) return NULL; /* if we call the normal mailbox_open() here the plugins will see mailbox_open() called twice and they could break. */ box = ns->storage->storage_class->v. mailbox_open(ns->storage, name, NULL, flags); if (box == NULL) shared_mailbox_copy_error(storage, ns); return box; } static int shared_mailbox_create(struct mail_storage *storage, const char *name, bool directory) { struct mail_namespace *ns; int ret; if (shared_storage_get_namespace(storage, &name, &ns) < 0) return -1; ret = mail_storage_mailbox_create(ns->storage, name, directory); if (ret < 0) shared_mailbox_copy_error(storage, ns); return ret; } struct mail_storage shared_storage = { MEMBER(name) SHARED_STORAGE_NAME, MEMBER(mailbox_is_file) FALSE, /* unknown at this point */ { NULL, NULL, shared_alloc, shared_create, index_storage_destroy, NULL, shared_mailbox_open, shared_mailbox_create } };