~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/imap/imap-fetch.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "imap-common.h"
4
4
#include "array.h"
6
6
#include "istream.h"
7
7
#include "ostream.h"
8
8
#include "str.h"
9
 
#include "message-send.h"
10
9
#include "message-size.h"
11
10
#include "imap-date.h"
12
11
#include "imap-utf7.h"
24
23
#define ENVELOPE_NIL_REPLY \
25
24
        "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)"
26
25
 
27
 
static ARRAY_DEFINE(fetch_handlers, struct imap_fetch_handler);
 
26
static ARRAY(struct imap_fetch_handler) fetch_handlers;
28
27
 
29
28
static int imap_fetch_handler_cmp(const struct imap_fetch_handler *h1,
30
29
                                  const struct imap_fetch_handler *h2)
45
44
        return strcmp(name, h->name);
46
45
}
47
46
 
48
 
bool imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name,
49
 
                             const struct imap_arg **args)
 
47
bool imap_fetch_init_handler(struct imap_fetch_init_context *init_ctx)
50
48
{
51
49
        const struct imap_fetch_handler *handler;
52
50
        const char *lookup_name, *p;
53
51
 
54
 
        for (p = name; i_isalnum(*p) || *p == '-'; p++) ;
55
 
        lookup_name = t_strdup_until(name, p);
 
52
        for (p = init_ctx->name; i_isalnum(*p) || *p == '-'; p++) ;
 
53
        lookup_name = t_strdup_until(init_ctx->name, p);
56
54
 
57
55
        handler = array_bsearch(&fetch_handlers, lookup_name,
58
56
                                imap_fetch_handler_bsearch);
59
57
        if (handler == NULL) {
60
 
                client_send_command_error(ctx->cmd,
61
 
                        t_strconcat("Unknown parameter ", name, NULL));
62
 
                return FALSE;
63
 
        }
64
 
 
65
 
        return handler->init(ctx, name, args);
 
58
                init_ctx->error = t_strdup_printf("Unknown parameter: %s",
 
59
                                                  init_ctx->name);
 
60
                return FALSE;
 
61
        }
 
62
        if (!handler->init(init_ctx)) {
 
63
                i_assert(init_ctx->error != NULL);
 
64
                return FALSE;
 
65
        }
 
66
        return TRUE;
 
67
}
 
68
 
 
69
void imap_fetch_init_nofail_handler(struct imap_fetch_context *ctx,
 
70
                                    bool (*init)(struct imap_fetch_init_context *))
 
71
{
 
72
        struct imap_fetch_init_context init_ctx;
 
73
 
 
74
        memset(&init_ctx, 0, sizeof(init_ctx));
 
75
        init_ctx.fetch_ctx = ctx;
 
76
        init_ctx.pool = ctx->ctx_pool;
 
77
 
 
78
        if (!init(&init_ctx))
 
79
                i_unreached();
 
80
}
 
81
 
 
82
int imap_fetch_att_list_parse(struct client *client, pool_t pool,
 
83
                              const struct imap_arg *list,
 
84
                              struct imap_fetch_context **fetch_ctx_r,
 
85
                              const char **error_r)
 
86
{
 
87
        struct imap_fetch_init_context init_ctx;
 
88
        const char *str;
 
89
 
 
90
        memset(&init_ctx, 0, sizeof(init_ctx));
 
91
        init_ctx.fetch_ctx = imap_fetch_alloc(client, pool);
 
92
        init_ctx.pool = pool;
 
93
        init_ctx.args = list;
 
94
 
 
95
        while (imap_arg_get_atom(init_ctx.args, &str)) {
 
96
                init_ctx.name = t_str_ucase(str);
 
97
                init_ctx.args++;
 
98
                if (!imap_fetch_init_handler(&init_ctx)) {
 
99
                        *error_r = t_strconcat("Invalid fetch-att list: ",
 
100
                                               init_ctx.error, NULL);
 
101
                        imap_fetch_free(&init_ctx.fetch_ctx);
 
102
                        return -1;
 
103
                }
 
104
        }
 
105
        if (!IMAP_ARG_IS_EOL(init_ctx.args)) {
 
106
                *error_r = "fetch-att list contains non-atoms.";
 
107
                imap_fetch_free(&init_ctx.fetch_ctx);
 
108
                return -1;
 
109
        }
 
110
        *fetch_ctx_r = init_ctx.fetch_ctx;
 
111
        return 0;
66
112
}
67
113
 
68
114
struct imap_fetch_context *
69
 
imap_fetch_init(struct client_command_context *cmd, struct mailbox *box)
 
115
imap_fetch_alloc(struct client *client, pool_t pool)
70
116
{
71
 
        struct client *client = cmd->client;
72
117
        struct imap_fetch_context *ctx;
73
118
 
74
 
        ctx = p_new(cmd->pool, struct imap_fetch_context, 1);
 
119
        ctx = p_new(pool, struct imap_fetch_context, 1);
75
120
        ctx->client = client;
76
 
        ctx->cmd = cmd;
77
 
        ctx->box = box;
 
121
        ctx->ctx_pool = pool;
 
122
        pool_ref(pool);
78
123
 
79
 
        ctx->cur_str = str_new(default_pool, 8192);
80
 
        p_array_init(&ctx->all_headers, cmd->pool, 64);
81
 
        p_array_init(&ctx->handlers, cmd->pool, 16);
82
 
        p_array_init(&ctx->tmp_keywords, cmd->pool,
 
124
        p_array_init(&ctx->all_headers, pool, 64);
 
125
        p_array_init(&ctx->handlers, pool, 16);
 
126
        p_array_init(&ctx->tmp_keywords, pool,
83
127
                     client->keywords.announce_count + 8);
84
 
        ctx->line_finished = TRUE;
85
128
        return ctx;
86
129
}
87
130
 
88
 
bool imap_fetch_add_changed_since(struct imap_fetch_context *ctx,
89
 
                                  uint64_t modseq)
90
 
{
91
 
        struct mail_search_arg *search_arg;
92
 
 
93
 
        search_arg = p_new(ctx->search_args->pool, struct mail_search_arg, 1);
94
 
        search_arg->type = SEARCH_MODSEQ;
95
 
        search_arg->value.modseq =
96
 
                p_new(ctx->cmd->pool, struct mail_search_modseq, 1);
97
 
        search_arg->value.modseq->modseq = modseq + 1;
98
 
 
99
 
        search_arg->next = ctx->search_args->args->next;
100
 
        ctx->search_args->args->next = search_arg;
101
 
 
102
 
        return imap_fetch_init_handler(ctx, "MODSEQ", NULL);
103
 
}
104
 
 
105
131
#undef imap_fetch_add_handler
106
 
void imap_fetch_add_handler(struct imap_fetch_context *ctx,
107
 
                            bool buffered, bool want_deinit,
108
 
                            const char *name, const char *nil_reply,
 
132
void imap_fetch_add_handler(struct imap_fetch_init_context *ctx,
 
133
                            enum imap_fetch_handler_flags flags,
 
134
                            const char *nil_reply,
109
135
                            imap_fetch_handler_t *handler, void *context)
110
136
{
111
137
        /* partially because of broken clients, but also partially because
112
138
           it potentially can make client implementations faster, we have a
113
139
           buffered parameter which basically means that the handler promises
114
 
           to write the output in ctx->cur_str. The cur_str is then sent to
115
 
           client before calling any non-buffered handlers.
 
140
           to write the output in fetch_ctx->state.cur_str. The cur_str is then
 
141
           sent to client before calling any non-buffered handlers.
116
142
 
117
143
           We try to keep the handler registration order the same as the
118
144
           client requested them. This is especially useful to get UID
123
149
 
124
150
        if (context == NULL) {
125
151
                /* don't allow duplicate handlers */
126
 
                array_foreach(&ctx->handlers, ctx_handler) {
 
152
                array_foreach(&ctx->fetch_ctx->handlers, ctx_handler) {
127
153
                        if (ctx_handler->handler == handler &&
128
154
                            ctx_handler->context == NULL)
129
155
                                return;
133
159
        memset(&h, 0, sizeof(h));
134
160
        h.handler = handler;
135
161
        h.context = context;
136
 
        h.buffered = buffered;
137
 
        h.want_deinit = want_deinit;
138
 
        h.name = p_strdup(ctx->cmd->pool, name);
139
 
        h.nil_reply = p_strdup(ctx->cmd->pool, nil_reply);
 
162
        h.buffered = (flags & IMAP_FETCH_HANDLER_FLAG_BUFFERED) != 0;
 
163
        h.want_deinit = (flags & IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT) != 0;
 
164
        h.name = p_strdup(ctx->pool, ctx->name);
 
165
        h.nil_reply = p_strdup(ctx->pool, nil_reply);
140
166
 
141
 
        if (!buffered)
142
 
                array_append(&ctx->handlers, &h, 1);
 
167
        if (!h.buffered)
 
168
                array_append(&ctx->fetch_ctx->handlers, &h, 1);
143
169
        else {
144
 
                array_insert(&ctx->handlers, ctx->buffered_handlers_count,
145
 
                             &h, 1);
146
 
                ctx->buffered_handlers_count++;
 
170
                array_insert(&ctx->fetch_ctx->handlers,
 
171
                             ctx->fetch_ctx->buffered_handlers_count, &h, 1);
 
172
                ctx->fetch_ctx->buffered_handlers_count++;
147
173
        }
148
174
}
149
175
 
150
176
static void
151
 
expunges_drop_known(struct imap_fetch_context *ctx,
 
177
expunges_drop_known(struct mailbox *box,
 
178
                    const struct imap_fetch_qresync_args *qresync_args,
152
179
                    struct mailbox_transaction_context *trans,
153
180
                    ARRAY_TYPE(seq_range) *expunged_uids)
154
181
{
157
184
        const uint32_t *seqs, *uids;
158
185
        unsigned int i, count;
159
186
 
160
 
        seqs = array_get(ctx->qresync_sample_seqset, &count);
161
 
        uids = array_idx(ctx->qresync_sample_uidset, 0);
162
 
        i_assert(array_count(ctx->qresync_sample_uidset) == count);
 
187
        seqs = array_get(qresync_args->qresync_sample_seqset, &count);
 
188
        uids = array_idx(qresync_args->qresync_sample_uidset, 0);
 
189
        i_assert(array_count(qresync_args->qresync_sample_uidset) == count);
163
190
        i_assert(count > 0);
164
191
 
165
 
        mailbox_get_open_status(ctx->box, STATUS_MESSAGES, &status);
 
192
        mailbox_get_open_status(box, STATUS_MESSAGES, &status);
166
193
        mail = mail_alloc(trans, 0, NULL);
167
194
 
168
195
        /* FIXME: we could do removals from the middle as well */
176
203
        mail_free(&mail);
177
204
}
178
205
 
179
 
static int get_expunges_fallback(struct imap_fetch_context *ctx,
180
 
                                 const ARRAY_TYPE(seq_range) *uid_filter_arr,
181
 
                                 ARRAY_TYPE(seq_range) *expunged_uids)
 
206
static int
 
207
get_expunges_fallback(struct mailbox *box,
 
208
                      const struct imap_fetch_qresync_args *qresync_args,
 
209
                      const ARRAY_TYPE(seq_range) *uid_filter_arr,
 
210
                      ARRAY_TYPE(seq_range) *expunged_uids)
182
211
{
183
212
        struct mailbox_transaction_context *trans;
184
213
        struct mail_search_args *search_args;
202
231
        i_array_init(&search_args->args->value.seqset, count);
203
232
        array_append_array(&search_args->args->value.seqset, uid_filter_arr);
204
233
 
205
 
        trans = mailbox_transaction_begin(ctx->box, 0);
 
234
        trans = mailbox_transaction_begin(box, 0);
206
235
        search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
207
236
        mail_search_args_unref(&search_args);
208
237
 
249
278
                                          uid_filter[i].seq2);
250
279
        }
251
280
 
252
 
        mailbox_get_open_status(ctx->box, STATUS_UIDNEXT, &status);
 
281
        mailbox_get_open_status(box, STATUS_UIDNEXT, &status);
253
282
        seq_range_array_remove_range(expunged_uids, status.uidnext,
254
283
                                     (uint32_t)-1);
255
284
 
256
285
        if (mailbox_search_deinit(&search_ctx) < 0)
257
286
                ret = -1;
258
287
 
259
 
        if (ret == 0 && ctx->qresync_sample_seqset != NULL &&
260
 
            array_is_created(ctx->qresync_sample_seqset))
261
 
                expunges_drop_known(ctx, trans, expunged_uids);
 
288
        if (ret == 0 && qresync_args->qresync_sample_seqset != NULL &&
 
289
            array_is_created(qresync_args->qresync_sample_seqset))
 
290
                expunges_drop_known(box, qresync_args, trans, expunged_uids);
262
291
 
263
292
        (void)mailbox_transaction_commit(&trans);
264
293
        return ret;
265
294
}
266
295
 
267
 
static int
268
 
imap_fetch_send_vanished(struct imap_fetch_context *ctx)
 
296
int imap_fetch_send_vanished(struct client *client, struct mailbox *box,
 
297
                             const struct mail_search_args *search_args,
 
298
                             const struct imap_fetch_qresync_args *qresync_args)
269
299
{
270
 
        const struct mail_search_arg *uidarg = ctx->search_args->args;
 
300
        const struct mail_search_arg *uidarg = search_args->args;
271
301
        const struct mail_search_arg *modseqarg = uidarg->next;
272
 
        const ARRAY_TYPE(seq_range) *uid_filter = &uidarg->value.seqset;
273
 
        uint64_t modseq = modseqarg->value.modseq->modseq - 1;
 
302
        const ARRAY_TYPE(seq_range) *uid_filter;
 
303
        uint64_t modseq;
274
304
        ARRAY_TYPE(seq_range) expunged_uids_range;
275
305
        string_t *str;
276
306
        int ret = 0;
277
307
 
 
308
        i_assert(uidarg->type == SEARCH_UIDSET);
 
309
        i_assert(modseqarg->type == SEARCH_MODSEQ);
 
310
 
 
311
        uid_filter = &uidarg->value.seqset;
 
312
        modseq = modseqarg->value.modseq->modseq - 1;
 
313
 
278
314
        i_array_init(&expunged_uids_range, array_count(uid_filter));
279
 
        if (!mailbox_get_expunged_uids(ctx->box, modseq, uid_filter, &expunged_uids_range)) {
 
315
        if (!mailbox_get_expunged_uids(box, modseq, uid_filter, &expunged_uids_range)) {
280
316
                /* return all expunged UIDs */
281
 
                if (get_expunges_fallback(ctx, uid_filter,
 
317
                if (get_expunges_fallback(box, qresync_args, uid_filter,
282
318
                                          &expunged_uids_range) < 0) {
283
319
                        array_clear(&expunged_uids_range);
284
320
                        ret = -1;
289
325
                str_append(str, "* VANISHED (EARLIER) ");
290
326
                imap_write_seq_range(str, &expunged_uids_range);
291
327
                str_append(str, "\r\n");
292
 
                o_stream_send(ctx->client->output, str_data(str), str_len(str));
 
328
                o_stream_nsend(client->output, str_data(str), str_len(str));
293
329
                str_free(&str);
294
330
        }
295
331
        array_free(&expunged_uids_range);
296
332
        return ret;
297
333
}
298
334
 
299
 
int imap_fetch_begin(struct imap_fetch_context *ctx)
300
 
{
301
 
        const void *data;
302
 
 
303
 
        if (ctx->send_vanished) {
304
 
                if (imap_fetch_send_vanished(ctx) < 0) {
305
 
                        ctx->failed = TRUE;
306
 
                        return -1;
307
 
                }
308
 
        }
309
 
 
310
 
        if (ctx->flags_update_seen) {
311
 
                if (mailbox_is_readonly(ctx->box))
312
 
                        ctx->flags_update_seen = FALSE;
313
 
                else if (!ctx->flags_have_handler) {
314
 
                        ctx->flags_show_only_seen_changes = TRUE;
315
 
                        (void)imap_fetch_init_handler(ctx, "FLAGS", NULL);
316
 
                }
317
 
        }
 
335
static void imap_fetch_init(struct imap_fetch_context *ctx)
 
336
{
 
337
        if (ctx->initialized)
 
338
                return;
 
339
        ctx->initialized = TRUE;
 
340
 
 
341
        if (ctx->flags_update_seen && !ctx->flags_have_handler) {
 
342
                ctx->flags_show_only_seen_changes = TRUE;
 
343
                imap_fetch_init_nofail_handler(ctx, imap_fetch_flags_init);
 
344
        }
 
345
        if ((ctx->fetch_data &
 
346
             (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
 
347
                ctx->fetch_data |= MAIL_FETCH_NUL_STATE;
 
348
}
 
349
 
 
350
void imap_fetch_begin(struct imap_fetch_context *ctx, struct mailbox *box,
 
351
                      struct mail_search_args *search_args)
 
352
{
 
353
        struct mailbox_header_lookup_ctx *wanted_headers = NULL;
 
354
        const char *const *headers;
 
355
 
 
356
        i_assert(!ctx->state.fetching);
 
357
 
 
358
        imap_fetch_init(ctx);
 
359
        memset(&ctx->state, 0, sizeof(ctx->state));
318
360
 
319
361
        if (array_count(&ctx->all_headers) > 0 &&
320
362
            ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
321
363
                                 MAIL_FETCH_STREAM_BODY)) == 0)) {
322
 
                (void)array_append_space(&ctx->all_headers);
 
364
                array_append_zero(&ctx->all_headers);
323
365
 
324
 
                data = array_idx(&ctx->all_headers, 0);
325
 
                ctx->all_headers_ctx =
326
 
                        mailbox_header_lookup_init(ctx->box, data);
 
366
                headers = array_idx(&ctx->all_headers, 0);
 
367
                wanted_headers = mailbox_header_lookup_init(box, headers);
 
368
                array_delete(&ctx->all_headers,
 
369
                             array_count(&ctx->all_headers)-1, 1);
327
370
        }
328
371
 
329
 
        if ((ctx->fetch_data &
330
 
             (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
331
 
                ctx->fetch_data |= MAIL_FETCH_NUL_STATE;
332
 
 
333
 
        ctx->trans = mailbox_transaction_begin(ctx->box,
 
372
        ctx->state.trans = mailbox_transaction_begin(box,
334
373
                MAILBOX_TRANSACTION_FLAG_HIDE |
335
374
                MAILBOX_TRANSACTION_FLAG_REFRESH);
336
 
        ctx->select_counter = ctx->client->select_counter;
337
 
 
338
 
        /* Delayed uidset -> seqset conversion. VANISHED needs the uidset. */
339
 
        mail_search_args_init(ctx->search_args, ctx->box, TRUE,
340
 
                              &ctx->cmd->client->search_saved_uidset);
341
 
        ctx->search_ctx =
342
 
                mailbox_search_init(ctx->trans, ctx->search_args, NULL,
343
 
                                    ctx->fetch_data, ctx->all_headers_ctx);
344
 
        return 0;
 
375
 
 
376
        mail_search_args_init(search_args, box, TRUE,
 
377
                              &ctx->client->search_saved_uidset);
 
378
        ctx->state.search_ctx =
 
379
                mailbox_search_init(ctx->state.trans, search_args, NULL,
 
380
                                    ctx->fetch_data, wanted_headers);
 
381
        ctx->state.cur_str = str_new(default_pool, 8192);
 
382
        ctx->state.fetching = TRUE;
 
383
        ctx->state.line_finished = TRUE;
 
384
 
 
385
        if (wanted_headers != NULL)
 
386
                mailbox_header_lookup_unref(&wanted_headers);
345
387
}
346
388
 
347
389
static int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
349
391
        const unsigned char *data;
350
392
        size_t len;
351
393
 
352
 
        data = str_data(ctx->cur_str);
353
 
        len = str_len(ctx->cur_str);
 
394
        data = str_data(ctx->state.cur_str);
 
395
        len = str_len(ctx->state.cur_str);
354
396
 
355
397
        if (len == 0)
356
398
                return 0;
359
401
           to buffer */
360
402
        if (data[len-1] == ' ') {
361
403
                len--;
362
 
                ctx->first = FALSE;
 
404
                ctx->state.cur_first = FALSE;
363
405
        }
364
406
 
365
407
        if (o_stream_send(ctx->client->output, data, len) < 0)
366
408
                return -1;
367
409
 
368
 
        str_truncate(ctx->cur_str, 0);
 
410
        str_truncate(ctx->state.cur_str, 0);
369
411
        return 0;
370
412
}
371
413
 
373
415
{
374
416
        const struct imap_fetch_context_handler *handler;
375
417
 
376
 
        if (!ctx->first)
377
 
                str_append_c(ctx->cur_str, ' ');
 
418
        if (!ctx->state.cur_first)
 
419
                str_append_c(ctx->state.cur_str, ' ');
378
420
 
379
 
        handler = array_idx(&ctx->handlers, ctx->cur_handler);
380
 
        str_printfa(ctx->cur_str, "%s %s ",
 
421
        handler = array_idx(&ctx->handlers, ctx->state.cur_handler);
 
422
        str_printfa(ctx->state.cur_str, "%s %s ",
381
423
                    handler->name, handler->nil_reply);
382
424
 
383
425
        if (!handler->buffered) {
387
429
        return 0;
388
430
}
389
431
 
390
 
static int imap_fetch_more_int(struct imap_fetch_context *ctx)
 
432
static int imap_fetch_more_int(struct imap_fetch_context *ctx, bool cancel)
391
433
{
 
434
        struct imap_fetch_state *state = &ctx->state;
392
435
        struct client *client = ctx->client;
393
436
        const struct imap_fetch_context_handler *handlers;
394
437
        unsigned int count;
395
438
        int ret;
396
439
 
397
 
        if (ctx->cont_handler != NULL) {
398
 
                ret = ctx->cont_handler(ctx);
 
440
        if (state->cont_handler != NULL) {
 
441
                ret = state->cont_handler(ctx);
399
442
                if (ret == 0)
400
443
                        return 0;
401
444
 
403
446
                        if (client->output->closed)
404
447
                                return -1;
405
448
 
406
 
                        if (ctx->cur_mail->expunged) {
 
449
                        if (state->cur_mail->expunged) {
407
450
                                /* not an error, just lost it. */
408
 
                                ctx->partial_fetch = TRUE;
 
451
                                state->skipped_expunged_msgs = TRUE;
409
452
                                if (imap_fetch_send_nil_reply(ctx) < 0)
410
453
                                        return -1;
411
454
                        } else {
413
456
                        }
414
457
                }
415
458
 
416
 
                ctx->cont_handler = NULL;
417
 
                ctx->cur_offset = 0;
418
 
                ctx->cur_handler++;
419
 
                if (ctx->cur_input != NULL)
420
 
                        i_stream_unref(&ctx->cur_input);
 
459
                state->cont_handler = NULL;
 
460
                state->cur_offset = 0;
 
461
                state->cur_handler++;
 
462
                if (state->cur_input != NULL)
 
463
                        i_stream_unref(&state->cur_input);
421
464
        }
422
465
 
423
466
        handlers = array_get(&ctx->handlers, &count);
429
472
                                return ret;
430
473
                }
431
474
 
432
 
                if (ctx->cur_mail == NULL) {
433
 
                        if (ctx->cmd->cancel)
 
475
                if (state->cur_mail == NULL) {
 
476
                        if (cancel)
434
477
                                return 1;
435
478
 
436
 
                        if (!mailbox_search_next(ctx->search_ctx,
437
 
                                                 &ctx->cur_mail))
 
479
                        if (!mailbox_search_next(state->search_ctx,
 
480
                                                 &state->cur_mail))
438
481
                                break;
439
482
 
440
 
                        str_printfa(ctx->cur_str, "* %u FETCH (",
441
 
                                    ctx->cur_mail->seq);
442
 
                        ctx->first = TRUE;
443
 
                        ctx->line_finished = FALSE;
 
483
                        str_printfa(state->cur_str, "* %u FETCH (",
 
484
                                    state->cur_mail->seq);
 
485
                        state->cur_first = TRUE;
 
486
                        state->line_finished = FALSE;
444
487
                }
445
488
 
446
 
                for (; ctx->cur_handler < count; ctx->cur_handler++) {
447
 
                        if (str_len(ctx->cur_str) > 0 &&
448
 
                            !handlers[ctx->cur_handler].buffered) {
 
489
                for (; state->cur_handler < count; state->cur_handler++) {
 
490
                        if (str_len(state->cur_str) > 0 &&
 
491
                            !handlers[state->cur_handler].buffered) {
449
492
                                /* first non-buffered handler.
450
493
                                   flush the buffer. */
451
 
                                ctx->line_partial = TRUE;
 
494
                                state->line_partial = TRUE;
452
495
                                if (imap_fetch_flush_buffer(ctx) < 0)
453
496
                                        return -1;
454
497
                        }
455
498
 
456
 
                        i_assert(ctx->cur_input == NULL);
 
499
                        i_assert(state->cur_input == NULL);
457
500
                        T_BEGIN {
458
501
                                const struct imap_fetch_context_handler *h =
459
 
                                        &handlers[ctx->cur_handler];
 
502
                                        &handlers[state->cur_handler];
460
503
 
461
 
                                ret = h->handler(ctx, ctx->cur_mail,
 
504
                                ret = h->handler(ctx, state->cur_mail,
462
505
                                                 h->context);
463
506
                        } T_END;
464
507
 
466
509
                                return 0;
467
510
 
468
511
                        if (ret < 0) {
469
 
                                if (ctx->cur_mail->expunged) {
 
512
                                if (state->cur_mail->expunged) {
470
513
                                        /* not an error, just lost it. */
471
 
                                        ctx->partial_fetch = TRUE;
 
514
                                        state->skipped_expunged_msgs = TRUE;
472
515
                                        if (imap_fetch_send_nil_reply(ctx) < 0)
473
516
                                                return -1;
474
517
                                } else {
475
518
                                        i_assert(ret < 0 ||
476
 
                                                 ctx->cont_handler != NULL);
 
519
                                                 state->cont_handler != NULL);
477
520
                                        return -1;
478
521
                                }
479
522
                        }
480
523
 
481
 
                        ctx->cont_handler = NULL;
482
 
                        ctx->cur_offset = 0;
483
 
                        if (ctx->cur_input != NULL)
484
 
                                i_stream_unref(&ctx->cur_input);
 
524
                        state->cont_handler = NULL;
 
525
                        state->cur_offset = 0;
 
526
                        if (state->cur_input != NULL)
 
527
                                i_stream_unref(&state->cur_input);
485
528
                }
486
529
 
487
 
                if (str_len(ctx->cur_str) > 0) {
 
530
                if (str_len(state->cur_str) > 0) {
488
531
                        /* no non-buffered handlers */
489
532
                        if (imap_fetch_flush_buffer(ctx) < 0)
490
533
                                return -1;
491
534
                }
492
535
 
493
 
                ctx->line_finished = TRUE;
494
 
                ctx->line_partial = FALSE;
495
 
                if (o_stream_send(client->output, ")\r\n", 3) < 0)
496
 
                        return -1;
 
536
                state->line_finished = TRUE;
 
537
                state->line_partial = FALSE;
 
538
                o_stream_nsend(client->output, ")\r\n", 3);
497
539
                client->last_output = ioloop_time;
498
540
 
499
 
                ctx->cur_mail = NULL;
500
 
                ctx->cur_handler = 0;
 
541
                state->cur_mail = NULL;
 
542
                state->cur_handler = 0;
501
543
        }
502
544
 
503
545
        return 1;
504
546
}
505
547
 
506
 
int imap_fetch_more(struct imap_fetch_context *ctx)
 
548
int imap_fetch_more(struct imap_fetch_context *ctx,
 
549
                    struct client_command_context *cmd)
507
550
{
508
551
        int ret;
509
552
 
510
 
        i_assert(ctx->client->output_lock == NULL ||
511
 
                 ctx->client->output_lock == ctx->cmd);
 
553
        i_assert(ctx->client->output_cmd_lock == NULL ||
 
554
                 ctx->client->output_cmd_lock == cmd);
512
555
 
513
 
        ret = imap_fetch_more_int(ctx);
 
556
        ret = imap_fetch_more_int(ctx, cmd->cancel);
514
557
        if (ret < 0)
515
 
                ctx->failed = TRUE;
516
 
        if (ctx->line_partial) {
 
558
                ctx->state.failed = TRUE;
 
559
        if (ctx->state.line_partial) {
517
560
                /* nothing can be sent until FETCH is finished */
518
 
                ctx->client->output_lock = ctx->cmd;
519
 
        }
520
 
        return ret;
521
 
}
522
 
 
523
 
int imap_fetch_deinit(struct imap_fetch_context *ctx)
524
 
{
 
561
                ctx->client->output_cmd_lock = cmd;
 
562
        }
 
563
        if (cmd->cancel && ctx->client->output_cmd_lock != NULL) {
 
564
                /* canceling didn't really work. we must not output
 
565
                   anything anymore. */
 
566
                if (!ctx->client->destroyed)
 
567
                        client_disconnect(ctx->client, "Failed to cancel FETCH");
 
568
                ctx->client->output_cmd_lock = NULL;
 
569
        }
 
570
        return ret;
 
571
}
 
572
 
 
573
int imap_fetch_more_no_lock_update(struct imap_fetch_context *ctx)
 
574
{
 
575
        int ret;
 
576
 
 
577
        ret = imap_fetch_more_int(ctx, FALSE);
 
578
        if (ret < 0) {
 
579
                ctx->state.failed = TRUE;
 
580
                if (!ctx->state.line_finished) {
 
581
                        client_disconnect(ctx->client,
 
582
                                "NOTIFY failed in the middle of FETCH reply");
 
583
                }
 
584
        }
 
585
        return ret;
 
586
}
 
587
 
 
588
int imap_fetch_end(struct imap_fetch_context *ctx)
 
589
{
 
590
        struct imap_fetch_state *state = &ctx->state;
 
591
 
 
592
        if (ctx->state.fetching) {
 
593
                ctx->state.fetching = FALSE;
 
594
                if (!state->line_finished) {
 
595
                        if (imap_fetch_flush_buffer(ctx) < 0)
 
596
                                state->failed = TRUE;
 
597
                        if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
 
598
                                state->failed = TRUE;
 
599
                }
 
600
        }
 
601
        ctx->client->output_cmd_lock = NULL;
 
602
 
 
603
        if (state->cur_str != NULL)
 
604
                str_free(&state->cur_str);
 
605
 
 
606
        if (state->cur_input != NULL)
 
607
                i_stream_unref(&state->cur_input);
 
608
 
 
609
        if (state->search_ctx != NULL) {
 
610
                if (mailbox_search_deinit(&state->search_ctx) < 0)
 
611
                        state->failed = TRUE;
 
612
        }
 
613
 
 
614
        if (state->trans != NULL) {
 
615
                /* even if something failed, we want to commit changes to
 
616
                   cache, as well as possible \Seen flag changes for FETCH
 
617
                   replies we returned so far. */
 
618
                if (mailbox_transaction_commit(&state->trans) < 0)
 
619
                        state->failed = TRUE;
 
620
        }
 
621
        return state->failed ? -1 : 0;
 
622
}
 
623
 
 
624
void imap_fetch_free(struct imap_fetch_context **_ctx)
 
625
{
 
626
        struct imap_fetch_context *ctx = *_ctx;
525
627
        const struct imap_fetch_context_handler *handler;
526
628
 
 
629
        *_ctx = NULL;
 
630
 
 
631
        (void)imap_fetch_end(ctx);
 
632
 
527
633
        array_foreach(&ctx->handlers, handler) {
528
634
                if (handler->want_deinit)
529
635
                        handler->handler(ctx, NULL, handler->context);
530
636
        }
531
 
 
532
 
        if (!ctx->line_finished) {
533
 
                if (imap_fetch_flush_buffer(ctx) < 0)
534
 
                        ctx->failed = TRUE;
535
 
                if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
536
 
                        ctx->failed = TRUE;
537
 
        }
538
 
        str_free(&ctx->cur_str);
539
 
 
540
 
        if (ctx->cur_input != NULL)
541
 
                i_stream_unref(&ctx->cur_input);
542
 
 
543
 
        mail_search_args_unref(&ctx->search_args);
544
 
        if (ctx->search_ctx != NULL) {
545
 
                if (mailbox_search_deinit(&ctx->search_ctx) < 0)
546
 
                        ctx->failed = TRUE;
547
 
        }
548
 
        if (ctx->all_headers_ctx != NULL)
549
 
                mailbox_header_lookup_unref(&ctx->all_headers_ctx);
550
 
 
551
 
        if (ctx->trans != NULL) {
552
 
                /* even if something failed, we want to commit changes to
553
 
                   cache, as well as possible \Seen flag changes for FETCH
554
 
                   replies we returned so far. */
555
 
                if (mailbox_transaction_commit(&ctx->trans) < 0)
556
 
                        ctx->failed = TRUE;
557
 
        }
558
 
        return ctx->failed ? -1 : 0;
 
637
        pool_unref(&ctx->ctx_pool);
559
638
}
560
639
 
561
640
static int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
566
645
        if (mail_get_special(mail, MAIL_FETCH_IMAP_BODY, &body) < 0)
567
646
                return -1;
568
647
 
569
 
        if (ctx->first)
570
 
                ctx->first = FALSE;
 
648
        if (ctx->state.cur_first)
 
649
                ctx->state.cur_first = FALSE;
571
650
        else {
572
651
                if (o_stream_send(ctx->client->output, " ", 1) < 0)
573
652
                        return -1;
580
659
        return 1;
581
660
}
582
661
 
583
 
static bool fetch_body_init(struct imap_fetch_context *ctx, const char *name,
584
 
                            const struct imap_arg **args)
 
662
static bool fetch_body_init(struct imap_fetch_init_context *ctx)
585
663
{
586
 
        if (name[4] == '\0') {
587
 
                ctx->fetch_data |= MAIL_FETCH_IMAP_BODY;
588
 
                imap_fetch_add_handler(ctx, FALSE, FALSE, name,
589
 
                                       "("BODY_NIL_REPLY")", fetch_body, NULL);
 
664
        if (ctx->name[4] == '\0') {
 
665
                ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_BODY;
 
666
                imap_fetch_add_handler(ctx, 0, "("BODY_NIL_REPLY")",
 
667
                                       fetch_body, NULL);
590
668
                return TRUE;
591
669
        }
592
 
        return fetch_body_section_init(ctx, name, args);
 
670
        return imap_fetch_body_section_init(ctx);
593
671
}
594
672
 
595
673
static int fetch_bodystructure(struct imap_fetch_context *ctx,
601
679
                             &bodystructure) < 0)
602
680
                return -1;
603
681
 
604
 
        if (ctx->first)
605
 
                ctx->first = FALSE;
 
682
        if (ctx->state.cur_first)
 
683
                ctx->state.cur_first = FALSE;
606
684
        else {
607
685
                if (o_stream_send(ctx->client->output, " ", 1) < 0)
608
686
                        return -1;
616
694
        return 1;
617
695
}
618
696
 
619
 
static bool
620
 
fetch_bodystructure_init(struct imap_fetch_context *ctx, const char *name,
621
 
                         const struct imap_arg **args ATTR_UNUSED)
 
697
static bool fetch_bodystructure_init(struct imap_fetch_init_context *ctx)
622
698
{
623
 
        ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
624
 
        imap_fetch_add_handler(ctx, FALSE, FALSE, name,
625
 
                               "("BODY_NIL_REPLY" NIL NIL NIL NIL)",
 
699
        ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
 
700
        imap_fetch_add_handler(ctx, 0, "("BODY_NIL_REPLY" NIL NIL NIL NIL)",
626
701
                               fetch_bodystructure, NULL);
627
702
        return TRUE;
628
703
}
635
710
        if (mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE, &envelope) < 0)
636
711
                return -1;
637
712
 
638
 
        if (ctx->first)
639
 
                ctx->first = FALSE;
 
713
        if (ctx->state.cur_first)
 
714
                ctx->state.cur_first = FALSE;
640
715
        else {
641
716
                if (o_stream_send(ctx->client->output, " ", 1) < 0)
642
717
                        return -1;
649
724
        return 1;
650
725
}
651
726
 
652
 
static bool
653
 
fetch_envelope_init(struct imap_fetch_context *ctx, const char *name,
654
 
                    const struct imap_arg **args ATTR_UNUSED)
 
727
static bool fetch_envelope_init(struct imap_fetch_init_context *ctx)
655
728
{
656
 
        ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE;
657
 
        imap_fetch_add_handler(ctx, FALSE, FALSE, name, ENVELOPE_NIL_REPLY,
 
729
        ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE;
 
730
        imap_fetch_add_handler(ctx, 0, ENVELOPE_NIL_REPLY,
658
731
                               fetch_envelope, NULL);
659
732
        return TRUE;
660
733
}
666
739
        const char *const *keywords;
667
740
 
668
741
        flags = mail_get_flags(mail);
669
 
        if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0) {
 
742
        if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0 &&
 
743
            !mailbox_is_readonly(mail->box)) {
670
744
                /* Add \Seen flag */
671
 
                ctx->seen_flags_changed = TRUE;
 
745
                ctx->state.seen_flags_changed = TRUE;
672
746
                flags |= MAIL_SEEN;
673
747
                mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
674
748
        } else if (ctx->flags_show_only_seen_changes) {
678
752
        keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords,
679
753
                        mail_get_keyword_indexes(mail));
680
754
 
681
 
        str_append(ctx->cur_str, "FLAGS (");
682
 
        imap_write_flags(ctx->cur_str, flags, keywords);
683
 
        str_append(ctx->cur_str, ") ");
 
755
        str_append(ctx->state.cur_str, "FLAGS (");
 
756
        imap_write_flags(ctx->state.cur_str, flags, keywords);
 
757
        str_append(ctx->state.cur_str, ") ");
684
758
        return 1;
685
759
}
686
760
 
687
 
static bool
688
 
fetch_flags_init(struct imap_fetch_context *ctx, const char *name,
689
 
                 const struct imap_arg **args ATTR_UNUSED)
 
761
bool imap_fetch_flags_init(struct imap_fetch_init_context *ctx)
690
762
{
691
 
        ctx->flags_have_handler = TRUE;
692
 
        ctx->fetch_data |= MAIL_FETCH_FLAGS;
693
 
        imap_fetch_add_handler(ctx, TRUE, FALSE, name, "()", fetch_flags, NULL);
 
763
        ctx->fetch_ctx->flags_have_handler = TRUE;
 
764
        ctx->fetch_ctx->fetch_data |= MAIL_FETCH_FLAGS;
 
765
        imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
 
766
                               "()", fetch_flags, NULL);
694
767
        return TRUE;
695
768
}
696
769
 
702
775
        if (mail_get_received_date(mail, &date) < 0)
703
776
                return -1;
704
777
 
705
 
        str_printfa(ctx->cur_str, "INTERNALDATE \"%s\" ",
 
778
        str_printfa(ctx->state.cur_str, "INTERNALDATE \"%s\" ",
706
779
                    imap_to_datetime(date));
707
780
        return 1;
708
781
}
709
782
 
710
 
static bool
711
 
fetch_internaldate_init(struct imap_fetch_context *ctx, const char *name,
712
 
                        const struct imap_arg **args ATTR_UNUSED)
 
783
static bool fetch_internaldate_init(struct imap_fetch_init_context *ctx)
713
784
{
714
 
        ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE;
715
 
        imap_fetch_add_handler(ctx, TRUE, FALSE, name,
 
785
        ctx->fetch_ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE;
 
786
        imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
716
787
                               "\"01-Jan-1970 00:00:00 +0000\"",
717
788
                               fetch_internaldate, NULL);
718
789
        return TRUE;
726
797
        modseq = mail_get_modseq(mail);
727
798
        if (ctx->client->highest_fetch_modseq < modseq)
728
799
                ctx->client->highest_fetch_modseq = modseq;
729
 
        str_printfa(ctx->cur_str, "MODSEQ (%llu) ",
 
800
        str_printfa(ctx->state.cur_str, "MODSEQ (%llu) ",
730
801
                    (unsigned long long)modseq);
731
802
        return 1;
732
803
}
733
804
 
734
 
static bool
735
 
fetch_modseq_init(struct imap_fetch_context *ctx, const char *name,
736
 
                  const struct imap_arg **args ATTR_UNUSED)
 
805
bool imap_fetch_modseq_init(struct imap_fetch_init_context *ctx)
737
806
{
738
 
        (void)client_enable(ctx->client, MAILBOX_FEATURE_CONDSTORE);
739
 
        imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL,
740
 
                               fetch_modseq, NULL);
 
807
        (void)client_enable(ctx->fetch_ctx->client, MAILBOX_FEATURE_CONDSTORE);
 
808
        imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
 
809
                               NULL, fetch_modseq, NULL);
741
810
        return TRUE;
742
811
}
743
812
 
744
813
static int fetch_uid(struct imap_fetch_context *ctx, struct mail *mail,
745
814
                     void *context ATTR_UNUSED)
746
815
{
747
 
        str_printfa(ctx->cur_str, "UID %u ", mail->uid);
 
816
        str_printfa(ctx->state.cur_str, "UID %u ", mail->uid);
748
817
        return 1;
749
818
}
750
819
 
751
 
static bool
752
 
fetch_uid_init(struct imap_fetch_context *ctx ATTR_UNUSED, const char *name,
753
 
               const struct imap_arg **args ATTR_UNUSED)
 
820
bool imap_fetch_uid_init(struct imap_fetch_init_context *ctx)
754
821
{
755
 
        imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL, fetch_uid, NULL);
 
822
        imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
 
823
                               NULL, fetch_uid, NULL);
756
824
        return TRUE;
757
825
}
758
826
 
764
832
        if (mail_get_special(mail, MAIL_FETCH_GUID, &value) < 0)
765
833
                return -1;
766
834
 
767
 
        str_append(ctx->cur_str, "X-GUID ");
768
 
        imap_quote_append_string(ctx->cur_str, value, FALSE);
769
 
        str_append_c(ctx->cur_str, ' ');
 
835
        str_append(ctx->state.cur_str, "X-GUID ");
 
836
        imap_append_astring(ctx->state.cur_str, value);
 
837
        str_append_c(ctx->state.cur_str, ' ');
770
838
        return 1;
771
839
}
772
840
 
773
 
static bool
774
 
fetch_guid_init(struct imap_fetch_context *ctx ATTR_UNUSED, const char *name,
775
 
                const struct imap_arg **args ATTR_UNUSED)
 
841
static bool fetch_guid_init(struct imap_fetch_init_context *ctx)
776
842
{
777
 
        ctx->fetch_data |= MAIL_FETCH_GUID;
778
 
        imap_fetch_add_handler(ctx, TRUE, FALSE, name, "", fetch_guid, NULL);
 
843
        ctx->fetch_ctx->fetch_data |= MAIL_FETCH_GUID;
 
844
        imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
 
845
                               "", fetch_guid, NULL);
779
846
        return TRUE;
780
847
}
781
848
 
792
859
        if (imap_utf8_to_utf7(name, mutf7_name) < 0)
793
860
                i_panic("FETCH: Mailbox name not UTF-8: %s", name);
794
861
 
795
 
        str_append(ctx->cur_str, "X-MAILBOX ");
796
 
        imap_quote_append_string(ctx->cur_str, str_c(mutf7_name), FALSE);
797
 
        str_append_c(ctx->cur_str, ' ');
 
862
        str_append(ctx->state.cur_str, "X-MAILBOX ");
 
863
        imap_append_astring(ctx->state.cur_str, str_c(mutf7_name));
 
864
        str_append_c(ctx->state.cur_str, ' ');
798
865
        return 1;
799
866
}
800
867
 
801
 
static bool
802
 
fetch_x_mailbox_init(struct imap_fetch_context *ctx ATTR_UNUSED,
803
 
                     const char *name,
804
 
                     const struct imap_arg **args ATTR_UNUSED)
 
868
static bool fetch_x_mailbox_init(struct imap_fetch_init_context *ctx)
805
869
{
806
 
        imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL,
807
 
                               fetch_x_mailbox, NULL);
 
870
        imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
 
871
                               NULL, fetch_x_mailbox, NULL);
808
872
        return TRUE;
809
873
}
810
874
 
811
875
static int fetch_x_real_uid(struct imap_fetch_context *ctx, struct mail *mail,
812
876
                            void *context ATTR_UNUSED)
813
877
{
814
 
        str_printfa(ctx->cur_str, "X-REAL-UID %u ",
 
878
        str_printfa(ctx->state.cur_str, "X-REAL-UID %u ",
815
879
                    mail_get_real_mail(mail)->uid);
816
880
        return 1;
817
881
}
818
882
 
819
 
static bool
820
 
fetch_x_real_uid_init(struct imap_fetch_context *ctx ATTR_UNUSED,
821
 
                      const char *name,
822
 
                      const struct imap_arg **args ATTR_UNUSED)
 
883
static bool fetch_x_real_uid_init(struct imap_fetch_init_context *ctx)
823
884
{
824
 
        imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL,
825
 
                               fetch_x_real_uid, NULL);
 
885
        imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
 
886
                               NULL, fetch_x_real_uid, NULL);
826
887
        return TRUE;
827
888
}
828
889
 
834
895
        if (mail_get_save_date(mail, &date) < 0)
835
896
                return -1;
836
897
 
837
 
        str_printfa(ctx->cur_str, "X-SAVEDATE \"%s\" ",
 
898
        str_printfa(ctx->state.cur_str, "X-SAVEDATE \"%s\" ",
838
899
                    imap_to_datetime(date));
839
900
        return 1;
840
901
}
841
902
 
842
 
static bool
843
 
fetch_x_savedate_init(struct imap_fetch_context *ctx, const char *name,
844
 
                      const struct imap_arg **args ATTR_UNUSED)
 
903
static bool fetch_x_savedate_init(struct imap_fetch_init_context *ctx)
845
904
{
846
 
        ctx->fetch_data |= MAIL_FETCH_SAVE_DATE;
847
 
        imap_fetch_add_handler(ctx, TRUE, FALSE, name,
 
905
        ctx->fetch_ctx->fetch_data |= MAIL_FETCH_SAVE_DATE;
 
906
        imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
848
907
                               "\"01-Jan-1970 00:00:00 +0000\"",
849
908
                               fetch_x_savedate, NULL);
850
909
        return TRUE;
852
911
 
853
912
static const struct imap_fetch_handler
854
913
imap_fetch_default_handlers[] = {
 
914
        { "BINARY", imap_fetch_binary_init },
855
915
        { "BODY", fetch_body_init },
856
916
        { "BODYSTRUCTURE", fetch_bodystructure_init },
857
917
        { "ENVELOPE", fetch_envelope_init },
858
 
        { "FLAGS", fetch_flags_init },
 
918
        { "FLAGS", imap_fetch_flags_init },
859
919
        { "INTERNALDATE", fetch_internaldate_init },
860
 
        { "MODSEQ", fetch_modseq_init },
861
 
        { "RFC822", fetch_rfc822_init },
862
 
        { "UID", fetch_uid_init },
 
920
        { "MODSEQ", imap_fetch_modseq_init },
 
921
        { "RFC822", imap_fetch_rfc822_init },
 
922
        { "UID", imap_fetch_uid_init },
863
923
        { "X-GUID", fetch_guid_init },
864
924
        { "X-MAILBOX", fetch_x_mailbox_init },
865
925
        { "X-REAL-UID", fetch_x_real_uid_init },