struct dict_settings set;
const char *error;
+ if ((type_flags & MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED) != 0) {
+ /* IMAP METADATA support isn't enabled, so don't allow using
+ mail_attribute_dict. */
+ mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE,
+ "Generic mailbox attributes not enabled");
+ return -1;
+ }
+
if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0)
return -1;
*mailbox_prefix_r = guid_128_to_string(metadata.guid);
}
i_assert(dtransp != NULL);
- if (*dtransp != NULL) {
- /* transaction already created */
+ if (*dtransp != NULL &&
+ (type_flags & MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED) == 0) {
+ /* Transaction already created. Even if it was, don't use it
+ if _FLAG_VALIDATED is being used. It'll be handled below by
+ returning failure. */
if (mailbox_get_metadata(t->box, MAILBOX_METADATA_GUID,
&metadata) < 0)
return -1;
if (index_storage_get_dict(t->box, type_flags, &dict, mailbox_prefix_r) < 0)
return -1;
+ i_assert(*dtransp == NULL);
*dtransp = *dtrans_r = dict_transaction_begin(dict);
return 0;
}
struct mailbox_attribute_internal ireg;
unsigned int insert_idx;
+ /* Validated attributes must have a set() callback that validates the
+ provided values. Also read-only _RANK_AUTHORITY attributes don't
+ need validation. */
+ i_assert((iattr->flags & MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED) == 0 ||
+ iattr->set != NULL ||
+ iattr->rank == MAIL_ATTRIBUTE_INTERNAL_RANK_AUTHORITY);
+
(void)array_bsearch_insert_pos(&mailbox_internal_attributes,
iattr, mailbox_attribute_internal_cmp, &insert_idx);
}
static const struct mailbox_attribute_internal *
-mailbox_internal_attribute_get(enum mail_attribute_type type_flags,
- const char *key)
+mailbox_internal_attribute_get_int(enum mail_attribute_type type_flags,
+ const char *key)
{
const struct mailbox_attribute_internal *iattr;
struct mailbox_attribute_internal dreg;
}
}
+static const struct mailbox_attribute_internal *
+mailbox_internal_attribute_get(enum mail_attribute_type type_flags,
+ const char *key)
+{
+ const struct mailbox_attribute_internal *iattr;
+
+ iattr = mailbox_internal_attribute_get_int(type_flags, key);
+ if ((type_flags & MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED) != 0 &&
+ iattr != NULL &&
+ (iattr->flags & MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED) == 0) {
+ /* only validated attributes can be accessed */
+ iattr = NULL;
+ }
+ return iattr;
+}
+
static void
mailbox_internal_attributes_get(enum mail_attribute_type type_flags,
const char *prefix, bool have_dict, ARRAY_TYPE(const_string) *attrs)
if (regs[i].type != dreg.type)
return;
+ 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;
default:
i_unreached();
}
+ /* the value was validated. */
+ type_flags &= ~MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED;
}
ret = t->box->v.attribute_set(t, type_flags, key, value);
if (iattr != NULL) {
switch (iattr->rank) {
case MAIL_ATTRIBUTE_INTERNAL_RANK_OVERRIDE:
+ /* we already checked that this attribute has
+ validated-flag */
+ type_flags &= ~MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED;
+
+ if (iattr->get == NULL)
+ break;
if ((ret = iattr->get(box, key, value_r)) != 0) {
if (ret < 0)
return -1;
MAIL_ATTRIBUTE_TYPE_SHARED
};
#define MAIL_ATTRIBUTE_TYPE_MASK 0x0f
+/* Allow accessing only attributes with
+ MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED. */
+#define MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED 0x80
enum mail_attribute_value_flags {
MAIL_ATTRIBUTE_VALUE_FLAG_READONLY = 0x01,
enum mail_attribute_internal_flags {
/* Apply this attribute to the given key and its children. */
- MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN = 0x01
+ MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN = 0x01,
+ /* This attribute can be set/get even without generic METADATA support.
+ These attributes don't count towards any quotas either, so the set()
+ callback should validate that the value isn't excessively large. */
+ MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED = 0x02,
};
struct mailbox_attribute_internal {