+ - check:
+ - dsyncing between two namespace separators is probably broken..
- remove mail_deliver_session after all, do all the stuff transparently
by hooking into mailbox_copy().
- use this hook also to do the mail deduplication: 1) sort all destination
struct mail_namespace *ns;
struct mailbox *box;
enum mail_error error;
- const char *errstr, *storage_name;
+ const char *errstr;
if (*ctx->dest_parent != '\0') {
/* prefix destination mailbox name with given parent mailbox */
- storage_name = ctx->dest_parent;
- ns = mail_namespace_find(user->namespaces, &storage_name);
+ ns = mail_namespace_find(user->namespaces, ctx->dest_parent);
if (ns == NULL) {
i_error("Can't find namespace for parent mailbox %s",
ctx->dest_parent);
return -1;
}
name = t_strdup_printf("%s%c%s", ctx->dest_parent,
- ns->sep, name);
+ mail_namespace_get_sep(ns), name);
}
- storage_name = name;
- ns = mail_namespace_find(user->namespaces, &storage_name);
+ ns = mail_namespace_find(user->namespaces, name);
if (ns == NULL) {
i_error("Can't find namespace for mailbox %s", name);
return -1;
}
- box = mailbox_alloc(ns->list, storage_name, MAILBOX_FLAG_SAVEONLY |
+ box = mailbox_alloc(ns->list, name, MAILBOX_FLAG_SAVEONLY |
MAILBOX_FLAG_KEEP_RECENT);
if (mailbox_create(box, NULL, FALSE) < 0) {
errstr = mailbox_get_last_error(box, &error);
struct doveadm_mail_iter **iter_r)
{
struct doveadm_mail_iter *iter;
- const char *storage_name;
-
- storage_name = mail_namespace_get_storage_name(info->ns, info->name);
iter = i_new(struct doveadm_mail_iter, 1);
- iter->box = mailbox_alloc(info->ns->list, storage_name,
+ iter->box = mailbox_alloc(info->ns->list, info->name,
MAILBOX_FLAG_KEEP_RECENT |
MAILBOX_FLAG_IGNORE_ACLS);
iter->search_args = search_args;
unsigned int len;
while ((info = mailbox_list_iter_next(iter->iter)) != NULL) {
+ char sep = mail_namespace_get_sep(info->ns);
+
if ((info->flags & (MAILBOX_NOSELECT |
MAILBOX_NONEXISTENT)) != 0) {
if (iter->only_selectable)
continue;
}
len = strlen(info->name);
- if (len > 0 && info->name[len-1] == info->ns->sep) {
+ if (len > 0 &&
+ info->name[len-1] == sep) {
/* when listing "foo/%" it lists "foo/". skip it. */
continue;
}
if (mail_search_args_match_mailbox(iter->search_args,
- info->name, info->ns->sep))
+ info->name, sep))
break;
}
return info;
struct mailbox_cmd_context *ctx = (struct mailbox_cmd_context *)_ctx;
struct mail_namespace *ns;
struct mailbox *box;
+ struct mail_storage *storage;
const char *const *namep;
array_foreach(&ctx->mailboxes, namep) {
- const char *storage_name = *namep;
+ const char *name = *namep;
unsigned int len;
bool directory = FALSE;
- ns = mail_namespace_find(user->namespaces, &storage_name);
+ ns = mail_namespace_find(user->namespaces, name);
if (ns == NULL)
- i_fatal("Can't find namespace for: %s", *namep);
+ i_fatal("Can't find namespace for: %s", name);
- len = strlen(storage_name);
- if (len > 0 && storage_name[len-1] == ns->real_sep) {
- storage_name = t_strndup(storage_name, len-1);
+ len = strlen(name);
+ if (len > 0 && name[len-1] == mail_namespace_get_sep(ns)) {
+ name = t_strndup(name, len-1);
directory = TRUE;
}
- box = mailbox_alloc(ns->list, storage_name, 0);
+ box = mailbox_alloc(ns->list, name, 0);
+ storage = mailbox_get_storage(box);
if (mailbox_create(box, NULL, directory) < 0) {
- i_error("Can't create mailbox %s: %s", *namep,
+ i_error("Can't create mailbox %s: %s", name,
mailbox_get_last_error(box, NULL));
}
if (ctx->ctx.subscriptions) {
- if (mailbox_list_set_subscribed(ns->list, storage_name,
- TRUE) < 0) {
- i_error("Can't subscribe to mailbox %s: %s", *namep,
- mailbox_list_get_last_error(ns->list, NULL));
+ if (mailbox_set_subscribed(box, TRUE) < 0) {
+ i_error("Can't subscribe to mailbox %s: %s", name,
+ mail_storage_get_last_error(storage, NULL));
}
}
mailbox_free(&box);
struct mailbox_cmd_context *ctx = (struct mailbox_cmd_context *)_ctx;
struct mail_namespace *ns;
struct mailbox *box;
+ struct mail_storage *storage;
const char *const *namep;
array_foreach(&ctx->mailboxes, namep) {
- const char *storage_name = *namep;
+ const char *name = *namep;
- ns = mail_namespace_find(user->namespaces, &storage_name);
+ ns = mail_namespace_find(user->namespaces, name);
if (ns == NULL)
- i_fatal("Can't find namespace for: %s", *namep);
+ i_fatal("Can't find namespace for: %s", name);
- box = mailbox_alloc(ns->list, storage_name, 0);
+ box = mailbox_alloc(ns->list, name, 0);
+ storage = mailbox_get_storage(box);
if (mailbox_delete(box) < 0) {
- i_error("Can't delete mailbox %s: %s", *namep,
+ i_error("Can't delete mailbox %s: %s", name,
mailbox_get_last_error(box, NULL));
}
if (ctx->ctx.subscriptions) {
- if (mailbox_list_set_subscribed(ns->list, storage_name,
- FALSE) < 0) {
- i_error("Can't unsubscribe mailbox %s: %s", *namep,
- mailbox_list_get_last_error(ns->list, NULL));
+ if (mailbox_set_subscribed(box, FALSE) < 0) {
+ i_error("Can't unsubscribe mailbox %s: %s", name,
+ mail_storage_get_last_error(storage, NULL));
}
}
mailbox_free(&box);
const char *oldname = ctx->oldname;
const char *newname = ctx->newname;
- oldns = mail_namespace_find(user->namespaces, &oldname);
+ oldns = mail_namespace_find(user->namespaces, oldname);
if (oldns == NULL)
i_fatal("Can't find namespace for: %s", oldname);
- newns = mail_namespace_find(user->namespaces, &newname);
+ newns = mail_namespace_find(user->namespaces, newname);
if (newns == NULL)
i_fatal("Can't find namespace for: %s", newname);
mailbox_get_last_error(oldbox, NULL));
}
if (ctx->ctx.subscriptions) {
- if (mailbox_list_set_subscribed(oldns->list, oldname, FALSE) < 0) {
+ if (mailbox_set_subscribed(oldbox, FALSE) < 0) {
i_error("Can't unsubscribe mailbox %s: %s", ctx->oldname,
- mailbox_list_get_last_error(oldns->list, NULL));
+ mailbox_get_last_error(oldbox, NULL));
}
- if (mailbox_list_set_subscribed(newns->list, newname, TRUE) < 0) {
+ if (mailbox_set_subscribed(newbox, TRUE) < 0) {
i_error("Can't subscribe to mailbox %s: %s", ctx->newname,
- mailbox_list_get_last_error(newns->list, NULL));
+ mailbox_get_last_error(newbox, NULL));
}
}
const char *const *namep;
array_foreach(&ctx->mailboxes, namep) {
- const char *storage_name = *namep;
+ const char *name = *namep;
- ns = mail_namespace_find(user->namespaces, &storage_name);
+ ns = mail_namespace_find(user->namespaces, name);
if (ns == NULL)
- i_fatal("Can't find namespace for: %s", *namep);
+ i_fatal("Can't find namespace for: %s", name);
- box = mailbox_alloc(ns->list, storage_name, 0);
- if (mailbox_list_set_subscribed(ns->list, storage_name,
- ctx->ctx.subscriptions) < 0) {
- i_error("Can't %s mailbox %s: %s", *namep,
+ box = mailbox_alloc(ns->list, name, 0);
+ if (mailbox_set_subscribed(box, ctx->ctx.subscriptions) < 0) {
+ i_error("Can't %s mailbox %s: %s", name,
ctx->ctx.subscriptions ? "subscribe to" :
"unsubscribe",
- mailbox_list_get_last_error(ns->list, NULL));
+ mail_storage_get_last_error(mailbox_get_storage(box), NULL));
}
mailbox_free(&box);
}
i_fatal("Mailbox name not valid UTF-8: %s", mailbox);
mailbox = str_c(str);
- ns = mail_namespace_find(user->namespaces, &mailbox);
+ ns = mail_namespace_find(user->namespaces, mailbox);
if (ns == NULL)
i_fatal("Can't find namespace for mailbox %s", mailbox);
#include "mail-namespace.h"
#include "mail-storage.h"
#include "mail-search-build.h"
+#include "mailbox-list-private.h"
#include "dsync-worker-private.h"
#include <ctype.h>
struct local_dsync_mailbox {
struct mail_namespace *ns;
mailbox_guid_t guid;
- const char *storage_name;
+ const char *name;
};
struct local_dsync_mailbox_change {
static void
local_dsync_worker_add_mailbox(struct local_dsync_worker *worker,
- struct mail_namespace *ns,
- const char *storage_name,
+ struct mail_namespace *ns, const char *name,
const mailbox_guid_t *guid)
{
struct local_dsync_mailbox *lbox;
lbox = p_new(worker->pool, struct local_dsync_mailbox, 1);
lbox->ns = ns;
memcpy(lbox->guid.guid, guid->guid, sizeof(lbox->guid.guid));
- lbox->storage_name = p_strdup(worker->pool, storage_name);
+ lbox->name = p_strdup(worker->pool, name);
hash_table_insert(worker->mailbox_hash, &lbox->guid, lbox);
}
return iter_next_deleted(iter, worker, dsync_box_r);
dsync_box_r->name = info->name;
- dsync_box_r->name_sep = info->ns->sep;
+ dsync_box_r->name_sep = mail_namespace_get_sep(info->ns);
- storage_name = mail_namespace_get_storage_name(info->ns, info->name);
+ storage_name = mailbox_list_get_storage_name(info->ns->list, info->name);
dsync_str_sha_to_guid(storage_name, &dsync_box_r->name_sha1);
/* get last change timestamp */
if ((info->flags & MAILBOX_NOSELECT) != 0) {
dsync_box_r->flags |= DSYNC_MAILBOX_FLAG_NOSELECT;
- local_dsync_worker_add_mailbox(worker, info->ns, storage_name,
+ local_dsync_worker_add_mailbox(worker, info->ns, info->name,
&dsync_box_r->name_sha1);
return 1;
}
- box = mailbox_alloc(info->ns->list, storage_name, flags);
+ box = mailbox_alloc(info->ns->list, info->name, flags);
if (mailbox_get_status(box, status_items, &status) < 0 ||
mailbox_get_metadata(box, metadata_items, &metadata) < 0) {
i_error("Failed to sync mailbox %s: %s", info->name,
i_error("Mailboxes don't have unique GUIDs: "
"%s is shared by %s and %s",
dsync_guid_to_str(&dsync_box_r->mailbox_guid),
- old_lbox->storage_name, storage_name);
+ old_lbox->name, info->name);
mailbox_free(&box);
_iter->failed = TRUE;
return -1;
}
- local_dsync_worker_add_mailbox(worker, info->ns, storage_name,
+ local_dsync_worker_add_mailbox(worker, info->ns, info->name,
&dsync_box_r->mailbox_guid);
mailbox_free(&box);
return 1;
return &iter->iter;
}
-static struct mail_namespace *
-find_subscription_ns(struct local_dsync_worker *worker, const char *vname)
-{
- struct mail_namespace *const *nsp;
-
- array_foreach(&worker->subs_namespaces, nsp) {
- if (strncmp((*nsp)->prefix, vname, (*nsp)->prefix_len) == 0)
- return *nsp;
- }
- return NULL;
-}
-
static int
local_worker_subs_iter_next(struct dsync_worker_subs_iter *_iter,
struct dsync_worker_subscription *rec_r)
(struct local_dsync_worker *)_iter->worker;
struct local_dsync_dir_change *change, change_lookup;
const struct mailbox_info *info;
- struct mail_namespace *subs_ns;
const char *storage_name;
memset(rec_r, 0, sizeof(*rec_r));
if (info == NULL)
return -1;
- subs_ns = find_subscription_ns(worker, info->name);
- if (subs_ns == NULL)
- subs_ns = info->ns;
- storage_name = mail_namespace_get_storage_name(subs_ns, info->name);
- if (subs_ns != info->ns)
- storage_name = t_strconcat(subs_ns->prefix, storage_name, NULL);
-
+ storage_name = mailbox_list_get_storage_name(info->ns->list, info->name);
dsync_str_sha_to_guid(storage_name, &change_lookup.name_sha1);
change_lookup.list = info->ns->list;
{
struct local_dsync_worker *worker =
(struct local_dsync_worker *)_worker;
- struct mail_namespace *ns, *subs_ns;
- const char *storage_name;
+ struct mail_namespace *ns;
+ struct mailbox *box;
- storage_name = name;
- ns = mail_namespace_find(worker->user->namespaces,
- &storage_name);
+ ns = mail_namespace_find(worker->user->namespaces, name);
if (ns == NULL) {
i_error("Can't find namespace for mailbox %s", name);
return;
}
- subs_ns = find_subscription_ns(worker, name);
- if (subs_ns != NULL) {
- /* subscription is being written to a different namespace
- than where the mailbox exists. */
- storage_name = mail_namespace_get_storage_name(subs_ns, name);
- storage_name = t_strconcat(subs_ns->prefix, storage_name, NULL);
- /* drop the common prefix */
- i_assert(strncmp(ns->prefix, storage_name,
- strlen(ns->prefix)) == 0);
- storage_name += strlen(ns->prefix);
- }
+ box = mailbox_alloc(ns->list, name, 0);
+ ns = mailbox_get_namespace(box);
mailbox_list_set_changelog_timestamp(ns->list, last_change);
- if (mailbox_list_set_subscribed(ns->list, storage_name, set) < 0) {
+ if (mailbox_set_subscribed(box, set) < 0) {
dsync_worker_set_failure(_worker);
i_error("Can't update subscription %s: %s", name,
- mailbox_list_get_last_error(ns->list, NULL));
+ mail_storage_get_last_error(mailbox_get_storage(box),
+ NULL));
}
mailbox_list_set_changelog_timestamp(ns->list, (time_t)-1);
+ mailbox_free(&box);
}
static int local_mailbox_open(struct local_dsync_worker *worker,
return -1;
}
- box = mailbox_alloc(lbox->ns->list, lbox->storage_name, flags);
+ box = mailbox_alloc(lbox->ns->list, lbox->name, flags);
if (mailbox_sync(box, 0) < 0 ||
mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) {
- i_error("Failed to sync mailbox %s: %s", lbox->storage_name,
+ i_error("Failed to sync mailbox %s: %s", lbox->name,
mailbox_get_last_error(box, NULL));
mailbox_free(&box);
return -1;
if (memcmp(metadata.guid, guid->guid, sizeof(guid->guid)) != 0) {
i_error("Mailbox %s changed its GUID (%s -> %s)",
- lbox->storage_name, dsync_guid_to_str(guid),
+ lbox->name, dsync_guid_to_str(guid),
mail_guid_128_to_string(metadata.guid));
mailbox_free(&box);
return -1;
const struct dsync_mailbox *dsync_box,
bool creating)
{
- if (dsync_box->name_sep != ns->sep) {
+ char list_sep, ns_sep = mail_namespace_get_sep(ns);
+
+ if (dsync_box->name_sep != ns_sep) {
/* mailbox names use different separators. convert them. */
name = mailbox_name_convert(worker, name,
- dsync_box->name_sep, ns->sep);
+ dsync_box->name_sep, ns_sep);
}
if (creating) {
+ list_sep = mailbox_list_get_hierarchy_sep(ns->list);
if (!mailbox_list_is_valid_create_name(ns->list, name)) {
/* change any real separators to alt separators,
drop any potentially invalid characters */
- name = mailbox_name_cleanup(name, ns->real_sep,
+ name = mailbox_name_cleanup(name, list_sep,
worker->alt_char);
}
if (!mailbox_list_is_valid_create_name(ns->list, name)) {
&dsync_box->mailbox_guid);
if (lbox != NULL) {
/* use the existing known mailbox name */
- return mailbox_alloc(lbox->ns->list, lbox->storage_name, 0);
+ return mailbox_alloc(lbox->ns->list, lbox->name, 0);
}
- name = dsync_box->name;
- ns = mail_namespace_find(worker->user->namespaces, &name);
+ ns = mail_namespace_find(worker->user->namespaces, dsync_box->name);
if (ns == NULL) {
i_error("Can't find namespace for mailbox %s", dsync_box->name);
return NULL;
}
- name = local_worker_convert_mailbox_name(worker, name, ns,
+ name = local_worker_convert_mailbox_name(worker, dsync_box->name, ns,
dsync_box, creating);
if (!dsync_mailbox_is_noselect(dsync_box)) {
local_dsync_worker_add_mailbox(worker, ns, name,
mailbox_list_set_changelog_timestamp(lbox->ns->list,
dsync_box->last_change);
- box = mailbox_alloc(lbox->ns->list, lbox->storage_name, 0);
+ box = mailbox_alloc(lbox->ns->list, lbox->name, 0);
if (mailbox_delete(box) < 0) {
- i_error("Can't delete mailbox %s: %s", lbox->storage_name,
+ i_error("Can't delete mailbox %s: %s", lbox->name,
mailbox_get_last_error(box, NULL));
dsync_worker_set_failure(_worker);
}
struct mail_namespace *ns;
const char *storage_name;
- storage_name = dsync_box->name;
- ns = mail_namespace_find(worker->user->namespaces, &storage_name);
+ ns = mail_namespace_find(worker->user->namespaces, dsync_box->name);
+ storage_name = mailbox_list_get_storage_name(ns->list, dsync_box->name);
mailbox_list_set_changelog_timestamp(ns->list, dsync_box->last_change);
if (mailbox_list_delete_dir(ns->list, storage_name) < 0) {
list = lbox->ns->list;
newname = local_worker_convert_mailbox_name(worker, dsync_box->name,
lbox->ns, dsync_box, TRUE);
- if (strcmp(lbox->storage_name, newname) == 0) {
+ if (strcmp(lbox->name, newname) == 0) {
/* nothing changed after all. probably because some characters
in mailbox name weren't valid. */
return;
}
mailbox_list_set_changelog_timestamp(list, dsync_box->last_change);
- old_box = mailbox_alloc(list, lbox->storage_name, 0);
+ old_box = mailbox_alloc(list, lbox->name, 0);
new_box = mailbox_alloc(list, newname, 0);
if (mailbox_rename(old_box, new_box, FALSE) < 0) {
- i_error("Can't rename mailbox %s to %s: %s", lbox->storage_name,
+ i_error("Can't rename mailbox %s to %s: %s", lbox->name,
newname, mailbox_get_last_error(old_box, NULL));
dsync_worker_set_failure(_worker);
} else {
- lbox->storage_name = p_strdup(worker->pool, newname);
+ lbox->name = p_strdup(worker->pool, newname);
}
mailbox_free(&old_box);
mailbox_free(&new_box);
bool cmd_create(struct client_command_context *cmd)
{
struct mail_namespace *ns;
- const char *mailbox, *storage_name;
+ const char *mailbox, *orig_mailbox;
struct mailbox *box;
bool directory;
size_t len;
if (!client_read_string_args(cmd, 1, &mailbox))
return FALSE;
- ns = client_find_namespace(cmd, mailbox, &storage_name);
+ orig_mailbox = mailbox;
+ ns = client_find_namespace(cmd, &mailbox);
if (ns == NULL)
return TRUE;
- len = strlen(mailbox);
- if (len == 0 || mailbox[len-1] != ns->sep)
+ len = strlen(orig_mailbox);
+ if (len == 0 || orig_mailbox[len-1] != mail_namespace_get_sep(ns))
directory = FALSE;
- else if (*storage_name == '\0') {
- client_send_tagline(cmd, "NO ["IMAP_RESP_CODE_ALREADYEXISTS
- "] Namespace already exists.");
- return TRUE;
- } else {
+ else {
/* name ends with hierarchy separator - client is just
informing us that it wants to create children under this
mailbox. */
directory = TRUE;
- mailbox = t_strndup(mailbox, len-1);
- /* drop also from storage_name. it's already dropped when
+ /* drop separator from mailbox. it's already dropped when
WORKAROUND_TB_EXTRA_MAILBOX_SEP is enabled */
- len = strlen(storage_name);
- if (storage_name[len-1] == ns->real_sep)
- storage_name = t_strndup(storage_name, len-1);
+ if (len == strlen(mailbox))
+ mailbox = t_strndup(mailbox, len-1);
}
- ns = client_find_namespace(cmd, mailbox, &storage_name);
- if (ns == NULL)
- return TRUE;
-
- box = mailbox_alloc(ns->list, storage_name, 0);
+ box = mailbox_alloc(ns->list, mailbox, 0);
if (mailbox_create(box, NULL, directory) < 0)
client_send_storage_error(cmd, mailbox_get_storage(box));
else
struct client *client = cmd->client;
struct mail_namespace *ns;
struct mailbox *box;
- const char *name, *storage_name;
+ const char *name;
/* <mailbox> */
if (!client_read_string_args(cmd, 1, &name))
return TRUE;
}
- ns = client_find_namespace(cmd, name, &storage_name);
+ ns = client_find_namespace(cmd, &name);
if (ns == NULL)
return TRUE;
- box = mailbox_alloc(ns->list, storage_name, 0);
+ box = mailbox_alloc(ns->list, name, 0);
if (client->mailbox != NULL &&
mailbox_backends_equal(box, client->mailbox)) {
/* deleting selected mailbox. close it first */
bool inboxcase;
inboxcase = strncasecmp(ctx->ns->prefix, "INBOX", 5) == 0 &&
- ctx->ns->prefix[5] == ctx->ns->sep;
+ ctx->ns->prefix[5] == mail_namespace_get_sep(ctx->ns);
glob = imap_match_init_multiple(pool_datastack_create(),
ctx->patterns, inboxcase,
- ctx->ns->sep);
+ mail_namespace_get_sep(ctx->ns));
ns_prefix = ctx->ns->prefix;
match = imap_match(glob, ns_prefix);
if (match == IMAP_MATCH_YES) {
}
while ((match & IMAP_MATCH_PARENT) != 0) {
- p = strrchr(ns_prefix, ctx->ns->sep);
+ p = strrchr(ns_prefix, mail_namespace_get_sep(ctx->ns));
i_assert(p != NULL);
ns_prefix = t_strdup_until(ns_prefix, p);
match = imap_match(glob, ns_prefix);
return ns_prefix;
}
+static void list_reply_append_ns_sep_param(string_t *str, char sep)
+{
+ str_append_c(str, '"');
+ if (sep == '\\')
+ str_append(str, "\\\\");
+ else
+ str_append_c(str, sep);
+ str_append_c(str, '"');
+}
+
static void
list_namespace_send_prefix(struct cmd_list_context *ctx, bool have_children)
{
const char *name;
string_t *str;
bool same_ns, ends_with_sep;
+ char ns_sep = mail_namespace_get_sep(ctx->ns);
ctx->cur_ns_send_prefix = FALSE;
name = ns_get_listed_prefix(ctx);
len = strlen(ctx->ns->prefix);
- ends_with_sep = ctx->ns->prefix[len-1] == ctx->ns->sep;
+ ends_with_sep = ctx->ns->prefix[len-1] == ns_sep;
/* we may be listing namespace's parent. in such case we always want to
set the name as nonexistent. */
}
str = t_str_new(128);
- str_append(str, "* LIST (");
+ str_printfa(str, "* %s (", ctx->lsub ? "LSUB" : "LIST");
+ if (ctx->lsub)
+ flags |= MAILBOX_NONEXISTENT;
mailbox_flags2str(ctx, str, flags);
- str_printfa(str, ") \"%s\" ", ctx->ns->sep_str);
+ str_append(str, ") ");
+ list_reply_append_ns_sep_param(str, ns_sep);
+ str_append_c(str, ' ');
imap_quote_append_string(str, name, FALSE);
mailbox_childinfo2str(ctx, str, flags);
{
struct imap_status_result result;
struct mail_namespace *ns;
- const char *storage_name, *error;
+ const char *error;
if ((flags & (MAILBOX_NONEXISTENT | MAILBOX_NOSELECT)) != 0) {
/* doesn't exist, don't even try to get STATUS */
/* if we're listing subscriptions and there are subscriptions=no
namespaces, ctx->ns may not point to correct one */
- storage_name = name;
- ns = mail_namespace_find(ctx->ns->user->namespaces, &storage_name);
- if (imap_status_get(ctx->cmd, ns, storage_name,
+ ns = mail_namespace_find(ctx->ns->user->namespaces, name);
+ if (imap_status_get(ctx->cmd, ns, name,
&ctx->status_items, &result, &error) < 0) {
client_send_line(ctx->cmd->client,
t_strconcat("* ", error, NULL));
str_truncate(str, 0);
str_printfa(str, "* %s (", ctx->lsub ? "LSUB" : "LIST");
mailbox_flags2str(ctx, str, flags);
- str_printfa(str, ") \"%s\" ", ctx->ns->sep_str);
+ str_append(str, ") ");
+ list_reply_append_ns_sep_param(str,
+ mail_namespace_get_sep(ctx->ns));
+ str_append_c(str, ' ');
imap_quote_append_string(str, name, FALSE);
mailbox_childinfo2str(ctx, str, flags);
-> cur_ns_prefix="", cur_ref="baz"
*/
skip_namespace_prefix(&cur_ns_prefix, &cur_ref, TRUE,
- ctx->ns->sep);
+ mail_namespace_get_sep(ctx->ns));
if (*cur_ref != '\0' && *cur_ns_prefix != '\0') {
/* reference parameter didn't match with
i_assert(*cur_ref == '\0');
skip_namespace_prefix(&cur_ns_prefix, &cur_pattern,
- cur_ref == ctx->ref, ctx->ns->sep);
+ cur_ref == ctx->ref,
+ mail_namespace_get_sep(ctx->ns));
if (*cur_pattern == '\0' && *cur_ns_prefix == '\0') {
/* trying to list the namespace prefix itself. */
inbox_glob =
imap_match_init(pool_datastack_create(),
t_strconcat(ctx->ref, *pat, NULL),
- TRUE, ctx->ns->sep);
+ TRUE, mail_namespace_get_sep(ctx->ns));
match = imap_match(inbox_glob, "INBOX");
if (match == IMAP_MATCH_YES)
list_want_send_prefix(struct cmd_list_context *ctx, const char *pattern)
{
/* don't send the prefix if we're listing subscribed mailboxes */
- if ((ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
- if ((ctx->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0) {
- /* using parent's subscriptions file. it'll handle
- this internally */
- return FALSE;
- }
- /* send prefix if namespace has at least some subscriptions,
- but pattern doesn't match any children (e.g. "%") */
- return TRUE;
- }
+ if ((ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0)
+ return FALSE;
/* send the prefix if namespace is listable. if children are listable
we may or may not need to send it. */
don't do it if we're listing only the prefix itself
(LIST "" foo/ needs to return "foo/" entry) */
len = strlen(cur_ns_prefix);
- if (cur_ns_prefix[len-1] == ns->sep &&
+ if (cur_ns_prefix[len-1] == mail_namespace_get_sep(ns) &&
strcmp(cur_pattern, cur_ns_prefix) != 0) {
ctx->cur_ns_skip_trailing_sep = TRUE;
cur_ns_prefix = t_strndup(cur_ns_prefix, len-1);
/* check if this namespace prefix matches the current pattern */
pat_glob = imap_match_init(pool_datastack_create(), orig_cur_pattern,
- inboxcase, ns->sep);
+ inboxcase, mail_namespace_get_sep(ns));
match = imap_match(pat_glob, cur_ns_prefix);
if (match == IMAP_MATCH_YES) {
if (list_want_send_prefix(ctx, orig_cur_pattern))
if (*p == '*')
return TRUE;
}
+ if ((ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
+ /* the namespace prefix itself may be subscribed. */
+ return TRUE;
+ }
+ return FALSE;
} else {
while ((match & IMAP_MATCH_PARENT) != 0) {
- p = strrchr(cur_ns_prefix, ns->sep);
+ p = strrchr(cur_ns_prefix, mail_namespace_get_sep(ns));
if (p == NULL)
break;
cur_ns_prefix = t_strdup_until(cur_ns_prefix, p);
if (list_want_send_prefix(ctx, orig_cur_pattern))
ctx->cur_ns_send_prefix = TRUE;
}
+ return (match & IMAP_MATCH_CHILDREN) != 0;
}
-
- return (match & IMAP_MATCH_CHILDREN) != 0;
}
static void list_namespace_init(struct cmd_list_context *ctx)
cur_ns_prefix = ns->prefix;
cur_ref = ctx->ref;
- if ((ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0 &&
- (ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
- /* ignore namespaces which don't have subscriptions */
- return;
- }
-
ctx->cur_ns_skip_trailing_sep = FALSE;
if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0)
(void)array_append_space(&used_patterns); /* NULL-terminate */
pat = array_idx(&used_patterns, 0);
- cur_ref = mail_namespace_fix_sep(ns, cur_ref);
ctx->list_iter = mailbox_list_iter_init_multiple(ns->list, pat,
ctx->list_flags);
}
static void list_inbox(struct cmd_list_context *ctx)
{
- const char *str;
+ string_t *str;
/* INBOX always exists */
if (!ctx->inbox_found && ctx->cur_ns_match_inbox &&
(ctx->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
(ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) {
- str = t_strdup_printf("* LIST (\\Unmarked) \"%s\" \"INBOX\"",
- ctx->ns->sep_str);
- client_send_line(ctx->cmd->client, str);
+ str = t_str_new(64);
+ str_append(str, "* LIST (\\Unmarked) ");
+ list_reply_append_ns_sep_param(str,
+ mail_namespace_get_sep(ctx->ns));
+ str_append(str, " \"INBOX\"");
+ client_send_line(ctx->cmd->client, str_c(str));
}
}
/* Special request to return the hierarchy delimiter and mailbox root
name. If namespace has a prefix, it's returned as the mailbox root.
Otherwise we'll emulate UW-IMAP behavior. */
- ns = mail_namespace_find_visible(client->user->namespaces, &ref);
+ ns = mail_namespace_find_visible(client->user->namespaces, ref);
if (ns != NULL) {
ns_prefix = ns->prefix;
- ns_sep = ns->sep;
+ ns_sep = mail_namespace_get_sep(ns);
} else {
ns_prefix = "";
ns_sep = mail_namespaces_get_root_sep(client->user->namespaces);
static void list_namespaces(struct mail_namespace *ns,
enum namespace_type type, string_t *str)
{
+ char ns_sep;
bool found = FALSE;
while (ns != NULL) {
str_append_c(str, '(');
found = TRUE;
}
+ ns_sep = mail_namespace_get_sep(ns);
str_append_c(str, '(');
imap_quote_append_string(str, ns->prefix, FALSE);
str_append(str, " \"");
- str_append(str, ns->sep_str);
+ if (ns_sep == '\\')
+ str_append_c(str, '\\');
+ str_append_c(str, ns_sep);
str_append(str, "\")");
}
{
struct mail_namespace *old_ns, *new_ns;
struct mailbox *old_box, *new_box;
- const char *oldname, *newname, *storage_oldname, *storage_newname;
+ const char *oldname, *newname;
unsigned int oldlen;
/* <old name> <new name> */
if (!client_read_string_args(cmd, 2, &oldname, &newname))
return FALSE;
- old_ns = client_find_namespace(cmd, oldname, &storage_oldname);
+ old_ns = client_find_namespace(cmd, &oldname);
if (old_ns == NULL)
return TRUE;
- new_ns = client_find_namespace(cmd, newname, &storage_newname);
+ new_ns = client_find_namespace(cmd, &newname);
if (new_ns == NULL)
return TRUE;
/* disallow box -> box/child, because it may break clients and
there's really no point in doing it anyway. */
old_ns = mailbox_list_get_namespace(old_ns->list);
- oldlen = strlen(storage_oldname);
- if (strncmp(storage_oldname, storage_newname, oldlen) == 0 &&
- storage_newname[oldlen] == old_ns->real_sep) {
+ oldlen = strlen(oldname);
+ if (strncmp(oldname, newname, oldlen) == 0 &&
+ newname[oldlen] == mail_namespace_get_sep(old_ns)) {
client_send_tagline(cmd,
"NO Can't rename mailbox under its own child.");
return TRUE;
}
}
- old_box = mailbox_alloc(old_ns->list, storage_oldname, 0);
- new_box = mailbox_alloc(new_ns->list, storage_newname, 0);
+ old_box = mailbox_alloc(old_ns->list, oldname, 0);
+ new_box = mailbox_alloc(new_ns->list, newname, 0);
if (mailbox_rename(old_box, new_box, TRUE) < 0)
client_send_storage_error(cmd, mailbox_get_storage(old_box));
else
struct client *client = cmd->client;
struct imap_select_context *ctx;
const struct imap_arg *args, *list_args;
- const char *mailbox, *storage_name;
+ const char *mailbox;
int ret;
/* <mailbox> [(optional parameters)] */
ctx = p_new(cmd->pool, struct imap_select_context, 1);
ctx->cmd = cmd;
- ctx->ns = client_find_namespace(cmd, mailbox, &storage_name);
+ ctx->ns = client_find_namespace(cmd, &mailbox);
if (ctx->ns == NULL) {
close_selected_mailbox(client);
return TRUE;
(void)client_enable(client, MAILBOX_FEATURE_CONDSTORE);
}
- ret = select_open(ctx, storage_name, readonly);
+ ret = select_open(ctx, mailbox, readonly);
if (ret == 0)
return FALSE;
cmd_select_finish(ctx, ret);
struct imap_status_items items;
struct imap_status_result result;
struct mail_namespace *ns;
- const char *mailbox, *storage_name, *error;
+ const char *mailbox, *error;
bool selected_mailbox;
/* <mailbox> <status items> */
if (imap_status_parse_items(cmd, list_args, &items) < 0)
return TRUE;
- ns = client_find_namespace(cmd, mailbox, &storage_name);
+ ns = client_find_namespace(cmd, &mailbox);
if (ns == NULL)
return TRUE;
selected_mailbox = client->mailbox != NULL &&
- mailbox_equals(client->mailbox, ns, storage_name);
- if (imap_status_get(cmd, ns, storage_name, &items,
+ mailbox_equals(client->mailbox, ns, mailbox);
+ if (imap_status_get(cmd, ns, mailbox, &items,
&result, &error) < 0) {
client_send_tagline(cmd, error);
return TRUE;
#include "imap-commands.h"
#include "mail-namespace.h"
-static bool have_listable_namespace_prefix(struct mail_namespace *ns,
- const char *name)
-{
- unsigned int name_len = strlen(name);
-
- for (; ns != NULL; ns = ns->next) {
- if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
- NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
- continue;
-
- if (ns->prefix_len <= name_len)
- continue;
-
- /* if prefix has multiple hierarchies, allow subscribing to
- any of the hierarchies */
- if (strncmp(ns->prefix, name, name_len) == 0 &&
- ns->prefix[name_len] == ns->sep)
- return TRUE;
- }
- return FALSE;
-}
-
static bool
-subscribe_is_valid_name(struct client_command_context *cmd, const char *mailbox)
+subscribe_is_valid_name(struct client_command_context *cmd, struct mailbox *box)
{
- struct mail_namespace *ns;
- struct mailbox *box;
- const char *storage_name;
int ret;
- if (have_listable_namespace_prefix(cmd->client->user->namespaces,
- mailbox)) {
- /* subscribing to a listable namespace prefix, allow it. */
- return TRUE;
- }
-
- /* see if the mailbox exists */
- ns = client_find_namespace(cmd, mailbox, &storage_name);
- if (ns == NULL)
- return FALSE;
-
- box = mailbox_alloc(ns->list, storage_name, 0);
if ((ret = mailbox_exists(box)) < 0) {
client_send_storage_error(cmd, mailbox_get_storage(box));
- mailbox_free(&box);
return FALSE;
}
- mailbox_free(&box);
-
if (ret == 0) {
client_send_tagline(cmd, t_strdup_printf(
- "NO "MAIL_ERRSTR_MAILBOX_NOT_FOUND, mailbox));
+ "NO "MAIL_ERRSTR_MAILBOX_NOT_FOUND,
+ mailbox_get_vname(box)));
return FALSE;
}
return TRUE;
bool cmd_subscribe_full(struct client_command_context *cmd, bool subscribe)
{
- struct mail_namespace *ns, *box_ns;
- const char *mailbox, *storage_name, *subs_name, *subs_name2 = NULL;
+ struct mail_namespace *ns;
+ struct mailbox *box, *box2;
+ const char *mailbox, *orig_mailbox;
bool unsubscribed_mailbox2;
/* <mailbox> */
if (!client_read_string_args(cmd, 1, &mailbox))
return FALSE;
+ orig_mailbox = mailbox;
- box_ns = client_find_namespace(cmd, mailbox, &storage_name);
- if (box_ns == NULL)
- return TRUE;
- if (!mailbox_list_is_valid_existing_name(box_ns->list, storage_name)) {
- client_send_tagline(cmd, "NO [CANNOT] Invalid mailbox name");
+ ns = client_find_namespace(cmd, &mailbox);
+ if (ns == NULL)
return TRUE;
- }
-
- /* now find a namespace where the subscription can be added to */
- subs_name = mailbox;
- ns = mail_namespace_find_subscribable(cmd->client->user->namespaces,
- &subs_name);
- if (ns == NULL) {
- client_send_tagline(cmd, "NO Unknown subscription namespace.");
- return TRUE;
- }
-
- if (ns != box_ns) {
- /* subscription is being written to a different namespace
- than where the mailbox exists. */
- subs_name = t_strconcat(box_ns->prefix, storage_name, NULL);
- /* drop the common prefix */
- i_assert(strncmp(ns->prefix, subs_name, strlen(ns->prefix)) == 0);
- subs_name += strlen(ns->prefix);
- }
-
- if ((cmd->client->set->parsed_workarounds &
- WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
- *subs_name != '\0' &&
- subs_name[strlen(subs_name)-1] == ns->real_sep) {
- /* verify the validity without the trailing '/' */
- mailbox = t_strndup(mailbox, strlen(mailbox)-1);
- subs_name2 = subs_name;
- subs_name = t_strndup(subs_name, strlen(subs_name)-1);
- }
+ box = mailbox_alloc(ns->list, mailbox, 0);
if (subscribe) {
- if (!subscribe_is_valid_name(cmd, mailbox))
+ if (!subscribe_is_valid_name(cmd, box)) {
+ mailbox_free(&box);
return TRUE;
+ }
}
unsubscribed_mailbox2 = FALSE;
- if (!subscribe && subs_name2 != NULL) {
+ if (!subscribe && mailbox != orig_mailbox) {
/* try to unsubscribe both "box" and "box/" */
- if (mailbox_list_set_subscribed(ns->list, subs_name2,
- FALSE) == 0)
+ box2 = mailbox_alloc(ns->list, orig_mailbox, 0);
+ if (mailbox_set_subscribed(box2, FALSE) == 0)
unsubscribed_mailbox2 = TRUE;
+ mailbox_free(&box2);
}
- if (mailbox_list_set_subscribed(ns->list, subs_name, subscribe) < 0 &&
+ if (mailbox_set_subscribed(box, subscribe) < 0 &&
!unsubscribed_mailbox2) {
- client_send_list_error(cmd, ns->list);
+ client_send_storage_error(cmd, mailbox_get_storage(box));
} else {
client_send_tagline(cmd, subscribe ?
"OK Subscribe completed." :
"OK Unsubscribe completed.");
}
+ mailbox_free(&box);
return TRUE;
}
#include "imap-commands-util.h"
struct mail_namespace *
-client_find_namespace(struct client_command_context *cmd, const char *mailbox,
- const char **storage_name_r)
+client_find_namespace(struct client_command_context *cmd, const char **mailbox)
{
struct mail_namespace *namespaces = cmd->client->user->namespaces;
struct mail_namespace *ns;
- const char *storage_name, *p;
- unsigned int storage_name_len;
+ unsigned int name_len;
- storage_name = mailbox;
- ns = mail_namespace_find(namespaces, &storage_name);
+ ns = mail_namespace_find(namespaces, *mailbox);
if (ns == NULL) {
client_send_tagline(cmd, t_strdup_printf(
"NO Client tried to access nonexistent namespace. "
return NULL;
}
- storage_name_len = strlen(storage_name);
+ name_len = strlen(*mailbox);
if ((cmd->client->set->parsed_workarounds &
WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
- storage_name_len > 0 &&
- storage_name[storage_name_len-1] == ns->real_sep) {
+ name_len > 0 &&
+ (*mailbox)[name_len-1] == mail_namespace_get_sep(ns)) {
/* drop the extra trailing hierarchy separator */
- storage_name = t_strndup(storage_name, storage_name_len-1);
+ *mailbox = t_strndup(*mailbox, name_len-1);
}
-
- if (ns->real_sep != ns->sep && ns->prefix_len < strlen(mailbox)) {
- /* make sure there are no real separators used in the mailbox
- name. */
- mailbox += ns->prefix_len;
- for (p = mailbox; *p != '\0'; p++) {
- if (*p == ns->real_sep) {
- client_send_tagline(cmd, t_strdup_printf(
- "NO Character not allowed "
- "in mailbox name: '%c'",
- ns->real_sep));
- return NULL;
- }
- }
- }
-
- *storage_name_r = storage_name;
return ns;
}
{
struct mail_namespace *ns;
struct mailbox *box;
- const char *storage_name, *error_string;
+ const char *error_string;
enum mail_error error;
- ns = client_find_namespace(cmd, name, &storage_name);
+ ns = client_find_namespace(cmd, &name);
if (ns == NULL)
return -1;
if (cmd->client->mailbox != NULL &&
- mailbox_equals(cmd->client->mailbox, ns, storage_name)) {
+ mailbox_equals(cmd->client->mailbox, ns, name)) {
*destbox_r = cmd->client->mailbox;
return 0;
}
- box = mailbox_alloc(ns->list, storage_name,
+ box = mailbox_alloc(ns->list, name,
MAILBOX_FLAG_SAVEONLY | MAILBOX_FLAG_KEEP_RECENT);
if (mailbox_open(box) < 0) {
error_string = mailbox_get_last_error(box, &error);
if (ns1 != ns2)
return FALSE;
- name1 = mailbox_get_name(box1);
+ name1 = mailbox_get_vname(box1);
if (strcmp(name1, name2) == 0)
return TRUE;
/* Finds namespace for given mailbox from namespaces. If namespace isn't found
or mailbox name is invalid, sends a tagged NO reply to client. */
struct mail_namespace *
-client_find_namespace(struct client_command_context *cmd, const char *mailbox,
- const char **storage_name_r);
+client_find_namespace(struct client_command_context *cmd, const char **mailbox);
/* Returns TRUE if mailbox is selected. If not, sends "No mailbox selected"
error message to client. */
*error_str_r = NULL;
name = mailbox_name_to_mutf7(name);
- ns = mail_namespace_find(ctx->user->namespaces, &name);
+ ns = mail_namespace_find(ctx->user->namespaces, name);
if (ns == NULL) {
*error_str_r = "Unknown namespace";
*error_r = MAIL_ERROR_PARAMS;
return -1;
}
- if (*name == '\0' && (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
+ if (strcmp(name, ns->prefix) == 0 &&
+ (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
/* delivering to a namespace prefix means we actually want to
deliver to the INBOX instead */
name = "INBOX";
}
if (ctx->lda_mailbox_autosubscribe) {
/* (try to) subscribe to it */
- (void)mailbox_list_set_subscribed(ns->list, name, TRUE);
+ (void)mailbox_set_subscribed(box, TRUE);
}
/* and try opening again */
static struct mailbox *
cydir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
- const char *name, enum mailbox_flags flags)
+ const char *vname, enum mailbox_flags flags)
{
struct cydir_mailbox *mbox;
struct index_mailbox_context *ibox;
mbox->box.list = list;
mbox->box.mail_vfuncs = &cydir_mail_vfuncs;
- index_storage_mailbox_alloc(&mbox->box, name, flags,
+ index_storage_mailbox_alloc(&mbox->box, vname, flags,
CYDIR_INDEX_PREFIX);
ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
struct mail_index_transaction *trans;
struct dbox_sync_rebuild_context *rebuild_ctx;
enum mail_error error;
- const char *name;
int ret;
- name = mail_namespace_get_storage_name(ns, vname);
- box = mailbox_alloc(ns->list, name, MAILBOX_FLAG_READONLY |
+ box = mailbox_alloc(ns->list, vname, MAILBOX_FLAG_READONLY |
MAILBOX_FLAG_KEEP_RECENT |
MAILBOX_FLAG_IGNORE_ACLS);
i_assert(box->storage == &ctx->storage->storage.storage);
dbox_storage_destroy(_storage);
}
-struct mailbox *
+static struct mailbox *
mdbox_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
- const char *name, enum mailbox_flags flags)
+ const char *vname, enum mailbox_flags flags)
{
struct mdbox_mailbox *mbox;
struct index_mailbox_context *ibox;
mbox->box.list = list;
mbox->box.mail_vfuncs = &mdbox_mail_vfuncs;
- index_storage_mailbox_alloc(&mbox->box, name, flags, DBOX_INDEX_PREFIX);
+ index_storage_mailbox_alloc(&mbox->box, vname,
+ flags, DBOX_INDEX_PREFIX);
ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
ibox->save_commit_pre = mdbox_transaction_save_commit_pre;
extern struct mail_vfuncs mdbox_mail_vfuncs;
-struct mailbox *
-mdbox_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
- const char *name, enum mailbox_flags flags);
-
int mdbox_mail_open(struct dbox_mail *mail, uoff_t *offset_r,
struct dbox_file **file_r);
static struct mailbox *
sdbox_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
- const char *name, enum mailbox_flags flags)
+ const char *vname, enum mailbox_flags flags)
{
struct sdbox_mailbox *mbox;
struct index_mailbox_context *ibox;
mbox->box.list = list;
mbox->box.mail_vfuncs = &sdbox_mail_vfuncs;
- index_storage_mailbox_alloc(&mbox->box, name, flags, DBOX_INDEX_PREFIX);
+ index_storage_mailbox_alloc(&mbox->box, vname,
+ flags, DBOX_INDEX_PREFIX);
ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
ibox->save_commit_pre = sdbox_transaction_save_commit_pre;
static struct mailbox *
imapc_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
- const char *name, enum mailbox_flags flags)
+ const char *vname, enum mailbox_flags flags)
{
struct imapc_mailbox *mbox;
struct index_mailbox_context *ibox;
mbox->box.list = list;
mbox->box.mail_vfuncs = &imapc_mail_vfuncs;
- index_storage_mailbox_alloc(&mbox->box, name, flags, NULL);
+ index_storage_mailbox_alloc(&mbox->box, vname, flags, NULL);
ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
ibox->save_commit_pre = imapc_transaction_save_commit_pre;
return 0;
}
-void index_storage_mailbox_alloc(struct mailbox *box, const char *name,
+void index_storage_mailbox_alloc(struct mailbox *box, const char *vname,
enum mailbox_flags flags,
const char *index_prefix)
{
struct index_mailbox_context *ibox;
- string_t *vname;
- i_assert(name != NULL);
-
- box->name = p_strdup(box->pool, name);
- vname = t_str_new(128);
- mail_namespace_get_vname(box->list->ns, vname, name);
- box->vname = p_strdup(box->pool, str_c(vname));
+ i_assert(vname != NULL);
+ box->vname = p_strdup(box->pool, vname);
+ box->name = p_strdup(box->pool,
+ mailbox_list_get_storage_name(box->list, vname));
box->flags = flags;
box->index_prefix = p_strdup(box->pool, index_prefix);
ibox->next_lock_notify = time(NULL) + LOCK_NOTIFY_INTERVAL;
MODULE_CONTEXT_SET(box, index_storage_module, ibox);
- box->inbox_user = strcmp(name, "INBOX") == 0 &&
+ box->inbox_user = strcmp(box->name, "INBOX") == 0 &&
(box->list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0;
- box->inbox_any = strcmp(name, "INBOX") == 0 &&
+ box->inbox_any = strcmp(box->name, "INBOX") == 0 &&
(box->list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0;
}
unsigned int secs_left);
void index_storage_lock_notify_reset(struct mailbox *box);
-void index_storage_mailbox_alloc(struct mailbox *box, const char *name,
+void index_storage_mailbox_alloc(struct mailbox *box, const char *vname,
enum mailbox_flags flags,
const char *index_prefix);
int index_storage_mailbox_exists(struct mailbox *box);
static struct mailbox *
maildir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
- const char *name, enum mailbox_flags flags)
+ const char *vname, enum mailbox_flags flags)
{
struct maildir_mailbox *mbox;
struct index_mailbox_context *ibox;
mbox->box.list = list;
mbox->box.mail_vfuncs = &maildir_mail_vfuncs;
- index_storage_mailbox_alloc(&mbox->box, name, flags,
+ index_storage_mailbox_alloc(&mbox->box, vname, flags,
MAILDIR_INDEX_PREFIX);
ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
static struct mailbox *
mbox_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
- const char *name, enum mailbox_flags flags)
+ const char *vname, enum mailbox_flags flags)
{
struct mbox_mailbox *mbox;
struct index_mailbox_context *ibox;
mbox->box.list = list;
mbox->box.mail_vfuncs = &mbox_mail_vfuncs;
- index_storage_mailbox_alloc(&mbox->box, name, flags, MBOX_INDEX_PREFIX);
+ index_storage_mailbox_alloc(&mbox->box, vname,
+ flags, MBOX_INDEX_PREFIX);
ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
ibox->save_commit_pre = mbox_transaction_save_commit_pre;
static struct mailbox *
raw_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
- const char *name, enum mailbox_flags flags)
+ const char *vname, enum mailbox_flags flags)
{
struct raw_mailbox *mbox;
pool_t pool;
mbox->box.list = list;
mbox->box.mail_vfuncs = &raw_mail_vfuncs;
- index_storage_mailbox_alloc(&mbox->box, name, flags, NULL);
+ index_storage_mailbox_alloc(&mbox->box, vname, flags, NULL);
mbox->mtime = mbox->ctime = (time_t)-1;
mbox->storage = (struct raw_storage *)storage;
}
static int
-shared_get_storage(struct mailbox_list **list, const char **name,
+shared_get_storage(struct mailbox_list **list, const char *vname,
struct mail_storage **storage_r)
{
struct mail_namespace *ns = (*list)->ns;
+ const char *name = vname;
- if (shared_storage_get_namespace(&ns, name) < 0)
+ if (shared_storage_get_namespace(&ns, &name) < 0)
return -1;
*list = ns->list;
*storage_r = ns->storage;
return mailbox_list_is_valid_create_name(ns->list, name);
}
+static char shared_list_get_hierarchy_sep(struct mailbox_list *list ATTR_UNUSED)
+{
+ return '/';
+}
+
static const char *
shared_list_get_path(struct mailbox_list *list, const char *name,
enum mailbox_list_path_type type)
enum mailbox_list_iter_flags flags)
{
struct shared_mailbox_list_iterate_context *ctx;
+ char sep = mail_namespace_get_sep(list->ns);
ctx = i_new(struct shared_mailbox_list_iterate_context, 1);
ctx->ctx.list = list;
ctx->info.ns = list->ns;
ctx->info.flags = MAILBOX_NONEXISTENT;
ctx->glob = imap_match_init_multiple(default_pool, patterns,
- FALSE, list->ns->sep);
+ FALSE, sep);
return &ctx->ctx;
}
struct mailbox_list shared_mailbox_list = {
.name = "shared",
- .hierarchy_sep = '/',
.props = 0,
.mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH,
shared_is_valid_pattern,
shared_is_valid_existing_name,
shared_is_valid_create_name,
+ shared_list_get_hierarchy_sep,
+ mailbox_list_default_get_vname,
+ mailbox_list_default_get_storage_name,
shared_list_get_path,
shared_list_get_temp_prefix,
shared_list_join_refpattern,
const char *domain = NULL, *username = NULL, *userdomain = NULL;
const char *name, *p, *next, **dest, *error;
string_t *prefix, *location;
+ char ns_sep = mail_namespace_get_sep(ns);
int ret;
p = storage->ns_prefix_pattern;
}
p++;
- next = strchr(name, *p != '\0' ? *p : ns->sep);
+ next = strchr(name, *p != '\0' ? *p : ns_sep);
if (next == NULL) {
*dest = name;
name = "";
}
if (*p != '\0') {
if (*name == '\0' ||
- (name[1] == '\0' && *name == ns->sep)) {
+ (name[1] == '\0' && *name == ns_sep)) {
/* trying to open <prefix>/<user> mailbox */
name = "INBOX";
} else {
*_ns = mail_namespace_find_prefix(user->namespaces, str_c(prefix));
if (*_ns != NULL) {
- *_name = mail_namespace_fix_sep(ns, name);
+ *_name = mailbox_list_get_storage_name(ns->list,
+ t_strconcat(ns->prefix, name, NULL));
return 0;
}
new_ns->flags = (NAMESPACE_FLAG_SUBSCRIPTIONS & ns->flags) |
NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_HIDDEN |
NAMESPACE_FLAG_AUTOCREATED | NAMESPACE_FLAG_INBOX_ANY;
- new_ns->sep = ns->sep;
new_ns->mail_set = _storage->set;
location = t_str_new(256);
ns_set = p_new(user->pool, struct mail_namespace_settings, 1);
ns_set->type = "shared";
- ns_set->separator = p_strdup_printf(user->pool, "%c", new_ns->sep);
+ ns_set->separator = p_strdup_printf(user->pool, "%c", ns_sep);
ns_set->prefix = new_ns->prefix;
ns_set->location = p_strdup(user->pool, str_c(location));
ns_set->hidden = TRUE;
return -1;
}
ns->flags |= NAMESPACE_FLAG_USABLE;
- *_name = mail_namespace_fix_sep(new_ns, name);
+ *_name = mailbox_list_get_storage_name(new_ns->list,
+ t_strconcat(new_ns->prefix, name, NULL));
*_ns = new_ns;
mail_user_add_namespace(user, &new_ns);
static void pattern_parse(struct mailbox_list *list, const char *pattern,
const char **prefix_r, int *recurse_level_r)
{
- char sep = list->hierarchy_sep;
+ char sep = mailbox_list_get_hierarchy_sep(list);
const char *prefix_start, *prefix_end;
bool seen_wildcards = FALSE;
int recurse_level = 0;
const char *prefix, *cur_prefix, *const *tmp;
enum mailbox_list_iter_flags subs_flags;
int cur_recurse_level;
+ char sep;
subs_flags = MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
return FALSE;
}
- ctx->glob = imap_match_init_multiple(default_pool, patterns, TRUE,
- list->hierarchy_sep);
+ sep = mailbox_list_get_hierarchy_sep(list);
+ ctx->glob = imap_match_init_multiple(default_pool, patterns, TRUE, sep);
if ((flags & (MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
MAILBOX_LIST_ITER_RETURN_SUBSCRIBED)) != 0) {
/* we'll need to know the subscriptions */
- ctx->subs_tree = mailbox_tree_init(list->hierarchy_sep);
+ ctx->subs_tree = mailbox_tree_init(sep);
if (mailbox_list_subscriptions_fill(&ctx->ctx, ctx->subs_tree,
ctx->glob, FALSE) < 0) {
/* let the backend handle this failure */
mailbox_list_index_iterate_init(ctx->view, prefix,
ctx->recurse_level);
ctx->prefix = *prefix == '\0' ? i_strdup(ctx->ns_prefix) :
- i_strdup_printf("%s%s%c", ctx->ns_prefix, prefix,
- list->hierarchy_sep);
+ i_strdup_printf("%s%s%c", ctx->ns_prefix, prefix, sep);
}
return TRUE;
}
struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list);
const char *path;
enum mail_index_open_flags index_flags = 0;
+ char sep;
int ret;
index_flags = mail_storage_settings_to_index_flags(list->mail_set);
}
path = t_strconcat(dir, "/"MAILBOX_LIST_INDEX_NAME, NULL);
- ilist->list_index = mailbox_list_index_alloc(path, list->hierarchy_sep,
+ sep = mailbox_list_get_hierarchy_sep(list);
+ ilist->list_index = mailbox_list_index_alloc(path, sep,
ilist->mail_index);
if (mailbox_list_index_open_or_create(ilist->list_index) < 0) {
/* skip indexing */
ctx->ctx.flags = flags;
ctx->info_pool = pool_alloconly_create("fs list", 1024);
ctx->next = fs_list_next;
- ctx->sep = _list->ns->sep;
+ ctx->sep = mail_namespace_get_sep(_list->ns);
ctx->info.ns = _list->ns;
prefix_len = strlen(_list->ns->prefix);
test_pattern += prefix_len;
/* check pattern also when it's converted to use real
separators. */
- real_pattern = mail_namespace_fix_sep(_list->ns, test_pattern);
+ real_pattern =
+ mailbox_list_get_storage_name(_list, test_pattern);
if (mailbox_list_is_valid_pattern(_list, test_pattern) &&
mailbox_list_is_valid_pattern(_list, real_pattern)) {
if (strcasecmp(*patterns, "INBOX") == 0) {
struct mailbox_node *node;
enum mailbox_info_flags flags;
struct mail_namespace *ns;
- const char *path, *dir, *fname, *storage_name;
+ const char *path, *dir, *fname, *subs_name, *storage_name;
unsigned int len;
struct stat st;
}
/* see if this is for another subscriptions=no namespace */
- storage_name = ctx->info.name;
+ subs_name = ctx->info.name;
ns = mail_namespace_find_unsubscribable(ctx->info.ns->user->namespaces,
- &storage_name);
- if (ns == NULL) {
+ subs_name);
+ if (ns == NULL)
ns = ctx->info.ns;
- storage_name = mail_namespace_get_storage_name(ns, storage_name);
- }
/* if name ends with hierarchy separator, drop the separator */
- len = strlen(storage_name);
- if (len > 0 && storage_name[len-1] == ns->real_sep)
- storage_name = t_strndup(storage_name, len-1);
+ len = strlen(subs_name);
+ if (len > 0 && subs_name[len-1] == mail_namespace_get_sep(ns))
+ subs_name = t_strndup(subs_name, len-1);
+ storage_name = mailbox_list_get_storage_name(ns->list, subs_name);
if (!mailbox_list_is_valid_pattern(ns->list, storage_name)) {
/* broken entry in subscriptions file */
ctx->info.flags = MAILBOX_NONEXISTENT;
return fs_list_is_valid_common_nonfs(list, name);
}
+static char fs_list_get_hierarchy_sep(struct mailbox_list *list ATTR_UNUSED)
+{
+ return '/';
+}
+
static const char *
fs_list_get_path(struct mailbox_list *_list, const char *name,
enum mailbox_list_path_type type)
static int fs_list_delete_dir(struct mailbox_list *list, const char *name)
{
const char *path, *child_name, *child_path, *p;
+ char sep;
path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
if (fs_list_rmdir(list, name, path) == 0)
} else if (errno == ENOTEMPTY || errno == EEXIST) {
/* mbox workaround: if only .imap/ directory is preventing the
deletion, remove it */
- child_name = t_strdup_printf("%s%cchild", name,
- list->ns->real_sep);
+ sep = mailbox_list_get_hierarchy_sep(list);
+ child_name = t_strdup_printf("%s%cchild", name, sep);
child_path = mailbox_list_get_path(list, child_name,
MAILBOX_LIST_PATH_TYPE_INDEX);
if (strncmp(path, child_path, strlen(path)) == 0) {
const char *newname, bool rename_children)
{
struct mail_storage *oldstorage;
- const char *oldpath, *newpath, *alt_newpath, *root_path;
+ const char *oldvname, *oldpath, *newpath, *alt_newpath, *root_path;
const char *p, *origin;
enum mailbox_list_path_type path_type, alt_path_type;
struct stat st;
gid_t gid;
bool rmdir_parent = FALSE;
- if (mailbox_list_get_storage(&oldlist, &oldname, &oldstorage) < 0)
+ oldvname = mailbox_list_get_vname(oldlist, oldname);
+ if (mailbox_list_get_storage(&oldlist, oldvname, &oldstorage) < 0)
return -1;
if (rename_children) {
struct mailbox_list fs_mailbox_list = {
.name = MAILBOX_LIST_NAME_FS,
- .hierarchy_sep = '/',
.props = 0,
.mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH,
fs_is_valid_pattern,
fs_is_valid_existing_name,
fs_is_valid_create_name,
+ fs_list_get_hierarchy_sep,
+ mailbox_list_default_get_vname,
+ mailbox_list_default_get_storage_name,
fs_list_get_path,
fs_list_get_temp_prefix,
fs_list_join_refpattern,
static void
maildir_fill_parents(struct maildir_list_iterate_context *ctx,
struct imap_match_glob *glob, bool update_only,
- string_t *mailbox)
+ const char *vname)
{
struct mail_namespace *ns = ctx->ctx.list->ns;
struct mailbox_node *node;
- const char *p, *mailbox_c;
- bool created;
+ const char *p;
+ unsigned int vname_len = strlen(vname);
+ bool created, ns_sep = mail_namespace_get_sep(ns);
- mailbox_c = str_c(mailbox);
- while ((p = strrchr(mailbox_c, ns->sep)) != NULL) {
- str_truncate(mailbox, (size_t) (p-mailbox_c));
- mailbox_c = str_c(mailbox);
- if (imap_match(glob, mailbox_c) != IMAP_MATCH_YES)
+ while ((p = strrchr(vname, ns_sep)) != NULL) {
+ vname = t_strdup_until(vname, p);
+ if (imap_match(glob, vname) != IMAP_MATCH_YES)
continue;
- if (ns->prefix_len > 0 && str_len(mailbox) == ns->prefix_len-1 &&
- strncmp(mailbox_c, ns->prefix, ns->prefix_len - 1) == 0 &&
- mailbox_c[ns->prefix_len-1] == ns->sep) {
+ if (ns->prefix_len > 0 && vname_len == ns->prefix_len-1 &&
+ strncmp(vname, ns->prefix, ns->prefix_len - 1) == 0 &&
+ vname[ns->prefix_len-1] == ns_sep) {
/* don't return matches to namespace prefix itself */
continue;
}
created = FALSE;
node = update_only ?
- mailbox_tree_lookup(ctx->tree_ctx, mailbox_c) :
- mailbox_tree_get(ctx->tree_ctx, mailbox_c, &created);
+ mailbox_tree_lookup(ctx->tree_ctx, vname) :
+ mailbox_tree_get(ctx->tree_ctx, vname, &created);
if (node != NULL) {
if (created) {
/* we haven't yet seen this mailbox,
}
static void maildir_set_children(struct maildir_list_iterate_context *ctx,
- string_t *mailbox)
+ const char *vname)
{
struct mailbox_node *node;
- const char *p, *mailbox_c;
+ const char *p;
char hierarchy_sep;
- hierarchy_sep = ctx->ctx.list->ns->sep;
+ hierarchy_sep = mail_namespace_get_sep(ctx->ctx.list->ns);
/* mark the first existing parent as containing children */
- mailbox_c = str_c(mailbox);
- while ((p = strrchr(mailbox_c, hierarchy_sep)) != NULL) {
- str_truncate(mailbox, (size_t) (p-mailbox_c));
- mailbox_c = str_c(mailbox);
+ while ((p = strrchr(vname, hierarchy_sep)) != NULL) {
+ vname = t_strdup_until(vname, p);
- node = mailbox_tree_lookup(ctx->tree_ctx, mailbox_c);
+ node = mailbox_tree_lookup(ctx->tree_ctx, vname);
if (node != NULL) {
node->flags &= ~MAILBOX_NOCHILDREN;
node->flags |= MAILBOX_CHILDREN;
}
static int
-maildir_fill_readdir(struct maildir_list_iterate_context *ctx,
- struct imap_match_glob *glob, bool update_only)
+maildir_fill_readdir_entry(struct maildir_list_iterate_context *ctx,
+ struct imap_match_glob *glob, const struct dirent *d,
+ bool update_only)
{
struct mailbox_list *list = ctx->ctx.list;
- struct mail_namespace *ns = list->ns;
- DIR *dirp;
- struct dirent *d;
- const char *mailbox_name;
- string_t *mailbox;
+ const char *fname, *storage_name, *vname;
enum mailbox_info_flags flags;
enum imap_match_result match;
struct mailbox_node *node;
struct stat st;
int ret;
+ fname = d->d_name;
+ if (fname[0] == ctx->prefix_char)
+ storage_name = fname + 1;
+ else {
+ if (ctx->prefix_char != '\0' || fname[0] == '.')
+ return 0;
+ storage_name = fname;
+ }
+
+ /* skip . and .. */
+ if (fname[0] == '.' &&
+ (fname[1] == '\0' || (fname[1] == '.' && fname[2] == '\0')))
+ return 0;
+
+ vname = mailbox_list_get_vname(list, storage_name);
+
+ /* make sure the pattern matches */
+ match = imap_match(glob, vname);
+ if ((match & (IMAP_MATCH_YES | IMAP_MATCH_PARENT)) == 0)
+ return 0;
+
+ /* check if this is an actual mailbox */
+ if (maildir_delete_trash_dir(ctx, fname))
+ return 0;
+
+ T_BEGIN {
+ ret = list->v.get_mailbox_flags(list, ctx->dir, fname,
+ mailbox_list_get_file_type(d), &st, &flags);
+ } T_END;
+ if (ret <= 0)
+ return ret;
+
+ /* we know the children flags ourself, so ignore if any of
+ them were set. */
+ flags &= ~(MAILBOX_NOINFERIORS | MAILBOX_CHILDREN | MAILBOX_NOCHILDREN);
+
+ if ((match & IMAP_MATCH_PARENT) != 0)
+ maildir_fill_parents(ctx, glob, update_only, vname);
+ else {
+ created = FALSE;
+ node = update_only ?
+ mailbox_tree_lookup(ctx->tree_ctx, vname) :
+ mailbox_tree_get(ctx->tree_ctx, vname, &created);
+
+ if (node != NULL) {
+ if (created)
+ node->flags = MAILBOX_NOCHILDREN;
+ else
+ node->flags &= ~MAILBOX_NONEXISTENT;
+ if (!update_only)
+ node->flags |= MAILBOX_MATCHED;
+ node->flags |= flags;
+ node_fix_parents(node);
+ } else {
+ i_assert(update_only);
+ maildir_set_children(ctx, vname);
+ }
+ }
+ return 0;
+}
+
+static int
+maildir_fill_readdir(struct maildir_list_iterate_context *ctx,
+ struct imap_match_glob *glob, bool update_only)
+{
+ struct mailbox_list *list = ctx->ctx.list;
+ struct mail_namespace *ns = list->ns;
+ DIR *dirp;
+ struct dirent *d;
+ int ret = 0;
+
dirp = opendir(ctx->dir);
if (dirp == NULL) {
if (errno == EACCES) {
return 0;
}
- mailbox = t_str_new(MAILBOX_LIST_NAME_MAX_LENGTH);
while ((d = readdir(dirp)) != NULL) {
- const char *fname = d->d_name;
-
- if (fname[0] == ctx->prefix_char)
- mailbox_name = fname + 1;
- else {
- if (ctx->prefix_char != '\0' || fname[0] == '.')
- continue;
- mailbox_name = fname;
- }
-
- /* skip . and .. */
- if (fname[0] == '.' &&
- (fname[1] == '\0' || (fname[1] == '.' && fname[2] == '\0')))
- continue;
-
- mailbox_name = mail_namespace_get_vname(ns, mailbox,
- mailbox_name);
-
- /* make sure the pattern matches */
- match = imap_match(glob, mailbox_name);
- if ((match & (IMAP_MATCH_YES | IMAP_MATCH_PARENT)) == 0)
- continue;
-
- /* check if this is an actual mailbox */
- if (maildir_delete_trash_dir(ctx, fname))
- continue;
-
T_BEGIN {
- ret = list->v.get_mailbox_flags(list, ctx->dir, fname,
- mailbox_list_get_file_type(d), &st, &flags);
+ ret = maildir_fill_readdir_entry(ctx, glob, d,
+ update_only);
} T_END;
- if (ret <= 0) {
- if (ret < 0)
- return -1;
- continue;
- }
-
- /* we know the children flags ourself, so ignore if any of
- them were set. */
- flags &= ~(MAILBOX_NOINFERIORS |
- MAILBOX_CHILDREN | MAILBOX_NOCHILDREN);
-
- if ((match & IMAP_MATCH_PARENT) != 0) {
- T_BEGIN {
- maildir_fill_parents(ctx, glob, update_only,
- mailbox);
- } T_END;
- } else {
- created = FALSE;
- node = update_only ?
- mailbox_tree_lookup(ctx->tree_ctx,
- mailbox_name) :
- mailbox_tree_get(ctx->tree_ctx,
- mailbox_name, &created);
-
- if (node != NULL) {
- if (created)
- node->flags = MAILBOX_NOCHILDREN;
- else
- node->flags &= ~MAILBOX_NONEXISTENT;
- if (!update_only)
- node->flags |= MAILBOX_MATCHED;
- node->flags |= flags;
- node_fix_parents(node);
- } else {
- i_assert(update_only);
- maildir_set_children(ctx, mailbox);
- }
- }
+ if (ret < 0)
+ break;
}
if (closedir(dirp) < 0) {
ctx->dir);
return -1;
}
+ if (ret < 0)
+ return -1;
if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
/* make sure INBOX is listed */
maildir_list_iter_init(struct mailbox_list *_list, const char *const *patterns,
enum mailbox_list_iter_flags flags)
{
+ struct maildir_mailbox_list *list =
+ (struct maildir_mailbox_list *)_list;
struct maildir_list_iterate_context *ctx;
struct imap_match_glob *glob;
pool_t pool;
+ char ns_sep = mail_namespace_get_sep(_list->ns);
int ret;
pool = pool_alloconly_create("maildir_list", 1024);
ctx->ctx.list = _list;
ctx->ctx.flags = flags;
ctx->pool = pool;
- ctx->tree_ctx = mailbox_tree_init(_list->ns->sep);
+ ctx->tree_ctx = mailbox_tree_init(ns_sep);
ctx->info.ns = _list->ns;
ctx->prefix_char = strcmp(_list->name, MAILBOX_LIST_NAME_IMAPDIR) == 0 ?
- '\0' : _list->hierarchy_sep;
+ '\0' : list->sep;
- glob = imap_match_init_multiple(pool, patterns, TRUE, _list->ns->sep);
+ glob = imap_match_init_multiple(pool, patterns, TRUE, ns_sep);
ctx->dir = _list->set.root_dir;
list = p_new(pool, struct maildir_mailbox_list, 1);
list->list = maildir_mailbox_list;
list->list.pool = pool;
+ list->sep = '.';
list->global_temp_prefix = MAILDIR_GLOBAL_TEMP_PREFIX;
list->temp_prefix = p_strconcat(pool, list->global_temp_prefix,
else if (list->name == imapdir_mailbox_list.name)
return t_strdup_printf("%s/%s", dir, name);
- return t_strdup_printf("%s/%c%s", dir, list->hierarchy_sep, name);
+ return t_strdup_printf("%s/%c%s", dir,
+ mailbox_list_get_hierarchy_sep(list), name);
}
static const char *
}
static bool
-maildir_list_is_valid_common(struct mailbox_list *list, const char *name,
- size_t *len_r)
+maildir_list_is_valid_common(struct maildir_mailbox_list *list,
+ const char *name, size_t *len_r)
{
size_t len;
/* check that there are no adjacent hierarchy separators */
for (len = 0; name[len] != '\0'; len++) {
- if (name[len] == list->hierarchy_sep &&
- name[len+1] == list->hierarchy_sep)
+ if (name[len] == list->sep &&
+ name[len+1] == list->sep)
return FALSE;
}
if (len == 0 || name[len-1] == '/')
return FALSE;
- if (name[0] == list->hierarchy_sep ||
- name[len-1] == list->hierarchy_sep)
+ if (name[0] == list->sep ||
+ name[len-1] == list->sep)
return FALSE;
*len_r = len;
}
static bool
-maildir_is_valid_existing_name(struct mailbox_list *list, const char *name)
+maildir_is_valid_existing_name(struct mailbox_list *_list, const char *name)
{
+ struct maildir_mailbox_list *list =
+ (struct maildir_mailbox_list *)_list;
size_t len;
if (!maildir_list_is_valid_common(list, name, &len))
return FALSE;
- if (list->mail_set->mail_full_filesystem_access)
+ if (_list->mail_set->mail_full_filesystem_access)
return TRUE;
return maildir_list_is_valid_common_nonfs(name);
}
static bool
-maildir_is_valid_create_name(struct mailbox_list *list, const char *name)
+maildir_is_valid_create_name(struct mailbox_list *_list, const char *name)
{
+ struct maildir_mailbox_list *list =
+ (struct maildir_mailbox_list *)_list;
size_t len;
if (!maildir_list_is_valid_common(list, name, &len))
if (len > MAILDIR_MAX_CREATE_MAILBOX_NAME_LENGTH)
return FALSE;
- if (list->mail_set->mail_full_filesystem_access)
+ if (_list->mail_set->mail_full_filesystem_access)
return TRUE;
if (!maildir_list_is_valid_common_nonfs(name))
return FALSE;
- if (mailbox_list_name_is_too_large(name, list->hierarchy_sep))
+ if (mailbox_list_name_is_too_large(name, list->sep))
return FALSE;
return TRUE;
}
+static char maildir_list_get_hierarchy_sep(struct mailbox_list *_list)
+{
+ struct maildir_mailbox_list *list =
+ (struct maildir_mailbox_list *)_list;
+
+ return list->sep;
+}
+
static const char *
maildir_list_get_path(struct mailbox_list *_list, const char *name,
enum mailbox_list_path_type type)
maildir_list_create_maildirfolder_file(list, path);
}
-static const char *mailbox_list_maildir_get_trash_dir(struct mailbox_list *list)
+static const char *
+mailbox_list_maildir_get_trash_dir(struct mailbox_list *_list)
{
+ struct maildir_mailbox_list *list =
+ (struct maildir_mailbox_list *)_list;
const char *root_dir;
- root_dir = mailbox_list_get_path(list, NULL,
+ root_dir = mailbox_list_get_path(_list, NULL,
MAILBOX_LIST_PATH_TYPE_DIR);
return t_strdup_printf("%s/%c%c"MAILBOX_LIST_MAILDIR_TRASH_DIR_NAME,
- root_dir, list->hierarchy_sep,
- list->hierarchy_sep);
+ root_dir, list->sep, list->sep);
}
static int
const char *const *names, *old_vname, *new_vname;
unsigned int i, count, old_vnamelen;
pool_t pool;
- string_t *str;
+ char old_ns_sep;
int ret;
ret = 0;
pool = pool_alloconly_create("Maildir++ children list", 1024);
i_array_init(&names_arr, 64);
- str = t_str_new(256);
- old_vname = t_strdup(mail_namespace_get_vname(oldlist->ns, str, oldname));
+ old_vname = mailbox_list_get_vname(oldlist, oldname);
old_vnamelen = strlen(oldname);
- str_truncate(str, 0);
- new_vname = t_strdup(mail_namespace_get_vname(newlist->ns, str, newname));
+ new_vname = mailbox_list_get_vname(newlist, newname);
- pattern = t_strdup_printf("%s%c*", old_vname, oldlist->ns->sep);
+ old_ns_sep = mail_namespace_get_sep(oldlist->ns);
+ pattern = t_strdup_printf("%s%c*", old_vname, old_ns_sep);
iter = mailbox_list_iter_init(oldlist, pattern,
MAILBOX_LIST_ITER_RETURN_NO_FLAGS |
MAILBOX_LIST_ITER_RAW_LIST);
/* verify that the prefix matches, otherwise we could have
problems with mailbox names containing '%' and '*' chars */
if (strncmp(info->name, old_vname, old_vnamelen) == 0 &&
- info->name[old_vnamelen] == oldlist->ns->sep) {
+ info->name[old_vnamelen] == old_ns_sep) {
name = p_strdup(pool, info->name + old_vnamelen);
array_append(&names_arr, &name, 1);
}
}
for (i = 0; i < count; i++) {
- old_childname = mail_namespace_get_storage_name(oldlist->ns,
+ old_childname = mailbox_list_get_storage_name(oldlist,
t_strconcat(old_vname, names[i], NULL));
if (strcmp(old_childname, new_vname) == 0) {
/* When doing RENAME "a" "a.b" we see "a.b" here.
continue;
}
- new_childname = mail_namespace_get_storage_name(newlist->ns,
+ new_childname = mailbox_list_get_storage_name(newlist,
t_strconcat(new_vname, names[i], NULL));
oldpath = mailbox_list_get_path(oldlist, old_childname,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
struct mailbox_list maildir_mailbox_list = {
.name = MAILBOX_LIST_NAME_MAILDIRPLUSPLUS,
- .hierarchy_sep = '.',
.props = MAILBOX_LIST_PROP_NO_MAILDIR_NAME |
MAILBOX_LIST_PROP_NO_ALT_DIR |
MAILBOX_LIST_PROP_NO_NOSELECT,
maildir_is_valid_pattern,
maildir_is_valid_existing_name,
maildir_is_valid_create_name,
+ maildir_list_get_hierarchy_sep,
+ mailbox_list_default_get_vname,
+ mailbox_list_default_get_storage_name,
maildir_list_get_path,
maildir_list_get_temp_prefix,
NULL,
struct mailbox_list imapdir_mailbox_list = {
.name = MAILBOX_LIST_NAME_IMAPDIR,
- .hierarchy_sep = '.',
.props = MAILBOX_LIST_PROP_NO_MAILDIR_NAME |
MAILBOX_LIST_PROP_NO_ALT_DIR |
MAILBOX_LIST_PROP_NO_NOSELECT,
maildir_is_valid_pattern,
maildir_is_valid_existing_name,
maildir_is_valid_create_name,
+ maildir_list_get_hierarchy_sep,
+ mailbox_list_default_get_vname,
+ mailbox_list_default_get_storage_name,
maildir_list_get_path,
maildir_list_get_temp_prefix,
NULL,
struct mailbox_list list;
const char *global_temp_prefix, *temp_prefix;
+ char sep;
};
struct mailbox_list_iterate_context *
return FALSE;
}
+static char none_list_get_hierarchy_sep(struct mailbox_list *list ATTR_UNUSED)
+{
+ return '/';
+}
+
static const char *
none_list_get_path(struct mailbox_list *list ATTR_UNUSED,
const char *name ATTR_UNUSED,
struct mailbox_list none_mailbox_list = {
.name = MAILBOX_LIST_NAME_NONE,
- .hierarchy_sep = '/',
.props = MAILBOX_LIST_PROP_NO_ROOT,
.mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH,
none_is_valid_pattern,
none_is_valid_existing_name,
none_is_valid_create_name,
+ none_list_get_hierarchy_sep,
+ mailbox_list_default_get_vname,
+ mailbox_list_default_get_storage_name,
none_list_get_path,
none_list_get_temp_prefix,
NULL,
/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
#include "lib.h"
-#include "str.h"
#include "subscription-file.h"
#include "mailbox-list-private.h"
#include "mailbox-list-subscriptions.h"
+static int
+mailbox_list_subscription_fill_one(struct mailbox_list_iter_update_context *update_ctx,
+ struct mail_namespace *default_ns,
+ const char *name)
+{
+ struct mail_namespace *namespaces = default_ns->user->namespaces;
+ struct mail_namespace *ns;
+ const char *vname;
+
+ /* default_ns is whatever namespace we're currently listing.
+ if we have e.g. prefix="" and prefix=pub/ namespaces with
+ pub/ namespace having subscriptions=no, we want to:
+
+ 1) when listing "" namespace we want to skip over any names
+ that begin with pub/. */
+ ns = mail_namespace_find_unsubscribable(namespaces, name);
+ if (ns != NULL && ns != default_ns)
+ return 0;
+
+ /* 2) when listing pub/ namespace, skip over entries that don't
+ begin with pub/. */
+ if (ns == NULL &&
+ (default_ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0)
+ return 0;
+
+ /* When listing shared namespace's subscriptions, we need to
+ autocreate all the visible child namespaces and use the
+ child namespace. */
+ if (ns != NULL && ns->type == NAMESPACE_SHARED &&
+ (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
+ /* we'll need to get the namespace autocreated.
+ one easy way is to just ask if a mailbox name under
+ it is valid, and it gets created */
+ (void)mailbox_list_is_valid_existing_name(ns->list, name);
+ ns = mail_namespace_find_unsubscribable(namespaces, name);
+ i_assert(ns != NULL &&
+ (ns->flags & NAMESPACE_FLAG_AUTOCREATED) != 0);
+ }
+
+ /* When listing pub/ namespace, skip over the namespace
+ prefix in the name. the rest of the name is storage_name. */
+ if (ns != NULL) {
+ i_assert(strncmp(name, ns->prefix, ns->prefix_len) == 0);
+ name += ns->prefix_len;
+ } else {
+ ns = default_ns;
+ }
+
+ if (!mailbox_list_is_valid_existing_name(ns->list, name)) {
+ /* we'll only get into trouble if we show this */
+ return -1;
+ } else {
+ vname = mailbox_list_get_vname(ns->list, name);
+ mailbox_list_iter_update(update_ctx, vname);
+ }
+ return 0;
+}
+
static int
mailbox_list_subscriptions_fill_real(struct mailbox_list_iterate_context *ctx,
struct mailbox_tree_context *tree_ctx,
struct imap_match_glob *glob,
bool update_only)
{
- struct mail_namespace *default_ns = ctx->list->ns;
- struct mail_namespace *namespaces = default_ns->user->namespaces;
+ struct mail_namespace *ns, *default_ns = ctx->list->ns;
+ struct mailbox_list *list = ctx->list;
struct mailbox_list_iter_update_context update_ctx;
struct subsfile_list_context *subsfile_ctx;
- struct mail_namespace *ns;
- const char *path, *name, *name2, *full_name, *orig_name;
- string_t *vname;
+ const char *path, *name;
- vname = str_new(default_pool, 256);
- path = t_strconcat(ctx->list->set.control_dir != NULL ?
- ctx->list->set.control_dir :
- ctx->list->set.root_dir,
- "/", ctx->list->set.subscription_fname, NULL);
- subsfile_ctx = subsfile_list_init(ctx->list, path);
+ if ((ctx->list->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0) {
+ /* need to list these using another namespace */
+ ns = mail_namespace_find_subscribable(default_ns->user->namespaces,
+ default_ns->prefix);
+ if (ns == NULL) {
+ /* no subscriptions */
+ return 0;
+ }
+ list = ns->list;
+ }
+
+ path = t_strconcat(list->set.control_dir != NULL ?
+ list->set.control_dir : list->set.root_dir,
+ "/", list->set.subscription_fname, NULL);
+ subsfile_ctx = subsfile_list_init(list, path);
memset(&update_ctx, 0, sizeof(update_ctx));
update_ctx.iter_ctx = ctx;
(ctx->flags & MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH) != 0;
while ((name = subsfile_list_next(subsfile_ctx)) != NULL) T_BEGIN {
- orig_name = name;
- full_name = name2 =
- t_strconcat(default_ns->prefix, name, NULL);
- ns = mail_namespace_find_unsubscribable(namespaces, &name2);
- if (ns == NULL)
- ns = default_ns;
- else if (ns->type == NAMESPACE_SHARED &&
- (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
- /* we'll need to get the namespace autocreated.
- one easy way is to just ask if a mailbox name under
- it is valid, and it gets created */
- (void)mailbox_list_is_valid_existing_name(ns->list,
- name2);
- name = full_name;
- ns = mail_namespace_find_unsubscribable(namespaces,
- &name);
- } else {
- name = name2;
- }
-
- if (!mailbox_list_is_valid_existing_name(ns->list, name)) {
- /* we'll only get into trouble if we show this */
+ if (mailbox_list_subscription_fill_one(&update_ctx, default_ns,
+ name) < 0) {
i_warning("Subscriptions file %s: "
"Ignoring invalid entry: %s",
- path, orig_name);
- } else {
- name = mail_namespace_get_vname(ns, vname, name);
- mailbox_list_iter_update(&update_ctx, name);
+ path, name);
}
} T_END;
- str_free(&vname);
return subsfile_list_deinit(subsfile_ctx);
}
struct mailbox_list *list)
{
ns->list = list;
-
- /* allow plugins to override real_sep */
- if (ns->real_sep == '\0')
- ns->real_sep = list->hierarchy_sep;
ns->prefix_len = strlen(ns->prefix);
-
- if (ns->set->separator != NULL)
- ns->sep = *ns->set->separator;
- if (ns->sep == '\0')
- ns->sep = ns->real_sep;
- if (ns->sep == '"' || ns->sep == '\\') {
- ns->sep_str[0] = '\\';
- ns->sep_str[1] = ns->sep;
- } else {
- ns->sep_str[0] = ns->sep;
- }
}
static void mail_namespace_free(struct mail_namespace *ns)
{
struct mail_namespace *ns, *inbox_ns = NULL;
unsigned int subscriptions_count = 0;
- char list_sep = '\0';
+ char ns_sep, list_sep = '\0';
for (ns = namespaces; ns != NULL; ns = ns->next) {
+ ns_sep = mail_namespace_get_sep(ns);
if (mail_namespace_find_prefix(ns->next, ns->prefix) != NULL) {
*error_r = t_strdup_printf(
"Duplicate namespace prefix: \"%s\"",
if (*ns->prefix != '\0' &&
(ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
NAMESPACE_FLAG_LIST_CHILDREN)) != 0 &&
- ns->prefix[strlen(ns->prefix)-1] != ns->sep) {
+ ns->prefix[strlen(ns->prefix)-1] != ns_sep) {
*error_r = t_strdup_printf(
"list=yes requires prefix=%s "
"to end with separator", ns->prefix);
if (*ns->prefix != '\0' &&
(ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
NAMESPACE_FLAG_LIST_CHILDREN)) != 0 &&
- ns->prefix[0] == ns->sep) {
+ ns->prefix[0] == ns_sep) {
*error_r = t_strdup_printf(
"list=yes requires prefix=%s "
"not to start with separator", ns->prefix);
if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
NAMESPACE_FLAG_LIST_CHILDREN)) != 0) {
if (list_sep == '\0')
- list_sep = ns->sep;
- else if (list_sep != ns->sep) {
+ list_sep = ns_sep;
+ else if (list_sep != ns_sep) {
*error_r = "All list=yes namespaces must use "
"the same separator";
return FALSE;
mail_namespace_unref(&ns);
}
-const char *mail_namespace_fix_sep(struct mail_namespace *ns, const char *name)
-{
- char *ret, *p;
-
- if (ns->sep == ns->real_sep)
- return name;
- if (ns->type == NAMESPACE_SHARED &&
- (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
- /* shared namespace root. the backend storage's hierarchy
- separator isn't known yet, so do nothing. */
- return name;
- }
-
- ret = p_strdup(unsafe_data_stack_pool, name);
- for (p = ret; *p != '\0'; p++) {
- if (*p == ns->sep)
- *p = ns->real_sep;
- }
- return ret;
-}
-
-const char *mail_namespace_get_storage_name(struct mail_namespace *ns,
- const char *name)
-{
- unsigned int len = strlen(ns->prefix);
-
- if (len > 0) {
- if (strncmp(ns->prefix, name, len) == 0)
- name += len;
- else {
- i_assert(strcasecmp(name, "INBOX") == 0);
- }
- }
- return mail_namespace_fix_sep(ns, name);
-}
-
-const char *mail_namespace_get_vname(struct mail_namespace *ns, string_t *dest,
- const char *name)
-{
- str_truncate(dest, 0);
- if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0 ||
- strcasecmp(name, "INBOX") != 0 ||
- ns->user != ns->owner)
- str_append(dest, ns->prefix);
-
- for (; *name != '\0'; name++) {
- if (*name == ns->real_sep)
- str_append_c(dest, ns->sep);
- else
- str_append_c(dest, *name);
- }
- return str_c(dest);
-}
-
struct mail_storage *
mail_namespace_get_default_storage(struct mail_namespace *ns)
{
return ns->storage;
}
-char mail_namespaces_get_root_sep(const struct mail_namespace *namespaces)
+char mail_namespace_get_sep(struct mail_namespace *ns)
+{
+ return *ns->set->separator != '\0' ? *ns->set->separator :
+ mailbox_list_get_hierarchy_sep(ns->list);
+}
+
+char mail_namespaces_get_root_sep(struct mail_namespace *namespaces)
{
while ((namespaces->flags & NAMESPACE_FLAG_LIST_PREFIX) == 0)
namespaces = namespaces->next;
- return namespaces->sep;
+ return mail_namespace_get_sep(namespaces);
}
static bool mail_namespace_is_usable_prefix(struct mail_namespace *ns,
if (strncmp(ns->prefix, mailbox, ns->prefix_len-1) == 0 &&
mailbox[ns->prefix_len-1] == '\0' &&
- ns->prefix[ns->prefix_len-1] == ns->sep) {
+ ns->prefix[ns->prefix_len-1] == mail_namespace_get_sep(ns)) {
/* we're trying to access the namespace prefix itself */
return TRUE;
}
}
static struct mail_namespace *
-mail_namespace_find_mask(struct mail_namespace *namespaces,
- const char **mailbox,
+mail_namespace_find_mask(struct mail_namespace *namespaces, const char *box,
enum namespace_flags flags,
enum namespace_flags mask)
{
struct mail_namespace *ns = namespaces;
- const char *box = *mailbox;
struct mail_namespace *best = NULL;
- unsigned int len, best_len = 0;
+ unsigned int best_len = 0;
bool inbox;
inbox = strncasecmp(box, "INBOX", 5) == 0;
if (inbox && box[5] == '\0') {
/* find the INBOX namespace */
- *mailbox = "INBOX";
while (ns != NULL) {
if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
(ns->flags & mask) == flags)
best_len = ns->prefix_len;
}
}
-
- if (best != NULL) {
- if (best_len > 0) {
- len = strlen(*mailbox);
- *mailbox += I_MIN(len, best_len);
- } else if (inbox && (box[5] == best->sep || box[5] == '\0'))
- *mailbox = t_strconcat("INBOX", box+5, NULL);
-
- *mailbox = mail_namespace_fix_sep(best, *mailbox);
- }
return best;
}
static struct mail_namespace *
-mail_namespace_find_shared(struct mail_namespace *ns, const char **mailbox)
+mail_namespace_find_shared(struct mail_namespace *ns, const char *mailbox)
{
struct mailbox_list *list = ns->list;
struct mail_storage *storage;
}
struct mail_namespace *
-mail_namespace_find(struct mail_namespace *namespaces, const char **mailbox)
+mail_namespace_find(struct mail_namespace *namespaces, const char *mailbox)
{
struct mail_namespace *ns;
if (ns != NULL && ns->type == NAMESPACE_SHARED &&
(ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
/* see if we need to autocreate a namespace for shared user */
- if (strchr(*mailbox, ns->sep) != NULL)
+ if (strchr(mailbox, mail_namespace_get_sep(ns)) != NULL)
return mail_namespace_find_shared(ns, mailbox);
}
return ns;
struct mail_namespace *
mail_namespace_find_visible(struct mail_namespace *namespaces,
- const char **mailbox)
+ const char *mailbox)
{
return mail_namespace_find_mask(namespaces, mailbox, 0,
NAMESPACE_FLAG_HIDDEN);
struct mail_namespace *
mail_namespace_find_subscribable(struct mail_namespace *namespaces,
- const char **mailbox)
+ const char *mailbox)
{
return mail_namespace_find_mask(namespaces, mailbox,
NAMESPACE_FLAG_SUBSCRIPTIONS,
struct mail_namespace *
mail_namespace_find_unsubscribable(struct mail_namespace *namespaces,
- const char **mailbox)
+ const char *mailbox)
{
return mail_namespace_find_mask(namespaces, mailbox,
0, NAMESPACE_FLAG_SUBSCRIPTIONS);
return namespaces;
}
-bool mail_namespace_update_name(const struct mail_namespace *ns,
- const char **mailbox)
-{
- struct mail_namespace tmp_ns = *ns;
-
- /* FIXME: a bit kludgy.. */
- tmp_ns.next = NULL;
- return mail_namespace_find_mask(&tmp_ns, mailbox, 0, 0) != NULL;
-}
-
struct mail_namespace *
mail_namespace_find_prefix(struct mail_namespace *namespaces,
const char *prefix)
for (ns = namespaces; ns != NULL; ns = ns->next) {
if (ns->prefix_len == len + 1 &&
strncmp(ns->prefix, prefix, len) == 0 &&
- ns->prefix[len] == ns->sep)
+ ns->prefix[len] == mail_namespace_get_sep(ns))
return ns;
}
return NULL;
int refcount;
enum namespace_type type;
- char sep, real_sep, sep_str[3];
enum namespace_flags flags;
char *prefix;
/* Destroy a single namespace and remove it from user's namespaces list. */
void mail_namespace_destroy(struct mail_namespace *ns);
-/* Update hierarchy separators in given name to real_sep characters. */
-const char *mail_namespace_fix_sep(struct mail_namespace *ns, const char *name);
-/* Skip namespace prefix and change hierarchy separators. */
-const char *mail_namespace_get_storage_name(struct mail_namespace *ns,
- const char *name);
-/* Write virtual mailbox name to dest and return it. Separators are changed to
- virtual ones and namespace prefix is inserted except for INBOX. */
-const char *mail_namespace_get_vname(struct mail_namespace *ns, string_t *dest,
- const char *name);
/* Returns the default storage to use for newly created mailboxes. */
struct mail_storage *
mail_namespace_get_default_storage(struct mail_namespace *ns);
+/* Return namespace's hierarchy separator. */
+char mail_namespace_get_sep(struct mail_namespace *ns);
/* Returns the hierarchy separator for mailboxes that are listed at root. */
-char mail_namespaces_get_root_sep(const struct mail_namespace *namespaces)
+char mail_namespaces_get_root_sep(struct mail_namespace *namespaces)
ATTR_PURE;
-/* Returns namespace based on the mailbox name's prefix. Updates mailbox to
- be a valid name inside the namespace (prefix is skipped, hierarchy separator
- is changed to real_sep). If no namespaces were found, returns NULL. */
+/* Returns namespace based on the mailbox name's prefix, or NULL if no matching
+ namespace could be found. */
struct mail_namespace *
-mail_namespace_find(struct mail_namespace *namespaces, const char **mailbox);
+mail_namespace_find(struct mail_namespace *namespaces, const char *mailbox);
/* Like above, but ignore hidden namespaces. */
struct mail_namespace *
mail_namespace_find_visible(struct mail_namespace *namespaces,
- const char **mailbox);
+ const char *mailbox);
/* Like above, but find only from namespaces with subscriptions flag set. */
struct mail_namespace *
mail_namespace_find_subscribable(struct mail_namespace *namespaces,
- const char **mailbox);
+ const char *mailbox);
/* Like above, but find only from namespaces with subscriptions flag not set. */
struct mail_namespace *
mail_namespace_find_unsubscribable(struct mail_namespace *namespaces,
- const char **mailbox);
+ const char *mailbox);
/* Returns the INBOX namespace */
struct mail_namespace *
mail_namespace_find_inbox(struct mail_namespace *namespaces);
-/* Returns TRUE if the given namespace matches the mailbox's prefix.
- Updates mailbox name to be a valid name inside the namespace. */
-bool mail_namespace_update_name(const struct mail_namespace *ns,
- const char **mailbox);
-
/* Find a namespace with given prefix. */
struct mail_namespace *
mail_namespace_find_prefix(struct mail_namespace *namespaces,
arg->value.mailbox_glob =
imap_match_init(default_pool, arg->value.str,
- TRUE, ns->sep);
+ TRUE, mail_namespace_get_sep(ns));
break;
}
case SEARCH_INTHREAD:
struct mailbox *(*mailbox_alloc)(struct mail_storage *storage,
struct mailbox_list *list,
- const char *name,
+ const char *vname,
enum mailbox_flags flags);
int (*purge)(struct mail_storage *storage);
};
return TRUE;
}
-struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *name,
+struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
enum mailbox_flags flags)
{
struct mailbox_list *new_list = list;
struct mail_storage *storage;
struct mailbox *box;
- if (mailbox_list_get_storage(&new_list, &name, &storage) < 0) {
+ if (mailbox_list_get_storage(&new_list, vname, &storage) < 0) {
/* just use the first storage. FIXME: does this break? */
storage = list->ns->storage;
}
T_BEGIN {
- box = storage->v.mailbox_alloc(storage, new_list, name, flags);
+ box = storage->v.mailbox_alloc(storage, new_list, vname, flags);
hook_mailbox_allocated(box);
} T_END;
return box;
}
+static bool have_listable_namespace_prefix(struct mail_namespace *ns,
+ const char *name)
+{
+ unsigned int name_len = strlen(name);
+
+ for (; ns != NULL; ns = ns->next) {
+ if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
+ NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
+ continue;
+
+ if (ns->prefix_len <= name_len)
+ continue;
+
+ /* if prefix has multiple hierarchies, match
+ any of the hierarchies */
+ if (strncmp(ns->prefix, name, name_len) == 0 &&
+ ns->prefix[name_len] == mail_namespace_get_sep(ns))
+ return TRUE;
+ }
+ return FALSE;
+}
+
int mailbox_exists(struct mailbox *box)
{
if (!mailbox_list_is_valid_existing_name(box->list, box->name)) {
return -1;
}
+ if (have_listable_namespace_prefix(box->storage->user->namespaces,
+ box->vname)) {
+ /* listable namespace prefix always exists */
+ return 1;
+ }
+
return box->v.exists(box);
}
+static int mailbox_check_mismatching_separators(struct mailbox *box)
+{
+ struct mail_namespace *ns = box->list->ns;
+ const char *p, *vname = box->vname;
+ char list_sep, ns_sep;
+
+ list_sep = mailbox_list_get_hierarchy_sep(box->list);
+ ns_sep = mail_namespace_get_sep(ns);
+
+ if (ns_sep == list_sep)
+ return 0;
+
+ if (ns->prefix_len > 0) {
+ /* vname is prefix with or without separator */
+ i_assert(strncmp(vname, ns->prefix, ns->prefix_len-1) == 0);
+ vname += ns->prefix_len - 1;
+ if (vname[0] != '\0') {
+ i_assert(vname[0] == ns->prefix[ns->prefix_len-1]);
+ vname++;
+ }
+ }
+
+ for (p = vname; *p != '\0'; p++) {
+ if (*p == list_sep) {
+ mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
+ t_strdup_printf("NO Character not allowed "
+ "in mailbox name: '%c'",
+ list_sep));
+ return -1;
+ }
+ }
+ return 0;
+}
+
static int mailbox_open_full(struct mailbox *box, struct istream *input)
{
int ret;
if (box->opened)
return 0;
+ if (mailbox_check_mismatching_separators(box) < 0)
+ return -1;
if (!mailbox_list_is_valid_existing_name(box->list, box->name)) {
mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
"Invalid mailbox name");
return src->v.rename(src, dest, rename_children);
}
+int mailbox_set_subscribed(struct mailbox *box, bool set)
+{
+ struct mail_namespace *ns;
+ struct mailbox_list *list = box->list;
+ const char *subs_name;
+
+ if (!mailbox_list_is_valid_existing_name(list, box->name)) {
+ mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
+ "Invalid mailbox name");
+ return -1;
+ }
+
+ if ((list->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0)
+ subs_name = box->name;
+ else {
+ /* subscriptions=no namespace, find another one where we can
+ add the subscription to */
+ ns = mail_namespace_find_subscribable(list->ns->user->namespaces,
+ box->vname);
+ if (ns == NULL) {
+ mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
+ "This namespace has no subscriptions");
+ return -1;
+ }
+ /* use <orig ns prefix><orig storage name> as the
+ subscription name */
+ subs_name = t_strconcat(list->ns->prefix, box->name, NULL);
+ /* drop the common prefix (typically there isn't one) */
+ i_assert(strncmp(ns->prefix, subs_name, strlen(ns->prefix)) == 0);
+ subs_name += strlen(ns->prefix);
+
+ list = ns->list;
+ }
+ return mailbox_list_set_subscribed(list, subs_name, set);
+}
+
struct mail_storage *mailbox_get_storage(const struct mailbox *box)
{
return box->storage;
/* Initialize mailbox without actually opening any files or verifying that
it exists. Note that append and copy may open the selected mailbox again
with possibly different readonly-state. */
-struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *name,
+struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
enum mailbox_flags flags);
/* Returns 1 if mailbox exists (even if it's unselectable),
0 if not and -1 if some error occurred. */
fails, the error is set to src's storage. */
int mailbox_rename(struct mailbox *src, struct mailbox *dest,
bool rename_children);
+/* Subscribe/unsubscribe mailbox. Subscribing to
+ nonexistent mailboxes is optional. */
+int mailbox_set_subscribed(struct mailbox *box, bool set);
/* Enable the given feature for the mailbox. */
int mailbox_enable(struct mailbox *box, enum mailbox_feature features);
struct mailbox_list *(*alloc)(void);
void (*deinit)(struct mailbox_list *list);
- int (*get_storage)(struct mailbox_list **list, const char **name,
+ int (*get_storage)(struct mailbox_list **list, const char *vname,
struct mail_storage **storage_r);
bool (*is_valid_pattern)(struct mailbox_list *list,
const char *pattern);
bool (*is_valid_create_name)(struct mailbox_list *list,
const char *name);
+ char (*get_hierarchy_sep)(struct mailbox_list *list);
+ const char *(*get_vname)(struct mailbox_list *list,
+ const char *storage_name);
+ const char *(*get_storage_name)(struct mailbox_list *list,
+ const char *vname);
const char *(*get_path)(struct mailbox_list *list, const char *name,
enum mailbox_list_path_type type);
struct mailbox_list {
const char *name;
- char hierarchy_sep;
enum mailbox_list_properties props;
size_t mailbox_name_max_length;
int mailbox_list_settings_parse(struct mail_user *user, const char *data,
struct mailbox_list_settings *set_r,
const char **error_r);
+const char *mailbox_list_default_get_storage_name(struct mailbox_list *list,
+ const char *vname);
+const char *mailbox_list_default_get_vname(struct mailbox_list *list,
+ const char *storage_name);
const char *mailbox_list_get_unexpanded_path(struct mailbox_list *list,
enum mailbox_list_path_type type);
+const char *mailbox_list_get_storage_name(struct mailbox_list *list,
+ const char *vname);
+const char *mailbox_list_get_vname(struct mailbox_list *list, const char *name);
const char *
mailbox_list_get_root_path(const struct mailbox_list_settings *set,
enum mailbox_list_path_type type);
return mailbox_list_get_root_path(&set, type);
}
+const char *mailbox_list_default_get_storage_name(struct mailbox_list *list,
+ const char *vname)
+{
+ struct mail_namespace *ns = list->ns;
+ unsigned int prefix_len = strlen(ns->prefix);
+ char list_sep, ns_sep, *ret, *p;
+
+ if (prefix_len > 0) {
+ /* skip namespace prefix, except if this is INBOX */
+ if (strncmp(ns->prefix, vname, prefix_len) == 0)
+ vname += prefix_len;
+ else if (strncmp(ns->prefix, vname, prefix_len-1) == 0 &&
+ ns->prefix[prefix_len-1] == mail_namespace_get_sep(ns)) {
+ /* trying to access the namespace prefix itself */
+ vname = "";
+ } else {
+ i_assert(strcasecmp(vname, "INBOX") == 0);
+ }
+ }
+
+ list_sep = mailbox_list_get_hierarchy_sep(list);
+ ns_sep = mail_namespace_get_sep(ns);
+
+ if (list_sep == ns_sep)
+ return vname;
+ if (ns->type == NAMESPACE_SHARED &&
+ (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
+ /* shared namespace root. the backend storage's hierarchy
+ separator isn't known yet, so do nothing. */
+ return vname;
+ }
+
+ ret = p_strdup(unsafe_data_stack_pool, vname);
+ for (p = ret; *p != '\0'; p++) {
+ if (*p == ns_sep)
+ *p = list_sep;
+ }
+ return ret;
+}
+
+const char *mailbox_list_get_storage_name(struct mailbox_list *list,
+ const char *vname)
+{
+ return list->v.get_storage_name(list, vname);
+}
+
+const char *mailbox_list_default_get_vname(struct mailbox_list *list,
+ const char *storage_name)
+{
+ unsigned int i, prefix_len, name_len;
+ char list_sep, ns_sep, *ret;
+
+ if ((list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
+ strcasecmp(storage_name, "INBOX") == 0 &&
+ list->ns->user == list->ns->owner) {
+ /* user's INBOX - use as-is */
+ return "INBOX";
+ }
+ if (*storage_name == '\0') {
+ /* return namespace prefix without the separator */
+ if (list->ns->prefix_len == 0)
+ return list->ns->prefix;
+ else {
+ return t_strndup(list->ns->prefix,
+ list->ns->prefix_len - 1);
+ }
+ }
+
+ prefix_len = strlen(list->ns->prefix);
+ list_sep = mailbox_list_get_hierarchy_sep(list);
+ ns_sep = mail_namespace_get_sep(list->ns);
+
+ if (list_sep == ns_sep && prefix_len == 0)
+ return storage_name;
+
+ /* @UNSAFE */
+ name_len = strlen(storage_name);
+ ret = t_malloc(prefix_len + name_len + 1);
+ memcpy(ret, list->ns->prefix, prefix_len);
+ for (i = 0; i < name_len; i++) {
+ ret[i + prefix_len] = storage_name[i] == list_sep ? ns_sep :
+ storage_name[i];
+ }
+ ret[i + prefix_len] = '\0';
+ return ret;
+}
+
+const char *mailbox_list_get_vname(struct mailbox_list *list, const char *name)
+{
+ return list->v.get_vname(list, name);
+}
+
void mailbox_list_destroy(struct mailbox_list **_list)
{
struct mailbox_list *list = *_list;
return list->ns->user;
}
-int mailbox_list_get_storage(struct mailbox_list **list, const char **name,
+int mailbox_list_get_storage(struct mailbox_list **list, const char *vname,
struct mail_storage **storage_r)
{
if ((*list)->v.get_storage != NULL)
- return (*list)->v.get_storage(list, name, storage_r);
+ return (*list)->v.get_storage(list, vname, storage_r);
else {
*storage_r = (*list)->ns->storage;
return 0;
*storage = list->ns->storage;
}
+char mailbox_list_get_hierarchy_sep(struct mailbox_list *list)
+{
+ return list->v.get_hierarchy_sep(list);
+}
+
static void
mailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
mode_t *file_mode_r, mode_t *dir_mode_r,
return FALSE;
glob = imap_match_init(pool_datastack_create(), pattern,
- TRUE, ns->sep);
+ TRUE, mail_namespace_get_sep(ns));
return imap_match(glob, "INBOX") == IMAP_MATCH_YES;
}
unsigned int len;
len = ns->prefix_len;
- if (len > 0 && ns->prefix[len-1] == ns->sep)
+ if (len > 0 && ns->prefix[len-1] == mail_namespace_get_sep(ns))
len--;
if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
result = IMAP_MATCH_CHILDREN;
else {
glob = imap_match_init(pool_datastack_create(), pattern,
- TRUE, ns->sep);
+ TRUE, mail_namespace_get_sep(ns));
result = imap_match(glob, prefix_without_sep);
}
break;
/* see if parent matches */
- p = strrchr(name, ns->sep);
+ p = strrchr(name, mail_namespace_get_sep(ns));
if (p == NULL)
break;
mailbox_list_get_namespace(const struct mailbox_list *list) ATTR_PURE;
struct mail_user *
mailbox_list_get_user(const struct mailbox_list *list) ATTR_PURE;
-int mailbox_list_get_storage(struct mailbox_list **list, const char **name,
+int mailbox_list_get_storage(struct mailbox_list **list, const char *vname,
struct mail_storage **storage_r);
void mailbox_list_get_closest_storage(struct mailbox_list *list,
struct mail_storage **storage);
+char mailbox_list_get_hierarchy_sep(struct mailbox_list *list);
/* Returns the mode and GID that should be used when creating new files to
the specified mailbox or to mailbox list root. (gid_t)-1 is
struct mailbox *
test_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
- const char *name, enum mailbox_flags flags);
+ const char *vname, enum mailbox_flags flags);
struct mail *
test_mailbox_mail_alloc(struct mailbox_transaction_context *t,
#include "lib.h"
#include "array.h"
#include "mail-storage-private.h"
+#include "mailbox-list-private.h"
#include "test-mail-storage.h"
#define TEST_UID_VALIDITY 1
struct mailbox *
test_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
- const char *name, enum mailbox_flags flags)
+ const char *vname, enum mailbox_flags flags)
{
struct mailbox *box;
pool_t pool;
pool = pool_alloconly_create("test mailbox", 1024);
box = p_new(pool, struct mailbox, 1);
*box = test_mailbox;
- box->name = p_strdup(pool, name);
+ box->vname = p_strdup(pool, vname);
+ box->name = p_strdup(pool, mailbox_list_get_storage_name(list, vname));
box->storage = storage;
box->list = list;
const char *name;
int ret;
- name = mail_namespace_get_storage_name(backend->backend.list->ns,
- vname);
+ name = mailbox_list_get_storage_name(backend->backend.list, vname);
acl_cache_flush(backend->backend.cache, name);
aclobj = acl_object_init_from_name(&backend->backend, name);
#include "file-dotlock.h"
#include "nfs-workarounds.h"
#include "mail-storage-private.h"
+#include "mailbox-list-private.h"
#include "mail-namespace.h"
#include "acl-cache.h"
#include "acl-backend-vfile.h"
struct acl_backend_vfile *backend =
(struct acl_backend_vfile *)_backend;
struct acl_object_vfile *aclobj;
- const char *dir;
+ const char *dir, *vname;
aclobj = i_new(struct acl_object_vfile, 1);
aclobj->aclobj.backend = _backend;
aclobj->aclobj.name = i_strdup(name);
if (backend->global_dir != NULL) T_BEGIN {
- struct mail_namespace *ns =
- mailbox_list_get_namespace(_backend->list);
- string_t *vname;
-
- vname = t_str_new(128);
- mail_namespace_get_vname(ns, vname, name);
+ vname = mailbox_list_get_vname(backend->backend.list, name);
aclobj->global_path = i_strconcat(backend->global_dir, "/",
- str_c(vname), NULL);
+ vname, NULL);
} T_END;
dir = acl_backend_vfile_get_local_dir(_backend, name);
struct mail_namespace *ns = mailbox_list_get_namespace(backend->list);
const char *p;
- p = strrchr(name, ns->real_sep);
+ p = strrchr(name, mail_namespace_get_sep(ns));
return p == NULL ? NULL : t_strdup_until(name, p);
}
struct mail_namespace *ns = ctx->ctx.list->ns;
struct mailbox_list_iter_update_context update_ctx;
const char *name;
- string_t *vname = NULL;
int ret;
if ((ctx->ctx.flags & (MAILBOX_LIST_ITER_RAW_LIST |
return;
/* no LOOKUP right by default, we can optimize this */
- vname = t_str_new(256);
memset(&update_ctx, 0, sizeof(update_ctx));
update_ctx.iter_ctx = &ctx->ctx;
update_ctx.glob =
nonowner_list_ctx = acl_backend_nonowner_lookups_iter_init(backend);
while ((ret = acl_backend_nonowner_lookups_iter_next(nonowner_list_ctx,
&name)) > 0) {
- if (vname != NULL)
- name = mail_namespace_get_vname(ns, vname, name);
- mailbox_list_iter_update(&update_ctx, name);
+ T_BEGIN {
+ const char *vname =
+ mailbox_list_get_vname(ns->list, name);
+ mailbox_list_iter_update(&update_ctx, vname);
+ } T_END;
}
acl_backend_nonowner_lookups_iter_deinit(&nonowner_list_ctx);
ctx->ctx.flags = flags;
inboxcase = (list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0;
- ctx->sep = list->ns->sep;
+ ctx->sep = mail_namespace_get_sep(list->ns);
ctx->glob = imap_match_init_multiple(default_pool, patterns,
inboxcase, ctx->sep);
/* see if all patterns have only a single '*' and it's at the end.
static const char *
acl_mailbox_list_iter_get_name(struct mailbox_list_iterate_context *ctx,
- const char *name)
+ const char *vname)
{
struct mail_namespace *ns = ctx->list->ns;
+ const char *name;
unsigned int len;
- name = mail_namespace_get_storage_name(ns, name);
+ name = mailbox_list_get_storage_name(ns->list, vname);
len = strlen(name);
- if (len > 0 && name[len-1] == ns->real_sep) {
+ if (len > 0 && name[len-1] == mailbox_list_get_hierarchy_sep(ns->list)) {
/* name ends with separator. this can happen if doing e.g.
LIST "" foo/% and it lists "foo/". */
name = t_strndup(name, len-1);
const char *str;
enum mail_error error;
- ns = mail_namespace_find(namespaces, &name);
+ ns = mail_namespace_find(namespaces, name);
if (ns == NULL) {
if (namespaces->mail_set->mail_debug)
i_debug("autocreate: No namespace found for %s", name);
autosubscribe_mailbox(struct mail_namespace *namespaces, const char *name)
{
struct mail_namespace *ns;
+ struct mailbox *box;
const char *str;
enum mail_error error;
- ns = mail_namespace_find_subscribable(namespaces, &name);
+ ns = mail_namespace_find_subscribable(namespaces, name);
if (ns == NULL) {
if (namespaces->mail_set->mail_debug)
i_debug("autocreate: No namespace found for %s", name);
return;
}
- if (mailbox_list_set_subscribed(ns->list, name, TRUE) < 0) {
- str = mailbox_list_get_last_error(ns->list,
- &error);
+ box = mailbox_alloc(ns->list, name, 0);
+ if (mailbox_set_subscribed(box, TRUE) < 0) {
+ str = mailbox_get_last_error(box, &error);
if (error != MAIL_ERROR_EXISTS && ns->mail_set->mail_debug) {
i_debug("autocreate: Failed to subscribe mailbox "
"%s: %s", name, str);
}
}
+ mailbox_free(&box);
}
static void autosubscribe_mailboxes(struct mail_namespace *namespaces)
#include "strescape.h"
#include "unichar.h"
#include "mail-storage-private.h"
-#include "mail-namespace.h"
+#include "mailbox-list-private.h"
#include "fts-mailbox.h"
#include "solr-connection.h"
#include "fts-solr-plugin.h"
struct solr_virtual_uid_map_context {
struct fts_backend *backend;
struct mailbox *box;
- string_t *vname;
};
struct fts_backend_solr_get_last_uids_context {
ARRAY_TYPE(fts_backend_uid_map) *last_uids;
struct mailbox *box;
- string_t *vname;
};
static struct solr_connection *solr_conn = NULL;
struct fts_backend_solr_get_last_uids_context *ctx = context;
struct fts_backend_uid_map *map;
struct mail_namespace *ns;
- const char *vname;
ns = solr_get_namespaces(ctx->backend, ctx->box, ns_prefix);
- for (; ns != NULL; ns = ns->alias_chain_next) {
- vname = mail_namespace_get_vname(ns, ctx->vname, mailbox);
+ for (; ns != NULL; ns = ns->alias_chain_next) T_BEGIN {
+ const char *vname = mailbox_list_get_vname(ns->list, mailbox);
map = array_append_space(ctx->last_uids);
map->mailbox = p_strdup(ctx->pool, vname);
map->uidvalidity = uidvalidity;
map->uid = *uid;
- }
+ } T_END;
return FALSE;
}
const char *name, *p;
name = pattern->pattern;
- if (!mail_namespace_update_name(pattern->ns, &name))
- name = mail_namespace_fix_sep(pattern->ns, name);
-
fts_box_name_get_root(&ns, &name);
if (strcmp(name, "*") == 0) {
ctx.pool = pool;
ctx.last_uids = last_uids;
ctx.box = backend->box;
- ctx.vname = t_str_new(256);
str = t_str_new(256);
str_printfa(str, "fl=uid,box,uidv,ns&rows=%u&q=last_uid:TRUE+user:",
{
struct solr_virtual_uid_map_context *ctx = context;
struct mail_namespace *ns;
- const char *vname;
- bool convert_inbox;
+ bool convert_inbox, ret;
ns = solr_get_namespaces(ctx->backend, ctx->box, ns_prefix);
convert_inbox = (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
strcmp(mailbox, "INBOX") == 0;
for (; ns != NULL; ns = ns->alias_chain_next) {
- vname = convert_inbox ? ns->prefix :
- mail_namespace_get_vname(ns, ctx->vname, mailbox);
- if (fts_mailbox_get_virtual_uid(ctx->box, vname, uidvalidity,
- *uid, uid))
+ T_BEGIN {
+ const char *vname = convert_inbox ? ns->prefix :
+ mailbox_list_get_vname(ns->list, mailbox);
+ ret = fts_mailbox_get_virtual_uid(ctx->box, vname,
+ uidvalidity,
+ *uid, uid);
+ } T_END;
+ if (ret)
return TRUE;
}
return FALSE;
memset(&uid_map_ctx, 0, sizeof(uid_map_ctx));
uid_map_ctx.backend = ctx->backend;
uid_map_ctx.box = box;
- uid_map_ctx.vname = t_str_new(256);
return solr_connection_select(solr_conn, str_c(str),
solr_virtual_uid_map,
&uid_map_ctx,
#include "mail-namespace.h"
#include "mail-search-build.h"
#include "mail-storage-private.h"
+#include "mailbox-list-private.h"
#include "fts-api-private.h"
#include "fts-mailbox.h"
#include "fts-storage.h"
int ret;
T_BEGIN {
- string_t *tmp1, *tmp2;
const char *vname1, *vname2;
- tmp1 = t_str_new(128);
- tmp2 = t_str_new(128);
- vname1 = mail_namespace_get_vname(box1->ns, tmp1, box1->name);
- vname2 = mail_namespace_get_vname(box2->ns, tmp2, box2->name);
+ vname1 = mailbox_list_get_vname(box1->ns->list, box1->name);
+ vname2 = mailbox_list_get_vname(box2->ns->list, box2->name);
ret = strcmp(vname1, vname2);
} T_END;
return ret;
const struct fts_orig_mailboxes *boxes;
const struct fts_backend_uid_map *last_uids;
unsigned int boxi, uidi, box_count, last_uid_count;
- const char *vname;
- string_t *tmp;
int ret, vret = 0;
if (vctx->pool == NULL)
boxes = array_get(&vctx->orig_mailboxes, &box_count);
last_uids = array_get(&vctx->last_uids, &last_uid_count);
- tmp = t_str_new(256);
boxi = vctx->boxi;
uidi = vctx->uidi;
while (vret == 0 && boxi < box_count && uidi < last_uid_count) {
- vname = mail_namespace_get_vname(boxes[boxi].ns, tmp,
- boxes[boxi].name);
- ret = strcmp(vname, last_uids[uidi].mailbox);
+ T_BEGIN {
+ const char *vname;
+
+ vname = mailbox_list_get_vname(boxes[boxi].ns->list,
+ boxes[boxi].name);
+ ret = strcmp(vname, last_uids[uidi].mailbox);
+ } T_END;
if (ret == 0) {
/* match. check also that uidvalidity matches. */
mailbox_get_open_status(boxes[boxi].box,
{
struct mail_namespace *ns;
struct mailbox *box;
- const char *storage_name;
int ret;
if (ACL_USER_CONTEXT(cmd->client->user) == NULL) {
return NULL;
}
- ns = client_find_namespace(cmd, name, &storage_name);
+ ns = client_find_namespace(cmd, &name);
if (ns == NULL)
return NULL;
/* Force opening the mailbox so that we can give a nicer error message
if mailbox isn't selectable but is listable. */
- box = mailbox_alloc(ns->list, storage_name, ACL_MAILBOX_FLAGS |
+ box = mailbox_alloc(ns->list, name, ACL_MAILBOX_FLAGS |
MAILBOX_FLAG_IGNORE_ACLS);
ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_ADMIN);
if (ret > 0)
{
struct mail_namespace *ns;
struct mailbox *box;
- const char *mailbox, *storage_name;
+ const char *mailbox;
const char *const *rights;
string_t *str;
return TRUE;
}
- ns = client_find_namespace(cmd, mailbox, &storage_name);
+ ns = client_find_namespace(cmd, &mailbox);
if (ns == NULL)
return TRUE;
- box = mailbox_alloc(ns->list, storage_name,
+ box = mailbox_alloc(ns->list, mailbox,
ACL_MAILBOX_FLAGS | MAILBOX_FLAG_IGNORE_ACLS);
if (acl_object_get_my_rights(acl_mailbox_get_aclobj(box),
pool_datastack_create(), &rights) < 0) {
struct mailbox *box;
struct quota_root_iter *iter;
struct quota_root *root;
- const char *mailbox, *storage_name, *name;
+ const char *mailbox, *name;
string_t *quotaroot_reply, *quota_reply;
/* <mailbox> */
if (!client_read_string_args(cmd, 1, &mailbox))
return FALSE;
- ns = client_find_namespace(cmd, mailbox, &storage_name);
+ ns = client_find_namespace(cmd, &mailbox);
if (ns == NULL)
return TRUE;
return TRUE;
}
- box = mailbox_alloc(ns->list, storage_name, MAILBOX_FLAG_READONLY |
+ box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY |
MAILBOX_FLAG_KEEP_RECENT);
/* build QUOTAROOT reply and QUOTA reply for all quota roots */
#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_iter {
- struct mailbox_list_iterate_context *ctx;
- string_t *name;
- struct mailbox_info info;
-};
-
struct listescape_mailbox_list {
union mailbox_list_module_context module_ctx;
- ARRAY_DEFINE(iters, struct listescape_mailbox_list_iter);
char escape_char;
};
const char *listescape_plugin_version = DOVECOT_VERSION;
-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 listescape_mailbox_list *mlist,
- struct mail_namespace *ns, const char *str, bool vname)
+ struct mail_namespace *ns, const char *str)
{
+ char ns_sep = mail_namespace_get_sep(ns);
+ char list_sep = mailbox_list_get_hierarchy_sep(ns->list);
string_t *esc = t_str_new(64);
unsigned int i;
if (i > ns->prefix_len)
i = ns->prefix_len;
- if (vname && i > 0 && strncmp(ns->prefix, str, i) == 0) {
+ if (i > 0 && strncmp(ns->prefix, str, i) == 0) {
str_append_n(esc, str, i);
str += i;
}
str++;
}
for (; *str != '\0'; str++) {
- if (*str == ns->sep) {
- if (!vname)
- str_append_c(esc, ns->list->hierarchy_sep);
- else
- str_append_c(esc, *str);
- } else if (*str == ns->list->hierarchy_sep ||
- *str == mlist->escape_char || *str == '/')
+ if (*str == ns_sep)
+ str_append_c(esc, *str);
+ else if (*str == list_sep ||
+ *str == mlist->escape_char || *str == '/')
str_printfa(esc, "%c%02x", mlist->escape_char, *str);
else
str_append_c(esc, *str);
return str_c(esc);
}
-static void list_unescape_str(struct listescape_mailbox_list *mlist,
- struct mail_namespace *ns,
- const char *str, string_t *dest)
+static const char *
+list_unescape(struct listescape_mailbox_list *mlist,
+ struct mail_namespace *ns, const char *str)
{
+ char ns_sep = mail_namespace_get_sep(ns);
+ char list_sep = mailbox_list_get_hierarchy_sep(ns->list);
+ string_t *dest = t_str_new(strlen(str));
unsigned int num;
for (; *str != '\0'; str++) {
str_append_c(dest, num);
str += 2;
- } else if (*str == ns->list->hierarchy_sep)
- str_append_c(dest, ns->sep);
+ } else if (*str == list_sep)
+ str_append_c(dest, ns_sep);
else
str_append_c(dest, *str);
}
+ return str_c(dest);
}
-static struct mail_namespace *
-listescape_find_orig_ns(struct mail_namespace *parent_ns, const char *name)
-{
- struct mail_namespace *ns, *best = NULL;
-
- for (ns = parent_ns->user->namespaces; ns != NULL; ns = ns->next) {
- if ((ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0)
- continue;
-
- if (strncmp(ns->prefix, parent_ns->prefix,
- parent_ns->prefix_len) == 0 &&
- strncmp(ns->prefix + parent_ns->prefix_len, name,
- ns->prefix_len) == 0) {
- if (best == NULL || ns->prefix_len > best->prefix_len)
- best = ns;
- }
- }
- return best != NULL ? best : parent_ns;
-}
-
-static const char *const *
-iter_escape_patterns(struct mailbox_list *list,
- const char *const *patterns,
- enum mailbox_list_iter_flags flags)
+static const char *listescape_list_get_vname(struct mailbox_list *list,
+ const char *storage_name)
{
struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
- struct mail_namespace *orig_ns;
- const char **escaped_patterns;
- unsigned int i;
+ const char *vname;
- escaped_patterns = t_new(const char *, str_array_length(patterns) + 1);
- for (i = 0; patterns[i] != NULL; i++) {
- if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
- /* we may be listing subscriptions for other namespaces
- prefixes. don't escape characters in the namespace
- prefixes. */
- orig_ns = listescape_find_orig_ns(list->ns,
- patterns[i]);
- } else {
- orig_ns = list->ns;
- }
- escaped_patterns[i] = list_escape(mlist, orig_ns,
- patterns[i], TRUE);
- }
- return escaped_patterns;
+ vname = mlist->module_ctx.super.get_vname(list, storage_name);
+ return list_unescape(mlist, list->ns, vname);
}
-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)
+static const char *listescape_list_get_storage_name(struct mailbox_list *list,
+ const char *vname)
{
struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
- struct mailbox_list_iterate_context *ctx;
- struct listescape_mailbox_list_iter *liter;
-
- /* this is kind of kludgy. In ACL code we want to convert patterns,
- in maildir renaming code we don't. so for now just use the _RAW_LIST
- flag.. */
- if ((flags & MAILBOX_LIST_ITER_RAW_LIST) == 0)
- patterns = iter_escape_patterns(list, patterns, flags);
- /* 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;
-
- liter = array_append_space(&mlist->iters);
- liter->ctx = ctx;
- liter->name = str_new(default_pool, 256);
- return ctx;
-}
-
-static struct listescape_mailbox_list_iter *
-listescape_mailbox_list_iter_find(struct listescape_mailbox_list *mlist,
- struct mailbox_list_iterate_context *ctx)
-{
- struct listescape_mailbox_list_iter *liter;
-
- array_foreach_modifiable(&mlist->iters, liter) {
- if (liter->ctx == ctx)
- return liter;
- }
- return NULL;
-}
-
-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);
- struct mail_namespace *ns;
- struct listescape_mailbox_list_iter *liter;
- const struct mailbox_info *info;
-
- liter = listescape_mailbox_list_iter_find(mlist, ctx);
- i_assert(liter != NULL);
-
- 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)
- return info;
-
- ns = (ctx->flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0 ?
- ctx->list->ns :
- listescape_find_orig_ns(ctx->list->ns, info->name);
-
- if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
- strcasecmp(info->name, "INBOX") == 0)
- return info;
-
- str_truncate(liter->name, 0);
- str_append(liter->name, ns->prefix);
- list_unescape_str(mlist, ns, info->name + ns->prefix_len, liter->name);
- liter->info = *info;
- liter->info.name = str_c(liter->name);
- return &liter->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);
- struct listescape_mailbox_list_iter *liters;
- unsigned int i, count;
- int ret;
-
- liters = array_get_modifiable(&mlist->iters, &count);
- for (i = 0; i < count; i++) {
- if (liters[i].ctx == ctx) {
- str_free(&liters[i].name);
- array_delete(&mlist->iters, i, 1);
- }
- }
-
- 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_alloc(struct mail_storage *storage,
- struct mailbox_list *list,
- const char *name, enum mailbox_flags flags)
-{
- struct listescape_mail_storage *mstorage = LIST_ESCAPE_CONTEXT(storage);
- struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
-
- if (list->hierarchy_sep != list->ns->sep)
- name = list_escape(mlist, list->ns, name, FALSE);
- return mstorage->module_ctx.super.
- mailbox_alloc(storage, list, name, flags);
-}
-
-static int listescape_set_subscribed(struct mailbox_list *list,
- const char *name, bool set)
-{
- struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
- struct mail_namespace *ns;
- const char *esc_name;
-
- ns = listescape_find_orig_ns(list->ns, name);
- if (ns == list->ns || strncmp(ns->prefix, name, ns->prefix_len) != 0)
- name = list_escape(mlist, ns, name, FALSE);
- else {
- esc_name = list_escape(mlist, ns, name + ns->prefix_len, FALSE);
- name = t_strconcat(ns->prefix, esc_name, NULL);
- }
- return mlist->module_ctx.super.set_subscribed(list, name, set);
-}
-
-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(mlist, list->ns, name, FALSE);
- 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(mlist, list->ns, name, FALSE);
- 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;
- struct mail_storage_vfuncs *v = storage->vlast;
-
- mstorage = p_new(storage->pool, struct listescape_mail_storage, 1);
- mstorage->module_ctx.super = *v;
- storage->vlast = &mstorage->module_ctx.super;
- v->mailbox_alloc = listescape_mailbox_alloc;
-
- MODULE_CONTEXT_SET(storage, listescape_storage_module, mstorage);
+ return mlist->module_ctx.super.
+ get_storage_name(list, list_escape(mlist, list->ns, vname));
}
static void listescape_mailbox_list_created(struct mailbox_list *list)
struct mailbox_list_vfuncs *v = list->vlast;
struct listescape_mailbox_list *mlist;
const char *env;
+ char ns_sep = mail_namespace_get_sep(list->ns);
+ char list_sep = mailbox_list_get_hierarchy_sep(list);
- if (list->hierarchy_sep == list->ns->sep)
+ if (list_sep == ns_sep)
return;
- list->ns->real_sep = list->ns->sep;
-
mlist = p_new(list->pool, struct listescape_mailbox_list, 1);
mlist->module_ctx.super = *v;
list->vlast = &mlist->module_ctx.super;
- p_array_init(&mlist->iters, list->pool, 4);
- v->iter_init = listescape_mailbox_list_iter_init;
- v->iter_next = listescape_mailbox_list_iter_next;
- v->iter_deinit = listescape_mailbox_list_iter_deinit;
- v->set_subscribed = listescape_set_subscribed;
- v->is_valid_existing_name = listescape_is_valid_existing_name;
- v->is_valid_create_name = listescape_is_valid_create_name;
+ v->get_vname = listescape_list_get_vname;
+ v->get_storage_name = listescape_list_get_storage_name;
env = mail_user_plugin_getenv(list->ns->user, "listescape_char");
mlist->escape_char = env != NULL && *env != '\0' ?
}
static struct mail_storage_hooks listescape_mail_storage_hooks = {
- .mail_storage_created = listescape_mail_storage_created,
.mailbox_list_created = listescape_mailbox_list_created
};
struct mail_search_context *ctx;
struct mail *mail;
struct mail_search_args *search_args;
- const char *storage_name;
enum mail_error error;
uoff_t size;
int ret = 0;
- storage_name = mail_namespace_get_storage_name(ns, vname);
-
rule = quota_root_rule_find(root->set, vname);
if (rule != NULL && rule->ignore) {
/* mailbox not included in quota */
return 0;
}
- box = mailbox_alloc(ns->list, storage_name,
+ box = mailbox_alloc(ns->list, vname,
MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT);
if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
error = mailbox_get_last_mail_error(box);
#include "write-full.h"
#include "str.h"
#include "maildir-storage.h"
+#include "mailbox-list-private.h"
#include "quota-private.h"
#include <stdio.h>
T_BEGIN {
const char *path, *storage_name;
- storage_name = mail_namespace_get_storage_name(
- ctx->info->ns, ctx->info->name);
+ storage_name = mailbox_list_get_storage_name(
+ ctx->info->ns->list, ctx->info->name);
path = mailbox_list_get_path(ctx->list, storage_name,
MAILBOX_LIST_PATH_TYPE_MAILBOX);
str_truncate(ctx->path, 0);
{
struct mailbox_list *list;
struct mail_storage *storage;
- const char *name = "";
if (root->limits_initialized)
return root->maildirsize_path != NULL;
i_assert(root->maildirsize_path != NULL);
list = root->maildirsize_ns->list;
- if (mailbox_list_get_storage(&list, &name, &storage) == 0 &&
+ if (mailbox_list_get_storage(&list, "", &storage) == 0 &&
strcmp(storage->name, MAILDIR_STORAGE_NAME) != 0) {
/* non-maildir namespace, skip */
if ((storage->class_flags &
array_foreach(&root->set->rules, rule) {
name = rule->mailbox_name;
- if (mail_namespace_find(namespaces, &name) == NULL)
+ if (mail_namespace_find(namespaces, name) == NULL)
i_error("quota: Unknown namespace: %s", name);
}
}
{
struct mailbox_list *list = ns->list;
struct mail_storage *storage;
- const char *name = "";
/* this check works as long as there is only one storage per list */
- if (mailbox_list_get_storage(&list, &name, &storage) == 0 &&
+ if (mailbox_list_get_storage(&list, "", &storage) == 0 &&
(storage->class_flags & MAIL_STORAGE_CLASS_FLAG_NOQUOTA) != 0)
return FALSE;
if (snarf_name == NULL)
return FALSE;
- snarf_ns = mail_namespace_find(user->namespaces, &snarf_name);
+ snarf_ns = mail_namespace_find(user->namespaces, snarf_name);
if (snarf_ns == NULL) {
i_error("snarf: Namespace not found for mailbox: %s",
snarf_name);
static struct mailbox *
snarf_mailbox_alloc(struct mail_storage *storage,
- struct mailbox_list *list, const char *name,
- enum mailbox_flags flags)
+ struct mailbox_list *list,
+ const char *vname, enum mailbox_flags flags)
{
struct snarf_mail_storage *sstorage = SNARF_CONTEXT(storage);
struct mail_namespace *ns = mailbox_list_get_namespace(list);
const char *snarf_name;
struct stat st;
- if (strcmp(name, "INBOX") == 0 &&
+ if (strcmp(vname, "INBOX") == 0 &&
(ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
if (stat(sstorage->snarf_path, &st) == 0)
sstorage->snarfing_disabled = FALSE;
if (snarf_box_find(storage->user, &snarf_list,
&snarf_name)) {
list = snarf_list;
- name = snarf_name;
+ vname = snarf_name;
}
}
}
box = sstorage->module_ctx.super.
- mailbox_alloc(storage, list, name, flags);
+ mailbox_alloc(storage, list, vname, flags);
if (sstorage->snarfing_disabled) {
box->inbox_user = TRUE;
box->inbox_any = TRUE;
struct trash_mailbox *trash)
{
struct mail_namespace *ns;
- const char *name;
- for (ns = user->namespaces; ns != NULL; ns = ns->next) {
- name = trash->name;
- if (mail_namespace_update_name(ns, &name)) {
- if (name != trash->name)
- trash->name = p_strdup(user->pool, name);
- trash->ns = ns;
- return TRUE;
- }
+ ns = mail_namespace_find(user->namespaces, trash->name);
+ if (ns != NULL) {
+ trash->ns = ns;
+ return TRUE;
}
return FALSE;
}
if (*line == '-' || *line == '!') line++;
bbox->ns = strcasecmp(line, "INBOX") == 0 ?
mail_namespace_find_inbox(user->namespaces) :
- mail_namespace_find(user->namespaces, &line);
+ mail_namespace_find(user->namespaces, line);
if (bbox->ns == NULL) {
*error_r = t_strdup_printf("Namespace not found for %s",
bbox->name);
return box->vname;
else {
return t_strdup_printf("<hidden>%c%s",
- box->list->hierarchy_sep, box->name);
+ mail_namespace_get_sep(box->list->ns),
+ box->vname);
}
}
flags |= MAILBOX_FLAG_KEEP_RECENT;
mailbox = bbox->name;
- ns = mail_namespace_find(user->namespaces, &mailbox);
+ ns = mail_namespace_find(user->namespaces, mailbox);
bbox->box = mailbox_alloc(ns->list, mailbox, flags);
if (mailbox_open(bbox->box) < 0)
static struct mailbox *
virtual_mailbox_alloc(struct mail_storage *_storage, struct mailbox_list *list,
- const char *name, enum mailbox_flags flags)
+ const char *vname, enum mailbox_flags flags)
{
struct virtual_storage *storage = (struct virtual_storage *)_storage;
struct virtual_mailbox *mbox;
mbox->box.mail_vfuncs = &virtual_mail_vfuncs;
mbox->vfuncs = virtual_mailbox_vfuncs;
- index_storage_mailbox_alloc(&mbox->box, name, flags,
+ index_storage_mailbox_alloc(&mbox->box, vname, flags,
VIRTUAL_INDEX_PREFIX);
mbox->storage = storage;
{
struct mail_namespace *ns;
struct mail_storage *storage;
- const char *inbox, *ident;
+ const char *ident;
struct client *client;
enum mailbox_flags flags;
const char *errmsg;
pop3_client_count++;
DLLIST_PREPEND(&pop3_clients, client);
- inbox = "INBOX";
- ns = mail_namespace_find(user->namespaces, &inbox);
+ ns = mail_namespace_find(user->namespaces, "INBOX");
if (ns == NULL) {
client_send_line(client, "-ERR No INBOX namespace for user.");
client_destroy(client, "No INBOX namespace for user.");