bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
c519de264df14a9d525e2604671c332590ce54e3Timo Sirainen "\"text\" \"plain\" NIL NIL NIL \"7bit\" 0 0"
61530b48694398df42744204e35535dbe3f745c4Timo Sirainen "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)"
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainenstatic ARRAY(struct imap_fetch_handler) fetch_handlers;
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainenstatic int imap_fetch_handler_cmp(const struct imap_fetch_handler *h1,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
2b3b0df76184799317584b596af8df5afec3ebddTimo Sirainen array_append(&fetch_handlers, handlers, count);
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen array_sort(&fetch_handlers, imap_fetch_handler_cmp);
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainenvoid imap_fetch_handler_unregister(const char *name)
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen const struct imap_fetch_handler *handler, *first_handler;
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen first_handler = array_idx(&fetch_handlers, 0);
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen array_delete(&fetch_handlers, handler - first_handler, 1);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenimap_fetch_handler_bsearch(const char *name, const struct imap_fetch_handler *h)
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainenconst struct imap_fetch_handler *imap_fetch_handler_lookup(const char *name)
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen return array_bsearch(&fetch_handlers, name, imap_fetch_handler_bsearch);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenbool imap_fetch_init_handler(struct imap_fetch_init_context *init_ctx)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen for (p = init_ctx->name; i_isalnum(*p) || *p == '-'; p++) ;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen lookup_name = t_strdup_until(init_ctx->name, p);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen handler = array_bsearch(&fetch_handlers, lookup_name,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen init_ctx->error = t_strdup_printf("Unknown parameter: %s",
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenvoid imap_fetch_init_nofail_handler(struct imap_fetch_context *ctx,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen bool (*init)(struct imap_fetch_init_context *))
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenint imap_fetch_att_list_parse(struct client *client, pool_t pool,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char **error_r)
cddfd1355db6b60c71d7ee3c0b4f23b3efcc9ad1Timo Sirainen init_ctx.fetch_ctx = imap_fetch_alloc(client, pool, "NOTIFY");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen while (imap_arg_get_atom(init_ctx.args, &str)) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *error_r = t_strconcat("Invalid fetch-att list: ",
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *error_r = "fetch-att list contains non-atoms.";
cddfd1355db6b60c71d7ee3c0b4f23b3efcc9ad1Timo Sirainenimap_fetch_alloc(struct client *client, pool_t pool, const char *reason)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen ctx = p_new(pool, struct imap_fetch_context, 1);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_init_context *ctx,
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* partially because of broken clients, but also partially because
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen it potentially can make client implementations faster, we have a
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen buffered parameter which basically means that the handler promises
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen to write the output in fetch_ctx->state.cur_str. The cur_str is then
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen sent to client before calling any non-buffered handlers.
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen We try to keep the handler registration order the same as the
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen client requested them. This is especially useful to get UID
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen returned first, which some clients rely on..
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen const struct imap_fetch_context_handler *ctx_handler;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* don't allow duplicate handlers */
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen array_foreach(&ctx->fetch_ctx->handlers, ctx_handler) {
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen h.buffered = (flags & IMAP_FETCH_HANDLER_FLAG_BUFFERED) != 0;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen h.want_deinit = (flags & IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT) != 0;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen array_append(&ctx->fetch_ctx->handlers, &h, 1);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->buffered_handlers_count, &h, 1);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const struct imap_fetch_qresync_args *qresync_args,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen seqs = array_get(qresync_args->qresync_sample_seqset, &count);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen uids = array_idx(qresync_args->qresync_sample_uidset, 0);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen i_assert(array_count(qresync_args->qresync_sample_uidset) == count);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen mailbox_get_open_status(box, STATUS_MESSAGES, &status);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* FIXME: we could do removals from the middle as well */
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen for (i = 0; i < count && seqs[i] <= status.messages; i++) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen seq_range_array_remove_range(expunged_uids, 1, uids[i-1]);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const struct imap_fetch_qresync_args *qresync_args,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen uid_filter = array_get(uid_filter_arr, &count);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen /* search UIDs only in given range */
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen i_array_init(&search_args->args->value.seqset, count);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen array_append_array(&search_args->args->value.seqset, uid_filter_arr);
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi trans = mailbox_transaction_begin(box, 0, "FETCH send VANISHED");
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen while (mailbox_search_next(search_ctx, &mail)) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen else if (++i < count)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* next_uid .. mail->uid-1 are expunged */
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen else if (++i < count)
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen seq_range_array_add_range(expunged_uids, next_uid,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen for (; i < count; i++) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen seq_range_array_add_range(expunged_uids, uid_filter[i].seq1,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen mailbox_get_open_status(box, STATUS_UIDNEXT, &status);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen seq_range_array_remove_range(expunged_uids, status.uidnext,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (ret == 0 && qresync_args->qresync_sample_seqset != NULL &&
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen array_is_created(qresync_args->qresync_sample_seqset))
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen expunges_drop_known(box, qresync_args, trans, expunged_uids);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenint imap_fetch_send_vanished(struct client *client, struct mailbox *box,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const struct imap_fetch_qresync_args *qresync_args)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const struct mail_search_arg *uidarg = search_args->args;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen const struct mail_search_arg *modseqarg = uidarg->next;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen i_array_init(&expunged_uids_range, array_count(uid_filter));
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (!mailbox_get_expunged_uids(box, modseq, uid_filter, &expunged_uids_range)) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* return all expunged UIDs */
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (get_expunges_fallback(box, qresync_args, uid_filter,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen imap_write_seq_range(str, &expunged_uids_range);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen o_stream_nsend(client->output, str_data(str), str_len(str));
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenstatic void imap_fetch_init(struct imap_fetch_context *ctx)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (ctx->flags_update_seen && !ctx->flags_have_handler) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen imap_fetch_init_nofail_handler(ctx, imap_fetch_flags_init);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenvoid imap_fetch_begin(struct imap_fetch_context *ctx, struct mailbox *box,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers = NULL;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen wanted_headers = mailbox_header_lookup_init(box, headers);
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen /* Hide the implicit \Seen flag addition. Otherwise a separate
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen untagged FETCH FLAGS (\Seen) would be sent on top of the
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen one FLAGS (\Seen) already added in the main FETCH reply.
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen We don't set this always, because some plugins might want
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen to do their own flag changes which we don't want hidden.
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen (Of course this isn't perfect since if implicit \Seen flags
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen are added, other flag changes are also hidden.) */
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi ctx->state.trans = mailbox_transaction_begin(box, trans_flags,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen mailbox_search_init(ctx->state.trans, search_args, NULL,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen ctx->state.cur_str = str_new(default_pool, 8192);
ceb8c97c6c9fe0ee7eb544645c6bdb74dfcb519dJosef 'Jeff' Sipek mailbox_header_lookup_unref(&wanted_headers);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* there's an extra space at the end if we added any fetch items
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainenstatic int imap_fetch_send_nil_reply(struct imap_fetch_context *ctx)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen const struct imap_fetch_context_handler *handler;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen handler = array_idx(&ctx->handlers, ctx->state.cur_handler);
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainenstatic void imap_fetch_fix_empty_reply(struct imap_fetch_context *ctx)
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen if (ctx->state.line_partial && ctx->state.cur_first) {
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen /* we've flushed an empty "FETCH (" reply so
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen far. we can't take it back, but RFC 3501
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen doesn't allow returning empty "FETCH ()"
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen either, so just add the current message's
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen UID there. */
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainenstatic bool imap_fetch_cur_failed(struct imap_fetch_context *ctx)
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen IMAP_CLIENT_FETCH_FAILURE_DISCONNECT_IMMEDIATELY)
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen if (!array_is_created(&ctx->fetch_failed_uids))
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen p_array_init(&ctx->fetch_failed_uids, ctx->ctx_pool, 8);
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen seq_range_array_add(&ctx->fetch_failed_uids, ctx->state.cur_mail->uid);
289bd999f282a307b05e6f8beef33155a50fb837Timo Sirainen /* preserve the first error, since it may change in storage. */
289bd999f282a307b05e6f8beef33155a50fb837Timo Sirainen mailbox_get_last_error(ctx->state.cur_mail->box, &ctx->error));
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenstatic int imap_fetch_more_int(struct imap_fetch_context *ctx, bool cancel)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const struct imap_fetch_context_handler *handlers;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen /* not an error, just lost it. */
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen state->cur_str_prefix_size = str_len(state->cur_str);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen for (; state->cur_handler < count; state->cur_handler++) {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* first non-buffered handler.
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen flush the buffer. */
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen /* not an error, just lost it. */
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen str_len(state->cur_str) != state->cur_str_prefix_size)) {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* no non-buffered handlers */
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenint imap_fetch_more(struct imap_fetch_context *ctx,
5a7acd67806132cbc1ec9578df60d712d307e4beTimo Sirainen i_assert(ctx->client->output_cmd_lock == NULL ||
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen /* nothing can be sent until FETCH is finished */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (cmd->cancel && ctx->client->output_cmd_lock != NULL) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* canceling didn't really work. we must not output
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen anything anymore. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_disconnect(ctx->client, "Failed to cancel FETCH");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenint imap_fetch_more_no_lock_update(struct imap_fetch_context *ctx)
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen /* we can't send any more replies to client, because
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen the FETCH reply wasn't fully sent. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen "NOTIFY failed in the middle of FETCH reply");
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenint imap_fetch_end(struct imap_fetch_context *ctx)
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (mailbox_search_deinit(&state->search_ctx) < 0)
5eca7b6535c3e74fb98aef5c34f096d9252a8f46Timo Sirainen /* even if something failed, we want to commit changes to
5eca7b6535c3e74fb98aef5c34f096d9252a8f46Timo Sirainen cache, as well as possible \Seen flag changes for FETCH
5eca7b6535c3e74fb98aef5c34f096d9252a8f46Timo Sirainen replies we returned so far. */
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (mailbox_transaction_commit(&state->trans) < 0)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenvoid imap_fetch_free(struct imap_fetch_context **_ctx)
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen const struct imap_fetch_context_handler *handler;
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen handler->handler(ctx, NULL, handler->context);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_BODY, &body) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, "BODY (", 6) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send_str(ctx->client->output, body) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_body_init(struct imap_fetch_init_context *ctx)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_BODY;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, 0, "("BODY_NIL_REPLY")",
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainenstatic int fetch_bodystructure(struct imap_fetch_context *ctx,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, "BODYSTRUCTURE (", 15) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send_str(ctx->client->output, bodystructure) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_bodystructure_init(struct imap_fetch_init_context *ctx)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, 0, "("BODY_NIL_REPLY" NIL NIL NIL NIL)",
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE, &envelope) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, "ENVELOPE (", 10) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send_str(ctx->client->output, envelope) < 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_send(ctx->client->output, ")", 1) < 0)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_envelope_init(struct imap_fetch_init_context *ctx)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, 0, ENVELOPE_NIL_REPLY,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0 &&
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* Add \Seen flag */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen } else if (ctx->flags_show_only_seen_changes) {
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords,
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen imap_write_flags(ctx->state.cur_str, flags, keywords);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenbool imap_fetch_flags_init(struct imap_fetch_init_context *ctx)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_FLAGS;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_internaldate(struct imap_fetch_context *ctx, struct mail *mail,
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_printfa(ctx->state.cur_str, "INTERNALDATE \"%s\" ",
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_internaldate_init(struct imap_fetch_init_context *ctx)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
94478f96b2845d619aa1a9b8cf507d598ac74eccTimo Sirainen "\"01-Jan-1970 00:00:00 +0000\"",
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainenstatic int fetch_modseq(struct imap_fetch_context *ctx, struct mail *mail,
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (ctx->client->highest_fetch_modseq < modseq)
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi str_printfa(ctx->state.cur_str, "MODSEQ (%"PRIu64") ", modseq);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenbool imap_fetch_modseq_init(struct imap_fetch_init_context *ctx)
0ff8b7fd6b7021a845538f6bcf755d97d488fddbTimo Sirainen if (ctx->fetch_ctx->client->nonpermanent_modseqs) {
0ff8b7fd6b7021a845538f6bcf755d97d488fddbTimo Sirainen ctx->error = "FETCH MODSEQ can't be used with non-permanent modseqs";
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen (void)client_enable(ctx->fetch_ctx->client, MAILBOX_FEATURE_CONDSTORE);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_uid(struct imap_fetch_context *ctx, struct mail *mail,
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_printfa(ctx->state.cur_str, "UID %u ", mail->uid);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenbool imap_fetch_uid_init(struct imap_fetch_init_context *ctx)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainenstatic int fetch_guid(struct imap_fetch_context *ctx, struct mail *mail,
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_GUID, &value) < 0)
44f93baa7b8dca7d00bf187cd3db1c15eed384d2Timo Sirainen imap_append_astring(ctx->state.cur_str, value);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_guid_init(struct imap_fetch_init_context *ctx)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_GUID;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainenstatic int fetch_x_mailbox(struct imap_fetch_context *ctx, struct mail *mail,
f46f53badf6082e289ac38807e701305c521f11dTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_MAILBOX_NAME, &name) < 0) {
f46f53badf6082e289ac38807e701305c521f11dTimo Sirainen /* This can happen with virtual mailbox if the backend mail
f46f53badf6082e289ac38807e701305c521f11dTimo Sirainen is expunged. */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen i_panic("FETCH: Mailbox name not UTF-8: %s", name);
44f93baa7b8dca7d00bf187cd3db1c15eed384d2Timo Sirainen imap_append_astring(ctx->state.cur_str, str_c(mutf7_name));
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_x_mailbox_init(struct imap_fetch_init_context *ctx)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainenstatic int fetch_x_real_uid(struct imap_fetch_context *ctx, struct mail *mail,
d8615e0bec5fc8ffe6be9f64928c2f26b9b5a4deTimo Sirainen if (mail_get_backend_mail(mail, &real_mail) < 0)
d8615e0bec5fc8ffe6be9f64928c2f26b9b5a4deTimo Sirainen str_printfa(ctx->state.cur_str, "X-REAL-UID %u ", real_mail->uid);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_x_real_uid_init(struct imap_fetch_init_context *ctx)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainenstatic int fetch_x_savedate(struct imap_fetch_context *ctx, struct mail *mail,
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_printfa(ctx->state.cur_str, "X-SAVEDATE \"%s\" ",
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_x_savedate_init(struct imap_fetch_init_context *ctx)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_SAVE_DATE;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen "\"01-Jan-1970 00:00:00 +0000\"",
16834f18f903048c772112838c015051642a0e77Timo Sirainenstatic const struct imap_fetch_handler
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "BODYSTRUCTURE", fetch_bodystructure_init },