mailbox-list.c revision 9c66dd5c3e2ba484a5c7cdb98a139bda31fdfaa4
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen then start renaming them to larger names from end to beginning, which
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen eventually would start causing the failures when trying to use too
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen long mailbox names. */
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen struct mailbox_list_iterate_context *backend_ctx;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int i, count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; i < count; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen unsigned int idx;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_append(&mailbox_list_drivers, &list, 1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int idx;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen enum mailbox_list_flags flags, const char **error_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int idx;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0');
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainen *error_r = t_strdup_printf("Unknown mailbox list driver: %s",
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* copy settings */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.index_dir = set->index_dir == NULL ||
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.control_dir = set->control_dir == NULL ||
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen p_strdup(list->pool, set->subscription_fname);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.maildir_name = set->maildir_name == NULL ||
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen (list->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 ? "" :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("%s: root=%s, index=%s, control=%s, inbox=%s",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk list->set.root_dir == NULL ? "" : list->set.root_dir,
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk list->set.index_dir == NULL ? "" : list->set.index_dir,
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainenstatic int fix_path(struct mail_namespace *ns, const char *path,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen "No home directory for system user. "
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (mail_user_try_home_expand(ns->user, &path) < 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen *error_r = "Home directory not set for user. "
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen "Can't expand ~/ for ";
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenstatic const char *split_next_arg(const char *const **_args)
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainen /* string ends with ":", just ignore it. */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenint mailbox_list_settings_parse(const char *data,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mail_namespace *ns, const char **error_r)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* <root dir> */
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (fix_path(ns, str, &set->root_dir, &error) < 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen *error_r = t_strdup_printf("Unknown setting: %s", key);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen *error_r = t_strconcat(error, key, " in: ", data, NULL);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (set->index_dir != NULL && strcmp(set->index_dir, "MEMORY") == 0)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid mailbox_list_destroy(struct mailbox_list **_list)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenconst char *mailbox_list_get_driver_name(const struct mailbox_list *list)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenchar mailbox_list_get_hierarchy_sep(const struct mailbox_list *list)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenenum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenmailbox_list_get_namespace(const struct mailbox_list *list)
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen /* add the execute bit if either read or write bit is set */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenmailbox_list_get_user(const struct mailbox_list *list)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenint mailbox_list_get_storage(struct mailbox_list **list, const char **name,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return (*list)->v.get_storage(list, name, storage_r);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid mailbox_list_get_closest_storage(struct mailbox_list *list,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainenmailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
b82d6d7f02734007c129fa25bc876049c8d9bddeTimo Sirainen path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen mailbox_list_set_critical(list, "stat(%s) failed: %m",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("Namespace %s: Permission lookup failed from %s",
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* return defaults */
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen /* return safe defaults */
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* we're getting permissions from a file.
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen apply +x modes as necessary. */
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* directory's GID is used automatically for new
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen } else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen /* group has same permissions as world, so don't bother
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen changing it */
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* using our own gid, no need to change it */
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen if (list->mail_set->mail_debug && name == NULL) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("Namespace %s: Using permissions from %s: "
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainenvoid mailbox_list_get_permissions(struct mailbox_list *list,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (list->file_create_mode != (mode_t)-1 && name == NULL) {
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r,
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainenvoid mailbox_list_get_dir_permissions(struct mailbox_list *list,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (list->dir_create_mode != (mode_t)-1 && name == NULL) {
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen mailbox_list_get_permissions_full(list, name, &file_mode,
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainenbool mailbox_list_is_valid_pattern(struct mailbox_list *list,
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen return list->v.is_valid_pattern(list, pattern);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenbool mailbox_list_is_valid_existing_name(struct mailbox_list *list,
9f1a154d6f436e67f22f737f66bb148b502d4d2aTimo Sirainen if (*name == '\0' && *list->ns->prefix != '\0') {
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen /* an ugly way to get to mailbox root (e.g. Maildir/ when
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen it's not the INBOX) */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return list->v.is_valid_existing_name(list, name);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenbool mailbox_list_is_valid_create_name(struct mailbox_list *list,
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen const char *p;
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen /* safer to just disallow all control characters */
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen if (*p < ' ')
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenconst char *mailbox_list_get_path(struct mailbox_list *list, const char *name,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenconst char *mailbox_list_get_temp_prefix(struct mailbox_list *list)
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainenconst char *mailbox_list_get_global_temp_prefix(struct mailbox_list *list)
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainenconst char *mailbox_list_join_refpattern(struct mailbox_list *list,
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen return list->v.join_refpattern(list, ref, pattern);
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen /* the default implementation: */
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen /* merge reference and pattern */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenint mailbox_list_get_mailbox_name_status(struct mailbox_list *list,
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen if (!mailbox_list_is_valid_existing_name(list, name)) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return list->v.get_mailbox_name_status(list, name, status);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainenmailbox_list_iter_init(struct mailbox_list *list, const char *pattern,
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen return mailbox_list_iter_init_multiple(list, patterns, flags);
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainenmailbox_list_iter_init_multiple(struct mailbox_list *list,
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen const char *const *patterns,
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen return list->v.iter_init(list, patterns, flags);
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainenns_next(struct ns_list_iterate_context *ctx, struct mail_namespace *ns)
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SKIP_ALIASES) != 0) {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenstatic const struct mailbox_info *
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenmailbox_list_ns_iter_next(struct mailbox_list_iterate_context *_ctx)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen info = mailbox_list_iter_next(ctx->backend_ctx);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if (info == NULL && ctx->namespaces != NULL) {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen /* go to the next namespace */
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen mailbox_list_iter_init_multiple(ctx->namespaces->list,
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen ctx->namespaces = ns_next(ctx, ctx->namespaces->next);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenmailbox_list_ns_iter_deinit(struct mailbox_list_iterate_context *_ctx)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenmailbox_list_iter_init_namespaces(struct mail_namespace *namespaces,
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen const char *const *patterns,
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen unsigned int i, count;
ebded144e74a668973ec9ba6e7e169d4e6dc766cTimo Sirainen pool = pool_alloconly_create("mailbox list namespaces", 512);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen ctx = p_new(pool, struct ns_list_iterate_context, 1);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen ctx->ctx.list = p_new(pool, struct mailbox_list, 1);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen ctx->ctx.list->v.iter_next = mailbox_list_ns_iter_next;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen ctx->ctx.list->v.iter_deinit = mailbox_list_ns_iter_deinit;
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen ctx->patterns = p_new(pool, const char *, count + 1);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen for (i = 0; i < count; i++)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen ctx->patterns[i] = p_strdup(pool, patterns[i]);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen ctx->backend_ctx = mailbox_list_iter_init_multiple(namespaces->list,
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen ctx->namespaces = ns_next(ctx, namespaces->next);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenmailbox_list_iter_next(struct mailbox_list_iterate_context *ctx)
b337d3b6871b878d6467d7d8ed600433af5da5a1Timo Sirainen ctx->list->ns->flags |= NAMESPACE_FLAG_USABLE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenint mailbox_list_iter_deinit(struct mailbox_list_iterate_context **_ctx)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mailbox_list_iterate_context *ctx = *_ctx;
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainenint mailbox_list_mailbox(struct mailbox_list *list, const char *name,
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainenstatic bool mailbox_list_init_changelog(struct mailbox_list *list)
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen /* don't do this in mailbox_list_create(), because _get_path() might be
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen overridden by storage (mbox). */
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen path = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_INDEX);
32f4b9ab23148bec295196a8029a43ff89ce124dTimo Sirainen path = t_strconcat(path, "/"MAILBOX_LOG_FILE_NAME, NULL);
32f4b9ab23148bec295196a8029a43ff89ce124dTimo Sirainen mailbox_list_get_permissions(list, NULL, &mode, &gid, &gid_origin);
32f4b9ab23148bec295196a8029a43ff89ce124dTimo Sirainen mailbox_log_set_permissions(list->changelog, mode, gid, gid_origin);
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenvoid mailbox_list_add_change(struct mailbox_list *list,
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen const uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen stamp = list->changelog_timestamp != (time_t)-1 ?
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen memcpy(rec.mailbox_guid, mailbox_guid, sizeof(rec.mailbox_guid));
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen mailbox_log_record_set_timestamp(&rec, stamp);
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen (void)mailbox_log_append(list->changelog, &rec);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenint mailbox_list_set_subscribed(struct mailbox_list *list,
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen if (list->v.set_subscribed(list, name, set) < 0)
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen /* subscriptions are about names, not about mailboxes. it's possible
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen to have a subscription to non-existing mailbox. renames also don't
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen change subscriptions. so instead of using actual GUIDs, we'll use
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen hash of the name. */
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen mailbox_list_add_change(list, set ? MAILBOX_LOG_RECORD_SUBSCRIBE :
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenint mailbox_list_delete_mailbox(struct mailbox_list *list, const char *name)
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen if (!mailbox_list_is_valid_existing_name(list, name) || *name == '\0') {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen "Invalid mailbox name");
1d266a7419fafa25f3505a12217452a8c647074fTimo Sirainen (list->ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen "INBOX can't be deleted.");
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenstatic bool nullequals(const void *p1, const void *p2)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen return (p1 == NULL && p2 == NULL) || (p1 != NULL && p2 != NULL);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenint mailbox_list_rename_mailbox(struct mailbox_list *oldlist,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (mailbox_list_get_storage(&oldlist, &oldname, &oldstorage) < 0)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mailbox_list_get_closest_storage(newlist, &newstorage);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if (!mailbox_list_is_valid_existing_name(oldlist, oldname) ||
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen !mailbox_list_is_valid_create_name(newlist, newname)) {
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen mailbox_list_set_error(oldlist, MAIL_ERROR_PARAMS,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen "Invalid mailbox name");
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (strcmp(oldstorage->name, newstorage->name) != 0) {
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen "Can't rename mailbox to another storage type.");
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if (!nullequals(oldlist->set.index_dir, newlist->set.index_dir) ||
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen !nullequals(oldlist->set.control_dir, newlist->set.control_dir)) {
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen "Can't rename mailboxes across specified storages.");
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen mailbox_list_set_error(oldlist, MAIL_ERROR_NOTPOSSIBLE,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen "Renaming not supported across non-private namespaces.");
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen if (oldlist->v.rename_mailbox(oldlist, oldname, newlist, newname,
9c66dd5c3e2ba484a5c7cdb98a139bda31fdfaa4Timo Sirainen /* we'll track mailbox names, instead of GUIDs. We may be renaming a
9c66dd5c3e2ba484a5c7cdb98a139bda31fdfaa4Timo Sirainen non-selectable mailbox (directory), which doesn't even have a GUID */
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen mailbox_list_add_change(oldlist, MAILBOX_LOG_RECORD_RENAME, guid);
9c66dd5c3e2ba484a5c7cdb98a139bda31fdfaa4Timo Sirainenvoid mailbox_name_get_sha128(const char *name, uint8_t guid[MAIL_GUID_128_SIZE])
9c66dd5c3e2ba484a5c7cdb98a139bda31fdfaa4Timo Sirainen memcpy(guid, sha, I_MIN(sizeof(guid), sizeof(sha)));
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenstruct mailbox_log *mailbox_list_get_changelog(struct mailbox_list *list)
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen return !mailbox_list_init_changelog(list) ? NULL : list->changelog;
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainenvoid mailbox_list_set_changelog_timestamp(struct mailbox_list *list,
3ac0d8763b06a39c95187fe6170b1bf822b28a1fTimo Sirainenstatic int mailbox_list_try_delete(struct mailbox_list *list, const char *dir)
3ac0d8763b06a39c95187fe6170b1bf822b28a1fTimo Sirainen if (unlink_directory(dir, TRUE) == 0 || errno == ENOENT)
3ac0d8763b06a39c95187fe6170b1bf822b28a1fTimo Sirainen /* We're most likely using NFS and we can't delete
3ac0d8763b06a39c95187fe6170b1bf822b28a1fTimo Sirainen .nfs* files. */
4321f6c969e7b8f6b243ff5bb6b8d297921676f6Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_INUSE,
3ac0d8763b06a39c95187fe6170b1bf822b28a1fTimo Sirainen "Mailbox is still open in another session, "
3ac0d8763b06a39c95187fe6170b1bf822b28a1fTimo Sirainen "can't delete it.");
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenint mailbox_list_delete_index_control(struct mailbox_list *list,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* delete the index directory first, so that if we crash we don't
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen leave indexes for deleted mailboxes lying around */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (*index_dir != '\0' && strcmp(index_dir, path) != 0) {
3ac0d8763b06a39c95187fe6170b1bf822b28a1fTimo Sirainen if (mailbox_list_try_delete(list, index_dir) < 0)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* control directory next */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen dir = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_CONTROL);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainenstatic void node_fix_parents(struct mailbox_node *node)
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen /* If we happened to create any of the parents, we need to mark them
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen nonexistent. */
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainenmailbox_list_iter_update_real(struct mailbox_list_iter_update_context *ctx,
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen struct mail_namespace *ns = ctx->iter_ctx->list->ns;
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen enum mailbox_info_flags create_flags = 0, always_flags;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen const char *p;
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen (ctx->iter_ctx->flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) == 0)
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen create_flags = MAILBOX_NONEXISTENT | MAILBOX_NOCHILDREN;
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen mailbox_tree_get(ctx->tree_ctx, name, &created);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen /* We don't want to show the parent mailboxes unless
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen something else matches them, but if they are matched
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen we want to show them having child subscriptions */
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen /* We've a (possibly) non-subscribed parent mailbox
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen which has a subscribed child mailbox. Make sure we
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen return the parent mailbox. */
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen /* see if parent matches */
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen always_flags = MAILBOX_CHILDREN | ctx->parent_flags;
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainenvoid mailbox_list_iter_update(struct mailbox_list_iter_update_context *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenbool mailbox_list_name_is_too_large(const char *name, char sep)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (level_len > MAILBOX_MAX_HIERARCHY_NAME_LENGTH)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (level_len > MAILBOX_MAX_HIERARCHY_NAME_LENGTH)
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenmailbox_list_get_file_type(const struct dirent *d ATTR_UNUSED)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen switch (d->d_type) {
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainenbool mailbox_list_try_get_absolute_path(struct mailbox_list *list,
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen const char **name)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (!list->mail_set->mail_full_filesystem_access)
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen /* try to expand home directory */
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen /* ~/dir - use the configured home directory */
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen if (mail_user_try_home_expand(list->ns->user, name) == 0)
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen /* ~otheruser/dir - assume we're using system users */
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen /* fallback to using ~dir */
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainenint mailbox_list_create_parent_dir(struct mailbox_list *list,
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen mailbox_list_get_dir_permissions(list, mailbox, &mode, &gid, &origin);
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen if (mkdir_parents_chgrp(dir, mode, gid, origin) < 0 &&
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen mailbox_list_set_critical(list, "mkdir_parents(%s) failed: %m",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenconst char *mailbox_list_get_last_error(struct mailbox_list *list,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen return list->error_string != NULL ? list->error_string :
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen "Unknown internal list error";
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mailbox_list_clear_error(struct mailbox_list *list)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenvoid mailbox_list_set_error(struct mailbox_list *list,
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainenvoid mailbox_list_set_internal_error(struct mailbox_list *list)
ac4e6609cbdca594db1b1c02afb1e372ab22e060Timo Sirainen i_strdup(str) : i_strdup(MAIL_ERRSTR_CRITICAL_MSG);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mailbox_list_set_critical(struct mailbox_list *list, const char *fmt, ...)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* critical errors may contain sensitive data, so let user
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen see only "Internal error" with a timestamp to make it
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen easier to look from log files the actual error message. */
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenbool mailbox_list_set_error_from_errno(struct mailbox_list *list)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen if (!mail_error_from_errno(&error, &error_string))