From: Timo Sirainen Date: Wed, 14 Aug 2019 16:18:20 +0000 (+0300) Subject: lib-storage: Add mailbox_attribute_internal.iter() X-Git-Tag: 2.3.8~154 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ae83be9cc78eb5d433a477031987cc61286750ce;p=thirdparty%2Fdovecot%2Fcore.git lib-storage: Add mailbox_attribute_internal.iter() This mainly allows internal attributes with children to actually be able to list the childrens' keys. --- diff --git a/src/lib-storage/mailbox-attribute.c b/src/lib-storage/mailbox-attribute.c index bb52376cf5..78ca638f7a 100644 --- a/src/lib-storage/mailbox-attribute.c +++ b/src/lib-storage/mailbox-attribute.c @@ -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 = ®s[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; } diff --git a/src/lib-storage/mailbox-attribute.h b/src/lib-storage/mailbox-attribute.h index 093158a7f9..9a70580f63 100644 --- a/src/lib-storage/mailbox-attribute.h +++ b/src/lib-storage/mailbox-attribute.h @@ -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(