cmd-select.c revision 25c9f552d4cad01829c79f475d8fdb95525103b1
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "common.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "seq-range-array.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "commands.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "mail-search-build.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "imap-seqset.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "imap-fetch.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "imap-sync.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include <stdlib.h>
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainenstruct imap_select_context {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen struct client_command_context *cmd;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct mail_storage *storage;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct mailbox *box;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen struct imap_fetch_context *fetch_ctx;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen uint32_t qresync_uid_validity;
657afb33796f8216c568ad813627da89970760beTimo Sirainen uint64_t qresync_modseq;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen ARRAY_TYPE(seq_range) qresync_known_uids;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen ARRAY_TYPE(uint32_t) qresync_sample_seqset;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen ARRAY_TYPE(uint32_t) qresync_sample_uidset;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen unsigned int condstore:1;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen};
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainenstatic int select_qresync_get_uids(struct imap_select_context *ctx,
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen const ARRAY_TYPE(seq_range) *seqset,
657afb33796f8216c568ad813627da89970760beTimo Sirainen const ARRAY_TYPE(seq_range) *uidset)
657afb33796f8216c568ad813627da89970760beTimo Sirainen{
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen const struct seq_range *seq_range, *uid_range;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen struct seq_range_iter seq_iter;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen unsigned int i, seq_count, uid_count, diff, n = 0;
657afb33796f8216c568ad813627da89970760beTimo Sirainen uint32_t seq;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen /* change all n:m ranges to n,m and store the results */
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen seq_range = array_get(seqset, &seq_count);
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen uid_range = array_get(uidset, &uid_count);
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen seq_range_array_iter_init(&seq_iter, seqset);
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen i_array_init(&ctx->qresync_sample_uidset, uid_count);
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen i_array_init(&ctx->qresync_sample_seqset, uid_count);
d368b5e0c6ecc4361de943119db898e9c62e5f2cTimo Sirainen for (i = 0; i < uid_count; i++) {
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen if (!seq_range_array_iter_nth(&seq_iter, n++, &seq))
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen return -1;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen array_append(&ctx->qresync_sample_uidset,
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen &uid_range[i].seq1, 1);
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen array_append(&ctx->qresync_sample_seqset, &seq, 1);
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen diff = uid_range[i].seq2 - uid_range[i].seq1;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen if (diff > 0) {
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen n += diff - 1;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen if (!seq_range_array_iter_nth(&seq_iter, n++, &seq))
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen return -1;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen array_append(&ctx->qresync_sample_uidset,
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen &uid_range[i].seq2, 1);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen array_append(&ctx->qresync_sample_seqset, &seq, 1);
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen }
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen }
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen if (seq_range_array_iter_nth(&seq_iter, n, &seq))
657afb33796f8216c568ad813627da89970760beTimo Sirainen return -1;
657afb33796f8216c568ad813627da89970760beTimo Sirainen return 0;
657afb33796f8216c568ad813627da89970760beTimo Sirainen}
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainenstatic bool
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainenselect_parse_qresync(struct imap_select_context *ctx,
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen const struct imap_arg *args)
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen{
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen ARRAY_TYPE(seq_range) seqset, uidset;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen unsigned int count;
657afb33796f8216c568ad813627da89970760beTimo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if ((ctx->cmd->client->enabled_features &
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen MAILBOX_FEATURE_QRESYNC) == 0) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen client_send_command_error(ctx->cmd, "QRESYNC not enabled");
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return FALSE;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen }
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (args->type != IMAP_ARG_LIST) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen client_send_command_error(ctx->cmd,
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen "QRESYNC parameters missing");
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return FALSE;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen }
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen args = IMAP_ARG_LIST_ARGS(args);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen for (count = 0; args[count].type != IMAP_ARG_EOL; count++) ;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (count < 2 || count > 4 ||
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen args[0].type != IMAP_ARG_ATOM ||
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen args[1].type != IMAP_ARG_ATOM ||
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen (count > 2 && args[2].type != IMAP_ARG_ATOM) ||
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen (count > 3 && args[3].type != IMAP_ARG_LIST)) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen client_send_command_error(ctx->cmd,
826cb2b19f57bb9b6f73018b585bd922e820f9f6Timo Sirainen "Invalid QRESYNC parameters");
826cb2b19f57bb9b6f73018b585bd922e820f9f6Timo Sirainen return FALSE;
826cb2b19f57bb9b6f73018b585bd922e820f9f6Timo Sirainen }
826cb2b19f57bb9b6f73018b585bd922e820f9f6Timo Sirainen ctx->qresync_uid_validity =
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen strtoul(IMAP_ARG_STR_NONULL(&args[0]), NULL, 10);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen ctx->qresync_modseq =
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen strtoull(IMAP_ARG_STR_NONULL(&args[1]), NULL, 10);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (count > 2) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_array_init(&ctx->qresync_known_uids, 64);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (imap_seq_set_parse(IMAP_ARG_STR_NONULL(&args[2]),
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen &ctx->qresync_known_uids) < 0) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen client_send_command_error(ctx->cmd,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "Invalid QRESYNC known-uids");
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return FALSE;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen } else {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen i_array_init(&ctx->qresync_known_uids, 64);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen seq_range_array_add_range(&ctx->qresync_known_uids,
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen 1, (uint32_t)-1);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (count > 3) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen args = IMAP_ARG_LIST_ARGS(&args[3]);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (args[0].type != IMAP_ARG_ATOM ||
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen args[1].type != IMAP_ARG_ATOM ||
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen args[2].type != IMAP_ARG_EOL) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen client_send_command_error(ctx->cmd,
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen "Invalid QRESYNC known set parameters");
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return FALSE;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen t_array_init(&seqset, 32);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (imap_seq_set_parse(IMAP_ARG_STR_NONULL(&args[0]),
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen &seqset) < 0) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen client_send_command_error(ctx->cmd,
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen "Invalid QRESYNC known-sequence-set");
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return FALSE;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen t_array_init(&uidset, 32);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (imap_seq_set_parse(IMAP_ARG_STR_NONULL(&args[1]),
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen &uidset) < 0) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen client_send_command_error(ctx->cmd,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "Invalid QRESYNC known-uid-set");
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen return FALSE;
78ed6a99e980228a75fa59cff84327dc0ea82857Timo Sirainen }
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen if (select_qresync_get_uids(ctx, &seqset, &uidset) < 0) {
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen client_send_command_error(ctx->cmd,
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen "Invalid QRESYNC sets");
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen return FALSE;
78ed6a99e980228a75fa59cff84327dc0ea82857Timo Sirainen }
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen }
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen return TRUE;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen}
78ed6a99e980228a75fa59cff84327dc0ea82857Timo Sirainen
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainenstatic bool
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainenselect_parse_options(struct imap_select_context *ctx,
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen const struct imap_arg *args)
78ed6a99e980228a75fa59cff84327dc0ea82857Timo Sirainen{
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen const char *name;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen while (args->type != IMAP_ARG_EOL) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (args->type != IMAP_ARG_ATOM) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen client_send_command_error(ctx->cmd,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen "SELECT options contain non-atoms.");
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return FALSE;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen name = t_str_ucase(IMAP_ARG_STR(args));
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen args++;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (strcmp(name, "CONDSTORE") == 0)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen ctx->condstore = TRUE;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen else if (strcmp(name, "QRESYNC") == 0) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (!select_parse_qresync(ctx, args))
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return FALSE;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen args++;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen } else {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen client_send_command_error(ctx->cmd,
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen "Unknown FETCH modifier");
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return FALSE;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return TRUE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void select_context_free(struct imap_select_context *ctx)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (array_is_created(&ctx->qresync_known_uids))
3c9fbc33ee42feb08a6ac854ccbe833f538067f2Timo Sirainen array_free(&ctx->qresync_known_uids);
3c9fbc33ee42feb08a6ac854ccbe833f538067f2Timo Sirainen if (array_is_created(&ctx->qresync_sample_seqset))
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen array_free(&ctx->qresync_sample_seqset);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (array_is_created(&ctx->qresync_sample_uidset))
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen array_free(&ctx->qresync_sample_uidset);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainenstatic void cmd_select_finish(struct imap_select_context *ctx, int ret)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (ret < 0) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (ctx->box != NULL)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen mailbox_close(&ctx->box);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen client_send_storage_error(ctx->cmd, ctx->storage);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen ctx->cmd->client->mailbox = NULL;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen } else {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen client_send_tagline(ctx->cmd, mailbox_is_readonly(ctx->box) ?
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen "OK [READ-ONLY] Select completed." :
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen "OK [READ-WRITE] Select completed.");
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen select_context_free(ctx);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic bool cmd_select_continue(struct client_command_context *cmd)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen{
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen struct imap_select_context *ctx = cmd->context;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen int ret;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen if ((ret = imap_fetch_more(ctx->fetch_ctx)) == 0) {
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen /* unfinished */
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen return FALSE;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen ret = imap_fetch_deinit(ctx->fetch_ctx);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen cmd_select_finish(ctx, ret);
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen return TRUE;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen}
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainenstatic int select_qresync(struct imap_select_context *ctx)
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen{
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen struct imap_fetch_context *fetch_ctx;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen struct mail_search_args *search_args;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen search_args = mail_search_build_init();
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen search_args->args->type = SEARCH_UIDSET;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen search_args->args->value.seqset = ctx->qresync_known_uids;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen fetch_ctx = imap_fetch_init(ctx->cmd, ctx->box);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (fetch_ctx == NULL)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return -1;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen fetch_ctx->search_args = search_args;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen fetch_ctx->send_vanished = TRUE;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen fetch_ctx->qresync_sample_seqset = &ctx->qresync_sample_seqset;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen fetch_ctx->qresync_sample_uidset = &ctx->qresync_sample_uidset;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (!imap_fetch_add_unchanged_since(fetch_ctx, ctx->qresync_modseq) ||
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen !imap_fetch_init_handler(fetch_ctx, "UID", NULL) ||
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen !imap_fetch_init_handler(fetch_ctx, "FLAGS", NULL) ||
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen !imap_fetch_init_handler(fetch_ctx, "MODSEQ", NULL)) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen (void)imap_fetch_deinit(fetch_ctx);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return -1;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (imap_fetch_begin(fetch_ctx) == 0) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (imap_fetch_more(fetch_ctx) == 0) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* unfinished */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen ctx->fetch_ctx = fetch_ctx;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen ctx->cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen ctx->cmd->func = cmd_select_continue;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen ctx->cmd->context = ctx;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return FALSE;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return imap_fetch_deinit(fetch_ctx);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen}
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainenstatic int
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainenselect_open(struct imap_select_context *ctx, const char *mailbox, bool readonly)
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen{
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen struct client *client = ctx->cmd->client;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen struct mailbox_status status;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen enum mailbox_open_flags open_flags = 0;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen if (readonly)
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen open_flags |= MAILBOX_OPEN_READONLY | MAILBOX_OPEN_KEEP_RECENT;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen ctx->box = mailbox_open(ctx->storage, mailbox, NULL, open_flags);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (ctx->box == NULL)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return -1;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
4f7720c29123044476d0c44996e38dffa91c36e6Timo Sirainen if (client->enabled_features != 0)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen mailbox_enable(ctx->box, client->enabled_features);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (mailbox_sync(ctx->box, MAILBOX_SYNC_FLAG_FULL_READ,
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen STATUS_MESSAGES | STATUS_RECENT |
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen STATUS_FIRST_UNSEEN_SEQ | STATUS_UIDVALIDITY |
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen STATUS_UIDNEXT | STATUS_KEYWORDS |
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen STATUS_HIGHESTMODSEQ, &status) < 0)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return -1;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen client->mailbox = ctx->box;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen client->select_counter++;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen client->mailbox_examined = readonly;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen client->messages_count = status.messages;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen client->recent_count = status.recent;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen client->uidvalidity = status.uidvalidity;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen client_update_mailbox_flags(client, status.keywords);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen client_send_mailbox_flags(client, TRUE);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen client_send_line(client,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen t_strdup_printf("* %u EXISTS", status.messages));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen client_send_line(client,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen t_strdup_printf("* %u RECENT", status.recent));
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen if (status.first_unseen_seq != 0) {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen client_send_line(client,
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen t_strdup_printf("* OK [UNSEEN %u] First unseen.",
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen status.first_unseen_seq));
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen client_send_line(client,
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen t_strdup_printf("* OK [UIDVALIDITY %u] UIDs valid",
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen status.uidvalidity));
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen client_send_line(client,
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen t_strdup_printf("* OK [UIDNEXT %u] Predicted next UID",
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen status.uidnext));
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen if (status.nonpermanent_modseqs) {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen client_send_line(client,
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen "* OK [NOMODSEQ] No permanent modsequences");
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen } else {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen client_send_line(client,
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen t_strdup_printf("* OK [HIGHESTMODSEQ %llu]",
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen (unsigned long long)status.highest_modseq));
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen client->sync_last_full_modseq = status.highest_modseq;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen }
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen if (ctx->qresync_uid_validity == status.uidvalidity) {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen if (select_qresync(ctx) < 0)
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen return -1;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return 0;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen}
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainenbool cmd_select_full(struct client_command_context *cmd, bool readonly)
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen{
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen struct client *client = cmd->client;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen struct mailbox *box;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen struct imap_select_context *ctx;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen const struct imap_arg *args;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen const char *mailbox;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen int ret;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen /* <mailbox> [(optional parameters)] */
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen if (!client_read_args(cmd, 0, 0, &args))
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return FALSE;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (!IMAP_ARG_TYPE_IS_STRING(args[0].type)) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen client_send_command_error(cmd, "Invalid arguments.");
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen return FALSE;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen mailbox = IMAP_ARG_STR(&args[0]);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen ctx = p_new(cmd->pool, struct imap_select_context, 1);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen ctx->cmd = cmd;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen ctx->storage = client_find_storage(cmd, &mailbox);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (ctx->storage == NULL)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return TRUE;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen if (args[1].type == IMAP_ARG_LIST) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (!select_parse_options(ctx, IMAP_ARG_LIST_ARGS(&args[1]))) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen select_context_free(ctx);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return TRUE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_assert(client->mailbox_change_lock == NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen client->mailbox_change_lock = cmd;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen if (client->mailbox != NULL) {
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen client_search_updates_free(client);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen box = client->mailbox;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen client->mailbox = NULL;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (mailbox_close(&box) < 0) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen client_send_untagged_storage_error(client,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen mailbox_get_storage(box));
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* CLOSED response is required by QRESYNC */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen client_send_line(client, "* OK [CLOSED]");
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (ctx->condstore) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* Enable while no mailbox is opened to avoid sending
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen HIGHESTMODSEQ for previously opened mailbox */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen client_enable(client, MAILBOX_FEATURE_CONDSTORE);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen ret = select_open(ctx, mailbox, readonly);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen cmd_select_finish(ctx, ret);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return TRUE;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen}
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainenbool cmd_select(struct client_command_context *cmd)
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return cmd_select_full(cmd, FALSE);
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen}
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen