mailbox-attribute.c revision 3858a7a5da361c35f1e6e50c8e3214dc0cf379d6
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina/* Copyright (c) 2003-2016 Dovecot authors, see the included COPYING file */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#include "lib.h"
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#include "array.h"
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#include "str.h"
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#include "istream.h"
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#include "mail-storage-private.h"
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#include "bsearch-insert-pos.h"
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#include "mailbox-attribute-internal.h"
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinastatic ARRAY(struct mailbox_attribute_internal) mailbox_internal_attributes;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinastatic pool_t mailbox_attribute_pool;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid mailbox_attributes_init(void)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina{
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina mailbox_attribute_pool =
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina pool_alloconly_create("mailbox attributes", 2048);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina i_array_init(&mailbox_internal_attributes, 32);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* internal mailbox attributes */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina mailbox_attributes_internal_init();
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina}
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid mailbox_attributes_deinit(void)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina{
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina pool_unref(&mailbox_attribute_pool);
e880949305cee3aca79441fe6113a9d79e7c98f2Jakub Hrozek array_free(&mailbox_internal_attributes);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina}
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac/*
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina * Internal attributes
769347ad4d35d43488eb98f980143495b0db415dStef Walter */
769347ad4d35d43488eb98f980143495b0db415dStef Walter
769347ad4d35d43488eb98f980143495b0db415dStef Walterstatic int
769347ad4d35d43488eb98f980143495b0db415dStef Waltermailbox_attribute_internal_cmp(
769347ad4d35d43488eb98f980143495b0db415dStef Walter const struct mailbox_attribute_internal *reg1,
769347ad4d35d43488eb98f980143495b0db415dStef Walter const struct mailbox_attribute_internal *reg2)
769347ad4d35d43488eb98f980143495b0db415dStef Walter{
769347ad4d35d43488eb98f980143495b0db415dStef Walter if (reg1->type != reg2->type)
769347ad4d35d43488eb98f980143495b0db415dStef Walter return (int)reg1->type - (int)reg2->type;
769347ad4d35d43488eb98f980143495b0db415dStef Walter return strcmp(reg1->key, reg2->key);
b76419cf8830440b46c20a15585562343c7b1924Jakub Hrozek}
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid mailbox_attribute_register_internal(
769347ad4d35d43488eb98f980143495b0db415dStef Walter const struct mailbox_attribute_internal *iattr)
769347ad4d35d43488eb98f980143495b0db415dStef Walter{
769347ad4d35d43488eb98f980143495b0db415dStef Walter struct mailbox_attribute_internal ireg;
769347ad4d35d43488eb98f980143495b0db415dStef Walter unsigned int insert_idx;
769347ad4d35d43488eb98f980143495b0db415dStef Walter
769347ad4d35d43488eb98f980143495b0db415dStef Walter (void)array_bsearch_insert_pos(&mailbox_internal_attributes,
769347ad4d35d43488eb98f980143495b0db415dStef Walter iattr, mailbox_attribute_internal_cmp, &insert_idx);
769347ad4d35d43488eb98f980143495b0db415dStef Walter
769347ad4d35d43488eb98f980143495b0db415dStef Walter ireg = *iattr;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina ireg.key = p_strdup(mailbox_attribute_pool, iattr->key);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina array_insert(&mailbox_internal_attributes, insert_idx, &ireg, 1);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina}
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid mailbox_attribute_register_internals(
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina const struct mailbox_attribute_internal *iattrs, unsigned int count)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina{
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina unsigned int i;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina for (i = 0; i < count; i++)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina mailbox_attribute_register_internal(&iattrs[i]);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinastatic const struct mailbox_attribute_internal *
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinamailbox_internal_attribute_get(enum mail_attribute_type type,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina const char *key)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina{
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina const struct mailbox_attribute_internal *iattr;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina struct mailbox_attribute_internal dreg;
65976ea5e9767bfaced81dfb97dc87d59f50b57eSimo Sorce unsigned int insert_idx;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina memset(&dreg, 0, sizeof(dreg));
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina dreg.type = type;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina dreg.key = key;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (array_bsearch_insert_pos(&mailbox_internal_attributes,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov &dreg, mailbox_attribute_internal_cmp,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina &insert_idx)) {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* exact match */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return array_idx(&mailbox_internal_attributes, insert_idx);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina if (insert_idx == 0) {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* not found at all */
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina return NULL;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina iattr = array_idx(&mailbox_internal_attributes, insert_idx-1);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina if (strncmp(iattr->key, key, strlen(iattr->key)) != 0) {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* iattr isn't a prefix of key */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return NULL;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina } else if ((iattr->flags & MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN) != 0) {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* iattr is a prefix of key and it wants to handle the key */
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina return iattr;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina } else {
8bccd95e275fae760a991da394235e4e70e57bbdMichal Zidek return NULL;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina}
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
07e941c1bbdc752142bbd3b838c540bc7ecd0ed7Stef Walterstatic void
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinamailbox_internal_attributes_get(enum mail_attribute_type type,
07e941c1bbdc752142bbd3b838c540bc7ecd0ed7Stef Walter const char *prefix, bool have_dict, ARRAY_TYPE(const_string) *attrs)
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina{
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina const struct mailbox_attribute_internal *regs;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov struct mailbox_attribute_internal dreg;
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina char *bare_prefix;
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina size_t plen;
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina unsigned int count, i;
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina bare_prefix = t_strdup_noconst(prefix);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov plen = strlen(bare_prefix);
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina if (plen > 0 && bare_prefix[plen-1] == '/') {
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březina bare_prefix[plen-1] = '\0';
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina plen--;
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina }
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac memset(&dreg, 0, sizeof(dreg));
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac dreg.type = type;
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac dreg.key = bare_prefix;
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac (void)array_bsearch_insert_pos(&mailbox_internal_attributes,
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac &dreg, mailbox_attribute_internal_cmp, &i);
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina regs = array_get(&mailbox_internal_attributes, &count);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina for (; i < count; i++) {
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac const char *key = regs[i].key;
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac if (regs[i].type != type)
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac return;
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac if (plen > 0) {
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac if (strncmp(key, bare_prefix, plen) != 0)
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac return;
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac if (key[plen] == '/') {
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac /* remove prefix */
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac key += plen + 1;
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac } else if (key[plen] == '\0') {
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac /* list the key itself, so this becomes an
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac empty key string. it's the same as how the
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac dict backend works too. */
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac key += plen;
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac } else {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return;
3bea01f01d76e1e95a8239c0d3f67073992136a1Jan Zeleny }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina if (have_dict || regs[i].rank == MAIL_ATTRIBUTE_INTERNAL_RANK_AUTHORITY)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina array_append(attrs, &key, 1);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina}
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březina/*
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina * Attribute API
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinastatic int
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinamailbox_attribute_set_common(struct mailbox_transaction_context *t,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina enum mail_attribute_type type, const char *key,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina const struct mail_attribute_value *value)
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina{
3bea01f01d76e1e95a8239c0d3f67073992136a1Jan Zeleny const struct mailbox_attribute_internal *iattr;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina int ret;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina iattr = mailbox_internal_attribute_get(type, key);
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* allow internal server attribute only for inbox */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (iattr != NULL && !t->box->inbox_any &&
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březina strncmp(key, MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER,
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina strlen(MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER)) == 0)
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina iattr = NULL;
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose /* handle internal attribute */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (iattr != NULL) {
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose switch (iattr->rank) {
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose case MAIL_ATTRIBUTE_INTERNAL_RANK_DEFAULT:
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose case MAIL_ATTRIBUTE_INTERNAL_RANK_OVERRIDE:
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* notify about assignment */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina if (iattr->set != NULL && iattr->set(t, key, value) < 0)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return -1;
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březina break;
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březina case MAIL_ATTRIBUTE_INTERNAL_RANK_AUTHORITY:
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina if (iattr->set == NULL) {
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březina mail_storage_set_error(t->box->storage, MAIL_ERROR_NOTPOSSIBLE, t_strdup_printf(
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina "The /%s/%s attribute cannot be changed",
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina (type == MAIL_ATTRIBUTE_TYPE_SHARED ? "shared" : "private"), key));
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return -1;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* assign internal attribute */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return iattr->set(t, key, value);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina default:
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina i_unreached();
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozek }
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozek }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* FIXME: v2.3 should move the internal_attribute to attribute_set()
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina parameter (as flag). not done yet for API backwards compatibility */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina t->internal_attribute = iattr != NULL &&
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozek iattr->rank != MAIL_ATTRIBUTE_INTERNAL_RANK_AUTHORITY;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina ret = t->box->v.attribute_set(t, type, key, value);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina t->internal_attribute = FALSE;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return ret;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina}
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinaint mailbox_attribute_set(struct mailbox_transaction_context *t,
458f5245dd5130d12666cce6faf8ef1ec7f80169Pavel Reichl enum mail_attribute_type type, const char *key,
458f5245dd5130d12666cce6faf8ef1ec7f80169Pavel Reichl const struct mail_attribute_value *value)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina{
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return mailbox_attribute_set_common(t, type, key, value);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina}
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinaint mailbox_attribute_unset(struct mailbox_transaction_context *t,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina enum mail_attribute_type type, const char *key)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina{
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina struct mail_attribute_value value;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina memset(&value, 0, sizeof(value));
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return mailbox_attribute_set_common(t, type, key, &value);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina}
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
9e2c64c6d4f5560e27207193efea6536a566865eMichal Zidekint mailbox_attribute_value_to_string(struct mail_storage *storage,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina const struct mail_attribute_value *value,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina const char **str_r)
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina{
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina string_t *str;
3f9e2c24dbc14b2eafbe4f5a5ee16fe9af3c3f75Jakub Hrozek const unsigned char *data;
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozek size_t size;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina if (value->value_stream == NULL) {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina *str_r = value->value;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return 0;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina str = t_str_new(128);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina i_stream_seek(value->value_stream, 0);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov while (i_stream_read_more(value->value_stream, &data, &size) > 0) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (memchr(data, '\0', size) != NULL) {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina mail_storage_set_error(storage, MAIL_ERROR_PARAMS,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina "Attribute string value has NULs");
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return -1;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina str_append_n(str, data, size);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina i_stream_skip(value->value_stream, size);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina if (value->value_stream->stream_errno != 0) {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina mail_storage_set_critical(storage, "read(%s) failed: %s",
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina i_stream_get_name(value->value_stream),
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina i_stream_get_error(value->value_stream));
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina return -1;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina }
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina i_assert(value->value_stream->eof);
*str_r = str_c(str);
return 0;
}
static int
mailbox_attribute_get_common(struct mailbox_transaction_context *t,
enum mail_attribute_type type, const char *key,
struct mail_attribute_value *value_r)
{
const struct mailbox_attribute_internal *iattr;
int ret;
iattr = mailbox_internal_attribute_get(type, key);
/* allow internal server attributes only for the inbox */
if (iattr != NULL && !t->box->inbox_user &&
strncmp(key, MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER,
strlen(MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER)) == 0)
iattr = NULL;
/* internal attribute */
if (iattr != NULL) {
switch (iattr->rank) {
case MAIL_ATTRIBUTE_INTERNAL_RANK_OVERRIDE:
if ((ret = iattr->get(t, key, value_r)) != 0) {
if (ret < 0)
return -1;
value_r->flags |= MAIL_ATTRIBUTE_VALUE_FLAG_READONLY;
return 1;
}
case MAIL_ATTRIBUTE_INTERNAL_RANK_DEFAULT:
break;
case MAIL_ATTRIBUTE_INTERNAL_RANK_AUTHORITY:
if ((ret = iattr->get(t, key, value_r)) <= 0)
return ret;
value_r->flags |= MAIL_ATTRIBUTE_VALUE_FLAG_READONLY;
return 1;
default:
i_unreached();
}
}
/* user entries - FIXME: v2.3 should move the internal_attribute to
attribute_get() parameter (as flag). not done yet for API backwards
compatibility */
t->internal_attribute = iattr != NULL &&
iattr->rank != MAIL_ATTRIBUTE_INTERNAL_RANK_AUTHORITY;
ret = t->box->v.attribute_get(t, type, key, value_r);
t->internal_attribute = FALSE;
if (ret != 0)
return ret;
/* default entries */
if (iattr != NULL) {
switch (iattr->rank) {
case MAIL_ATTRIBUTE_INTERNAL_RANK_DEFAULT:
if (iattr->get == NULL)
ret = 0;
else {
if ((ret = iattr->get(t, key, value_r)) < 0)
return ret;
}
if (ret > 0) {
value_r->flags |= MAIL_ATTRIBUTE_VALUE_FLAG_READONLY;
return 1;
}
case MAIL_ATTRIBUTE_INTERNAL_RANK_OVERRIDE:
break;
default:
i_unreached();
}
}
return 0;
}
int mailbox_attribute_get(struct mailbox_transaction_context *t,
enum mail_attribute_type type, const char *key,
struct mail_attribute_value *value_r)
{
int ret;
memset(value_r, 0, sizeof(*value_r));
if ((ret = mailbox_attribute_get_common(t, type, key, value_r)) <= 0)
return ret;
i_assert(value_r->value != NULL);
return 1;
}
int mailbox_attribute_get_stream(struct mailbox_transaction_context *t,
enum mail_attribute_type type, const char *key,
struct mail_attribute_value *value_r)
{
int ret;
memset(value_r, 0, sizeof(*value_r));
value_r->flags |= MAIL_ATTRIBUTE_VALUE_FLAG_INT_STREAMS;
if ((ret = mailbox_attribute_get_common(t, type, key, value_r)) <= 0)
return ret;
i_assert(value_r->value != NULL || value_r->value_stream != NULL);
return 1;
}
struct mailbox_attribute_internal_iter {
struct mailbox_attribute_iter iter;
ARRAY_TYPE(const_string) extra_attrs;
unsigned int extra_attr_idx;
struct mailbox_attribute_iter *real_iter;
};
struct mailbox_attribute_iter *
mailbox_attribute_iter_init(struct mailbox *box,
enum mail_attribute_type type, const char *prefix)
{
struct mailbox_attribute_internal_iter *intiter;
struct mailbox_attribute_iter *iter;
ARRAY_TYPE(const_string) extra_attrs;
const char *const *attr;
bool have_dict;
iter = box->v.attribute_iter_init(box, type, prefix);
i_assert(iter->box != NULL);
/* 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, prefix, have_dict, &extra_attrs);
/* any extra internal attributes to add? */
if (array_count(&extra_attrs) == 0) {
/* no */
return iter;
}
/* yes */
intiter = i_new(struct mailbox_attribute_internal_iter, 1);
intiter->real_iter = iter;
i_array_init(&intiter->extra_attrs, 4);
/* copy relevant attributes */
array_foreach(&extra_attrs, attr) {
/* skip internal server attributes unless we're interating inbox */
if (!box->inbox_any &&
strncmp(*attr, MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER,
strlen(MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER)) == 0)
continue;
array_append(&intiter->extra_attrs, attr, 1);
}
return &intiter->iter;
}
const char *mailbox_attribute_iter_next(struct mailbox_attribute_iter *iter)
{
struct mailbox_attribute_internal_iter *intiter;
const char *const *attrs;
unsigned int count, i;
const char *result;
if (iter->box != NULL) {
/* no internal attributes to add */
return iter->box->v.attribute_iter_next(iter);
}
/* filter out duplicate results */
intiter = (struct mailbox_attribute_internal_iter *)iter;
attrs = array_get(&intiter->extra_attrs, &count);
while ((result = intiter->real_iter->box->
v.attribute_iter_next(intiter->real_iter)) != NULL) {
for (i = 0; i < count; i++) {
if (strcasecmp(attrs[i], result) == 0)
break;
}
if (i == count) {
/* return normally */
return result;
}
/* this attribute name is also to be returned as extra;
skip now */
}
/* return extra attributes at the end */
if (intiter->extra_attr_idx < count)
return attrs[intiter->extra_attr_idx++];
return NULL;
}
int mailbox_attribute_iter_deinit(struct mailbox_attribute_iter **_iter)
{
struct mailbox_attribute_iter *iter = *_iter;
struct mailbox_attribute_internal_iter *intiter;
int ret;
*_iter = NULL;
if (iter->box != NULL) {
/* not wrapped */
return iter->box->v.attribute_iter_deinit(iter);
}
/* wrapped */
intiter = (struct mailbox_attribute_internal_iter *)iter;
ret = intiter->real_iter->box->v.attribute_iter_deinit(intiter->real_iter);
array_free(&intiter->extra_attrs);
i_free(intiter);
return ret;
}