static bool
subscribe_is_valid_name(struct client_command_context *cmd, const char *mailbox)
{
- enum mailbox_name_status name_status;
struct mail_namespace *ns;
+ struct mailbox *box;
const char *storage_name;
+ int ret;
if (have_listable_namespace_prefix(cmd->client->user->namespaces,
mailbox)) {
if (ns == NULL)
return FALSE;
- if (mailbox_list_get_mailbox_name_status(ns->list, storage_name,
- &name_status) < 0) {
- client_send_list_error(cmd, ns->list);
+ 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;
}
- if (name_status == MAILBOX_NAME_NONEXISTENT) {
+ mailbox_free(&box);
+
+ if (ret == 0) {
client_send_tagline(cmd, t_strdup_printf(
"NO "MAIL_ERRSTR_MAILBOX_NOT_FOUND, mailbox));
return FALSE;
index_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
+ index_storage_mailbox_exists,
cydir_mailbox_open,
index_storage_mailbox_close,
index_storage_mailbox_free,
index_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
+ index_storage_mailbox_exists,
mdbox_mailbox_open,
mdbox_mailbox_close,
index_storage_mailbox_free,
index_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
+ index_storage_mailbox_exists,
sdbox_mailbox_open,
sdbox_mailbox_close,
index_storage_mailbox_free,
index_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
+ index_storage_mailbox_exists,
imapc_mailbox_open,
imapc_mailbox_close,
index_storage_mailbox_free,
box->index_prefix);
}
+int index_storage_mailbox_exists(struct mailbox *box)
+{
+ struct stat st;
+ const char *path;
+
+ if (strcmp(box->name, "INBOX") == 0 &&
+ (box->list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
+ /* INBOX always exists */
+ return 1;
+ }
+
+ path = mailbox_list_get_path(box->list, box->name,
+ MAILBOX_LIST_PATH_TYPE_MAILBOX);
+ if (stat(path, &st) == 0)
+ return 1;
+ else if (ENOTFOUND(errno) || errno == EACCES)
+ return 0;
+ else {
+ mail_storage_set_critical(box->storage,
+ "stat(%s) failed: %m", path);
+ return -1;
+ }
+}
+
+
int index_storage_mailbox_open(struct mailbox *box, bool move_to_memory)
{
struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
void index_storage_mailbox_alloc(struct mailbox *box, const char *name,
enum mailbox_flags flags,
const char *index_prefix);
+int index_storage_mailbox_exists(struct mailbox *box);
int index_storage_mailbox_open(struct mailbox *box, bool move_to_memory);
int index_storage_mailbox_enable(struct mailbox *box,
enum mailbox_feature feature);
maildir_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
+ index_storage_mailbox_exists,
maildir_mailbox_open,
maildir_mailbox_close,
index_storage_mailbox_free,
mbox_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
+ index_storage_mailbox_exists,
mbox_mailbox_open,
mbox_mailbox_close,
index_storage_mailbox_free,
index_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
+ index_storage_mailbox_exists,
raw_mailbox_open,
index_storage_mailbox_close,
index_storage_mailbox_free,
return mailbox_list_get_path(ns->list, name, type);
}
-static int
-shared_list_get_mailbox_name_status(struct mailbox_list *list, const char *name,
- enum mailbox_name_status *status_r)
-{
- struct mail_namespace *ns = list->ns;
- int ret;
-
- if (shared_storage_get_namespace(&ns, &name) < 0)
- return -1;
- ret = mailbox_list_get_mailbox_name_status(ns->list, name, status_r);
- if (ret < 0)
- shared_list_copy_error(list, ns);
- return ret;
-}
-
static const char *
shared_list_get_temp_prefix(struct mailbox_list *list, bool global ATTR_UNUSED)
{
shared_is_valid_existing_name,
shared_is_valid_create_name,
shared_list_get_path,
- shared_list_get_mailbox_name_status,
shared_list_get_temp_prefix,
shared_list_join_refpattern,
shared_list_iter_init,
}
}
-static int
-fs_list_get_mailbox_name_status(struct mailbox_list *_list, const char *name,
- enum mailbox_name_status *status)
-{
- struct stat st;
- const char *path, *dir_path;
- enum mailbox_info_flags flags;
-
- if (strcmp(name, "INBOX") == 0 &&
- (_list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
- *status = MAILBOX_NAME_EXISTS_MAILBOX;
- return 0;
- }
-
- path = mailbox_list_get_path(_list, name,
- MAILBOX_LIST_PATH_TYPE_MAILBOX);
- if (stat(path, &st) == 0) {
- if (*_list->set.maildir_name != '\0' ||
- _list->v.is_internal_name == NULL || !S_ISDIR(st.st_mode)) {
- *status = MAILBOX_NAME_EXISTS_MAILBOX;
- return 0;
- }
-
- /* check if mailbox is selectable */
- if (mailbox_list_mailbox(_list, name, &flags) < 0)
- return -1;
- if ((flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) == 0)
- *status = MAILBOX_NAME_EXISTS_MAILBOX;
- else
- *status = MAILBOX_NAME_EXISTS_DIR;
- return 0;
- }
- if (errno == ENOENT) {
- /* see if the directory exists */
- dir_path = mailbox_list_get_path(_list, name,
- MAILBOX_LIST_PATH_TYPE_DIR);
- if (strcmp(path, dir_path) != 0 && stat(dir_path, &st) == 0) {
- *status = MAILBOX_NAME_EXISTS_DIR;
- return 0;
- }
- errno = ENOENT;
- }
-
- if (ENOTFOUND(errno) || errno == EACCES) {
- *status = MAILBOX_NAME_NONEXISTENT;
- return 0;
- } else {
- mailbox_list_set_critical(_list, "stat(%s) failed: %m", path);
- return -1;
- }
-}
-
static const char *
fs_list_get_temp_prefix(struct mailbox_list *_list, bool global)
{
fs_is_valid_existing_name,
fs_is_valid_create_name,
fs_list_get_path,
- fs_list_get_mailbox_name_status,
fs_list_get_temp_prefix,
fs_list_join_refpattern,
fs_list_iter_init,
return maildir_list_get_dirname_path(_list, root_dir, name);
}
-static int
-maildir_list_get_mailbox_name_status(struct mailbox_list *_list,
- const char *name,
- enum mailbox_name_status *status)
-{
- struct stat st;
- const char *path;
-
- path = mailbox_list_get_path(_list, name,
- MAILBOX_LIST_PATH_TYPE_MAILBOX);
-
- if ((strcmp(name, "INBOX") == 0 &&
- (_list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) ||
- stat(path, &st) == 0) {
- *status = MAILBOX_NAME_EXISTS_MAILBOX;
- return 0;
- }
-
- if (ENOTFOUND(errno) || errno == EACCES) {
- *status = MAILBOX_NAME_NONEXISTENT;
- return 0;
- } else {
- mailbox_list_set_critical(_list, "stat(%s) failed: %m", path);
- return -1;
- }
-}
-
static const char *
maildir_list_get_temp_prefix(struct mailbox_list *_list, bool global)
{
maildir_is_valid_existing_name,
maildir_is_valid_create_name,
maildir_list_get_path,
- maildir_list_get_mailbox_name_status,
maildir_list_get_temp_prefix,
NULL,
maildir_list_iter_init,
maildir_is_valid_existing_name,
maildir_is_valid_create_name,
maildir_list_get_path,
- maildir_list_get_mailbox_name_status,
maildir_list_get_temp_prefix,
NULL,
maildir_list_iter_init,
return NULL;
}
-static int
-none_list_get_mailbox_name_status(struct mailbox_list *list ATTR_UNUSED,
- const char *name ATTR_UNUSED,
- enum mailbox_name_status *status)
-{
- *status = MAILBOX_NAME_NONEXISTENT;
- return 0;
-}
-
static const char *
none_list_get_temp_prefix(struct mailbox_list *list ATTR_UNUSED,
bool global ATTR_UNUSED)
none_is_valid_existing_name,
none_is_valid_create_name,
none_list_get_path,
- none_list_get_mailbox_name_status,
none_list_get_temp_prefix,
NULL,
none_list_iter_init,
bool (*allow_new_keywords)(struct mailbox *box);
int (*enable)(struct mailbox *box, enum mailbox_feature features);
+ int (*exists)(struct mailbox *box);
int (*open)(struct mailbox *box);
void (*close)(struct mailbox *box);
void (*free)(struct mailbox *box);
return box;
}
+int mailbox_exists(struct mailbox *box)
+{
+ if (!mailbox_list_is_valid_existing_name(box->list, box->name)) {
+ mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
+ "Invalid mailbox name");
+ return -1;
+ }
+
+ return box->v.exists(box);
+}
+
static int mailbox_open_full(struct mailbox *box, struct istream *input)
{
int ret;
with possibly different readonly-state. */
struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *name,
enum mailbox_flags flags);
+/* Returns 1 if mailbox exists (even if it's unselectable),
+ 0 if not and -1 if some error occurred. */
+int mailbox_exists(struct mailbox *box);
/* Open the mailbox. If this function isn't called explicitly, it's also called
internally by lib-storage when necessary. */
int mailbox_open(struct mailbox *box);
const char *(*get_path)(struct mailbox_list *list, const char *name,
enum mailbox_list_path_type type);
- int (*get_mailbox_name_status)(struct mailbox_list *list,
- const char *name,
- enum mailbox_name_status *status);
const char *(*get_temp_prefix)(struct mailbox_list *list, bool global);
const char *(*join_refpattern)(struct mailbox_list *list,
return pattern;
}
-int mailbox_list_get_mailbox_name_status(struct mailbox_list *list,
- const char *name,
- enum mailbox_name_status *status)
-{
- if (!mailbox_list_is_valid_existing_name(list, name)) {
- mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
- "Invalid mailbox name");
- return -1;
- }
- return list->v.get_mailbox_name_status(list, name, status);
-}
-
struct mailbox_list_iterate_context *
mailbox_list_iter_init(struct mailbox_list *list, const char *pattern,
enum mailbox_list_iter_flags flags)
MAILBOX_MATCHED = 0x40000000
};
-enum mailbox_name_status {
- MAILBOX_NAME_NONEXISTENT,
- /* name points to a selectable mailbox */
- MAILBOX_NAME_EXISTS_MAILBOX,
- /* name points to non-selectable mailbox */
- MAILBOX_NAME_EXISTS_DIR
-};
-
enum mailbox_list_iter_flags {
/* Ignore index file and ACLs (used by ACL plugin internally) */
MAILBOX_LIST_ITER_RAW_LIST = 0x000001,
For INDEX=MEMORY it returns "" as the path. */
const char *mailbox_list_get_path(struct mailbox_list *list, const char *name,
enum mailbox_list_path_type type);
-/* Returns mailbox name status */
-int mailbox_list_get_mailbox_name_status(struct mailbox_list *list,
- const char *name,
- enum mailbox_name_status *status);
/* Returns mailbox's change log, or NULL if it doesn't have one. */
struct mailbox_log *mailbox_list_get_changelog(struct mailbox_list *list);
/* Specify timestamp to use when writing mailbox changes to changelog.
return 0;
}
+static int test_mailbox_exists(struct mailbox *box ATTR_UNUSED)
+{
+ return 1;
+}
+
static int test_mailbox_open(struct mailbox *box ATTR_UNUSED)
{
return 0;
test_mailbox_is_readonly,
test_mailbox_allow_new_keywords,
test_mailbox_enable,
+ test_mailbox_exists,
test_mailbox_open,
test_mailbox_close,
NULL,
return ret;
}
-static int acl_mailbox_have_visibility_rights(struct acl_mailbox_list *alist,
- const char *name)
-{
- struct acl_object *aclobj;
- const char *const *rights;
- unsigned int i;
- int ret;
-
- aclobj = acl_object_init_from_name(alist->rights.backend, name);
- ret = acl_object_get_my_rights(aclobj, pool_datastack_create(),
- &rights);
- acl_object_deinit(&aclobj);
-
- if (ret < 0)
- return -1;
-
- /* for now this is used only by IMAP SUBSCRIBE. we'll intentionally
- violate RFC 4314 here, because it says SUBSCRIBE should succeed only
- when mailbox has 'l' right. But there's no point in not allowing
- a subscribe for a mailbox that can be selected anyway. Just the
- opposite: subscribing to such mailboxes is a very useful feature. */
- for (i = 0; rights[i] != NULL; i++) {
- if (strcmp(rights[i], MAIL_ACL_LOOKUP) == 0 ||
- strcmp(rights[i], MAIL_ACL_READ) == 0 ||
- strcmp(rights[i], MAIL_ACL_INSERT) == 0)
- return 1;
- }
- return 0;
-}
-
-static int acl_get_mailbox_name_status(struct mailbox_list *list,
- const char *name,
- enum mailbox_name_status *status)
-{
- struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(list);
- int ret;
-
- T_BEGIN {
- ret = acl_mailbox_have_visibility_rights(alist, name);
- } T_END;
- if (ret < 0)
- return -1;
-
- if (alist->module_ctx.super.get_mailbox_name_status(list, name,
- status) < 0)
- return -1;
- if (ret == 0) {
- /* we shouldn't reveal this mailbox's existance */
- *status = MAILBOX_NAME_NONEXISTENT;
- }
- return 0;
-}
-
static int
acl_mailbox_list_create_dir(struct mailbox_list *list, const char *name,
enum mailbox_dir_create_type type)
v->iter_init = acl_mailbox_list_iter_init;
v->iter_next = acl_mailbox_list_iter_next;
v->iter_deinit = acl_mailbox_list_iter_deinit;
- v->get_mailbox_name_status = acl_get_mailbox_name_status;
v->create_mailbox_dir = acl_mailbox_list_create_dir;
MODULE_CONTEXT_SET(list, acl_mailbox_list_module, alist);
return abox->module_ctx.super.transaction_commit(ctx, changes_r);
}
+static int acl_mailbox_exists(struct mailbox *box)
+{
+ struct acl_mailbox *abox = ACL_CONTEXT(box);
+ const char *const *rights;
+ unsigned int i;
+
+ if (acl_object_get_my_rights(abox->aclobj, pool_datastack_create(),
+ &rights) < 0)
+ return -1;
+
+ /* for now this is used only by IMAP SUBSCRIBE. we'll intentionally
+ violate RFC 4314 here, because it says SUBSCRIBE should succeed only
+ when mailbox has 'l' right. But there's no point in not allowing
+ a subscribe for a mailbox that can be selected anyway. Just the
+ opposite: subscribing to such mailboxes is a very useful feature. */
+ for (i = 0; rights[i] != NULL; i++) {
+ if (strcmp(rights[i], MAIL_ACL_LOOKUP) == 0 ||
+ strcmp(rights[i], MAIL_ACL_READ) == 0 ||
+ strcmp(rights[i], MAIL_ACL_INSERT) == 0)
+ return abox->module_ctx.super.exists(box);
+ }
+ return 0;
+}
+
static int acl_mailbox_open_check_acl(struct mailbox *box)
{
struct acl_mailbox *abox = ACL_CONTEXT(box);
abox->acl_enabled = TRUE;
v->is_readonly = acl_is_readonly;
v->allow_new_keywords = acl_allow_new_keywords;
+ v->exists = acl_mailbox_exists;
v->open = acl_mailbox_open;
v->create = acl_mailbox_create;
v->update = acl_mailbox_update;
return mlist->module_ctx.super.set_subscribed(list, name, set);
}
-static int listescape_get_mailbox_name_status(struct mailbox_list *list,
- const char *name,
- enum mailbox_name_status *status)
-{
- struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
-
- name = list_escape(mlist, list->ns, name, FALSE);
- return mlist->module_ctx.super.
- get_mailbox_name_status(list, name, status);
-}
-
static bool listescape_is_valid_existing_name(struct mailbox_list *list,
const char *name)
{
v->iter_next = listescape_mailbox_list_iter_next;
v->iter_deinit = listescape_mailbox_list_iter_deinit;
v->set_subscribed = listescape_set_subscribed;
- v->get_mailbox_name_status = listescape_get_mailbox_name_status;
v->is_valid_existing_name = listescape_is_valid_existing_name;
v->is_valid_create_name = listescape_is_valid_create_name;
index_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
+ index_storage_mailbox_exists,
virtual_mailbox_open,
virtual_mailbox_close,
virtual_mailbox_free,