]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Add mailbox_attribute_internal.iter()
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 14 Aug 2019 16:18:20 +0000 (19:18 +0300)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Tue, 10 Sep 2019 07:02:17 +0000 (10:02 +0300)
This mainly allows internal attributes with children to actually be able to
list the childrens' keys.

src/lib-storage/mailbox-attribute.c
src/lib-storage/mailbox-attribute.h

index bb52376cf5f3756777a0b56acb329fb3dcf327bf..78ca638f7a2722c36fe7025693fe152ad66e4df5 100644 (file)
@@ -145,14 +145,39 @@ mailbox_internal_attribute_get(enum mail_attribute_type type_flags,
 }
 
 static void
-mailbox_internal_attributes_get(enum mail_attribute_type type_flags,
-       const char *prefix, bool have_dict, ARRAY_TYPE(const_string) *attrs)
+mailbox_internal_attributes_add_prefixes(ARRAY_TYPE(const_string) *attrs,
+                                        pool_t pool, unsigned int old_count,
+                                        const char *key)
+{
+       unsigned int new_count;
+
+       if (key[0] == '\0')
+               return;
+       new_count = array_count(attrs);
+       for (unsigned int i = old_count; i < new_count; i++) {
+               const char *const *old_keyp = array_idx(attrs, i);
+               const char *old_key = *old_keyp;
+               const char *prefixed_key;
+
+               if (old_key[0] == '\0')
+                       prefixed_key = p_strndup(pool, key, strlen(key)-1);
+               else
+                       prefixed_key = p_strconcat(pool, key, old_key, NULL);
+               array_idx_set(attrs, i, &prefixed_key);
+       }
+}
+
+static int
+mailbox_internal_attributes_get(struct mailbox *box,
+       enum mail_attribute_type type_flags, const char *prefix,
+       pool_t attr_pool, bool have_dict, ARRAY_TYPE(const_string) *attrs)
 {
        const struct mailbox_attribute_internal *regs;
        struct mailbox_attribute_internal dreg;
        char *bare_prefix;
        size_t plen;
-       unsigned int count, i;
+       unsigned int count, i, j;
+       int ret = 0;
 
        bare_prefix = t_strdup_noconst(prefix);
        plen = strlen(bare_prefix);
@@ -168,19 +193,39 @@ mailbox_internal_attributes_get(enum mail_attribute_type type_flags,
        (void)array_bsearch_insert_pos(&mailbox_internal_attributes,
                &dreg, mailbox_attribute_internal_cmp, &i);
 
+       /* iterate attributes that might have children whose keys begins with
+          the prefix */
        regs = array_get(&mailbox_internal_attributes, &count);
+       for (j = i; j > 0; j--) {
+               const struct mailbox_attribute_internal *attr = &regs[j-1];
+
+               if ((attr->flags & MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN) == 0 ||
+                   !str_begins(bare_prefix, attr->key))
+                       break;
+
+               /* For example: bare_prefix="foo/bar" and attr->key="foo/", so
+                  iter() is called with key_prefix="bar". It could add to
+                  attrs: { "", "baz" }, which means with the full prefix:
+                  { "foo/bar", "foo/bar/baz" } */
+               if (attr->iter != NULL &&
+                   attr->iter(box, bare_prefix + strlen(attr->key),
+                              attr_pool, attrs) < 0)
+                       ret = -1;
+       }
+
+       /* iterate attributes whose key begins with the prefix */
        for (; i < count; i++) {
                const char *key = regs[i].key;
 
                if (regs[i].type != dreg.type)
-                       return;
+                       return ret;
                if ((type_flags & MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED) != 0 &&
                    (regs[i].flags & MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED) == 0)
                        continue;
 
                if (plen > 0) {
                        if (strncmp(key, bare_prefix, plen) != 0)
-                               return;
+                               return ret;
                        if (key[plen] == '/') {
                                /* remove prefix */
                                key += plen + 1;
@@ -190,12 +235,24 @@ mailbox_internal_attributes_get(enum mail_attribute_type type_flags,
                                   dict backend works too. */
                                key += plen;
                        } else {
-                               return;
+                               return ret;
                        }
                }
-               if (have_dict || regs[i].rank == MAIL_ATTRIBUTE_INTERNAL_RANK_AUTHORITY)
+               if (regs[i].iter != NULL) {
+                       /* For example: bare_prefix="foo" and
+                          attr->key="foo/bar/", so key="bar/". iter() is
+                          always called with key_prefix="", so we're also
+                          responsible for adding the "bar/" prefix to the
+                          attrs that iter() returns. */
+                       unsigned int old_count = array_count(attrs);
+                       if (regs[i].iter(box, "", attr_pool, attrs) < 0)
+                               ret = -1;
+                       mailbox_internal_attributes_add_prefixes(attrs, attr_pool,
+                                                                old_count, key);
+               } else if (have_dict || regs[i].rank == MAIL_ATTRIBUTE_INTERNAL_RANK_AUTHORITY)
                        array_push_back(attrs, &key);
        }
+       return ret;
 }
 
 /*
@@ -403,11 +460,13 @@ int mailbox_attribute_get_stream(struct mailbox *box,
 
 struct mailbox_attribute_internal_iter { 
        struct mailbox_attribute_iter iter;
+       pool_t pool;
 
        ARRAY_TYPE(const_string) extra_attrs;
        unsigned int extra_attr_idx;
 
        struct mailbox_attribute_iter *real_iter;
+       bool iter_failed;
 };
 
 struct mailbox_attribute_iter *
@@ -419,7 +478,8 @@ mailbox_attribute_iter_init(struct mailbox *box,
        struct mailbox_attribute_iter *iter;
        ARRAY_TYPE(const_string) extra_attrs;
        const char *const *attr;
-       bool have_dict;
+       pool_t pool;
+       bool have_dict, failed = FALSE;
 
        iter = box->v.attribute_iter_init(box, type_flags, prefix);
        i_assert(iter->box != NULL);
@@ -428,19 +488,24 @@ mailbox_attribute_iter_init(struct mailbox *box,
        /* check which internal attributes may apply */
        t_array_init(&extra_attrs, 4);
        have_dict = box->storage->set->mail_attribute_dict[0] != '\0';
-       mailbox_internal_attributes_get(type_flags, prefix,
-                                       have_dict, &extra_attrs);
+       pool = pool_alloconly_create("mailbox internal attribute iter", 128);
+       if (mailbox_internal_attributes_get(box, type_flags, prefix, pool,
+                                           have_dict, &extra_attrs) < 0)
+               failed = TRUE;
 
        /* any extra internal attributes to add? */
-       if (array_count(&extra_attrs) == 0) {
+       if (array_count(&extra_attrs) == 0 && !failed) {
                /* no */
+               pool_unref(&pool);
                return iter;
        }
 
        /* yes */
-       intiter = i_new(struct mailbox_attribute_internal_iter, 1);
+       intiter = p_new(pool, struct mailbox_attribute_internal_iter, 1);
+       intiter->pool = pool;
        intiter->real_iter = iter;
-       i_array_init(&intiter->extra_attrs, 4);
+       intiter->iter_failed = failed;
+       p_array_init(&intiter->extra_attrs, pool, 4);
 
        /* copy relevant attributes */
        array_foreach(&extra_attrs, attr) {
@@ -511,7 +576,8 @@ int mailbox_attribute_iter_deinit(struct mailbox_attribute_iter **_iter)
        intiter->real_iter->box->attribute_iter_count--;
 
        ret = intiter->real_iter->box->v.attribute_iter_deinit(intiter->real_iter);
-       array_free(&intiter->extra_attrs);
-       i_free(intiter);
+       if (intiter->iter_failed)
+               ret = -1;
+       pool_unref(&intiter->pool);
        return ret;
 }
index 093158a7f9234af7c866ae6395ff00c8110821b2..9a70580f630ce6026f525b58c4bc4e8b41d24dd5 100644 (file)
@@ -256,6 +256,15 @@ struct mailbox_attribute_internal {
        /* Set the value of this internal attribute */
        int (*set)(struct mailbox_transaction_context *t, const char *key,
                   const struct mail_attribute_value *value);
+       /* If non-NULL, the function is responsible for iterating the
+          attribute. Typically this would be used for attributes with
+          MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN to get the children
+          iterated. If key_prefix is "", all keys should be returned.
+          Otherwise only the keys beginning with key_prefix should be
+          returned. The key_prefix is already relative to the
+          mailbox_attribute_internal.key. */
+       int (*iter)(struct mailbox *box, const char *key_prefix,
+                   pool_t pool, ARRAY_TYPE(const_string) *keys);
 };
 
 void mailbox_attribute_register_internal(