summaryrefslogtreecommitdiffstats
path: root/src/lib-storage/mailbox-keywords.c
blob: 78e85291e0b7d4d5b0e0ff20b45bc72b95a3cd1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "imap-arg.h"
#include "mail-storage-private.h"

static struct mail_keywords *
mailbox_keywords_create_skip(struct mailbox *box,
			     const char *const keywords[])
{
	struct mail_keywords *kw;

	T_BEGIN {
		ARRAY(const char *) valid_keywords;
		const char *error;

		t_array_init(&valid_keywords, 32);
		for (; *keywords != NULL; keywords++) {
			if (mailbox_keyword_is_valid(box, *keywords, &error))
				array_push_back(&valid_keywords, keywords);
		}
		array_append_zero(&valid_keywords); /* NULL-terminate */
		kw = mail_index_keywords_create(box->index, keywords);
	} T_END;
	return kw;
}

static bool
mailbox_keywords_are_valid(struct mailbox *box, const char *const keywords[],
			   const char **error_r)
{
	unsigned int i;

	for (i = 0; keywords[i] != NULL; i++) {
		if (!mailbox_keyword_is_valid(box, keywords[i], error_r))
			return FALSE;
	}
	return TRUE;
}

int mailbox_keywords_create(struct mailbox *box, const char *const keywords[],
			    struct mail_keywords **keywords_r)
{
	const char *error, *empty_keyword_list = NULL;

	i_assert(box->opened);

	if (keywords == NULL)
		keywords = &empty_keyword_list;
	if (!mailbox_keywords_are_valid(box, keywords, &error)) {
		mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, error);
		return -1;
	}

	*keywords_r = mail_index_keywords_create(box->index, keywords);
	return 0;
}

struct mail_keywords *
mailbox_keywords_create_valid(struct mailbox *box,
			      const char *const keywords[])
{
	const char *empty_keyword_list = NULL;
	const char *error;

	i_assert(box->opened);

	if (keywords == NULL)
		keywords = &empty_keyword_list;
	if (mailbox_keywords_are_valid(box, keywords, &error))
		return mail_index_keywords_create(box->index, keywords);
	else {
		/* found invalid keywords, do this the slow way */
		return mailbox_keywords_create_skip(box, keywords);
	}
}

struct mail_keywords *
mailbox_keywords_create_from_indexes(struct mailbox *box,
				     const ARRAY_TYPE(keyword_indexes) *idx)
{
	i_assert(box->opened);

	return mail_index_keywords_create_from_indexes(box->index, idx);
}

struct mail_keywords *mailbox_keywords_merge(struct mail_keywords *keywords1,
					     struct mail_keywords *keywords2)
{
	ARRAY_TYPE(keyword_indexes) keywords_merged;

	i_assert(keywords1->index == keywords2->index);

	t_array_init(&keywords_merged, keywords1->count + keywords2->count);
	/* duplicates are dropped by mail_index_keywords_create() */
	array_append(&keywords_merged, keywords1->idx, keywords1->count);
	array_append(&keywords_merged, keywords2->idx, keywords2->count);
	return mail_index_keywords_create_from_indexes(keywords1->index,
						       &keywords_merged);
}

void mailbox_keywords_ref(struct mail_keywords *keywords)
{
	mail_index_keywords_ref(keywords);
}

void mailbox_keywords_unref(struct mail_keywords **keywords)
{
	mail_index_keywords_unref(keywords);
}

bool mailbox_keyword_is_valid(struct mailbox *box, const char *keyword,
			      const char **error_r)
{
	unsigned int i, idx;

	i_assert(box->opened);

	/* if it already exists, skip validity checks */
	if (mail_index_keyword_lookup(box->index, keyword, &idx))
		return TRUE;

	if (*keyword == '\0') {
		*error_r = "Empty keywords not allowed";
		return FALSE;
	}
	if (box->disallow_new_keywords) {
		*error_r = "Can't create new keywords";
		return FALSE;
	}

	/* these are IMAP-specific restrictions, but for now IMAP is all we
	   care about */
	for (i = 0; keyword[i] != '\0'; i++) {
		if (!IS_ATOM_CHAR(keyword[i])) {
			if ((unsigned char)keyword[i] < 0x80)
				*error_r = "Invalid characters in keyword";
			else
				*error_r = "8bit characters in keyword";
			return FALSE;
		}
	}
	if (i > box->storage->set->mail_max_keyword_length) {
		*error_r = "Keyword length too long";
		return FALSE;
	}
	return TRUE;
}