1 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "imap-arg.h"
5 #include "mail-storage-private.h"
6
7 static struct mail_keywords *
mailbox_keywords_create_skip(struct mailbox * box,const char * const keywords[])8 mailbox_keywords_create_skip(struct mailbox *box,
9 const char *const keywords[])
10 {
11 struct mail_keywords *kw;
12
13 T_BEGIN {
14 ARRAY(const char *) valid_keywords;
15 const char *error;
16
17 t_array_init(&valid_keywords, 32);
18 for (; *keywords != NULL; keywords++) {
19 if (mailbox_keyword_is_valid(box, *keywords, &error))
20 array_push_back(&valid_keywords, keywords);
21 }
22 array_append_zero(&valid_keywords); /* NULL-terminate */
23 kw = mail_index_keywords_create(box->index, keywords);
24 } T_END;
25 return kw;
26 }
27
28 static bool
mailbox_keywords_are_valid(struct mailbox * box,const char * const keywords[],const char ** error_r)29 mailbox_keywords_are_valid(struct mailbox *box, const char *const keywords[],
30 const char **error_r)
31 {
32 unsigned int i;
33
34 for (i = 0; keywords[i] != NULL; i++) {
35 if (!mailbox_keyword_is_valid(box, keywords[i], error_r))
36 return FALSE;
37 }
38 return TRUE;
39 }
40
mailbox_keywords_create(struct mailbox * box,const char * const keywords[],struct mail_keywords ** keywords_r)41 int mailbox_keywords_create(struct mailbox *box, const char *const keywords[],
42 struct mail_keywords **keywords_r)
43 {
44 const char *error, *empty_keyword_list = NULL;
45
46 i_assert(box->opened);
47
48 if (keywords == NULL)
49 keywords = &empty_keyword_list;
50 if (!mailbox_keywords_are_valid(box, keywords, &error)) {
51 mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, error);
52 return -1;
53 }
54
55 *keywords_r = mail_index_keywords_create(box->index, keywords);
56 return 0;
57 }
58
59 struct mail_keywords *
mailbox_keywords_create_valid(struct mailbox * box,const char * const keywords[])60 mailbox_keywords_create_valid(struct mailbox *box,
61 const char *const keywords[])
62 {
63 const char *empty_keyword_list = NULL;
64 const char *error;
65
66 i_assert(box->opened);
67
68 if (keywords == NULL)
69 keywords = &empty_keyword_list;
70 if (mailbox_keywords_are_valid(box, keywords, &error))
71 return mail_index_keywords_create(box->index, keywords);
72 else {
73 /* found invalid keywords, do this the slow way */
74 return mailbox_keywords_create_skip(box, keywords);
75 }
76 }
77
78 struct mail_keywords *
mailbox_keywords_create_from_indexes(struct mailbox * box,const ARRAY_TYPE (keyword_indexes)* idx)79 mailbox_keywords_create_from_indexes(struct mailbox *box,
80 const ARRAY_TYPE(keyword_indexes) *idx)
81 {
82 i_assert(box->opened);
83
84 return mail_index_keywords_create_from_indexes(box->index, idx);
85 }
86
mailbox_keywords_merge(struct mail_keywords * keywords1,struct mail_keywords * keywords2)87 struct mail_keywords *mailbox_keywords_merge(struct mail_keywords *keywords1,
88 struct mail_keywords *keywords2)
89 {
90 ARRAY_TYPE(keyword_indexes) keywords_merged;
91
92 i_assert(keywords1->index == keywords2->index);
93
94 t_array_init(&keywords_merged, keywords1->count + keywords2->count);
95 /* duplicates are dropped by mail_index_keywords_create() */
96 array_append(&keywords_merged, keywords1->idx, keywords1->count);
97 array_append(&keywords_merged, keywords2->idx, keywords2->count);
98 return mail_index_keywords_create_from_indexes(keywords1->index,
99 &keywords_merged);
100 }
101
mailbox_keywords_ref(struct mail_keywords * keywords)102 void mailbox_keywords_ref(struct mail_keywords *keywords)
103 {
104 mail_index_keywords_ref(keywords);
105 }
106
mailbox_keywords_unref(struct mail_keywords ** keywords)107 void mailbox_keywords_unref(struct mail_keywords **keywords)
108 {
109 mail_index_keywords_unref(keywords);
110 }
111
mailbox_keyword_is_valid(struct mailbox * box,const char * keyword,const char ** error_r)112 bool mailbox_keyword_is_valid(struct mailbox *box, const char *keyword,
113 const char **error_r)
114 {
115 unsigned int i, idx;
116
117 i_assert(box->opened);
118
119 /* if it already exists, skip validity checks */
120 if (mail_index_keyword_lookup(box->index, keyword, &idx))
121 return TRUE;
122
123 if (*keyword == '\0') {
124 *error_r = "Empty keywords not allowed";
125 return FALSE;
126 }
127 if (box->disallow_new_keywords) {
128 *error_r = "Can't create new keywords";
129 return FALSE;
130 }
131
132 /* these are IMAP-specific restrictions, but for now IMAP is all we
133 care about */
134 for (i = 0; keyword[i] != '\0'; i++) {
135 if (!IS_ATOM_CHAR(keyword[i])) {
136 if ((unsigned char)keyword[i] < 0x80)
137 *error_r = "Invalid characters in keyword";
138 else
139 *error_r = "8bit characters in keyword";
140 return FALSE;
141 }
142 }
143 if (i > box->storage->set->mail_max_keyword_length) {
144 *error_r = "Keyword length too long";
145 return FALSE;
146 }
147 return TRUE;
148 }
149