mailbox-list.c revision 847caf605dc11acfb1861586b558d9cca4a85cb0
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen#define MAILBOX_LIST_LOCK_FNAME "mailboxes.lock"
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic ARRAY(const struct mailbox_list *) mailbox_list_drivers;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mailbox_list_fs_module,
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) {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen unsigned int idx;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo 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",
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen unsigned int idx;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct mailbox_list **list_r, const char **error_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if ((class = mailbox_list_find_class(driver)) == NULL) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if ((class->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen *error_r = "maildir_name not supported by this driver";
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if ((class->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen *error_r = "alt_dir not supported by this driver";
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0' ||
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen (class->props & MAILBOX_LIST_PROP_NO_ROOT) != 0);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->root_permissions.file_create_mode = (mode_t)-1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->root_permissions.dir_create_mode = (mode_t)-1;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen list->root_permissions.file_create_gid = (gid_t)-1;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen /* copy settings */
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen list->set.index_dir = set->index_dir == NULL ||
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen list->set.index_pvt_dir = set->index_pvt_dir == NULL ||
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen strcmp(set->index_pvt_dir, set->root_dir) == 0 ? NULL :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.index_cache_dir = set->index_cache_dir == NULL ||
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen strcmp(set->index_cache_dir, set->root_dir) == 0 ? NULL :
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen list->set.control_dir = set->control_dir == NULL ||
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
27586e4785d56aeb76e1fd96af8db799688dc64aTimo Sirainen p_strdup(list->pool, set->subscription_fname);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.alt_dir = p_strdup(list->pool, set->alt_dir);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.alt_dir_nocheck = set->alt_dir_nocheck;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.volatile_dir = p_strdup(list->pool, set->volatile_dir);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.iter_from_index_dir = set->iter_from_index_dir;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_debug("%s: root=%s, index=%s, indexpvt=%s, control=%s, inbox=%s, alt=%s",
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen list->set.root_dir == NULL ? "" : list->set.root_dir,
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen list->set.index_pvt_dir == NULL ? "" : list->set.index_pvt_dir,
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen list->set.alt_dir == NULL ? "" : list->set.alt_dir);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if ((flags & MAILBOX_LIST_FLAG_SECONDARY) == 0)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenstatic int fix_path(struct mail_user *user, const char *path, bool expand_home,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen /* no ~ expansion */
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen } else if (path[0] == '~' && path[1] != '/' && path[1] != '\0') {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen "No home directory for system user. "
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (mail_user_try_home_expand(user, &path) < 0) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen *error_r = "Home directory not set for user. "
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen "Can't expand ~/ for ";
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenstatic const char *split_next_arg(const char *const **_args)
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen /* string ends with ":", just ignore it. */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenvoid mailbox_list_settings_init_defaults(struct mailbox_list_settings *set_r)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen set_r->list_index_fname = MAILBOX_LIST_INDEX_DEFAULT_PREFIX;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenmailbox_list_settings_parse_full(struct mail_user *user, const char *data,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen const char **error_r)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen const char *const *tmp, *key, *value, **dest, *str, *fname, *error;
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen /* <root dir> */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (fix_path(user, str, expand_home, &set_r->root_dir, &error) < 0) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen if (strncmp(set_r->root_dir, "INBOX=", 6) == 0) {
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen /* probably mbox user trying to avoid root_dir */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen *error_r = t_strconcat("Mail root directory not given: ",
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen *error_r = "BROKENCHAR value must be a single character";
1728ff34ee03de825ad3aeed67d19f8ae140ee2eTimo Sirainen *error_r = t_strdup_printf("Unknown setting: %s", key);
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainen if (fix_path(user, value, expand_home, dest, &error) < 0) {
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainen *error_r = t_strconcat(error, key, " in: ", data, NULL);
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainen if (set_r->index_dir != NULL && strcmp(set_r->index_dir, "MEMORY") == 0)
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainen (set_r->index_dir == NULL || set_r->index_dir[0] == '\0')) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen *error_r = "ITERINDEX requires INDEX to be explicitly set";
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen (fname = strrchr(set_r->list_index_fname, '/')) != NULL) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* non-default LISTINDEX directory */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen t_strdup_until(set_r->list_index_fname, fname);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen set_r->index_dir != NULL && set_r->index_dir[0] == '\0') {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen *error_r = "LISTINDEX directory is relative but INDEX=MEMORY";
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenint mailbox_list_settings_parse(struct mail_user *user, const char *data,
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen const char **error_r)
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen return mailbox_list_settings_parse_full(user, data, TRUE,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenconst char *mailbox_list_get_unexpanded_path(struct mailbox_list *list,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const char *location = list->ns->unexpanded_set->location;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen if (*location == SETTING_STRVAR_EXPANDED[0]) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* set using -o or userdb lookup. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen i_assert(*location == SETTING_STRVAR_UNEXPANDED[0]);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen mail_set = mail_user_set_get_driver_settings(user->set_info,
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen user->unexpanded_set, MAIL_STORAGE_SET_DRIVER_NAME);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen i_assert(*location == SETTING_STRVAR_UNEXPANDED[0]);
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen /* type:settings */
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen if (mailbox_list_settings_parse_full(user, p + 1, FALSE,
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen if (!mailbox_list_set_get_root_path(&set, type, &path))
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenstatic bool need_escape_dirstart(const char *vname, const char *maildir_name)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen if (vname[1] == '.' && (vname[2] == '\0' || vname[2] == '/'))
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenmailbox_list_escape_name_params(const char *vname, const char *ns_prefix,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* no escaping of namespace prefix */
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen if (strncmp(ns_prefix, vname, ns_prefix_len) == 0) {
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen str_append_n(escaped_name, vname, ns_prefix_len);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen /* escape the mailbox name */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen str_printfa(escaped_name, "%c%02x", escape_char, *vname);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenmailbox_list_escape_name(struct mailbox_list *list, const char *vname)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return mailbox_list_escape_name_params(vname, list->ns->prefix,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen list->set.escape_char, list->set.maildir_name);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenmailbox_list_unescape_broken_chars(struct mailbox_list *list, char *name)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen unsigned char chr;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if ((src = strchr(name, list->set.broken_char)) == NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic char *mailbox_list_convert_sep(const char *storage_name, char src, char dest)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ret = p_strdup(unsafe_data_stack_pool, storage_name);
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainenconst char *mailbox_list_default_get_storage_name(struct mailbox_list *list,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen storage_name = mailbox_list_escape_name(list, vname);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (prefix_len > 0 && (strcmp(storage_name, "INBOX") != 0 ||
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen (ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0)) {
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen /* skip namespace prefix, except if this is INBOX */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen if (strncmp(ns->prefix, storage_name, prefix_len) == 0)
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen else if (strncmp(ns->prefix, storage_name, prefix_len-1) == 0 &&
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen ns->prefix[prefix_len-1] == mail_namespace_get_sep(ns)) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen /* trying to access the namespace prefix itself */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* we're converting a nonexistent mailbox name,
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen such as a LIST pattern. */
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen /* UTF-8 -> mUTF-7 conversion */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen list_sep = mailbox_list_get_hierarchy_sep(list);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (*storage_name == '\0' && ns->type == MAIL_NAMESPACE_TYPE_SHARED &&
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen (ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0 &&
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen !list->mail_set->mail_shared_explicit_inbox) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* opening shared/$user. it's the same as INBOX. */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (list_sep != ns_sep && list->set.escape_char == '\0') {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* shared namespace root. the backend storage's
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hierarchy separator isn't known yet, so do
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ret = mailbox_list_convert_sep(storage_name, ns_sep, list_sep);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen strchr(storage_name, list->set.broken_char) == NULL) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* no need to convert broken chars */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ret = p_strdup(unsafe_data_stack_pool, storage_name);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen if (mailbox_list_unescape_broken_chars(list, ret) < 0) {
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenconst char *mailbox_list_get_storage_name(struct mailbox_list *list,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenmailbox_list_unescape_name_params(const char *src, const char *ns_prefix,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned int num;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (strncmp(src, ns_prefix, ns_prefix_len) == 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenmailbox_list_unescape_name(struct mailbox_list *list, const char *src)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return mailbox_list_unescape_name_params(src, list->ns->prefix,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenmailbox_list_escape_broken_chars(struct mailbox_list *list, string_t *str)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen unsigned int i;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (strchr(str_c(str), list->set.broken_char) == NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenmailbox_list_escape_broken_name(struct mailbox_list *list,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (*vname == '&' || (unsigned char)*vname >= 0x80) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen str_printfa(str, "%c%02x", list->set.broken_char,
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen (unsigned char)*vname);
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainenconst char *mailbox_list_default_get_vname(struct mailbox_list *list,
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen if ((list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* user's INBOX - use as-is. NOTE: don't do case-insensitive
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen comparison, otherwise we can't differentiate between INBOX
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen and <ns prefix>/inBox. */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen list->ns->type == MAIL_NAMESPACE_TYPE_SHARED &&
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen (list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0 &&
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen !list->mail_set->mail_shared_explicit_inbox) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* convert to shared/$user, we don't really care about the
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen INBOX suffix here. */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* return namespace prefix without the separator */
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen /* mUTF-7 -> UTF-8 conversion */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen mailbox_list_escape_broken_name(list, vname, str);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen vname = mailbox_list_unescape_name(list, vname);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen list_sep = mailbox_list_get_hierarchy_sep(list);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* @UNSAFE */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ret = t_malloc_no0(MALLOC_ADD(prefix_len, name_len) + 1);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen for (i = 0; i < name_len; i++) {
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainenconst char *mailbox_list_get_vname(struct mailbox_list *list, const char *name)
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenvoid mailbox_list_destroy(struct mailbox_list **_list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (hash_table_is_created(list->guid_cache)) {
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen i_assert(array_count(&list->error_stack) == 0);
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainenconst char *mailbox_list_get_driver_name(const struct mailbox_list *list)
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainenmailbox_list_get_settings(const struct mailbox_list *list)
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainenenum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenmailbox_list_get_namespace(const struct mailbox_list *list)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen /* add the execute bit if either read or write bit is set */
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainenmailbox_list_get_user(const struct mailbox_list *list)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainenmailbox_list_get_storage_driver(struct mailbox_list *list, const char *driver,
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen array_foreach(&list->ns->all_storages, storagep) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen data = i_strchr_to_next(list->ns->set->location, ':');
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (mail_storage_create_full(list->ns, driver, data, 0,
15bfe73fb3988bb80e6afe6a60b9a715c7207600Timo Sirainen "Namespace %s: Failed to create storage '%s': %s",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenint mailbox_list_get_storage(struct mailbox_list **list, const char *vname,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return (*list)->v.get_storage(list, vname, storage_r);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen set = mailbox_settings_find((*list)->ns, vname);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (set != NULL && set->driver != NULL && set->driver[0] != '\0') {
e353d03d3643f380dc7e6dc29a512dec86b8a3deTimo Sirainen return mailbox_list_get_storage_driver(*list, set->driver,
e353d03d3643f380dc7e6dc29a512dec86b8a3deTimo Sirainen *storage_r = mail_namespace_get_default_storage((*list)->ns);
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainenvoid mailbox_list_get_default_storage(struct mailbox_list *list,
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen *storage = mail_namespace_get_default_storage(list->ns);
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainenchar mailbox_list_get_hierarchy_sep(struct mailbox_list *list)
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen /* the current API doesn't allow returning an error, so imap code
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen looks at the list's last error. make sure the error is cleared
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen so the error-check doesn't return something irrelevant */
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainenmailbox_list_get_permissions_stat(struct mailbox_list *list, const char *path,
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen mailbox_list_set_critical(list, "stat(%s) failed: %m",
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen i_debug("Namespace %s: %s doesn't exist yet, "
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen "using default permissions",
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen permissions_r->file_create_mode = (st.st_mode & 0666) | 0600;
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen permissions_r->dir_create_mode = (st.st_mode & 0777) | 0700;
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen /* we're getting permissions from a file.
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen apply +x modes as necessary. */
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen /* directory's GID is used automatically for new files */
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen } else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen /* group has same permissions as world, so don't bother
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen changing it */
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen /* using our own gid, no need to change it */
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen permissions_r->file_create_gid != (gid_t)-1) {
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen /* we need to stat() the parent directory to see if
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen it has setgid-bit set */
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch /* directory's GID is used automatically for
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenmailbox_list_get_permissions_internal(struct mailbox_list *list,
6763c5f6246a0705b141d99d32fe9e2096042bd3Timo Sirainen /* use safe defaults */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen permissions_r->file_create_gid_origin = "defaults";
6763c5f6246a0705b141d99d32fe9e2096042bd3Timo Sirainen (list->flags & MAILBOX_LIST_FLAG_NO_MAIL_FILES) != 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen /* a) iterating from index dir. Use the index dir's permissions
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen as well, since they might be in a faster storage.
758d8b46f9e8fd87cf58bb4912cddf6bf28918cfTimo Sirainen b) mail files don't exist in storage, but index files
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen if (mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR,
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen (void)mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_DIR,
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen /* no filesystem support in storage */
4225ae95dd2110fe678ee70c64be14784a53c364Timo Sirainen } else if (mailbox_list_get_permissions_stat(list, path, permissions_r)) {
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen /* got permissions from the given path */
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen permissions_r->gid_origin_is_mailbox_path = name != NULL;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen /* path couldn't be stat()ed, try parent mailbox */
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen p = strrchr(name, mailbox_list_get_hierarchy_sep(list));
2f552aa8fb0fc86473c2d7dea85d8237373fb35fTimo Sirainen /* return root defaults */
dbc86748934bc34826d9cc8c43d24df09b3ba402Timo Sirainen /* assume current defaults for mailboxes that don't exist or
dbc86748934bc34826d9cc8c43d24df09b3ba402Timo Sirainen can't be looked up for some other reason */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen mailbox_permissions_copy(&list->root_permissions, permissions_r,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (list->mail_set->mail_debug && name == NULL) {
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen i_debug("Namespace %s: Using permissions from %s: "
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen permissions_r->file_create_gid == (gid_t)-1 ? "default" :
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainenvoid mailbox_list_get_permissions(struct mailbox_list *list, const char *name,
5069b6adc4acb0efb3c6e87e778b820bae9bae9bTimo Sirainen mailbox_list_get_permissions_internal(list, name, permissions_r);
5069b6adc4acb0efb3c6e87e778b820bae9bae9bTimo Sirainenvoid mailbox_list_get_root_permissions(struct mailbox_list *list,
5069b6adc4acb0efb3c6e87e778b820bae9bae9bTimo Sirainen if (list->root_permissions.file_create_mode != (mode_t)-1)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen mailbox_list_get_permissions_internal(list, NULL,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenvoid mailbox_permissions_copy(struct mailbox_permissions *dest,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstatic const char *
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenget_expanded_path(const char *unexpanded_start, const char *unexpanded_stop,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const char *ret;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen unsigned int i, slash_count = 0, slash2_count = 0;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* get the expanded path up to the same amount of '/' characters.
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if there isn't the same amount of '/' characters, it means %variable
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen expansion added more of them and we can't handle this. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen for (i = 0; unexpanded_start+i != unexpanded_stop; i++) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenmailbox_list_try_mkdir_root_parent(struct mailbox_list *list,
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen const char **error_r)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen const char *expanded, *unexpanded, *root_dir, *p;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* get the directory path up to last %variable. for example
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen unexpanded path may be "/var/mail/%d/%2n/%n/Maildir", and we want
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen to get expanded="/var/mail/domain/nn" */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen unexpanded = mailbox_list_get_unexpanded_path(list, type);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* home directory used */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (!mailbox_list_get_root_path(list, type, &expanded))
70a2782edc5cb342ed67a46ce30a95ca316f86c9Timo Sirainen } else if (p == NULL) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (!mailbox_list_get_root_path(list, type, &expanded))
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen expanded = get_expanded_path(unexpanded, p, expanded);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* get the first existing parent directory's permissions */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (stat_first_parent(expanded, &root_dir, &st) < 0) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen t_strdup_printf("stat(%s) failed: %m", root_dir);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* if the parent directory doesn't have setgid-bit enabled, we don't
4b8a6aec5fe2daa564799867f31e39e7ea46b9c3Timo Sirainen copy any permissions from it. */
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen /* assuming we have e.g. /var/vmail/%d/%n directory, here we
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen want to create up to /var/vmail/%d with permissions from
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen the parent directory. we never want to create the %n
2cb0a0438b625cd399a4aaa0615d69f4b54d349aTimo Sirainen directory itself. */
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen /* this is the %n directory */
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen /* change the group for user directories */
4a14ae55292476bc0b8eb314d602a262ab094a52Timo Sirainen /* when using %h and the parent has setgid-bit,
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen copy the permissions from it for the home we're creating */
d85f37fe02fadcd5144560495a7196133c8ec947Timo Sirainenint mailbox_list_try_mkdir_root(struct mailbox_list *list, const char *path,
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen const char **error_r)
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen /* looks like it already exists, don't bother checking
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen mailbox_list_get_root_permissions(list, &perm);
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen if (!mailbox_list_get_root_path(list, type, &root_dir))
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen i_assert(strncmp(root_dir, path, strlen(root_dir)) == 0);
4b8a6aec5fe2daa564799867f31e39e7ea46b9c3Timo Sirainen if (strcmp(root_dir, path) != 0 && stat(root_dir, &st) == 0) {
4b8a6aec5fe2daa564799867f31e39e7ea46b9c3Timo Sirainen /* creating a subdirectory under an already existing root dir.
4b8a6aec5fe2daa564799867f31e39e7ea46b9c3Timo Sirainen use the root's permissions */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (mailbox_list_try_mkdir_root_parent(list, type,
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen /* the rest of the directories exist only for one user. create them
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen with default directory permissions */
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen if (mkdir_parents_chgrp(path, perm.dir_create_mode,
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen *error_r = mail_error_create_eacces_msg("mkdir", path);
43487bb7de9e907ad61e186714956a83f5be4a15Timo Sirainen *error_r = t_strdup_printf("mkdir(%s) failed: %m", path);
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainenint mailbox_list_mkdir_root(struct mailbox_list *list, const char *path,
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen if (mailbox_list_try_mkdir_root(list, path, type, &error) < 0) {
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainenmailbox_list_is_valid_fs_name(struct mailbox_list *list, const char *name,
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen const char **error_r)
a58e63b4928017b5af123967c1c98f8bcb242a9aTimo Sirainen if (list->mail_set->mail_full_filesystem_access)
a58e63b4928017b5af123967c1c98f8bcb242a9aTimo Sirainen /* make sure it's not absolute path */
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen /* make sure the mailbox name doesn't contain any foolishness:
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen "../" could give access outside the mailbox directory.
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen "./" and "//" could fool ACL checks.
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen some mailbox formats have reserved directory names, such as
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen Maildir's cur/new/tmp. if any of those would conflict with the
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen mailbox directory name, it's not valid. maildir++ is kludged here as
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen a special case because all of its mailbox dirs begin with "." */
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen allow_internal_dirs = list->v.is_internal_name == NULL ||
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen strcmp(list->name, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) == 0;
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen const char *const *names;
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen const char *n = *names;
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen if (*n == '\0') {
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen break; /* // */
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen if (*n == '.') {
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen break; /* ./ */
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen break; /* ../ */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* don't allow maildir_name to be used as part
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen of the mailbox name */
625042f95d7eb71f6b94a61ea4f461866be1bef9Timo Sirainenbool mailbox_list_is_valid_name(struct mailbox_list *list,
625042f95d7eb71f6b94a61ea4f461866be1bef9Timo Sirainen /* an ugly way to get to mailbox root (e.g. Maildir/
625042f95d7eb71f6b94a61ea4f461866be1bef9Timo Sirainen when it's not the INBOX) */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* either the list backend uses '/' as the hierarchy separator or
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen it doesn't use filesystem at all (PROP_NO_ROOT) */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if ((list->props & MAILBOX_LIST_PROP_NO_ROOT) == 0 &&
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen mailbox_list_get_hierarchy_sep(list) != '/' &&
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen *error_r = "Name must not have '/' characters";
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return mailbox_list_is_valid_fs_name(list, name, error_r);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenint mailbox_list_get_path(struct mailbox_list *list, const char *name,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char **path_r)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if ((ret = list->v.get_path(list, name, type, path_r)) <= 0)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenbool mailbox_list_get_root_path(struct mailbox_list *list,
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen const char **path_r)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if ((ret = list->v.get_path(list, NULL, type, path_r)) < 0)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenconst char *mailbox_list_get_root_forced(struct mailbox_list *list,
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen if (!mailbox_list_get_root_path(list, type, &path))
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenbool mailbox_list_set_get_root_path(const struct mailbox_list_settings *set,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char **path_r)
5c95939662dc6e4317f4eec60289bb12fd51982bTimo Sirainen /* relative path */
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen path = t_strconcat(path, "/", set->list_index_dir, NULL);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen /* fall through - default to index directory */
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen /* fall through */
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen /* in-memory indexes */
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainenconst char *mailbox_list_get_temp_prefix(struct mailbox_list *list)
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainenconst char *mailbox_list_get_global_temp_prefix(struct mailbox_list *list)
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainenconst char *mailbox_list_join_refpattern(struct mailbox_list *list,
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen return list->v.join_refpattern(list, ref, pattern);
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen /* the default implementation: */
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen /* merge reference and pattern */
688d869f3449827ac9b5a0a02dbc1b27177b6d20Timo Sirainenint mailbox_has_children(struct mailbox_list *list, const char *name)
9ba91492d2eb29199674b669c673332ae2b01438Timo Sirainen ret = mailbox_list_iter_next(iter) != NULL ? 1 : 0;
d3d2e50d6217e29fbc9c72d14c812c02dee291efTimo Sirainenint mailbox_list_mailbox(struct mailbox_list *list, const char *name,
d3d2e50d6217e29fbc9c72d14c812c02dee291efTimo Sirainen const char *path, *fname, *rootdir, *dir, *inbox;
d3d2e50d6217e29fbc9c72d14c812c02dee291efTimo Sirainen if ((list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
d3d2e50d6217e29fbc9c72d14c812c02dee291efTimo Sirainen /* special handling for INBOX, mainly because with Maildir++
9ba91492d2eb29199674b669c673332ae2b01438Timo Sirainen layout it needs to check if the cur/ directory exists,
9ba91492d2eb29199674b669c673332ae2b01438Timo Sirainen which the Maildir++ layout backend itself can't do.. */
9ba91492d2eb29199674b669c673332ae2b01438Timo Sirainen /* kludge: with imapc backend we can get here with
9ba91492d2eb29199674b669c673332ae2b01438Timo Sirainen list=Maildir++ (for indexes), but list->ns->list=imapc */
9ba91492d2eb29199674b669c673332ae2b01438Timo Sirainen box = mailbox_alloc(list->ns->list, "INBOX", 0);
ba36444cdf332c75ecdd2696e34c391eea75597cTimo Sirainen /* internal error or with imapc we can get here with
ba36444cdf332c75ecdd2696e34c391eea75597cTimo Sirainen login failures */
1728ff34ee03de825ad3aeed67d19f8ae140ee2eTimo Sirainen /* can't do this optimized. do it the slow way. */
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen iter = mailbox_list_iter_init(list, vname, 0);
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen rootdir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_MAILBOX);
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen if (mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR, &path) <= 0)
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen rootdir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_INDEX);
b6eced3d628ad0c50a3cbc9f966da0edc20108abTimo Sirainen if (mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_INDEX, &path) <= 0)
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen if (strncmp(path, rootdir, len) == 0 && path[len] == '/') {
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen /* looking up a regular mailbox under mail root dir */
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen } else if ((list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen /* looking up INBOX that's elsewhere */
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen /* looking up the root dir itself */
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen (list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen /* if INBOX is in e.g. ~/Maildir, it shouldn't be possible to
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen access it also via namespace prefix. */
db7ca286e3ef53f73a3e8e46104a31247ebfe213Timo Sirainen return list->v.get_mailbox_flags(list, dir, fname,
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainenstatic bool mailbox_list_init_changelog(struct mailbox_list *list)
43487bb7de9e907ad61e186714956a83f5be4a15Timo Sirainen /* don't do this in mailbox_list_create(), because _get_path() might be
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen overridden by storage (mbox). */
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_INDEX, &path))
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen path = t_strconcat(path, "/"MAILBOX_LOG_FILE_NAME, NULL);
43487bb7de9e907ad61e186714956a83f5be4a15Timo Sirainen mailbox_list_get_root_permissions(list, &perm);
43487bb7de9e907ad61e186714956a83f5be4a15Timo Sirainen mailbox_log_set_permissions(list->changelog, perm.file_create_mode,
43487bb7de9e907ad61e186714956a83f5be4a15Timo Sirainenint mailbox_list_mkdir_missing_index_root(struct mailbox_list *list)
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainen /* If index root dir hasn't been created yet, do it now.
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainen Do this here even if the index directory is the same as mail root
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainen directory, because it may not have been created elsewhere either. */
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainen if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_INDEX,
49c48631cfd07017d5f93d83713fffe4f13730c4Timo Sirainenint mailbox_list_mkdir_missing_list_index_root(struct mailbox_list *list)
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen return mailbox_list_mkdir_missing_index_root(list);
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen /* LISTINDEX points outside the index root directory */
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_LIST_INDEX,
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenvoid mailbox_list_add_change(struct mailbox_list *list,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (mailbox_list_mkdir_missing_index_root(list) <= 0)
5a0fc34c5cc525334c5a10531713017ae321c573Timo Sirainen stamp = list->changelog_timestamp != (time_t)-1 ?
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen memcpy(rec.mailbox_guid, mailbox_guid, sizeof(rec.mailbox_guid));
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen mailbox_log_record_set_timestamp(&rec, stamp);
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen (void)mailbox_log_append(list->changelog, &rec);
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainenint mailbox_list_set_subscribed(struct mailbox_list *list,
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen /* make sure we'll refresh the file on next list */
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen if ((ret = list->v.set_subscribed(list, name, set)) <= 0)
0b25846ba794ce19536a24d4065beaf2a0bd9464Timo Sirainenint mailbox_list_delete_dir(struct mailbox_list *list, const char *name)
0b25846ba794ce19536a24d4065beaf2a0bd9464Timo Sirainen if (!mailbox_list_is_valid_name(list, name, &error) || *name == '\0') {
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
0185427dd52fddec6fc76d6e99c7659620d4366eTimo Sirainen "Invalid mailbox name");
6bc5fed79741503437c6d46d9f282b66bd029c6bTimo Sirainenint mailbox_list_delete_symlink(struct mailbox_list *list, const char *name)
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen if (!mailbox_list_is_valid_name(list, name, &error) || *name == '\0') {
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen "Invalid mailbox name");
ff4bb2dfb5714eeb0408d3bb862de1646351d097Timo Sirainenvoid mailbox_name_get_sha128(const char *name, guid_128_t guid_128_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen memcpy(guid_128_r, sha, I_MIN(GUID_128_SIZE, sizeof(sha)));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstruct mailbox_log *mailbox_list_get_changelog(struct mailbox_list *list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return !mailbox_list_init_changelog(list) ? NULL : list->changelog;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mailbox_list_set_changelog_timestamp(struct mailbox_list *list,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenmailbox_list_get_file_type(const struct dirent *d ATTR_UNUSED)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen switch (d->d_type) {
77b5fd56e5a06d624f3ab92198272287333114f4Timo Sirainenint mailbox_list_dirent_is_alias_symlink(struct mailbox_list *list,
dd645357a6b851a3a9527d16e2bced731e46dcaaMartti Rannanjärvi const struct dirent *d)
77b5fd56e5a06d624f3ab92198272287333114f4Timo Sirainen if (mailbox_list_get_file_type(d) == MAILBOX_LIST_FILE_TYPE_SYMLINK)
77b5fd56e5a06d624f3ab92198272287333114f4Timo Sirainen path = t_strconcat(dir_path, "/", d->d_name, NULL);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen } else if (t_readlink(path, &linkpath, &error) < 0) {
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen i_error("t_readlink(%s) failed: %s", path, error);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen /* it's an alias only if it points to the same
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainenmailbox_list_try_get_home_path(struct mailbox_list *list, const char **name)
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen /* ~/dir - use the configured home directory */
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (mail_user_try_home_expand(list->ns->user, name) < 0)
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen /* ~otheruser/dir - assume we're using system users */
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainenbool mailbox_list_try_get_absolute_path(struct mailbox_list *list,
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen const char **name)
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (!list->mail_set->mail_full_filesystem_access)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen /* try to expand home directory */
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (!mailbox_list_try_get_home_path(list, name)) {
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen /* fallback to using actual "~name" mailbox */
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen /* okay, we have an absolute path now. but check first if it points to
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen same directory as one of our regular mailboxes. */
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen root_dir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_MAILBOX);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen if (strncmp(root_dir, *name, len) == 0 && (*name)[len] == '/') {
3e0b3ae576483a96b88802b27e93f3caeba09ddcTimo Sirainen /* yeah, we can replace the full path with mailbox
3e0b3ae576483a96b88802b27e93f3caeba09ddcTimo Sirainen name. this way we can use indexes. */
8ca217bf3aa23c7922d0d4aa44fcd2320416d61cMartti Rannanjärviconst char *mailbox_list_get_last_error(struct mailbox_list *list,
8ca217bf3aa23c7922d0d4aa44fcd2320416d61cMartti Rannanjärvi return list->error_string != NULL ? list->error_string :
8ca217bf3aa23c7922d0d4aa44fcd2320416d61cMartti Rannanjärvi "Unknown internal list error";
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenenum mail_error mailbox_list_get_last_mail_error(struct mailbox_list *list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenconst char *mailbox_list_get_last_internal_error(struct mailbox_list *list,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen return mailbox_list_get_last_error(list, error_r);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainenvoid mailbox_list_clear_error(struct mailbox_list *list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mailbox_list_set_error(struct mailbox_list *list,
8ca217bf3aa23c7922d0d4aa44fcd2320416d61cMartti Rannanjärvivoid mailbox_list_set_internal_error(struct mailbox_list *list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *str;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen str = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenvoid mailbox_list_set_critical(struct mailbox_list *list, const char *fmt, ...)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen list->last_internal_error = i_strdup_vprintf(fmt, va);
4654cf737f538f5de032b8c9908913f121917366Timo Sirainen /* critical errors may contain sensitive data, so let user
4654cf737f538f5de032b8c9908913f121917366Timo Sirainen see only "Internal error" with a timestamp to make it
4654cf737f538f5de032b8c9908913f121917366Timo Sirainen easier to look from log files the actual error message. */
4654cf737f538f5de032b8c9908913f121917366Timo Sirainenbool mailbox_list_set_error_from_errno(struct mailbox_list *list)
4654cf737f538f5de032b8c9908913f121917366Timo Sirainen if (!mail_error_from_errno(&error, &error_string))
4654cf737f538f5de032b8c9908913f121917366Timo Sirainen mailbox_list_set_error(list, error, error_string);
4654cf737f538f5de032b8c9908913f121917366Timo Sirainenvoid mailbox_list_last_error_push(struct mailbox_list *list)
4654cf737f538f5de032b8c9908913f121917366Timo Sirainen err->error_string = i_strdup(list->error_string);
4654cf737f538f5de032b8c9908913f121917366Timo Sirainen err->last_error_is_internal = list->last_error_is_internal;
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen err->last_internal_error = i_strdup(list->last_internal_error);
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainenvoid mailbox_list_last_error_pop(struct mailbox_list *list)
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen unsigned int count = array_count(&list->error_stack);
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen list->last_error_is_internal = err->last_error_is_internal;
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen list->last_internal_error = err->last_internal_error;
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainenint mailbox_list_init_fs(struct mailbox_list *list, const char *driver,
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen mail_user_init_fs_settings(list->ns->user, &fs_set, &ssl_set);
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen fs_set.temp_file_prefix = mailbox_list_get_global_temp_prefix(list);
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen if (fs_init(driver, args, &fs_set, fs_r, error_r) < 0)
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen /* add mailbox_list context to the parent fs, which allows
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen mailbox_list_fs_get_list() to work */
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen for (parent_fs = *fs_r; parent_fs->parent != NULL;
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen ctx = p_new(list->pool, struct mailbox_list_fs_context, 1);
&lock_dir)) {
&lock_dir)) {