enum mailbox_info_flags flags = MAILBOX_UNMARKED;
if (ctx->seen_inbox_namespace &&
- (ctx->ns->flags & NAMESPACE_FLAG_INBOX) == 0) {
+ (ctx->ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0) {
/* INBOX doesn't exist. use the default INBOX flags */
return flags;
}
of handling INBOX/ namespace */
continue;
}
- if ((ctx->ns->flags & NAMESPACE_FLAG_INBOX) == 0) {
+ if ((ctx->ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0) {
/* INBOX is in non-empty prefix namespace,
and we're now listing prefixless namespace
that contains INBOX. There's no way we can
enum imap_match_result match, ret;
if (*ctx->ns->prefix != '\0' &&
- (ctx->ns->flags & NAMESPACE_FLAG_INBOX) == 0)
+ (ctx->ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0)
return IMAP_MATCH_NO;
/* if the original reference and pattern combined produces something
ctx->cur_ns_skip_trailing_sep = FALSE;
- if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0)
+ if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0)
ctx->seen_inbox_namespace = TRUE;
if (*cur_ns_prefix != '\0') {
/* INBOX always exists */
if (!ctx->inbox_found && ctx->cur_ns_match_inbox &&
- (ctx->ns->flags & NAMESPACE_FLAG_INBOX) != 0 &&
+ (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);
return -1;
}
- if (*name == '\0' && (ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
+ if (*name == '\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";
int ret = 0;
if (ctx->default_list == NULL ||
- (ns->flags & NAMESPACE_FLAG_INBOX) != 0)
+ (ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0)
ctx->default_list = ns->list;
iter = mailbox_list_iter_init(ns->list, "*",
MAILBOX_LIST_PATH_TYPE_MAILBOX);
box->path = p_strdup(box->pool, path);
box->index = index_storage_alloc(box->list, name, flags, index_prefix);
- box->inbox = strcmp(name, "INBOX") == 0 &&
- (box->list->ns->flags & NAMESPACE_FLAG_INBOX) != 0;
+ box->inbox_user = strcmp(name, "INBOX") == 0 &&
+ (box->list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0;
+ box->inbox_any = strcmp(name, "INBOX") == 0 &&
+ (box->list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0;
if (box->file_create_mode == 0)
mailbox_refresh_permissions(box);
mail_index_set_permissions(box->index, box->file_create_mode,
mailbox_list_get_temp_prefix(list));
if (list->set.control_dir == NULL && list->set.inbox_path == NULL &&
- (ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
+ (ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0) {
/* put the temp files into tmp/ directory preferrably */
storage->temp_prefix = p_strconcat(_storage->pool, "tmp/",
storage->temp_prefix, NULL);
if (set->inbox_path == NULL && set->maildir_name == NULL &&
(strcmp(set->layout, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) == 0 ||
strcmp(set->layout, MAILBOX_LIST_NAME_FS) == 0) &&
- (ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
+ (ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0) {
/* Maildir++ INBOX is the Maildir base itself */
set->inbox_path = set->root_dir;
}
errmsg = eacces_error_get_creating("file_dotlock_create", path);
dir = strrchr(path, '/');
dir = dir == NULL ? "." : t_strdup_until(path, dir);
- if (!mbox->box.inbox) {
+ if (!mbox->box.inbox_any) {
mail_storage_set_critical(&mbox->storage->storage,
"%s (not INBOX -> no privileged locking)", errmsg);
} else if (!mbox->mbox_privileged_locking) {
}
move_to_memory = want_memory_indexes(mbox->storage, box->path);
- if (box->inbox) {
+ if (box->inbox_any) {
/* if INBOX isn't under the root directory, it's probably in
/var/mail and we want to allow privileged dotlocking */
rootdir = mailbox_list_get_path(box->list, NULL,
(box->list->props & MAILBOX_LIST_PROP_NO_NOSELECT) == 0)
return 0;
- if (box->inbox) {
+ if (box->inbox_any) {
if (create_inbox(box) < 0)
return -1;
} else {
new_ns->owner = owner;
new_ns->flags = (NAMESPACE_FLAG_SUBSCRIPTIONS & ns->flags) |
NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_HIDDEN |
- NAMESPACE_FLAG_AUTOCREATED;
+ NAMESPACE_FLAG_AUTOCREATED | NAMESPACE_FLAG_INBOX_ANY;
new_ns->sep = ns->sep;
new_ns->mail_set = _storage->set;
return 0;
if (strcmp(name, "INBOX") == 0 &&
- (list->ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
+ (list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0) {
mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
"INBOX can't be deleted.");
return -1;
static void inbox_flags_set(struct fs_list_iterate_context *ctx)
{
+ struct mail_namespace *ns = ctx->ctx.list->ns;
+
/* INBOX is always selectable */
ctx->info.flags &= ~(MAILBOX_NOSELECT | MAILBOX_NONEXISTENT);
- if (*ctx->ctx.list->ns->prefix != '\0') {
+ if (*ns->prefix != '\0' &&
+ (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
/* we're listing INBOX for a namespace with a prefix.
if there are children for the INBOX, they're returned under
the mailbox prefix, not under the INBOX itself. */
static struct mailbox_info *fs_list_inbox(struct fs_list_iterate_context *ctx)
{
+ struct mail_namespace *ns = ctx->ctx.list->ns;
+
ctx->info.flags = 0;
- ctx->info.name = "INBOX";
+ if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0)
+ ctx->info.name = "INBOX";
+ else {
+ ctx->info.name = p_strconcat(ctx->info_pool,
+ ns->prefix, "INBOX", NULL);
+ }
if (mailbox_list_mailbox(ctx->ctx.list, "INBOX", &ctx->info.flags) < 0)
ctx->ctx.failed = TRUE;
ctx->info.flags |= fs_list_get_subscription_flags(ctx, list_path);
/* make sure we give only one correct INBOX */
- if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
+ if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
if (strcasecmp(list_path, "INBOX") == 0) {
if (!list_file_inbox(ctx, fname))
return 0;
prefix unless it has children. */
return 0;
}
+ } else if ((ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0) {
+ /* shared namespace */
+ if (strcasecmp(fname, "INBOX") == 0 &&
+ list_file_is_inbox(ctx, fname)) {
+ if (!list_file_inbox(ctx, fname))
+ return 0;
+ }
}
if ((ctx->info.flags & MAILBOX_NOINFERIORS) == 0)
}
if (!ctx->inbox_found &&
- (ctx->ctx.list->ns->flags & NAMESPACE_FLAG_INBOX) != 0 &&
+ (ctx->ctx.list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0 &&
((ctx->glob != NULL &&
imap_match(ctx->glob, "INBOX") == IMAP_MATCH_YES) ||
ctx->inbox_match)) {
enum mailbox_info_flags flags;
if (strcmp(name, "INBOX") == 0 &&
- (_list->ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
+ (_list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
*status = MAILBOX_NAME_EXISTS_MAILBOX;
return 0;
}
static int
maildir_fill_inbox(struct maildir_list_iterate_context *ctx,
- struct imap_match_glob *glob,
+ struct imap_match_glob *glob, const char *inbox_name,
bool update_only)
{
struct mailbox_node *node;
}
if (update_only) {
- node = mailbox_tree_lookup(ctx->tree_ctx, "INBOX");
+ node = mailbox_tree_lookup(ctx->tree_ctx, inbox_name);
if (node != NULL)
node->flags &= ~MAILBOX_NONEXISTENT;
} else {
- node = mailbox_tree_get(ctx->tree_ctx, "INBOX", &created);
+ node = mailbox_tree_get(ctx->tree_ctx, inbox_name, &created);
if (created)
node->flags = MAILBOX_NOCHILDREN;
else
node->flags &= ~MAILBOX_NONEXISTENT;
- match = imap_match(glob, "INBOX");
+ match = imap_match(glob, inbox_name);
if ((match & (IMAP_MATCH_YES | IMAP_MATCH_PARENT)) != 0)
node->flags |= MAILBOX_MATCHED;
}
return -1;
}
- if ((ns->flags & NAMESPACE_FLAG_INBOX) == 0)
- return 0;
- else {
+ if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
/* make sure INBOX is listed */
- return maildir_fill_inbox(ctx, glob, update_only);
+ return maildir_fill_inbox(ctx, glob, "INBOX", update_only);
+ } else if ((ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0) {
+ /* show shared INBOX. */
+ return maildir_fill_inbox(ctx, glob,
+ t_strconcat(ns->prefix, "INBOX", NULL), update_only);
+ } else {
+ return 0;
}
}
MAILBOX_LIST_PATH_TYPE_MAILBOX);
if ((strcmp(name, "INBOX") == 0 &&
- (_list->ns->flags & NAMESPACE_FLAG_INBOX) != 0) ||
+ (_list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) ||
stat(path, &st) == 0) {
*status = MAILBOX_NAME_EXISTS_MAILBOX;
return 0;
return -1;
}
- if (ns_set->inbox)
- ns->flags |= NAMESPACE_FLAG_INBOX;
+ if (ns_set->inbox) {
+ ns->flags |= NAMESPACE_FLAG_INBOX_USER |
+ NAMESPACE_FLAG_INBOX_ANY;
+ }
if (ns_set->hidden)
ns->flags |= NAMESPACE_FLAG_HIDDEN;
if (ns_set->subscriptions)
for (ns = namespaces; ns != NULL; ns = ns->next) {
if (namespace_set_alias_for(ns, namespaces, error_r) < 0)
return FALSE;
- if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
+ if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
if (inbox_ns != NULL) {
*error_r = "namespace configuration error: "
"There can be only one namespace with "
/* no namespaces defined, create a default one */
ns = i_new(struct mail_namespace, 1);
ns->type = NAMESPACE_PRIVATE;
- ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST_PREFIX |
- NAMESPACE_FLAG_SUBSCRIPTIONS;
+ ns->flags = NAMESPACE_FLAG_INBOX_USER | NAMESPACE_FLAG_INBOX_ANY |
+ NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_SUBSCRIPTIONS;
ns->owner = user;
inbox_set = p_new(user->pool, struct mail_namespace_settings, 1);
ns->user = user;
ns->owner = user;
ns->prefix = i_strdup("");
- ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST_PREFIX |
- NAMESPACE_FLAG_SUBSCRIPTIONS;
+ ns->flags = NAMESPACE_FLAG_INBOX_USER | NAMESPACE_FLAG_INBOX_ANY |
+ NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_SUBSCRIPTIONS;
ns->mail_set = mail_user_set_get_storage_set(user);
user->namespaces = ns;
return ns;
const char *name)
{
str_truncate(dest, 0);
- if ((ns->flags & NAMESPACE_FLAG_INBOX) == 0 ||
+ if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0 ||
strcasecmp(name, "INBOX") != 0 ||
ns->user != ns->owner)
str_append(dest, ns->prefix);
/* find the INBOX namespace */
*mailbox = "INBOX";
while (ns != NULL) {
- if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0 &&
+ if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
(ns->flags & mask) == flags)
return ns;
if (*ns->prefix == '\0')
struct mail_namespace *
mail_namespace_find_inbox(struct mail_namespace *namespaces)
{
- while ((namespaces->flags & NAMESPACE_FLAG_INBOX) == 0)
+ while ((namespaces->flags & NAMESPACE_FLAG_INBOX_USER) == 0)
namespaces = namespaces->next;
return namespaces;
}
};
enum namespace_flags {
- /* Namespace contains the INBOX mailbox (there can be only one) */
- NAMESPACE_FLAG_INBOX = 0x01,
+ /* Namespace contains the user's INBOX mailbox (there can be only
+ one) */
+ NAMESPACE_FLAG_INBOX_USER = 0x01,
+ /* Namespace contains someone's INBOX. This is set for both user's
+ INBOX namespace and also for any other users' shared namespaces. */
+ NAMESPACE_FLAG_INBOX_ANY = 0x02,
/* Namespace is visible only by explicitly using its full prefix */
- NAMESPACE_FLAG_HIDDEN = 0x02,
+ NAMESPACE_FLAG_HIDDEN = 0x04,
/* Namespace prefix is visible with LIST */
- NAMESPACE_FLAG_LIST_PREFIX = 0x04,
+ NAMESPACE_FLAG_LIST_PREFIX = 0x08,
/* Namespace prefix isn't visible with LIST, but child mailboxes are */
- NAMESPACE_FLAG_LIST_CHILDREN = 0x08,
+ NAMESPACE_FLAG_LIST_CHILDREN = 0x10,
/* Namespace uses its own subscriptions. */
- NAMESPACE_FLAG_SUBSCRIPTIONS = 0x10,
+ NAMESPACE_FLAG_SUBSCRIPTIONS = 0x20,
/* Namespace was created automatically (for shared mailboxes) */
NAMESPACE_FLAG_AUTOCREATED = 0x1000,
unsigned int backend_readonly:1;
/* Mailbox is being deleted */
unsigned int deleting:1;
- /* TRUE if this is the INBOX */
- unsigned int inbox:1;
+ /* TRUE if this is an INBOX for this user */
+ unsigned int inbox_user:1;
+ /* TRUE if this is an INBOX for this namespace (user or shared) */
+ unsigned int inbox_any:1;
};
struct mail_vfuncs {
} T_END;
if (ret < 0 && box->storage->error == MAIL_ERROR_NOTFOUND &&
- box->input == NULL && box->inbox) T_BEGIN {
+ box->input == NULL && box->inbox_user) T_BEGIN {
/* INBOX should always exist. try to create it and retry. */
(void)mailbox_create(box, NULL, FALSE);
mailbox_close(box);
"Storage root can't be deleted");
return -1;
}
- if (box->inbox) {
+ if (box->inbox_any) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
"INBOX can't be deleted.");
return -1;
memset(status_r, 0, sizeof(*status_r));
ret = box->v.sync_deinit(ctx, status_r);
- if (ret < 0 && box->inbox &&
+ if (ret < 0 && box->inbox_user &&
!box->storage->user->inbox_open_error_logged) {
errormsg = mail_storage_get_last_error(box->storage, &error);
if (error == MAIL_ERROR_NOTPOSSIBLE) {
{
struct imap_match_glob *glob;
- if ((ns->flags & NAMESPACE_FLAG_INBOX) == 0)
+ if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0)
return FALSE;
glob = imap_match_init(pool_datastack_create(), pattern,
fname = "";
}
if (*fname == '\0' && *name == '\0' &&
- (list->ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
+ (list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
/* if INBOX is in e.g. ~/Maildir, it shouldn't be possible to
access it also via namespace prefix. */
inbox = mailbox_list_get_path(list, "INBOX",
update_ctx.iter_ctx = &ctx->ctx;
update_ctx.glob =
imap_match_init(pool_datastack_create(), "*",
- (ns->flags & NAMESPACE_FLAG_INBOX) != 0,
+ (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0,
ctx->sep);
update_ctx.match_parents = TRUE;
update_ctx.tree_ctx = mailbox_tree_init(ctx->sep);
ctx->ctx.list = list;
ctx->ctx.flags = flags;
- inboxcase = (list->ns->flags & NAMESPACE_FLAG_INBOX) != 0;
+ inboxcase = (list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0;
ctx->sep = (ctx->ctx.flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0 ?
list->ns->sep : list->ns->real_sep;
ctx->glob = imap_match_init_multiple(default_pool, patterns,
*ns_r = ns;
if (*name == '\0' && ns != mailbox_get_namespace(box) &&
- (ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
+ (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
/* ugly workaround to allow selecting INBOX from a Maildir/
when it's not in the inbox=yes namespace. */
return "INBOX";
ctx->list->ns :
listescape_find_orig_ns(ctx->list->ns, info->name);
- if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0 &&
+ if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
strcasecmp(info->name, "INBOX") == 0)
return info;
namespaces = array_get(&root->root.quota->namespaces, &count);
i_assert(count > 0);
for (i = 0; i < count; i++) {
- if ((namespaces[i]->flags & NAMESPACE_FLAG_INBOX) != 0) {
+ if ((namespaces[i]->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
mailbox_list_get_permissions(namespaces[i]->list,
NULL, &mode, &gid,
&gid_origin);