diff --git a/src/lib-storage/index/mbox/mbox-storage.c b/src/lib-storage/index/mbox/mbox-storage.c index eda0e59906..b92ff9e767 100644 --- a/src/lib-storage/index/mbox/mbox-storage.c +++ b/src/lib-storage/index/mbox/mbox-storage.c @@ -98,8 +98,10 @@ mbox_list_get_path(struct mailbox_list *list, const char *name, if (ret <= 0) return ret; - if (type == MAILBOX_LIST_PATH_TYPE_CONTROL || - type == MAILBOX_LIST_PATH_TYPE_INDEX) { + switch (type) { + case MAILBOX_LIST_PATH_TYPE_CONTROL: + case MAILBOX_LIST_PATH_TYPE_INDEX: + case MAILBOX_LIST_PATH_TYPE_LIST_INDEX: if (name == NULL && type == MAILBOX_LIST_PATH_TYPE_CONTROL && list->set.control_dir != NULL) { /* kind of a kludge for backwards compatibility: @@ -119,8 +121,14 @@ mbox_list_get_path(struct mailbox_list *list, const char *name, *path_r = t_strconcat(t_strdup_until(path, p), "/"MBOX_INDEX_DIR_NAME"/", p+1, NULL); - } else { + break; + case MAILBOX_LIST_PATH_TYPE_DIR: + case MAILBOX_LIST_PATH_TYPE_ALT_DIR: + case MAILBOX_LIST_PATH_TYPE_MAILBOX: + case MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX: + case MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE: *path_r = path; + break; } return 1; } diff --git a/src/lib-storage/list/mailbox-list-fs.c b/src/lib-storage/list/mailbox-list-fs.c index d7784d10ec..12db625813 100644 --- a/src/lib-storage/list/mailbox-list-fs.c +++ b/src/lib-storage/list/mailbox-list-fs.c @@ -129,6 +129,8 @@ fs_list_get_path(struct mailbox_list *_list, const char *name, return 0; *path_r = fs_list_get_path_to(set, set->index_pvt_dir, name); return 1; + case MAILBOX_LIST_PATH_TYPE_LIST_INDEX: + i_unreached(); } if (type == MAILBOX_LIST_PATH_TYPE_ALT_DIR || diff --git a/src/lib-storage/list/mailbox-list-index-backend.c b/src/lib-storage/list/mailbox-list-index-backend.c index 145d302638..db64ccd010 100644 --- a/src/lib-storage/list/mailbox-list-index-backend.c +++ b/src/lib-storage/list/mailbox-list-index-backend.c @@ -137,6 +137,8 @@ index_list_get_path(struct mailbox_list *_list, const char *name, case MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX: type = MAILBOX_LIST_PATH_TYPE_ALT_DIR; break; + case MAILBOX_LIST_PATH_TYPE_LIST_INDEX: + i_unreached(); default: break; } diff --git a/src/lib-storage/list/mailbox-list-index.c b/src/lib-storage/list/mailbox-list-index.c index f84be7feb4..2a6908c1fd 100644 --- a/src/lib-storage/list/mailbox-list-index.c +++ b/src/lib-storage/list/mailbox-list-index.c @@ -63,7 +63,7 @@ int mailbox_list_index_index_open(struct mailbox_list *list) if (ilist->opened) return 0; - if (mailbox_list_mkdir_missing_index_root(list) < 0) + if (mailbox_list_mkdir_missing_list_index_root(list) < 0) return -1; i_assert(ilist->index != NULL); @@ -872,7 +872,7 @@ static void mailbox_list_index_init_finish(struct mailbox_list *list) /* we've delayed this part of the initialization so that mbox format can override the index root directory path */ - if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_INDEX, + if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_LIST_INDEX, &dir)) { /* in-memory indexes */ dir = NULL; diff --git a/src/lib-storage/list/mailbox-list-maildir.c b/src/lib-storage/list/mailbox-list-maildir.c index 589e63cc67..7e26917d34 100644 --- a/src/lib-storage/list/mailbox-list-maildir.c +++ b/src/lib-storage/list/mailbox-list-maildir.c @@ -151,6 +151,8 @@ maildir_list_get_path(struct mailbox_list *_list, const char *name, *path_r = maildir_list_get_dirname_path(_list, _list->set.index_pvt_dir, name); return 1; + case MAILBOX_LIST_PATH_TYPE_LIST_INDEX: + i_unreached(); } if (type == MAILBOX_LIST_PATH_TYPE_ALT_DIR || diff --git a/src/lib-storage/mailbox-list-private.h b/src/lib-storage/mailbox-list-private.h index 6e536f5809..d6365a1274 100644 --- a/src/lib-storage/mailbox-list-private.h +++ b/src/lib-storage/mailbox-list-private.h @@ -139,6 +139,7 @@ struct mailbox_list { ARRAY(union mailbox_list_module_context *) module_contexts; bool index_root_dir_created:1; + bool list_index_root_dir_created:1; bool guid_cache_updated:1; bool guid_cache_invalidated:1; bool last_error_is_internal:1; diff --git a/src/lib-storage/mailbox-list.c b/src/lib-storage/mailbox-list.c index 7641c415c2..482e651fa0 100644 --- a/src/lib-storage/mailbox-list.c +++ b/src/lib-storage/mailbox-list.c @@ -166,6 +166,8 @@ int mailbox_list_create(const char *driver, struct mail_namespace *ns, p_strdup(list->pool, set->subscription_fname); list->set.list_index_fname = p_strdup(list->pool, set->list_index_fname); + list->set.list_index_dir = + p_strdup(list->pool, set->list_index_dir); list->set.maildir_name = p_strdup(list->pool, set->maildir_name); list->set.mailbox_dir_name = @@ -280,7 +282,7 @@ mailbox_list_settings_parse_full(struct mail_user *user, const char *data, struct mailbox_list_settings *set_r, const char **error_r) { - const char *const *tmp, *key, *value, **dest, *str, *error; + const char *const *tmp, *key, *value, **dest, *str, *fname, *error; *error_r = NULL; @@ -373,6 +375,18 @@ mailbox_list_settings_parse_full(struct mail_user *user, const char *data, *error_r = "ITERINDEX requires INDEX to be explicitly set"; return -1; } + if (set_r->list_index_fname != NULL && + (fname = strrchr(set_r->list_index_fname, '/')) != NULL) { + /* non-default LISTINDEX directory */ + set_r->list_index_dir = + t_strdup_until(set_r->list_index_fname, fname); + set_r->list_index_fname = fname+1; + if (set_r->list_index_dir[0] != '/' && + set_r->index_dir != NULL && set_r->index_dir[0] == '\0') { + *error_r = "LISTINDEX directory is relative but INDEX=MEMORY"; + return -1; + } + } return 0; } @@ -1416,6 +1430,20 @@ bool mailbox_list_set_get_root_path(const struct mailbox_list_settings *set, path = set->control_dir != NULL ? set->control_dir : set->root_dir; break; + case MAILBOX_LIST_PATH_TYPE_LIST_INDEX: + if (set->list_index_dir != NULL) { + if (set->list_index_dir[0] == '/') { + path = set->list_index_dir; + break; + } + /* relative path */ + if (!mailbox_list_set_get_root_path(set, + MAILBOX_LIST_PATH_TYPE_INDEX, &path)) + i_unreached(); + path = t_strconcat(path, "/", set->list_index_dir, NULL); + break; + } + /* fall through - default to index directory */ case MAILBOX_LIST_PATH_TYPE_INDEX: if (set->index_dir != NULL) { if (set->index_dir[0] == '\0') { @@ -1630,6 +1658,27 @@ int mailbox_list_mkdir_missing_index_root(struct mailbox_list *list) return 1; } +int mailbox_list_mkdir_missing_list_index_root(struct mailbox_list *list) +{ + const char *index_dir; + + if (list->set.list_index_dir == NULL) + return mailbox_list_mkdir_missing_index_root(list); + + /* LISTINDEX points outside the index root directory */ + if (list->list_index_root_dir_created) + return 1; + + if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_LIST_INDEX, + &index_dir)) + return 0; + if (mailbox_list_mkdir_root(list, index_dir, + MAILBOX_LIST_PATH_TYPE_LIST_INDEX) < 0) + return -1; + list->list_index_root_dir_created = TRUE; + return 1; +} + void mailbox_list_add_change(struct mailbox_list *list, enum mailbox_log_record_type type, const guid_128_t mailbox_guid) diff --git a/src/lib-storage/mailbox-list.h b/src/lib-storage/mailbox-list.h index bc9f098a89..a816b24189 100644 --- a/src/lib-storage/mailbox-list.h +++ b/src/lib-storage/mailbox-list.h @@ -82,7 +82,10 @@ enum mailbox_list_path_type { /* Return index directory ("" for in-memory) */ MAILBOX_LIST_PATH_TYPE_INDEX, /* Return the private index directory (NULL if none) */ - MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE + MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE, + /* Return mailbox list index directory (usually same as + MAILBOX_LIST_PATH_TYPE_INDEX) */ + MAILBOX_LIST_PATH_TYPE_LIST_INDEX, }; enum mailbox_list_file_type { @@ -109,6 +112,9 @@ struct mailbox_list_settings { const char *inbox_path; const char *subscription_fname; const char *list_index_fname; + /* Mailbox list index directory. NULL defaults to index directory. + The path may be relative to the index directory. */ + const char *list_index_dir; /* If non-empty, it means that mails exist in a maildir_name subdirectory. eg. if you have a directory containing directories: @@ -217,6 +223,9 @@ int mailbox_list_try_mkdir_root(struct mailbox_list *list, const char *path, same as mailbox root. Returns 1 if ok, 0 if there are no indexes, -1 if error. Calling this multiple times does the check only once. */ int mailbox_list_mkdir_missing_index_root(struct mailbox_list *list); +/* Like mailbox_list_mkdir_missing_index_root(), but for mailbox list + index root. */ +int mailbox_list_mkdir_missing_list_index_root(struct mailbox_list *list); /* Returns TRUE if name is ok, FALSE if it can't be safely passed to mailbox_list_*() functions */