~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to src/lib-storage/mail-search-args-imap.c

  • Committer: Package Import Robot
  • Author(s): Jelmer Vernooij
  • Date: 2015-05-24 15:01:19 UTC
  • mto: (4.1.53 sid)
  • mto: This revision was merged to the branch mainline in revision 102.
  • Revision ID: package-import@ubuntu.com-20150524150119-hsh6cbr1fqseapga
Tags: upstream-2.2.18
ImportĀ upstreamĀ versionĀ 2.2.18

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "lib.h"
 
4
#include "ioloop.h"
 
5
#include "array.h"
 
6
#include "str.h"
 
7
#include "utc-offset.h"
 
8
#include "mail-index.h"
 
9
#include "imap-date.h"
 
10
#include "imap-util.h"
 
11
#include "imap-quote.h"
 
12
#include "mail-search.h"
 
13
 
 
14
#include <time.h>
 
15
 
 
16
static bool
 
17
mail_search_subargs_to_imap(string_t *dest, const struct mail_search_arg *args,
 
18
                            const char *prefix, const char **error_r)
 
19
{
 
20
        const struct mail_search_arg *arg;
 
21
 
 
22
        str_append_c(dest, '(');
 
23
        for (arg = args; arg != NULL; arg = arg->next) {
 
24
                if (arg->next != NULL)
 
25
                        str_append(dest, prefix);
 
26
                if (!mail_search_arg_to_imap(dest, arg, error_r))
 
27
                        return FALSE;
 
28
                if (arg->next != NULL)
 
29
                        str_append_c(dest, ' ');
 
30
        }
 
31
        str_append_c(dest, ')');
 
32
        return TRUE;
 
33
}
 
34
 
 
35
static bool
 
36
mail_search_arg_to_imap_date(string_t *dest, const struct mail_search_arg *arg)
 
37
{
 
38
        time_t timestamp = arg->value.time;
 
39
        const char *str;
 
40
 
 
41
        if ((arg->value.search_flags &
 
42
             MAIL_SEARCH_ARG_FLAG_USE_TZ) == 0) {
 
43
                struct tm *tm = localtime(&timestamp);
 
44
                int tz_offset = utc_offset(tm, timestamp);
 
45
                timestamp -= tz_offset * 60;
 
46
        }
 
47
        if (!imap_to_date(timestamp, &str))
 
48
                return FALSE;
 
49
        str_printfa(dest, " \"%s\"", str);
 
50
        return TRUE;
 
51
}
 
52
 
 
53
bool mail_search_arg_to_imap(string_t *dest, const struct mail_search_arg *arg,
 
54
                             const char **error_r)
 
55
{
 
56
        unsigned int start_pos;
 
57
 
 
58
        if (arg->match_not)
 
59
                str_append(dest, "NOT ");
 
60
        start_pos = str_len(dest);
 
61
        switch (arg->type) {
 
62
        case SEARCH_OR:
 
63
                if (!mail_search_subargs_to_imap(dest, arg->value.subargs,
 
64
                                                 "OR ", error_r))
 
65
                        return FALSE;
 
66
                break;
 
67
        case SEARCH_SUB:
 
68
                if (!mail_search_subargs_to_imap(dest, arg->value.subargs,
 
69
                                                 "", error_r))
 
70
                        return FALSE;
 
71
                break;
 
72
        case SEARCH_ALL:
 
73
                str_append(dest, "ALL");
 
74
                break;
 
75
        case SEARCH_SEQSET:
 
76
                imap_write_seq_range(dest, &arg->value.seqset);
 
77
                break;
 
78
        case SEARCH_UIDSET:
 
79
                str_append(dest, "UID ");
 
80
                imap_write_seq_range(dest, &arg->value.seqset);
 
81
                break;
 
82
        case SEARCH_FLAGS:
 
83
                i_assert((arg->value.flags & MAIL_FLAGS_MASK) != 0);
 
84
                str_append_c(dest, '(');
 
85
                if ((arg->value.flags & MAIL_ANSWERED) != 0)
 
86
                        str_append(dest, "ANSWERED ");
 
87
                if ((arg->value.flags & MAIL_FLAGGED) != 0)
 
88
                        str_append(dest, "FLAGGED ");
 
89
                if ((arg->value.flags & MAIL_DELETED) != 0)
 
90
                        str_append(dest, "DELETED ");
 
91
                if ((arg->value.flags & MAIL_SEEN) != 0)
 
92
                        str_append(dest, "SEEN ");
 
93
                if ((arg->value.flags & MAIL_DRAFT) != 0)
 
94
                        str_append(dest, "DRAFT ");
 
95
                if ((arg->value.flags & MAIL_RECENT) != 0)
 
96
                        str_append(dest, "RECENT ");
 
97
                str_truncate(dest, str_len(dest)-1);
 
98
                str_append_c(dest, ')');
 
99
                break;
 
100
        case SEARCH_KEYWORDS: {
 
101
                const struct mail_keywords *kw = arg->value.keywords;
 
102
                const ARRAY_TYPE(keywords) *names_arr;
 
103
                const char *const *namep;
 
104
                unsigned int i;
 
105
 
 
106
                if (kw == NULL) {
 
107
                        /* uninitialized */
 
108
                        str_printfa(dest, "KEYWORD %s", arg->value.str);
 
109
                        break;
 
110
                }
 
111
 
 
112
                names_arr = mail_index_get_keywords(kw->index);
 
113
 
 
114
                str_append_c(dest, '(');
 
115
                for (i = 0; i < kw->count; i++) {
 
116
                        namep = array_idx(names_arr, kw->idx[i]);
 
117
                        if (i > 0)
 
118
                                str_append_c(dest, ' ');
 
119
                        str_printfa(dest, "KEYWORD %s", *namep);
 
120
                }
 
121
                str_append_c(dest, ')');
 
122
                break;
 
123
        }
 
124
 
 
125
        case SEARCH_BEFORE:
 
126
                switch (arg->value.date_type) {
 
127
                case MAIL_SEARCH_DATE_TYPE_SENT:
 
128
                        str_append(dest, "SENTBEFORE");
 
129
                        break;
 
130
                case MAIL_SEARCH_DATE_TYPE_RECEIVED:
 
131
                        str_append(dest, "BEFORE");
 
132
                        break;
 
133
                case MAIL_SEARCH_DATE_TYPE_SAVED:
 
134
                        str_append(dest, "X-SAVEDBEFORE");
 
135
                        break;
 
136
                }
 
137
                if (mail_search_arg_to_imap_date(dest, arg))
 
138
                        ;
 
139
                else if (arg->value.date_type != MAIL_SEARCH_DATE_TYPE_RECEIVED ||
 
140
                         arg->value.time > ioloop_time) {
 
141
                        *error_r = t_strdup_printf(
 
142
                                "SEARCH_BEFORE can't be written as IMAP for timestamp %ld (type=%d, use_tz=%d)",
 
143
                                (long)arg->value.time, arg->value.date_type,
 
144
                                (arg->value.search_flags & MAIL_SEARCH_ARG_FLAG_USE_TZ) != 0);
 
145
                        return FALSE;
 
146
                } else {
 
147
                        str_truncate(dest, start_pos);
 
148
                        str_printfa(dest, "OLDER %u",
 
149
                                    (unsigned int)(ioloop_time - arg->value.time + 1));
 
150
                }
 
151
                break;
 
152
        case SEARCH_ON:
 
153
                switch (arg->value.date_type) {
 
154
                case MAIL_SEARCH_DATE_TYPE_SENT:
 
155
                        str_append(dest, "SENTON");
 
156
                        break;
 
157
                case MAIL_SEARCH_DATE_TYPE_RECEIVED:
 
158
                        str_append(dest, "ON");
 
159
                        break;
 
160
                case MAIL_SEARCH_DATE_TYPE_SAVED:
 
161
                        str_append(dest, "X-SAVEDON");
 
162
                        break;
 
163
                }
 
164
                if (!mail_search_arg_to_imap_date(dest, arg)) {
 
165
                        *error_r = t_strdup_printf(
 
166
                                "SEARCH_ON can't be written as IMAP for timestamp %ld (type=%d, use_tz=%d)",
 
167
                                (long)arg->value.time, arg->value.date_type,
 
168
                                (arg->value.search_flags & MAIL_SEARCH_ARG_FLAG_USE_TZ) != 0);
 
169
                        return FALSE;
 
170
                }
 
171
                break;
 
172
        case SEARCH_SINCE:
 
173
                switch (arg->value.date_type) {
 
174
                case MAIL_SEARCH_DATE_TYPE_SENT:
 
175
                        str_append(dest, "SENTSINCE");
 
176
                        break;
 
177
                case MAIL_SEARCH_DATE_TYPE_RECEIVED:
 
178
                        str_append(dest, "SINCE");
 
179
                        break;
 
180
                case MAIL_SEARCH_DATE_TYPE_SAVED:
 
181
                        str_append(dest, "X-SAVEDSINCE");
 
182
                        break;
 
183
                }
 
184
                if (mail_search_arg_to_imap_date(dest, arg))
 
185
                        ;
 
186
                else if (arg->value.date_type != MAIL_SEARCH_DATE_TYPE_RECEIVED ||
 
187
                         arg->value.time >= ioloop_time) {
 
188
                        *error_r = t_strdup_printf(
 
189
                                "SEARCH_SINCE can't be written as IMAP for timestamp %ld (type=%d, use_tz=%d)",
 
190
                                (long)arg->value.time, arg->value.date_type,
 
191
                                (arg->value.search_flags & MAIL_SEARCH_ARG_FLAG_USE_TZ) != 0);
 
192
                        return FALSE;
 
193
                } else {
 
194
                        str_truncate(dest, start_pos);
 
195
                        str_printfa(dest, "YOUNGER %u",
 
196
                                    (unsigned int)(ioloop_time - arg->value.time));
 
197
                }
 
198
                break;
 
199
        case SEARCH_SMALLER:
 
200
                str_printfa(dest, "SMALLER %llu", (unsigned long long)arg->value.size);
 
201
                break;
 
202
        case SEARCH_LARGER:
 
203
                str_printfa(dest, "LARGER %llu", (unsigned long long)arg->value.size);
 
204
                break;
 
205
        case SEARCH_HEADER:
 
206
        case SEARCH_HEADER_ADDRESS:
 
207
        case SEARCH_HEADER_COMPRESS_LWSP:
 
208
                if (strcasecmp(arg->hdr_field_name, "From") == 0 ||
 
209
                    strcasecmp(arg->hdr_field_name, "To") == 0 ||
 
210
                    strcasecmp(arg->hdr_field_name, "Cc") == 0 ||
 
211
                    strcasecmp(arg->hdr_field_name, "Bcc") == 0 ||
 
212
                    strcasecmp(arg->hdr_field_name, "Subject") == 0)
 
213
                        str_append(dest, t_str_ucase(arg->hdr_field_name));
 
214
                else {
 
215
                        str_append(dest, "HEADER ");
 
216
                        imap_append_astring(dest, arg->hdr_field_name);
 
217
                }
 
218
                str_append_c(dest, ' ');
 
219
                imap_append_astring(dest, arg->value.str);
 
220
                break;
 
221
 
 
222
        case SEARCH_BODY:
 
223
                str_append(dest, "BODY ");
 
224
                imap_append_astring(dest, arg->value.str);
 
225
                break;
 
226
        case SEARCH_TEXT:
 
227
                str_append(dest, "TEXT ");
 
228
                imap_append_astring(dest, arg->value.str);
 
229
                break;
 
230
 
 
231
        /* extensions */
 
232
        case SEARCH_MODSEQ: {
 
233
                bool extended_output = FALSE;
 
234
 
 
235
                str_append(dest, "MODSEQ ");
 
236
                if (arg->value.str != NULL) {
 
237
                        str_printfa(dest, "/flags/%s", arg->value.str);
 
238
                        extended_output = TRUE;
 
239
                } else if (arg->value.flags != 0) {
 
240
                        str_append(dest, "/flags/");
 
241
                        imap_write_flags(dest, arg->value.flags, NULL);
 
242
                        extended_output = TRUE;
 
243
                }
 
244
                if (extended_output) {
 
245
                        str_append_c(dest, ' ');
 
246
                        switch (arg->value.modseq->type) {
 
247
                        case MAIL_SEARCH_MODSEQ_TYPE_ANY:
 
248
                                str_append(dest, "all");
 
249
                                break;
 
250
                        case MAIL_SEARCH_MODSEQ_TYPE_PRIVATE:
 
251
                                str_append(dest, "priv");
 
252
                                break;
 
253
                        case MAIL_SEARCH_MODSEQ_TYPE_SHARED:
 
254
                                str_append(dest, "shared");
 
255
                                break;
 
256
                        }
 
257
                        str_append_c(dest, ' ');
 
258
                }
 
259
                str_printfa(dest, "%llu", (unsigned long long)arg->value.modseq->modseq);
 
260
                break;
 
261
        }
 
262
        case SEARCH_INTHREAD:
 
263
                str_append(dest, "INTHREAD ");
 
264
                imap_append_astring(dest, mail_thread_type_to_str(arg->value.thread_type));
 
265
                str_append_c(dest, ' ');
 
266
                if (!mail_search_subargs_to_imap(dest, arg->value.subargs,
 
267
                                                 "", error_r))
 
268
                        return FALSE;
 
269
                break;
 
270
        case SEARCH_GUID:
 
271
                str_append(dest, "X-GUID ");
 
272
                imap_append_astring(dest, arg->value.str);
 
273
                break;
 
274
        case SEARCH_MAILBOX:
 
275
                *error_r = "SEARCH_MAILBOX can't be written as IMAP";
 
276
                return FALSE;
 
277
        case SEARCH_MAILBOX_GUID:
 
278
                *error_r = "SEARCH_MAILBOX_GUID can't be written as IMAP";
 
279
                return FALSE;
 
280
        case SEARCH_MAILBOX_GLOB:
 
281
                str_append(dest, "X-MAILBOX ");
 
282
                imap_append_astring(dest, arg->value.str);
 
283
                break;
 
284
        case SEARCH_REAL_UID:
 
285
                str_append(dest, "X-REAL-UID ");
 
286
                imap_write_seq_range(dest, &arg->value.seqset);
 
287
                break;
 
288
        }
 
289
        return TRUE;
 
290
}
 
291
 
 
292
bool mail_search_args_to_imap(string_t *dest, const struct mail_search_arg *args,
 
293
                              const char **error_r)
 
294
{
 
295
        const struct mail_search_arg *arg;
 
296
 
 
297
        for (arg = args; arg != NULL; arg = arg->next) {
 
298
                if (!mail_search_arg_to_imap(dest, arg, error_r))
 
299
                        return FALSE;
 
300
                if (arg->next != NULL)
 
301
                        str_append_c(dest, ' ');
 
302
        }
 
303
        return TRUE;
 
304
}