bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "imap-common.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "array.h"
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen#include "buffer.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "istream.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "ostream.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "str.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "message-size.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "imap-date.h"
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen#include "imap-utf7.h"
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen#include "mail-search-build.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "imap-commands.h"
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen#include "imap-quote.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "imap-fetch.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-util.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
de76b960297406115cf6bae473f004c08174b16aTimo Sirainen#include <ctype.h>
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen#define BODY_NIL_REPLY \
c519de264df14a9d525e2604671c332590ce54e3Timo Sirainen "\"text\" \"plain\" NIL NIL NIL \"7bit\" 0 0"
61530b48694398df42744204e35535dbe3f745c4Timo Sirainen#define ENVELOPE_NIL_REPLY \
61530b48694398df42744204e35535dbe3f745c4Timo Sirainen "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)"
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainenstatic ARRAY(struct imap_fetch_handler) fetch_handlers;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainenstatic int imap_fetch_handler_cmp(const struct imap_fetch_handler *h1,
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen const struct imap_fetch_handler *h2)
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return strcmp(h1->name, h2->name);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenvoid imap_fetch_handlers_register(const struct imap_fetch_handler *handlers,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen size_t count)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2b3b0df76184799317584b596af8df5afec3ebddTimo Sirainen array_append(&fetch_handlers, handlers, count);
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen array_sort(&fetch_handlers, imap_fetch_handler_cmp);
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen}
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainenvoid imap_fetch_handler_unregister(const char *name)
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen{
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen const struct imap_fetch_handler *handler, *first_handler;
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen first_handler = array_idx(&fetch_handlers, 0);
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen handler = imap_fetch_handler_lookup(name);
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen i_assert(handler != NULL);
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen array_delete(&fetch_handlers, handler - first_handler, 1);
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen}
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenstatic int
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenimap_fetch_handler_bsearch(const char *name, const struct imap_fetch_handler *h)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen return strcmp(name, h->name);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainenconst struct imap_fetch_handler *imap_fetch_handler_lookup(const char *name)
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen{
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen return array_bsearch(&fetch_handlers, name, imap_fetch_handler_bsearch);
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen}
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenbool imap_fetch_init_handler(struct imap_fetch_init_context *init_ctx)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen const struct imap_fetch_handler *handler;
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen const char *lookup_name, *p;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen for (p = init_ctx->name; i_isalnum(*p) || *p == '-'; p++) ;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen lookup_name = t_strdup_until(init_ctx->name, p);
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen handler = array_bsearch(&fetch_handlers, lookup_name,
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen imap_fetch_handler_bsearch);
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen if (handler == NULL) {
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen init_ctx->error = t_strdup_printf("Unknown parameter: %s",
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen init_ctx->name);
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen return FALSE;
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (!handler->init(init_ctx)) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen i_assert(init_ctx->error != NULL);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen return FALSE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen return TRUE;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen}
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenvoid imap_fetch_init_nofail_handler(struct imap_fetch_context *ctx,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen bool (*init)(struct imap_fetch_init_context *))
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen struct imap_fetch_init_context init_ctx;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&init_ctx);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen init_ctx.fetch_ctx = ctx;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen init_ctx.pool = ctx->ctx_pool;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen if (!init(&init_ctx))
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen i_unreached();
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen}
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenint imap_fetch_att_list_parse(struct client *client, pool_t pool,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const struct imap_arg *list,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct imap_fetch_context **fetch_ctx_r,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char **error_r)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct imap_fetch_init_context init_ctx;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char *str;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&init_ctx);
cddfd1355db6b60c71d7ee3c0b4f23b3efcc9ad1Timo Sirainen init_ctx.fetch_ctx = imap_fetch_alloc(client, pool, "NOTIFY");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen init_ctx.pool = pool;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen init_ctx.args = list;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen while (imap_arg_get_atom(init_ctx.args, &str)) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen init_ctx.name = t_str_ucase(str);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen init_ctx.args++;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!imap_fetch_init_handler(&init_ctx)) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *error_r = t_strconcat("Invalid fetch-att list: ",
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen init_ctx.error, NULL);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen imap_fetch_free(&init_ctx.fetch_ctx);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return -1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!IMAP_ARG_IS_EOL(init_ctx.args)) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *error_r = "fetch-att list contains non-atoms.";
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen imap_fetch_free(&init_ctx.fetch_ctx);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return -1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *fetch_ctx_r = init_ctx.fetch_ctx;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenstruct imap_fetch_context *
cddfd1355db6b60c71d7ee3c0b4f23b3efcc9ad1Timo Sirainenimap_fetch_alloc(struct client *client, pool_t pool, const char *reason)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct imap_fetch_context *ctx;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen ctx = p_new(pool, struct imap_fetch_context, 1);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ctx->client = client;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen ctx->ctx_pool = pool;
cddfd1355db6b60c71d7ee3c0b4f23b3efcc9ad1Timo Sirainen ctx->reason = p_strdup(pool, reason);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen pool_ref(pool);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen p_array_init(&ctx->all_headers, pool, 64);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen p_array_init(&ctx->handlers, pool, 16);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen p_array_init(&ctx->tmp_keywords, pool,
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen client->keywords.announce_count + 8);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return ctx;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen#undef imap_fetch_add_handler
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenvoid imap_fetch_add_handler(struct imap_fetch_init_context *ctx,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen enum imap_fetch_handler_flags flags,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen const char *nil_reply,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen imap_fetch_handler_t *handler, void *context)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
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
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..
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen */
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen const struct imap_fetch_context_handler *ctx_handler;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct imap_fetch_context_handler h;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (context == NULL) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* don't allow duplicate handlers */
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen array_foreach(&ctx->fetch_ctx->handlers, ctx_handler) {
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen if (ctx_handler->handler == handler &&
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen ctx_handler->context == NULL)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&h);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen h.handler = handler;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen h.context = context;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen h.buffered = (flags & IMAP_FETCH_HANDLER_FLAG_BUFFERED) != 0;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen h.want_deinit = (flags & IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT) != 0;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen h.name = p_strdup(ctx->pool, ctx->name);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen h.nil_reply = p_strdup(ctx->pool, nil_reply);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen if (!h.buffered)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen array_append(&ctx->fetch_ctx->handlers, &h, 1);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen else {
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen array_insert(&ctx->fetch_ctx->handlers,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->buffered_handlers_count, &h, 1);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->buffered_handlers_count++;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen }
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenstatic void
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenexpunges_drop_known(struct mailbox *box,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const struct imap_fetch_qresync_args *qresync_args,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen struct mailbox_transaction_context *trans,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen ARRAY_TYPE(seq_range) *expunged_uids)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen struct mailbox_status status;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen struct mail *mail;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen const uint32_t *seqs, *uids;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen unsigned int i, count;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
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);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_assert(count > 0);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen mailbox_get_open_status(box, STATUS_MESSAGES, &status);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen mail = mail_alloc(trans, 0, NULL);
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* FIXME: we could do removals from the middle as well */
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen for (i = 0; i < count && seqs[i] <= status.messages; i++) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen mail_set_seq(mail, seqs[i]);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (uids[i] != mail->uid)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen break;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (i > 0)
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen seq_range_array_remove_range(expunged_uids, 1, uids[i-1]);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen mail_free(&mail);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenstatic int
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenget_expunges_fallback(struct mailbox *box,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const struct imap_fetch_qresync_args *qresync_args,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const ARRAY_TYPE(seq_range) *uid_filter_arr,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen ARRAY_TYPE(seq_range) *expunged_uids)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct mailbox_transaction_context *trans;
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen struct mail_search_args *search_args;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct mail_search_context *search_ctx;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct mail *mail;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen const struct seq_range *uid_filter;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct mailbox_status status;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen unsigned int i, count;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen uint32_t next_uid;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen int ret = 0;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen uid_filter = array_get(uid_filter_arr, &count);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_assert(count > 0);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i = 0;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen next_uid = uid_filter[0].seq1;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen /* search UIDs only in given range */
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen search_args = mail_search_build_init();
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen search_args->args->type = SEARCH_UIDSET;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen i_array_init(&search_args->args->value.seqset, count);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen array_append_array(&search_args->args->value.seqset, uid_filter_arr);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
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);
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen mail_search_args_unref(&search_args);
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen while (mailbox_search_next(search_ctx, &mail)) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (mail->uid == next_uid) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (next_uid < uid_filter[i].seq2)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen next_uid++;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen else if (++i < count)
217cdf98fe6f3e5a9a932e41fa2e956c153a6947Timo Sirainen next_uid = uid_filter[i].seq1;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen else
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen break;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen } else {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* next_uid .. mail->uid-1 are expunged */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_assert(mail->uid > next_uid);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen while (mail->uid > uid_filter[i].seq2) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen seq_range_array_add_range(expunged_uids,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen next_uid,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen uid_filter[i].seq2);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i++;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_assert(i < count);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen next_uid = uid_filter[i].seq1;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (next_uid != mail->uid) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen seq_range_array_add_range(expunged_uids,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen next_uid,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen mail->uid - 1);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen if (uid_filter[i].seq2 != mail->uid)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen next_uid = mail->uid + 1;
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen else if (++i < count)
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen next_uid = uid_filter[i].seq1;
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen else
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen break;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (i < count) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen i_assert(next_uid <= uid_filter[i].seq2);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen seq_range_array_add_range(expunged_uids, next_uid,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen uid_filter[i].seq2);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i++;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen for (; i < count; i++) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen seq_range_array_add_range(expunged_uids, uid_filter[i].seq1,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen uid_filter[i].seq2);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen mailbox_get_open_status(box, STATUS_UIDNEXT, &status);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen seq_range_array_remove_range(expunged_uids, status.uidnext,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen (uint32_t)-1);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (mailbox_search_deinit(&search_ctx) < 0)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen ret = -1;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
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);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen (void)mailbox_transaction_commit(&trans);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return ret;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenint imap_fetch_send_vanished(struct client *client, struct mailbox *box,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const struct mail_search_args *search_args,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const struct imap_fetch_qresync_args *qresync_args)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const struct mail_search_arg *uidarg = search_args->args;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen const struct mail_search_arg *modseqarg = uidarg->next;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const ARRAY_TYPE(seq_range) *uid_filter;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen uint64_t modseq;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen ARRAY_TYPE(seq_range) expunged_uids_range;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen string_t *str;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen int ret = 0;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen i_assert(uidarg->type == SEARCH_UIDSET);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen i_assert(modseqarg->type == SEARCH_MODSEQ);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen uid_filter = &uidarg->value.seqset;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen modseq = modseqarg->value.modseq->modseq - 1;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
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 &expunged_uids_range) < 0) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen array_clear(&expunged_uids_range);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen ret = -1;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (array_count(&expunged_uids_range) > 0) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str = str_new(default_pool, 128);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_append(str, "* VANISHED (EARLIER) ");
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen imap_write_seq_range(str, &expunged_uids_range);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_append(str, "\r\n");
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen o_stream_nsend(client->output, str_data(str), str_len(str));
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_free(&str);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen array_free(&expunged_uids_range);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return ret;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenstatic void imap_fetch_init(struct imap_fetch_context *ctx)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (ctx->initialized)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen return;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen ctx->initialized = TRUE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (ctx->flags_update_seen && !ctx->flags_have_handler) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen ctx->flags_show_only_seen_changes = TRUE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen imap_fetch_init_nofail_handler(ctx, imap_fetch_flags_init);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if ((ctx->fetch_data &
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen ctx->fetch_data |= MAIL_FETCH_NUL_STATE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenvoid imap_fetch_begin(struct imap_fetch_context *ctx, struct mailbox *box,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct mail_search_args *search_args)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen{
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen enum mailbox_transaction_flags trans_flags =
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen MAILBOX_TRANSACTION_FLAG_REFRESH;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers = NULL;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen const char *const *headers;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen i_assert(!ctx->state.fetching);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen imap_fetch_init(ctx);
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&ctx->state);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
a342a31752dd71ac444259ca57ad33ea6b79a572Timo Sirainen if (array_count(&ctx->all_headers) > 0 &&
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ((ctx->fetch_data & (MAIL_FETCH_STREAM_HEADER |
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen MAIL_FETCH_STREAM_BODY)) == 0)) {
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&ctx->all_headers);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen headers = array_idx(&ctx->all_headers, 0);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen wanted_headers = mailbox_header_lookup_init(box, headers);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen array_delete(&ctx->all_headers,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen array_count(&ctx->all_headers)-1, 1);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen if (ctx->flags_update_seen) {
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
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.) */
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen trans_flags |= MAILBOX_TRANSACTION_FLAG_HIDE;
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen }
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi ctx->state.trans = mailbox_transaction_begin(box, trans_flags,
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi ctx->reason);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen mail_search_args_init(search_args, box, TRUE,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen &ctx->client->search_saved_uidset);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen ctx->state.search_ctx =
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen mailbox_search_init(ctx->state.trans, search_args, NULL,
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen ctx->fetch_data, wanted_headers);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen ctx->state.cur_str = str_new(default_pool, 8192);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen ctx->state.fetching = TRUE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
ceb8c97c6c9fe0ee7eb544645c6bdb74dfcb519dJosef 'Jeff' Sipek mailbox_header_lookup_unref(&wanted_headers);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainenstatic int imap_fetch_flush_buffer(struct imap_fetch_context *ctx)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen{
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen const unsigned char *data;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen size_t len;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen data = str_data(ctx->state.cur_str);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen len = str_len(ctx->state.cur_str);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
2412873209ff658bc4bd20123af2d6162464c4ffTimo Sirainen if (len == 0)
2412873209ff658bc4bd20123af2d6162464c4ffTimo Sirainen return 0;
2412873209ff658bc4bd20123af2d6162464c4ffTimo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* there's an extra space at the end if we added any fetch items
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen to buffer */
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (data[len-1] == ' ') {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen len--;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen ctx->state.cur_first = FALSE;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen }
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen ctx->state.line_partial = TRUE;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (o_stream_send(ctx->client->output, data, len) < 0)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen return -1;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_truncate(ctx->state.cur_str, 0);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen return 0;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen}
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainenstatic int imap_fetch_send_nil_reply(struct imap_fetch_context *ctx)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen{
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen const struct imap_fetch_context_handler *handler;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (!ctx->state.cur_first)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_append_c(ctx->state.cur_str, ' ');
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen handler = array_idx(&ctx->handlers, ctx->state.cur_handler);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_printfa(ctx->state.cur_str, "%s %s ",
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen handler->name, handler->nil_reply);
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen if (!handler->buffered) {
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return -1;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen }
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return 0;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen}
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainenstatic void imap_fetch_fix_empty_reply(struct imap_fetch_context *ctx)
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen{
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. */
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen str_printfa(ctx->state.cur_str, "UID %u ",
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen ctx->state.cur_mail->uid);
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen }
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen}
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainenstatic bool imap_fetch_cur_failed(struct imap_fetch_context *ctx)
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen{
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen ctx->failures = TRUE;
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen if (ctx->client->set->parsed_fetch_failure ==
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen IMAP_CLIENT_FETCH_FAILURE_DISCONNECT_IMMEDIATELY)
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen return FALSE;
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen
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
289bd999f282a307b05e6f8beef33155a50fb837Timo Sirainen if (ctx->error == MAIL_ERROR_NONE) {
289bd999f282a307b05e6f8beef33155a50fb837Timo Sirainen /* preserve the first error, since it may change in storage. */
289bd999f282a307b05e6f8beef33155a50fb837Timo Sirainen ctx->errstr = p_strdup(ctx->ctx_pool,
289bd999f282a307b05e6f8beef33155a50fb837Timo Sirainen mailbox_get_last_error(ctx->state.cur_mail->box, &ctx->error));
289bd999f282a307b05e6f8beef33155a50fb837Timo Sirainen }
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen return TRUE;
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen}
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenstatic int imap_fetch_more_int(struct imap_fetch_context *ctx, bool cancel)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen struct imap_fetch_state *state = &ctx->state;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen struct client *client = ctx->client;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const struct imap_fetch_context_handler *handlers;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen unsigned int count;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen int ret;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (state->cont_handler != NULL) {
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen ret = state->cont_handler(ctx);
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen if (ret == 0)
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen return 0;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen if (ret < 0) {
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen if (client->output->closed)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return -1;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (state->cur_mail->expunged) {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen /* not an error, just lost it. */
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->skipped_expunged_msgs = TRUE;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen if (imap_fetch_send_nil_reply(ctx) < 0)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return -1;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen } else {
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen if (!imap_fetch_cur_failed(ctx))
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen return -1;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen }
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen }
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->cont_handler = NULL;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->cur_handler++;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (state->cur_input != NULL)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen i_stream_unref(&state->cur_input);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen handlers = array_get(&ctx->handlers, &count);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen for (;;) {
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen CLIENT_OUTPUT_OPTIMAL_SIZE) {
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen ret = o_stream_flush(client->output);
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen if (ret <= 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return ret;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (state->cur_mail == NULL) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (cancel)
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen return 1;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (!mailbox_search_next(state->search_ctx,
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen &state->cur_mail))
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_printfa(state->cur_str, "* %u FETCH (",
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->cur_mail->seq);
f32c6ed9db6f4c535f97a2020401572efc8abf86Timo Sirainen ctx->fetched_mails_count++;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->cur_first = TRUE;
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen state->cur_str_prefix_size = str_len(state->cur_str);
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen i_assert(!state->line_partial);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen for (; state->cur_handler < count; state->cur_handler++) {
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (str_len(state->cur_str) > 0 &&
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen !handlers[state->cur_handler].buffered) {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* first non-buffered handler.
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen flush the buffer. */
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen return -1;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen }
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen i_assert(state->cur_input == NULL);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const struct imap_fetch_context_handler *h =
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen &handlers[state->cur_handler];
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen ret = h->handler(ctx, state->cur_mail,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen h->context);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen if (ret == 0)
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen return 0;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen if (ret < 0) {
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (state->cur_mail->expunged) {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen /* not an error, just lost it. */
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->skipped_expunged_msgs = TRUE;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen if (imap_fetch_send_nil_reply(ctx) < 0)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return -1;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen } else {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen i_assert(ret < 0 ||
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->cont_handler != NULL);
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen if (!imap_fetch_cur_failed(ctx))
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen return -1;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->cont_handler = NULL;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (state->cur_input != NULL)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen i_stream_unref(&state->cur_input);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen imap_fetch_fix_empty_reply(ctx);
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen if (str_len(state->cur_str) > 0 &&
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen (state->line_partial ||
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen str_len(state->cur_str) != state->cur_str_prefix_size)) {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* no non-buffered handlers */
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen if (state->line_partial)
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen o_stream_nsend(client->output, ")\r\n", 3);
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen client->last_output = ioloop_time;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->cur_mail = NULL;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->cur_handler = 0;
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen state->line_partial = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen return ctx->failures ? -1 : 1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenint imap_fetch_more(struct imap_fetch_context *ctx,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen struct client_command_context *cmd)
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen{
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen int ret;
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen
5a7acd67806132cbc1ec9578df60d712d307e4beTimo Sirainen i_assert(ctx->client->output_cmd_lock == NULL ||
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->client->output_cmd_lock == cmd);
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen ret = imap_fetch_more_int(ctx, cmd->cancel);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (ret < 0)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen ctx->state.failed = TRUE;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (ctx->state.line_partial) {
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen /* nothing can be sent until FETCH is finished */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->client->output_cmd_lock = cmd;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
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 if (!ctx->client->destroyed)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_disconnect(ctx->client, "Failed to cancel FETCH");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->client->output_cmd_lock = NULL;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenint imap_fetch_more_no_lock_update(struct imap_fetch_context *ctx)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen int ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ret = imap_fetch_more_int(ctx, FALSE);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ret < 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->state.failed = TRUE;
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen if (ctx->state.line_partial) {
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen /* we can't send any more replies to client, because
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen the FETCH reply wasn't fully sent. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_disconnect(ctx->client,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen "NOTIFY failed in the middle of FETCH reply");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen }
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen return ret;
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen}
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenint imap_fetch_end(struct imap_fetch_context *ctx)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen struct imap_fetch_state *state = &ctx->state;
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainen
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen if (ctx->state.fetching) {
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen ctx->state.fetching = FALSE;
46e17407ed48155ac7290a992216a11b2b2b3cf4Timo Sirainen if (state->line_partial) {
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen imap_fetch_fix_empty_reply(ctx);
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen if (imap_fetch_flush_buffer(ctx) < 0)
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen state->failed = TRUE;
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen if (o_stream_send(ctx->client->output, ")\r\n", 3) < 0)
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen state->failed = TRUE;
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen }
2ba4e9bedb0fa778dfbccec5370018b4d0040d9cTimo Sirainen }
5a7acd67806132cbc1ec9578df60d712d307e4beTimo Sirainen ctx->client->output_cmd_lock = NULL;
5a7acd67806132cbc1ec9578df60d712d307e4beTimo Sirainen
e9fbe5e18b798728041b7e2ffc6c4fa964fc35a3Josef 'Jeff' Sipek str_free(&state->cur_str);
2ba4e9bedb0fa778dfbccec5370018b4d0040d9cTimo Sirainen
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&state->cur_input);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (state->search_ctx != NULL) {
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (mailbox_search_deinit(&state->search_ctx) < 0)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->failed = TRUE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (state->trans != NULL) {
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)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen state->failed = TRUE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen return state->failed ? -1 : 0;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenvoid imap_fetch_free(struct imap_fetch_context **_ctx)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen{
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen struct imap_fetch_context *ctx = *_ctx;
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen const struct imap_fetch_context_handler *handler;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen *_ctx = NULL;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen (void)imap_fetch_end(ctx);
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen array_foreach(&ctx->handlers, handler) {
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen if (handler->want_deinit)
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen handler->handler(ctx, NULL, handler->context);
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen pool_unref(&ctx->ctx_pool);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen}
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_body(struct imap_fetch_context *ctx, struct mail *mail,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen const char *body;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_BODY, &body) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (ctx->state.cur_first)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen ctx->state.cur_first = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen else {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen }
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
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)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_body_init(struct imap_fetch_init_context *ctx)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen if (ctx->name[4] == '\0') {
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_BODY;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, 0, "("BODY_NIL_REPLY")",
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen fetch_body, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return TRUE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen return imap_fetch_body_section_init(ctx);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainenstatic int fetch_bodystructure(struct imap_fetch_context *ctx,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen struct mail *mail, void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen const char *bodystructure;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen &bodystructure) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (ctx->state.cur_first)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen ctx->state.cur_first = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen else {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen }
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
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)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_bodystructure_init(struct imap_fetch_init_context *ctx)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
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)",
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen fetch_bodystructure, NULL);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen return TRUE;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_envelope(struct imap_fetch_context *ctx, struct mail *mail,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen const char *envelope;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE, &envelope) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (ctx->state.cur_first)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen ctx->state.cur_first = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen else {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (o_stream_send(ctx->client->output, " ", 1) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen }
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
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)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
0b1f70057d59ed3fe7a163bd4fde0c75353910f3Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_envelope_init(struct imap_fetch_init_context *ctx)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, 0, ENVELOPE_NIL_REPLY,
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen fetch_envelope, NULL);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen return TRUE;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_flags(struct imap_fetch_context *ctx, struct mail *mail,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen enum mail_flags flags;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const char *const *keywords;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen flags = mail_get_flags(mail);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0 &&
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen !mailbox_is_readonly(mail->box)) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* Add \Seen flag */
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen ctx->state.seen_flags_changed = TRUE;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen flags |= MAIL_SEEN;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen } else if (ctx->flags_show_only_seen_changes) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen }
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords,
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen mail_get_keyword_indexes(mail));
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_append(ctx->state.cur_str, "FLAGS (");
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen imap_write_flags(ctx->state.cur_str, flags, keywords);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_append(ctx->state.cur_str, ") ");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenbool imap_fetch_flags_init(struct imap_fetch_init_context *ctx)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->flags_have_handler = TRUE;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_FLAGS;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen "()", fetch_flags, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return TRUE;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_internaldate(struct imap_fetch_context *ctx, struct mail *mail,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen time_t date;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_received_date(mail, &date) < 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
73d29cffe84aa9742353c40516a09e18385ab341Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_printfa(ctx->state.cur_str, "INTERNALDATE \"%s\" ",
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen imap_to_datetime(date));
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_internaldate_init(struct imap_fetch_init_context *ctx)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
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\"",
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen fetch_internaldate, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return TRUE;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainenstatic int fetch_modseq(struct imap_fetch_context *ctx, struct mail *mail,
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen void *context ATTR_UNUSED)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen{
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen uint64_t modseq;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen modseq = mail_get_modseq(mail);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (ctx->client->highest_fetch_modseq < modseq)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen ctx->client->highest_fetch_modseq = modseq;
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi str_printfa(ctx->state.cur_str, "MODSEQ (%"PRIu64") ", modseq);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen return 1;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen}
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenbool imap_fetch_modseq_init(struct imap_fetch_init_context *ctx)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen{
0ff8b7fd6b7021a845538f6bcf755d97d488fddbTimo Sirainen if (ctx->fetch_ctx->client->nonpermanent_modseqs) {
0ff8b7fd6b7021a845538f6bcf755d97d488fddbTimo Sirainen ctx->error = "FETCH MODSEQ can't be used with non-permanent modseqs";
0ff8b7fd6b7021a845538f6bcf755d97d488fddbTimo Sirainen return FALSE;
0ff8b7fd6b7021a845538f6bcf755d97d488fddbTimo Sirainen }
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen (void)client_enable(ctx->fetch_ctx->client, MAILBOX_FEATURE_CONDSTORE);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen NULL, fetch_modseq, NULL);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen return TRUE;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen}
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fetch_uid(struct imap_fetch_context *ctx, struct mail *mail,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen void *context ATTR_UNUSED)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_printfa(ctx->state.cur_str, "UID %u ", mail->uid);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenbool imap_fetch_uid_init(struct imap_fetch_init_context *ctx)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen NULL, fetch_uid, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return TRUE;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainenstatic int fetch_guid(struct imap_fetch_context *ctx, struct mail *mail,
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen void *context ATTR_UNUSED)
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen{
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen const char *value;
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen if (mail_get_special(mail, MAIL_FETCH_GUID, &value) < 0)
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen return -1;
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_append(ctx->state.cur_str, "X-GUID ");
44f93baa7b8dca7d00bf187cd3db1c15eed384d2Timo Sirainen imap_append_astring(ctx->state.cur_str, value);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_append_c(ctx->state.cur_str, ' ');
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen return 1;
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen}
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_guid_init(struct imap_fetch_init_context *ctx)
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_GUID;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen "", fetch_guid, NULL);
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen return TRUE;
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen}
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainenstatic int fetch_x_mailbox(struct imap_fetch_context *ctx, struct mail *mail,
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen void *context ATTR_UNUSED)
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen{
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen const char *name;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen string_t *mutf7_name;
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen
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. */
f46f53badf6082e289ac38807e701305c521f11dTimo Sirainen return -1;
f46f53badf6082e289ac38807e701305c521f11dTimo Sirainen }
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen mutf7_name = t_str_new(strlen(name)*2);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (imap_utf8_to_utf7(name, mutf7_name) < 0)
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen i_panic("FETCH: Mailbox name not UTF-8: %s", name);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_append(ctx->state.cur_str, "X-MAILBOX ");
44f93baa7b8dca7d00bf187cd3db1c15eed384d2Timo Sirainen imap_append_astring(ctx->state.cur_str, str_c(mutf7_name));
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_append_c(ctx->state.cur_str, ' ');
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen return 1;
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen}
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_x_mailbox_init(struct imap_fetch_init_context *ctx)
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen NULL, fetch_x_mailbox, NULL);
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen return TRUE;
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen}
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainenstatic int fetch_x_real_uid(struct imap_fetch_context *ctx, struct mail *mail,
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainen void *context ATTR_UNUSED)
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainen{
d8615e0bec5fc8ffe6be9f64928c2f26b9b5a4deTimo Sirainen struct mail *real_mail;
d8615e0bec5fc8ffe6be9f64928c2f26b9b5a4deTimo Sirainen
d8615e0bec5fc8ffe6be9f64928c2f26b9b5a4deTimo Sirainen if (mail_get_backend_mail(mail, &real_mail) < 0)
d8615e0bec5fc8ffe6be9f64928c2f26b9b5a4deTimo Sirainen return -1;
d8615e0bec5fc8ffe6be9f64928c2f26b9b5a4deTimo Sirainen str_printfa(ctx->state.cur_str, "X-REAL-UID %u ", real_mail->uid);
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainen return 1;
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainen}
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_x_real_uid_init(struct imap_fetch_init_context *ctx)
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen NULL, fetch_x_real_uid, NULL);
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainen return TRUE;
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainen}
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainen
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainenstatic int fetch_x_savedate(struct imap_fetch_context *ctx, struct mail *mail,
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen void *context ATTR_UNUSED)
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen{
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen time_t date;
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen if (mail_get_save_date(mail, &date) < 0)
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen return -1;
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_printfa(ctx->state.cur_str, "X-SAVEDATE \"%s\" ",
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen imap_to_datetime(date));
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen return 1;
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen}
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenstatic bool fetch_x_savedate_init(struct imap_fetch_init_context *ctx)
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen{
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\"",
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen fetch_x_savedate, NULL);
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen return TRUE;
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen}
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen
16834f18f903048c772112838c015051642a0e77Timo Sirainenstatic const struct imap_fetch_handler
16834f18f903048c772112838c015051642a0e77Timo Sirainenimap_fetch_default_handlers[] = {
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen { "BINARY", imap_fetch_binary_init },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "BODY", fetch_body_init },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "BODYSTRUCTURE", fetch_bodystructure_init },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "ENVELOPE", fetch_envelope_init },
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen { "FLAGS", imap_fetch_flags_init },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { "INTERNALDATE", fetch_internaldate_init },
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen { "MODSEQ", imap_fetch_modseq_init },
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen { "RFC822", imap_fetch_rfc822_init },
c1f8d7ab0d8b15f27bbf33324000fc39751d8564Josef 'Jeff' Sipek { "SNIPPET", imap_fetch_snippet_init },
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen { "UID", imap_fetch_uid_init },
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen { "X-GUID", fetch_guid_init },
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen { "X-MAILBOX", fetch_x_mailbox_init },
e9956754c88fcf31afe016c00a956cafb2c2864cTimo Sirainen { "X-REAL-UID", fetch_x_real_uid_init },
659c1d9d4f454b18dad8b3822e58b93815068c32Timo Sirainen { "X-SAVEDATE", fetch_x_savedate_init }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen};
16834f18f903048c772112838c015051642a0e77Timo Sirainen
16834f18f903048c772112838c015051642a0e77Timo Sirainenvoid imap_fetch_handlers_init(void)
16834f18f903048c772112838c015051642a0e77Timo Sirainen{
2b3b0df76184799317584b596af8df5afec3ebddTimo Sirainen i_array_init(&fetch_handlers, 32);
16834f18f903048c772112838c015051642a0e77Timo Sirainen imap_fetch_handlers_register(imap_fetch_default_handlers,
16834f18f903048c772112838c015051642a0e77Timo Sirainen N_ELEMENTS(imap_fetch_default_handlers));
16834f18f903048c772112838c015051642a0e77Timo Sirainen}
16834f18f903048c772112838c015051642a0e77Timo Sirainen
16834f18f903048c772112838c015051642a0e77Timo Sirainenvoid imap_fetch_handlers_deinit(void)
16834f18f903048c772112838c015051642a0e77Timo Sirainen{
2b3b0df76184799317584b596af8df5afec3ebddTimo Sirainen array_free(&fetch_handlers);
16834f18f903048c772112838c015051642a0e77Timo Sirainen}