From: Stephan Bosch Date: Thu, 5 Oct 2017 10:27:08 +0000 (+0200) Subject: lib-storage: mail-storage - Add API for allocating a mailbox based on a special-use... X-Git-Tag: 2.3.9~111 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9e2dba4dc26958bbb7b77edec0b70f4315d04000;p=thirdparty%2Fdovecot%2Fcore.git lib-storage: mail-storage - Add API for allocating a mailbox based on a special-use flag. --- diff --git a/src/lib-storage/mail-storage.c b/src/lib-storage/mail-storage.c index 7ebfbc2d83..4feda02fc1 100644 --- a/src/lib-storage/mail-storage.c +++ b/src/lib-storage/mail-storage.c @@ -911,13 +911,131 @@ struct mailbox *mailbox_alloc_guid(struct mailbox_list *list, return box; } +static bool +str_contains_special_use(const char *str, const char *special_use) +{ + const char *const *uses; + + i_assert(special_use != NULL); + if (*special_use != '\\') + return FALSE; + + uses = t_strsplit_spaces(str, " "); + return str_array_icase_find(uses, special_use); +} + +static int +namespace_find_special_use(struct mail_namespace *ns, const char *special_use, + const char **vname_r, enum mail_error *error_code_r) +{ + struct mailbox_list *list = ns->list; + struct mailbox_list_iterate_context *ctx; + const struct mailbox_info *info; + int ret = 0; + + *vname_r = NULL; + *error_code_r = MAIL_ERROR_NONE; + + if (!ns->special_use_mailboxes) + return 0; + if (!HAS_ALL_BITS(ns->type, MAIL_NAMESPACE_TYPE_PRIVATE)) + return 0; + + ctx = mailbox_list_iter_init(list, "*", + MAILBOX_LIST_ITER_SELECT_SPECIALUSE | + MAILBOX_LIST_ITER_RETURN_SPECIALUSE); + while ((info = mailbox_list_iter_next(ctx)) != NULL) { + if ((info->flags & + (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) != 0) + continue; + /* iter can only return mailboxes that have non-empty + special-use */ + i_assert(info->special_use != NULL && + *info->special_use != '\0'); + + if (str_contains_special_use(info->special_use, special_use)) { + *vname_r = t_strdup(info->vname); + ret = 1; + break; + } + } + if (mailbox_list_iter_deinit(&ctx) < 0) { + const char *error; + + error = mailbox_list_get_last_error(ns->list, error_code_r); + e_error(ns->user->event, + "Failed to find mailbox with SPECIAL-USE flag '%s' " + "in namespace '%s': %s", + special_use, ns->prefix, error); + return -1; + } + return ret; +} + +static int +namespaces_find_special_use(struct mail_namespace *namespaces, + const char *special_use, + struct mail_namespace **ns_r, + const char **vname_r, enum mail_error *error_code_r) +{ + struct mail_namespace *ns_inbox; + int ret; + + *error_code_r = MAIL_ERROR_NONE; + *vname_r = NULL; + + /* check user's INBOX namespace first */ + *ns_r = ns_inbox = mail_namespace_find_inbox(namespaces); + ret = namespace_find_special_use(*ns_r, special_use, + vname_r, error_code_r); + if (ret != 0) + return ret; + + /* check other namespaces */ + for (*ns_r = namespaces; *ns_r != NULL; *ns_r = (*ns_r)->next) { + if (*ns_r == ns_inbox) { + /* already checked */ + continue; + } + ret = namespace_find_special_use(*ns_r, special_use, + vname_r, error_code_r); + if (ret != 0) + return ret; + } + + *ns_r = ns_inbox; + return 0; +} + struct mailbox * -mailbox_alloc_for_user(struct mail_user *user, const char *vname, +mailbox_alloc_for_user(struct mail_user *user, const char *mname, enum mailbox_flags flags) { struct mail_namespace *ns; + struct mailbox *box; + const char *vname; + enum mail_error open_error = MAIL_ERROR_NONE; + int ret; - ns = mail_namespace_find(user->namespaces, vname); + if (HAS_ALL_BITS(flags, MAILBOX_FLAG_SPECIAL_USE)) { + ret = namespaces_find_special_use(user->namespaces, mname, + &ns, &vname, &open_error); + if (ret < 0) { + i_assert(open_error != MAIL_ERROR_NONE); + vname = t_strdup_printf( + "(error finding mailbox with SPECIAL-USE=%s)", + mname); + } else if (ret == 0) { + i_assert(open_error == MAIL_ERROR_NONE); + vname = t_strdup_printf( + "(nonexistent mailbox with SPECIAL-USE=%s)", + mname); + open_error = MAIL_ERROR_NOTFOUND; + } + } else { + vname = mname; + ns = mail_namespace_find(user->namespaces, mname); + } if (HAS_ALL_BITS(flags, MAILBOX_FLAG_POST_SESSION)) { flags |= MAILBOX_FLAG_SAVEONLY; @@ -937,7 +1055,11 @@ mailbox_alloc_for_user(struct mail_user *user, const char *vname, } } - return mailbox_alloc(ns->list, vname, flags); + i_assert(ns != NULL); + box = mailbox_alloc(ns->list, vname, flags); + if (open_error != MAIL_ERROR_NONE) + box->open_error = open_error; + return box; } void mailbox_set_reason(struct mailbox *box, const char *reason) diff --git a/src/lib-storage/mail-storage.h b/src/lib-storage/mail-storage.h index 0bff34621a..3c42707d07 100644 --- a/src/lib-storage/mail-storage.h +++ b/src/lib-storage/mail-storage.h @@ -73,6 +73,9 @@ enum mailbox_flags { useful in fixing index corruption errors that aren't otherwise detected and that are causing the full mailbox opening to fail. */ MAILBOX_FLAG_FSCK = 0x4000, + /* Interpret name argument for mailbox_alloc_for_user() as a SPECIAL-USE + flag. */ + MAILBOX_FLAG_SPECIAL_USE = 0x8000, }; enum mailbox_feature { @@ -523,9 +526,11 @@ struct mailbox *mailbox_alloc_guid(struct mailbox_list *list, const guid_128_t guid, enum mailbox_flags flags); /* Initialize mailbox for a particular user without actually opening any files - or verifying that it exists. */ + or verifying that it exists. The mname parameter is normally equal to the + mailbox vname, except when the MAILBOX_FLAG_SPECIAL_USE flag is set, in which + case it is the special-use flag. */ struct mailbox * -mailbox_alloc_for_user(struct mail_user *user, const char *vname, +mailbox_alloc_for_user(struct mail_user *user, const char *mname, enum mailbox_flags flags); /* Set a human-readable reason for why this mailbox is being accessed.