static void
mailbox_list_index_update_info(struct mailbox_list_index_iterate_context *ctx)
{
+ struct mailbox_list_index *ilist =
+ INDEX_LIST_CONTEXT_REQUIRE(ctx->ctx.list);
struct mailbox_list_index_node *node = ctx->next_node;
struct mailbox *box;
/* listing INBOX/INBOX */
ctx->info.vname = p_strconcat(ctx->ctx.info_pool,
ctx->ctx.list->ns->prefix, "INBOX", NULL);
- ctx->info.flags |= MAILBOX_NONEXISTENT;
+ if (node->raw_name != ilist->raw_inbox_inbox_name_ptr) {
+ /* We can't access it without escape character
+ configured. */
+ ctx->info.flags |= MAILBOX_NONEXISTENT;
+ }
}
if ((node->flags & MAILBOX_LIST_INDEX_FLAG_NONEXISTENT) != 0)
ctx->info.flags |= MAILBOX_NONEXISTENT;
}
static struct mailbox_list_index_node *
-mailbox_list_index_node_add(struct mailbox_list_index_sync_context *ctx,
- struct mailbox_list_index_node *parent,
- const char *name, uint32_t *seq_r)
+mailbox_list_index_node_add_common(struct mailbox_list_index_sync_context *ctx,
+ struct mailbox_list_index_node *parent)
{
struct mailbox_list_index_node *node;
- char *dup_name;
- mailbox_list_name_unescape(&name,
- ctx->list->mail_set->mailbox_list_storage_escape_char[0]);
node = p_new(ctx->ilist->mailbox_pool,
struct mailbox_list_index_node, 1);
node->flags = MAILBOX_LIST_INDEX_FLAG_NONEXISTENT |
MAILBOX_LIST_INDEX_FLAG_SYNC_EXISTS;
- /* we don't bother doing name deduplication here, even though it would
- be possible. */
- node->raw_name = dup_name = p_strdup(ctx->ilist->mailbox_pool, name);
node->name_id = ++ctx->ilist->highest_name_id;
node->uid = ctx->next_uid++;
}
hash_table_insert(ctx->ilist->mailbox_hash,
POINTER_CAST(node->uid), node);
+ return node;
+}
+
+static struct mailbox_list_index_node *
+mailbox_list_index_node_add(struct mailbox_list_index_sync_context *ctx,
+ struct mailbox_list_index_node *parent,
+ const char *name, uint32_t *seq_r)
+{
+ struct mailbox_list_index_node *node =
+ mailbox_list_index_node_add_common(ctx, parent);
+
+ char *dup_name;
+ mailbox_list_name_unescape(&name,
+ ctx->list->mail_set->mailbox_list_storage_escape_char[0]);
+
+ /* we don't bother doing name deduplication here, even though it would
+ be possible. */
+ node->raw_name = dup_name = p_strdup(ctx->ilist->mailbox_pool, name);
hash_table_insert(ctx->ilist->mailbox_names,
POINTER_CAST(node->name_id), dup_name);
return node;
}
+static struct mailbox_list_index_node *
+mailbox_list_index_node_add_inbox_inbox(struct mailbox_list_index_sync_context *ctx,
+ uint32_t *seq_r)
+{
+ struct mailbox_list_index_node *node =
+ mailbox_list_index_node_add_common(ctx, NULL);
+ node->raw_name = ctx->ilist->raw_inbox_inbox_name_ptr;
+ ctx->ilist->inbox_inbox_name_id = node->name_id;
+ node_add_to_index(ctx, node, seq_r);
+ return node;
+}
+
uint32_t mailbox_list_index_sync_name(struct mailbox_list_index_sync_context *ctx,
const char *name,
struct mailbox_list_index_node **node_r,
unsigned int i;
uint32_t seq = 0;
+ *created_r = FALSE;
+
path = *name == '\0' ? empty_path :
t_strsplit(name, ctx->sep);
/* find the last node that exists in the path */
i_assert(node != NULL);
if (!mail_index_lookup_seq(ctx->view, node->uid, &seq))
i_panic("mailbox list index: lost uid=%u", node->uid);
- *created_r = FALSE;
} else {
/* create missing parts of the path */
+ if (i == 0 && ctx->ilist->inbox_inbox_storage_name != NULL &&
+ strcmp(path[0], ctx->ilist->inbox_inbox_storage_name) == 0) {
+ node = mailbox_list_index_node_add_inbox_inbox(ctx, &seq);
+ i++;
+ }
for (; path[i] != NULL; i++) {
node = mailbox_list_index_node_add(ctx, node, path[i],
&seq);
buffer_append_zero(hdr_buf, sizeof(struct mailbox_list_index_header));
/* add existing names to header (with deduplication) */
+ struct mailbox_list_index_header2 hdr2 = { 0, };
array_foreach_elem(&existing_name_ids, id) {
if (id != prev_id) {
buffer_append(hdr_buf, &id, sizeof(id));
- name = hash_table_lookup(ilist->mailbox_names,
- POINTER_CAST(id));
+ if (id != ilist->inbox_inbox_name_id) {
+ name = hash_table_lookup(ilist->mailbox_names,
+ POINTER_CAST(id));
+ } else {
+ name = ilist->raw_inbox_inbox_name_ptr;
+ hdr2.inbox_inbox_name_id = id;
+ }
i_assert(name != NULL);
buffer_append(hdr_buf, name, strlen(name) + 1);
prev_id = id;
}
mail_index_update_header_ext(ctx->trans, ilist->ext_id,
0, hdr_buf->data, hdr_buf->used);
+ /* Update ext2 header if it has changed. Note that lib-index doesn't
+ currently support dropping the header entirely. */
+ if (hdr2.inbox_inbox_name_id != 0 || ilist->inbox_inbox_name_id != 0) {
+ mail_index_update_header_ext(ctx->trans, ilist->ext2_id,
+ 0, &hdr2, sizeof(hdr2));
+ }
buffer_free(&hdr_buf);
array_free(&existing_name_ids);
}
struct mailbox_list_index_node *node,
const char *name)
{
+ struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT_REQUIRE(list);
+
+ if (ilist->inbox_inbox_storage_name != NULL &&
+ strcmp(name, ilist->inbox_inbox_storage_name) == 0) {
+ for (; node != NULL; node = node->next) {
+ if (node->name_id == ilist->inbox_inbox_name_id)
+ return node;
+ }
+ return NULL;
+ }
+
mailbox_list_name_unescape(&name,
list->mail_set->mailbox_list_storage_escape_char[0]);
while (node != NULL) {
- if (strcmp(node->raw_name, name) == 0)
+ if (node->raw_name != ilist->raw_inbox_inbox_name_ptr &&
+ strcmp(node->raw_name, name) == 0)
return node;
node = node->next;
}
const struct mailbox_list_index_node *node,
string_t *escaped_name)
{
+ struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT_REQUIRE(list);
const char escape_chars[] = {
list->mail_set->mailbox_list_storage_escape_char[0],
mailbox_list_get_hierarchy_sep(list),
'\0'
};
- mailbox_list_name_escape(node->raw_name, escape_chars, escaped_name);
+ if (node->raw_name != ilist->raw_inbox_inbox_name_ptr)
+ mailbox_list_name_escape(node->raw_name, escape_chars, escaped_name);
+ else
+ str_append(escaped_name, ilist->inbox_inbox_storage_name);
}
void mailbox_list_index_node_get_path(struct mailbox_list *list,
char *name;
int ret = 0;
+ mail_index_map_get_header_ext(view, view->map, ilist->ext2_id, &data, &size);
+ if (size >= sizeof(struct mailbox_list_index_header2)) {
+ const struct mailbox_list_index_header2 *hdr2 = data;
+ ilist->inbox_inbox_name_id = hdr2->inbox_inbox_name_id;
+ } else {
+ ilist->inbox_inbox_name_id = 0;
+ }
+
mail_index_map_get_header_ext(view, view->map, ilist->ext_id, &data, &size);
if (size == 0)
return 0;
i += len + 1;
/* add id => name to hash table */
- hash_table_insert(ilist->mailbox_names, POINTER_CAST(id), name);
+ if (id != ilist->inbox_inbox_name_id) {
+ hash_table_insert(ilist->mailbox_names,
+ POINTER_CAST(id), name);
+ }
ilist->highest_name_id = id;
}
i_assert(i == size);
static int mailbox_list_index_node_cmp(const struct mailbox_list_index_node *n1,
const struct mailbox_list_index_node *n2)
{
+ /* Used only for duplicate checking, which skips raw_inbox_inbox_name_ptr
+ mailbox, so we don't need to check for that. */
return n1->parent == n2->parent &&
strcmp(n1->raw_name, n2->raw_name) == 0 ? 0 : -1;
}
/* invalid name_id - assign a new one */
node->name_id = ++ilist->highest_name_id;
node->corrupted_ext = TRUE;
- }
- node->raw_name = hash_table_lookup(ilist->mailbox_names,
+ } else if (irec->name_id != ilist->inbox_inbox_name_id) {
+ node->raw_name = hash_table_lookup(ilist->mailbox_names,
POINTER_CAST(irec->name_id));
+ } else {
+ node->raw_name = ilist->raw_inbox_inbox_name_ptr;
+ }
if (node->raw_name == NULL) {
*error_r = t_strdup_printf(
"name_id=%u not in index header", irec->name_id);
} else if (strcasecmp(node->raw_name, "INBOX") == 0) {
ilist->rebuild_on_missing_inbox = FALSE;
}
- if (hash_table_lookup(duplicate_hash, node) == NULL)
+
+ if (node->raw_name == ilist->raw_inbox_inbox_name_ptr) {
+ /* The raw_name's value may exist here for another
+ mailbox, but it's not a duplicate of this
+ <prefix>/INBOX, since it's unique. */
+ } else if (hash_table_lookup(duplicate_hash, node) == NULL)
hash_table_insert(duplicate_hash, node, node);
else {
const char *old_name = node->raw_name;
list->vlast = &ilist->module_ctx.super;
ilist->has_backing_store = has_backing_store;
ilist->pending_init = TRUE;
+ /* Make sure this gets a unique pointer, and the value is not "INBOX" */
+ ilist->raw_inbox_inbox_name_ptr = p_strdup(list->pool, "INBOXINBOX");
+
+ const char escape_char = list->mail_set->mailbox_list_storage_escape_char[0];
+ ilist->inbox_inbox_storage_name = escape_char == '\0' ? NULL :
+ p_strdup_printf(list->pool, "%c49NBOX", escape_char);
v->deinit = mailbox_list_index_deinit;
v->iter_init = mailbox_list_index_iter_init;
sizeof(struct mailbox_list_index_header),
sizeof(struct mailbox_list_index_record),
sizeof(uint32_t));
+ ilist->ext2_id = mail_index_ext_register(ilist->index, "list2",
+ sizeof(struct mailbox_list_index_header2),
+ 0, 0);
ilist->subs_hdr_ext_id = mail_index_ext_register(ilist->index, "subs",
sizeof(uint32_t), 0,
sizeof(uint32_t));
/* array of { uint32_t id; char name[]; } */
};
+struct mailbox_list_index_header2 {
+ /* ID number in mailbox_list_index_header which should be considered
+ as the <prefix>/INBOX mailbox, which would be escaped as
+ <escape char>49NBOX to differentiate it from the actual INBOX.
+ The name in the header can be anything - it would be used only by
+ old Dovecot versions. */
+ uint32_t inbox_inbox_name_id;
+};
+
struct mailbox_list_index_record {
/* points to given id in header */
uint32_t name_id;
bool corrupted_ext;
/* flags are corrupted on disk - need to update it */
bool corrupted_flags;
+ /* Raw (unescaped) mailbox name. Unfortunately for now, it may be
+ either in UTF8 or mUTF-7 depending on the mailbox_list_utf8 setting.
+
+ As a special case, if raw_name points to ilist->inbox_inbox_name,
+ it's actually the <ns prefix>/INBOX mailbox (not INBOX). */
const char *raw_name;
};
const char *path;
struct mail_index *index;
- uint32_t ext_id, msgs_ext_id, hmodseq_ext_id, subs_hdr_ext_id;
+ uint32_t ext_id, ext2_id, msgs_ext_id, hmodseq_ext_id, subs_hdr_ext_id;
uint32_t vsize_ext_id, first_saved_ext_id, deleted_count_id;
struct timeval last_refresh_timeval;
uint32_t sync_stamp;
struct timeout *to_refresh;
+ /* If mailbox_list_index_node.raw_name contains this pointer, it's
+ the <ns prefix>/INBOX (not INBOX). Note: Compare this against the
+ raw_name pointer directly - not the string content. */
+ void *raw_inbox_inbox_name_ptr;
+ /* <escape char>49NBOX, if mailbox_list_storage_escape_char is specified.
+ Otherwise NULL. */
+ const char *inbox_inbox_storage_name;
+ /* If mailbox_list_index_record.name_id contains this (non-0) ID, it's
+ the <ns prefix>/INBOX (not INBOX). */
+ uint32_t inbox_inbox_name_id;
+
/* uint32_t uid => node */
HASH_TABLE(void *, struct mailbox_list_index_node *) mailbox_hash;
struct mailbox_list_index_node *mailbox_tree;