/* Copyright (c) 2018 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "str.h" #include "istream.h" #include "array.h" #include "var-expand.h" #include "dlua-script.h" #include "dlua-script-private.h" #include "mail-storage.h" #include "mailbox-attribute.h" #include "mail-storage-lua.h" #include "mail-storage-lua-private.h" #include "mail-user.h" /* lookup mailbox attribute */ int lua_storage_mailbox_attribute_get(struct mailbox *box, const char *key, const char **value_r, size_t *value_len_r, const char **error_r) { struct mail_attribute_value value; enum mail_attribute_type attr_type; int ret; if (str_begins(key, "/private/")) { attr_type = MAIL_ATTRIBUTE_TYPE_PRIVATE; key += 9; } else if (str_begins(key, "/shared/")) { attr_type = MAIL_ATTRIBUTE_TYPE_SHARED; key += 8; } else { *error_r = "Invalid key prefix, must be /private/ or /shared/"; return -1; } /* get the attribute */ if ((ret = mailbox_attribute_get_stream(box, attr_type, key, &value)) < 0) { *error_r = mailbox_get_last_error(box, NULL); return ret; } else if (ret == 0) { /* was not found */ *value_r = NULL; *value_len_r = 0; return 0; } if (value.value_stream != NULL) { string_t *str = t_str_new(128); const unsigned char *data; size_t siz; while((ret = i_stream_read_more(value.value_stream, &data, &siz))>0) { str_append_data(str, data, siz); i_stream_skip(value.value_stream, siz); } i_assert(ret != 0); if (ret == -1 && !value.value_stream->eof) { /* we could not read the stream */ *error_r = i_stream_get_error(value.value_stream); ret = -1; } else { *value_r = str->data; *value_len_r = str->used; ret = 1; } i_stream_unref(&value.value_stream); return ret; } *value_r = value.value; if (value.value != NULL) *value_len_r = strlen(value.value); else *value_len_r = 0; return 1; } int lua_storage_mailbox_attribute_set(struct mailbox *box, const char *key, const char *value, size_t value_len, const char **error_r) { struct mail_attribute_value attr_value; enum mail_attribute_type attr_type; int ret; i_assert(value != NULL || value_len == 0); if (str_begins(key, "/private/")) { attr_type = MAIL_ATTRIBUTE_TYPE_PRIVATE; key += 9; } else if (str_begins(key, "/shared/")) { attr_type = MAIL_ATTRIBUTE_TYPE_SHARED; key += 8; } else { *error_r = "Invalid key prefix, must be /private/ or /shared/"; return -1; } struct mailbox_transaction_context *t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_NO_NOTIFY, __func__); i_zero(&attr_value); if (value != NULL) { /* use stream API to allow NULs in data */ attr_value.value_stream = i_stream_create_from_data(value, value_len); } ret = mailbox_attribute_set(t, attr_type, key, &attr_value); if (ret < 0) { *error_r = mailbox_get_last_error(box, NULL); mailbox_transaction_rollback(&t); } else if ((ret = mailbox_transaction_commit(&t)) < 0) { *error_r = mailbox_get_last_error(box, NULL); } if (attr_value.value_stream != NULL) i_stream_unref(&attr_value.value_stream); return ret; } int lua_storage_mailbox_attribute_list(struct mailbox *box, const char *prefix, ARRAY_TYPE(lua_storage_keyvalue) *items_r, const char **error_r) { const char *key, *orig_prefix = prefix; enum mail_attribute_type attr_type; int ret; if (str_begins(prefix, "/private/")) { attr_type = MAIL_ATTRIBUTE_TYPE_PRIVATE; prefix += 9; } else if (str_begins(prefix, "/shared/")) { attr_type = MAIL_ATTRIBUTE_TYPE_SHARED; prefix += 8; } else { *error_r = "Invalid key prefix, must be /private/ or /shared/"; return -1; } struct mailbox_attribute_iter *iter = mailbox_attribute_iter_init(box, attr_type, prefix); ret = 0; *error_r = NULL; while((key = mailbox_attribute_iter_next(iter)) != NULL) { struct lua_storage_keyvalue *item = array_append_space(items_r); item->key = t_strdup_printf("%s%s", orig_prefix, key); if (lua_storage_mailbox_attribute_get(box, item->key, &item->value, &item->value_len, error_r) < 0) { ret = -1; break; } } if (mailbox_attribute_iter_deinit(&iter) < 0 || ret == -1) { if (*error_r == NULL) *error_r = mailbox_get_last_error(box, NULL); return -1; } return 0; }