/src/pigeonhole/src/lib-sieve/sieve-stringlist.c
Line | Count | Source |
1 | | /* Copyright (c) Pigeonhole authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "array.h" |
5 | | #include "str.h" |
6 | | |
7 | | #include "sieve-common.h" |
8 | | #include "sieve-stringlist.h" |
9 | | |
10 | | /* |
11 | | * Default implementation |
12 | | */ |
13 | | |
14 | | int sieve_stringlist_read_all(struct sieve_stringlist *strlist, pool_t pool, |
15 | | const char *const **list_r) |
16 | 0 | { |
17 | 0 | if (strlist->read_all == NULL) { |
18 | 0 | ARRAY(const char *) items; |
19 | 0 | string_t *item; |
20 | 0 | int ret; |
21 | |
|
22 | 0 | sieve_stringlist_reset(strlist); |
23 | |
|
24 | 0 | p_array_init(&items, pool, 4); |
25 | |
|
26 | 0 | item = NULL; |
27 | 0 | while ((ret = sieve_stringlist_next_item(strlist, &item)) > 0) { |
28 | 0 | const char *stritem = p_strdup(pool, str_c(item)); |
29 | |
|
30 | 0 | array_append(&items, &stritem, 1); |
31 | 0 | } |
32 | |
|
33 | 0 | (void)array_append_space(&items); |
34 | 0 | *list_r = array_idx(&items, 0); |
35 | |
|
36 | 0 | return (ret < 0 ? -1 : 1); |
37 | 0 | } |
38 | | |
39 | 0 | return strlist->read_all(strlist, pool, list_r); |
40 | 0 | } |
41 | | |
42 | | int sieve_stringlist_get_length(struct sieve_stringlist *strlist) |
43 | 0 | { |
44 | 0 | if (strlist->get_length == NULL) { |
45 | 0 | string_t *item; |
46 | 0 | int count = 0; |
47 | 0 | int ret; |
48 | |
|
49 | 0 | sieve_stringlist_reset(strlist); |
50 | 0 | while ((ret = sieve_stringlist_next_item(strlist, &item)) > 0) |
51 | 0 | count++; |
52 | |
|
53 | 0 | sieve_stringlist_reset(strlist); |
54 | |
|
55 | 0 | return (ret < 0 ? -1 : count); |
56 | 0 | } |
57 | | |
58 | 0 | return strlist->get_length(strlist); |
59 | 0 | } |
60 | | |
61 | | /* |
62 | | * Single Stringlist |
63 | | */ |
64 | | |
65 | | /* Object */ |
66 | | |
67 | | static int |
68 | | sieve_single_stringlist_next_item(struct sieve_stringlist *_strlist, |
69 | | string_t **str_r); |
70 | | static void sieve_single_stringlist_reset(struct sieve_stringlist *_strlist); |
71 | | static int |
72 | | sieve_single_stringlist_get_length(struct sieve_stringlist *_strlist); |
73 | | |
74 | | struct sieve_single_stringlist { |
75 | | struct sieve_stringlist strlist; |
76 | | |
77 | | string_t *value; |
78 | | |
79 | | bool end:1; |
80 | | bool count_empty:1; |
81 | | }; |
82 | | |
83 | | struct sieve_stringlist * |
84 | | sieve_single_stringlist_create(const struct sieve_runtime_env *renv, |
85 | | string_t *str, bool count_empty) |
86 | 0 | { |
87 | 0 | struct sieve_single_stringlist *strlist; |
88 | |
|
89 | 0 | strlist = t_new(struct sieve_single_stringlist, 1); |
90 | 0 | strlist->strlist.runenv = renv; |
91 | 0 | strlist->strlist.exec_status = SIEVE_EXEC_OK; |
92 | 0 | strlist->strlist.next_item = sieve_single_stringlist_next_item; |
93 | 0 | strlist->strlist.reset = sieve_single_stringlist_reset; |
94 | 0 | strlist->strlist.get_length = sieve_single_stringlist_get_length; |
95 | 0 | strlist->count_empty = count_empty; |
96 | 0 | strlist->value = str; |
97 | |
|
98 | 0 | return &strlist->strlist; |
99 | 0 | } |
100 | | |
101 | | struct sieve_stringlist * |
102 | | sieve_single_stringlist_create_cstr(const struct sieve_runtime_env *renv, |
103 | | const char *cstr, bool count_empty) |
104 | 0 | { |
105 | 0 | string_t *str = t_str_new_const(cstr, strlen(cstr)); |
106 | |
|
107 | 0 | return sieve_single_stringlist_create(renv, str, count_empty); |
108 | 0 | } |
109 | | |
110 | | /* Implementation */ |
111 | | |
112 | | static int |
113 | | sieve_single_stringlist_next_item(struct sieve_stringlist *_strlist, |
114 | | string_t **str_r) |
115 | 0 | { |
116 | 0 | struct sieve_single_stringlist *strlist = |
117 | 0 | (struct sieve_single_stringlist *)_strlist; |
118 | |
|
119 | 0 | if (strlist->end) { |
120 | 0 | *str_r = NULL; |
121 | 0 | return 0; |
122 | 0 | } |
123 | | |
124 | 0 | *str_r = strlist->value; |
125 | 0 | strlist->end = TRUE; |
126 | 0 | return 1; |
127 | 0 | } |
128 | | |
129 | | static void sieve_single_stringlist_reset(struct sieve_stringlist *_strlist) |
130 | 0 | { |
131 | 0 | struct sieve_single_stringlist *strlist = |
132 | 0 | (struct sieve_single_stringlist *)_strlist; |
133 | |
|
134 | 0 | strlist->end = FALSE; |
135 | 0 | } |
136 | | |
137 | | static int sieve_single_stringlist_get_length(struct sieve_stringlist *_strlist) |
138 | 0 | { |
139 | 0 | struct sieve_single_stringlist *strlist = |
140 | 0 | (struct sieve_single_stringlist *)_strlist; |
141 | |
|
142 | 0 | return (strlist->count_empty || str_len(strlist->value) > 0 ? 1 : 0); |
143 | 0 | } |
144 | | |
145 | | /* |
146 | | * Index Stringlist |
147 | | */ |
148 | | |
149 | | /* Object */ |
150 | | |
151 | | static int |
152 | | sieve_index_stringlist_next_item(struct sieve_stringlist *_strlist, |
153 | | string_t **str_r); |
154 | | static void sieve_index_stringlist_reset(struct sieve_stringlist *_strlist); |
155 | | static int sieve_index_stringlist_get_length(struct sieve_stringlist *_strlist); |
156 | | static void |
157 | | sieve_index_stringlist_set_trace(struct sieve_stringlist *strlist, bool trace); |
158 | | |
159 | | struct sieve_index_stringlist { |
160 | | struct sieve_stringlist strlist; |
161 | | |
162 | | struct sieve_stringlist *source; |
163 | | |
164 | | int index; |
165 | | bool end:1; |
166 | | }; |
167 | | |
168 | | struct sieve_stringlist * |
169 | | sieve_index_stringlist_create(const struct sieve_runtime_env *renv, |
170 | | struct sieve_stringlist *source, int index) |
171 | 0 | { |
172 | 0 | struct sieve_index_stringlist *strlist; |
173 | |
|
174 | 0 | strlist = t_new(struct sieve_index_stringlist, 1); |
175 | 0 | strlist->strlist.runenv = renv; |
176 | 0 | strlist->strlist.exec_status = SIEVE_EXEC_OK; |
177 | 0 | strlist->strlist.next_item = sieve_index_stringlist_next_item; |
178 | 0 | strlist->strlist.reset = sieve_index_stringlist_reset; |
179 | 0 | strlist->strlist.get_length = sieve_index_stringlist_get_length; |
180 | 0 | strlist->strlist.set_trace = sieve_index_stringlist_set_trace; |
181 | 0 | strlist->source = source; |
182 | 0 | strlist->index = index; |
183 | |
|
184 | 0 | return &strlist->strlist; |
185 | 0 | } |
186 | | |
187 | | /* Implementation */ |
188 | | |
189 | | static int |
190 | | sieve_index_stringlist_next_item(struct sieve_stringlist *_strlist, |
191 | | string_t **str_r) |
192 | 0 | { |
193 | 0 | struct sieve_index_stringlist *strlist = |
194 | 0 | (struct sieve_index_stringlist *)_strlist; |
195 | 0 | int index, ret; |
196 | |
|
197 | 0 | if (strlist->end) { |
198 | 0 | *str_r = NULL; |
199 | 0 | return 0; |
200 | 0 | } |
201 | | |
202 | 0 | if (strlist->index < 0) { |
203 | 0 | int len = sieve_stringlist_get_length(strlist->source); |
204 | |
|
205 | 0 | if (len < 0) { |
206 | 0 | _strlist->exec_status = strlist->source->exec_status; |
207 | 0 | return -1; |
208 | 0 | } |
209 | | |
210 | 0 | if (len < -strlist->index) { |
211 | 0 | *str_r = NULL; |
212 | 0 | strlist->end = TRUE; |
213 | 0 | return 0; |
214 | 0 | } |
215 | 0 | index = len + 1 + strlist->index; |
216 | 0 | } else { |
217 | 0 | index = strlist->index; |
218 | 0 | } |
219 | | |
220 | 0 | i_assert(index > 0); |
221 | 0 | while (index > 0) { |
222 | 0 | ret = sieve_stringlist_next_item(strlist->source, str_r); |
223 | 0 | if (ret <= 0) { |
224 | 0 | if (ret < 0) { |
225 | 0 | _strlist->exec_status = |
226 | 0 | strlist->source->exec_status; |
227 | 0 | } |
228 | 0 | return ret; |
229 | 0 | } |
230 | | |
231 | 0 | index--; |
232 | 0 | } |
233 | | |
234 | 0 | strlist->end = TRUE; |
235 | 0 | return 1; |
236 | 0 | } |
237 | | |
238 | | static void sieve_index_stringlist_reset(struct sieve_stringlist *_strlist) |
239 | 0 | { |
240 | 0 | struct sieve_index_stringlist *strlist = |
241 | 0 | (struct sieve_index_stringlist *)_strlist; |
242 | |
|
243 | 0 | sieve_stringlist_reset(strlist->source); |
244 | 0 | strlist->end = FALSE; |
245 | 0 | } |
246 | | |
247 | | static int sieve_index_stringlist_get_length(struct sieve_stringlist *_strlist) |
248 | 0 | { |
249 | 0 | struct sieve_index_stringlist *strlist = |
250 | 0 | (struct sieve_index_stringlist *)_strlist; |
251 | 0 | int len; |
252 | |
|
253 | 0 | len = sieve_stringlist_get_length(strlist->source); |
254 | 0 | if (len < 0) { |
255 | 0 | _strlist->exec_status = strlist->source->exec_status; |
256 | 0 | return -1; |
257 | 0 | } |
258 | | |
259 | 0 | if (strlist->index < 0) { |
260 | 0 | if (-strlist->index >= len) |
261 | 0 | return 0; |
262 | 0 | } else if (strlist->index >= len) { |
263 | 0 | return 0; |
264 | 0 | } |
265 | | |
266 | 0 | return 1; |
267 | 0 | } |
268 | | |
269 | | static void |
270 | | sieve_index_stringlist_set_trace(struct sieve_stringlist *_strlist, bool trace) |
271 | 0 | { |
272 | 0 | struct sieve_index_stringlist *strlist = |
273 | 0 | (struct sieve_index_stringlist *)_strlist; |
274 | |
|
275 | 0 | sieve_stringlist_set_trace(strlist->source, trace); |
276 | 0 | } |