]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: mail-storage - Add API for allocating a mailbox based on a special-use...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Thu, 5 Oct 2017 10:27:08 +0000 (12:27 +0200)
committerStephan Bosch <stephan.bosch@open-xchange.com>
Tue, 8 Oct 2019 17:14:55 +0000 (19:14 +0200)
src/lib-storage/mail-storage.c
src/lib-storage/mail-storage.h

index 7ebfbc2d832c89b2793ddab0911e36ed3d4cb529..4feda02fc1da7b4c78d5d24756df85581a6862e1 100644 (file)
@@ -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)
index 0bff34621a54d0867b6d47105eeb7631ccff9a89..3c42707d07fe7d4d36f32183c8587d5e554784c2 100644 (file)
@@ -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.