bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen#include "lib.h"
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen#include "imap-arg.h"
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen#include "mail-storage-private.h"
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenstatic struct mail_keywords *
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenmailbox_keywords_create_skip(struct mailbox *box,
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen const char *const keywords[])
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen{
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen struct mail_keywords *kw;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen T_BEGIN {
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(const char *) valid_keywords;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen const char *error;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen t_array_init(&valid_keywords, 32);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen for (; *keywords != NULL; keywords++) {
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen if (mailbox_keyword_is_valid(box, *keywords, &error))
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen array_append(&valid_keywords, keywords, 1);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen }
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&valid_keywords); /* NULL-terminate */
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen kw = mail_index_keywords_create(box->index, keywords);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen } T_END;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return kw;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen}
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenstatic bool
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenmailbox_keywords_are_valid(struct mailbox *box, const char *const keywords[],
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen const char **error_r)
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen{
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen unsigned int i;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen for (i = 0; keywords[i] != NULL; i++) {
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen if (!mailbox_keyword_is_valid(box, keywords[i], error_r))
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return FALSE;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen }
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return TRUE;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen}
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenint mailbox_keywords_create(struct mailbox *box, const char *const keywords[],
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen struct mail_keywords **keywords_r)
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen{
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen const char *error, *empty_keyword_list = NULL;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen i_assert(box->opened);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen if (keywords == NULL)
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen keywords = &empty_keyword_list;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen if (!mailbox_keywords_are_valid(box, keywords, &error)) {
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, error);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return -1;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen }
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen *keywords_r = mail_index_keywords_create(box->index, keywords);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return 0;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen}
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenstruct mail_keywords *
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenmailbox_keywords_create_valid(struct mailbox *box,
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen const char *const keywords[])
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen{
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen const char *empty_keyword_list = NULL;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen const char *error;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen i_assert(box->opened);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen if (keywords == NULL)
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen keywords = &empty_keyword_list;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen if (mailbox_keywords_are_valid(box, keywords, &error))
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return mail_index_keywords_create(box->index, keywords);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen else {
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen /* found invalid keywords, do this the slow way */
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return mailbox_keywords_create_skip(box, keywords);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen }
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen}
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenstruct mail_keywords *
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenmailbox_keywords_create_from_indexes(struct mailbox *box,
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen const ARRAY_TYPE(keyword_indexes) *idx)
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen{
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen i_assert(box->opened);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return mail_index_keywords_create_from_indexes(box->index, idx);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen}
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenvoid mailbox_keywords_ref(struct mail_keywords *keywords)
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen{
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen mail_index_keywords_ref(keywords);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen}
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenvoid mailbox_keywords_unref(struct mail_keywords **keywords)
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen{
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen mail_index_keywords_unref(keywords);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen}
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainenbool mailbox_keyword_is_valid(struct mailbox *box, const char *keyword,
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen const char **error_r)
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen{
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen unsigned int i, idx;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen i_assert(box->opened);
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen /* if it already exists, skip validity checks */
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen if (mail_index_keyword_lookup(box->index, keyword, &idx))
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return TRUE;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen if (*keyword == '\0') {
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen *error_r = "Empty keywords not allowed";
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return FALSE;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen }
9a3da808c280163e69cc38639bf4931d0f83f7e3Timo Sirainen if (box->disallow_new_keywords) {
9a3da808c280163e69cc38639bf4931d0f83f7e3Timo Sirainen *error_r = "Can't create new keywords";
9a3da808c280163e69cc38639bf4931d0f83f7e3Timo Sirainen return FALSE;
9a3da808c280163e69cc38639bf4931d0f83f7e3Timo Sirainen }
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen /* these are IMAP-specific restrictions, but for now IMAP is all we
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen care about */
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen for (i = 0; keyword[i] != '\0'; i++) {
73592a4e11ebdc306a9fd030bff879318c84270aTimo Sirainen if (!IS_ATOM_CHAR(keyword[i])) {
73592a4e11ebdc306a9fd030bff879318c84270aTimo Sirainen if ((unsigned char)keyword[i] < 0x80)
73592a4e11ebdc306a9fd030bff879318c84270aTimo Sirainen *error_r = "Invalid characters in keyword";
73592a4e11ebdc306a9fd030bff879318c84270aTimo Sirainen else
73592a4e11ebdc306a9fd030bff879318c84270aTimo Sirainen *error_r = "8bit characters in keyword";
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return FALSE;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen }
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen }
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen if (i > box->storage->set->mail_max_keyword_length) {
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen *error_r = "Keyword length too long";
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return FALSE;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen }
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen return TRUE;
8871c97974dd4e682c7b8d5cff0bbc5b024f56f2Timo Sirainen}