cmd-select.c revision 167da1aee2bf5c9cbe7066ff65b406d92df3541c
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-common.h"
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen#include "seq-range-array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "time-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-commands.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-search-build.h"
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen#include "imap-search-args.h"
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen#include "imap-seqset.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-fetch.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-sync.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen#include <stdlib.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct imap_select_context {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct client_command_context *cmd;
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen struct mail_namespace *ns;
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen struct mailbox *box;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen struct timeval start_time;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct imap_fetch_context *fetch_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen uint32_t qresync_uid_validity;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint64_t qresync_modseq;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen ARRAY_TYPE(seq_range) qresync_known_uids;
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen ARRAY_TYPE(uint32_t) qresync_sample_seqset;
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen ARRAY_TYPE(uint32_t) qresync_sample_uidset;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen unsigned int condstore:1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen};
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
2d3aac5be07b96f72cf0551fac35ac74a4f07770Timo Sirainenstatic int select_qresync_get_uids(struct imap_select_context *ctx,
2d3aac5be07b96f72cf0551fac35ac74a4f07770Timo Sirainen const ARRAY_TYPE(seq_range) *seqset,
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen const ARRAY_TYPE(seq_range) *uidset)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen{
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen const struct seq_range *uid_range;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen struct seq_range_iter seq_iter;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen unsigned int i, uid_count, diff, n = 0;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen uint32_t seq;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen
a205d315b0978985ba77d871f44e4a98273612e6Timo Sirainen /* change all n:m ranges to n,m and store the results */
a205d315b0978985ba77d871f44e4a98273612e6Timo Sirainen uid_range = array_get(uidset, &uid_count);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen seq_range_array_iter_init(&seq_iter, seqset);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen i_array_init(&ctx->qresync_sample_uidset, uid_count);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen i_array_init(&ctx->qresync_sample_seqset, uid_count);
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen for (i = 0; i < uid_count; i++) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (!seq_range_array_iter_nth(&seq_iter, n++, &seq))
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return -1;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen array_append(&ctx->qresync_sample_uidset,
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen &uid_range[i].seq1, 1);
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen array_append(&ctx->qresync_sample_seqset, &seq, 1);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen diff = uid_range[i].seq2 - uid_range[i].seq1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (diff > 0) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen n += diff - 1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (!seq_range_array_iter_nth(&seq_iter, n++, &seq))
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return -1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen array_append(&ctx->qresync_sample_uidset,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen &uid_range[i].seq2, 1);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen array_append(&ctx->qresync_sample_seqset, &seq, 1);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (seq_range_array_iter_nth(&seq_iter, n, &seq))
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return -1;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen return 0;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen}
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstatic bool
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenselect_parse_qresync_known_set(struct imap_select_context *ctx,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen const struct imap_arg *args)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen ARRAY_TYPE(seq_range) seqset, uidset;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen const char *str;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen t_array_init(&seqset, 32);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (!imap_arg_get_atom(args, &str) ||
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen imap_seq_set_nostar_parse(str, &seqset) < 0) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client_send_command_error(ctx->cmd,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen "Invalid QRESYNC known-sequence-set");
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return FALSE;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen args++;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen t_array_init(&uidset, 32);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (!imap_arg_get_atom(args, &str) ||
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen imap_seq_set_nostar_parse(str, &uidset) < 0) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client_send_command_error(ctx->cmd,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen "Invalid QRESYNC known-uid-set");
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return FALSE;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen args++;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (select_qresync_get_uids(ctx, &seqset, &uidset) < 0) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen client_send_command_error(ctx->cmd, "Invalid QRESYNC sets");
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen return FALSE;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (!IMAP_ARG_IS_EOL(args)) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client_send_command_error(ctx->cmd,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen "Too many parameters to QRESYNC known set");
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return FALSE;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return TRUE;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenselect_parse_qresync(struct imap_select_context *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct imap_arg *args)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen const struct imap_arg *list_args;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *str;
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen unsigned int count;
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen if ((ctx->cmd->client->enabled_features &
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen MAILBOX_FEATURE_QRESYNC) == 0) {
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen client_send_command_error(ctx->cmd, "QRESYNC not enabled");
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen return FALSE;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen }
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen if (!imap_arg_get_list_full(args, &args, &count)) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen client_send_command_error(ctx->cmd,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "QRESYNC parameters missing");
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return FALSE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (!imap_arg_get_atom(&args[0], &str) ||
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen str_to_uint32(str, &ctx->qresync_uid_validity) < 0 ||
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen !imap_arg_get_atom(&args[1], &str) ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_to_uint64(str, &ctx->qresync_modseq) < 0) {
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen client_send_command_error(ctx->cmd,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen "Invalid QRESYNC parameters");
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen return FALSE;
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen args += 2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_array_init(&ctx->qresync_known_uids, 64);
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen if (imap_arg_get_atom(args, &str)) {
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen if (imap_seq_set_nostar_parse(str, &ctx->qresync_known_uids) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_command_error(ctx->cmd,
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen "Invalid QRESYNC known-uids");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen args++;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen seq_range_array_add_range(&ctx->qresync_known_uids,
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen 1, (uint32_t)-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (imap_arg_get_list(args, &list_args)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!select_parse_qresync_known_set(ctx, list_args))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen args++;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!IMAP_ARG_IS_EOL(args)) {
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen client_send_command_error(ctx->cmd,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Invalid QRESYNC parameters");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainenselect_parse_options(struct imap_select_context *ctx,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct imap_arg *args)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *name;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen while (!IMAP_ARG_IS_EOL(args)) {
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen if (!imap_arg_get_atom(args, &name)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_command_error(ctx->cmd,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen "SELECT options contain non-atoms.");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen name = t_str_ucase(name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen args++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcmp(name, "CONDSTORE") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->condstore = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcmp(name, "QRESYNC") == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!select_parse_qresync(ctx, args))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen args++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_command_error(ctx->cmd,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Unknown FETCH modifier");
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return FALSE;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void select_context_free(struct imap_select_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (array_is_created(&ctx->qresync_known_uids))
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen array_free(&ctx->qresync_known_uids);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (array_is_created(&ctx->qresync_sample_seqset))
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen array_free(&ctx->qresync_sample_seqset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (array_is_created(&ctx->qresync_sample_uidset))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_free(&ctx->qresync_sample_uidset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic void cmd_select_finish(struct imap_select_context *ctx, int ret)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen{
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen const char *resp_code;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen struct timeval end_time;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen int time_msecs;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (ret < 0) {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (ctx->box != NULL)
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen mailbox_free(&ctx->box);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen ctx->cmd->client->mailbox = NULL;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen } else {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen resp_code = mailbox_is_readonly(ctx->box) ?
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen "READ-ONLY" : "READ-WRITE";
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (gettimeofday(&end_time, NULL) < 0)
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen memset(&end_time, 0, sizeof(end_time));
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen time_msecs = timeval_diff_msecs(&end_time, &ctx->start_time);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen client_send_tagline(ctx->cmd, t_strdup_printf(
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen "OK [%s] %s completed (%d.%03d secs).", resp_code,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen ctx->cmd->client->mailbox_examined ? "Examine" : "Select",
a60c1c1fca85402e6fccbf3ae0784b7179ae186cTimo Sirainen time_msecs/1000, time_msecs%1000));
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen }
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen select_context_free(ctx);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen}
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic bool cmd_select_continue(struct client_command_context *cmd)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen{
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen struct imap_select_context *ctx = cmd->context;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen int ret;
325f4573edfa5b751832ac01023f3e81be992bf0Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (imap_fetch_more(ctx->fetch_ctx, cmd) == 0) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen /* unfinished */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return FALSE;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen ret = imap_fetch_end(ctx->fetch_ctx);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (ret < 0)
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen client_send_box_error(ctx->cmd, ctx->box);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen imap_fetch_free(&ctx->fetch_ctx);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen cmd_select_finish(ctx, ret);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return TRUE;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen}
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic int select_qresync(struct imap_select_context *ctx)
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen{
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen struct imap_fetch_context *fetch_ctx;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen struct mail_search_args *search_args;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen struct imap_fetch_qresync_args qresync_args;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen search_args = mail_search_build_init();
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen search_args->args->type = SEARCH_UIDSET;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen search_args->args->value.seqset = ctx->qresync_known_uids;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen imap_search_add_changed_since(search_args, ctx->qresync_modseq);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen memset(&qresync_args, 0, sizeof(qresync_args));
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen qresync_args.qresync_sample_seqset = &ctx->qresync_sample_seqset;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen qresync_args.qresync_sample_uidset = &ctx->qresync_sample_uidset;
a60c1c1fca85402e6fccbf3ae0784b7179ae186cTimo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (imap_fetch_send_vanished(ctx->cmd->client, ctx->box,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen search_args, &qresync_args) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_search_args_unref(&search_args);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fetch_ctx = imap_fetch_alloc(ctx->cmd->client, ctx->cmd->pool);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_uid_init);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_flags_init);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_modseq_init);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen imap_fetch_begin(fetch_ctx, ctx->box, search_args);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen mail_search_args_unref(&search_args);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (imap_fetch_more(fetch_ctx, ctx->cmd) == 0) {
dc049c5e83d947aaf1b97c26ae819cc9577e0475Timo Sirainen /* unfinished */
dc049c5e83d947aaf1b97c26ae819cc9577e0475Timo Sirainen ctx->fetch_ctx = fetch_ctx;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen ctx->cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen ctx->cmd->func = cmd_select_continue;
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen ctx->cmd->context = ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (imap_fetch_end(fetch_ctx) < 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return -1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen imap_fetch_free(&fetch_ctx);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
08fa343b3aace9343da3195686c65c5326eda207Timo Sirainenstatic int
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainenselect_open(struct imap_select_context *ctx, const char *mailbox, bool readonly)
08fa343b3aace9343da3195686c65c5326eda207Timo Sirainen{
dc049c5e83d947aaf1b97c26ae819cc9577e0475Timo Sirainen struct client *client = ctx->cmd->client;
dc049c5e83d947aaf1b97c26ae819cc9577e0475Timo Sirainen struct mailbox_status status;
dc049c5e83d947aaf1b97c26ae819cc9577e0475Timo Sirainen enum mailbox_flags flags = 0;
dc049c5e83d947aaf1b97c26ae819cc9577e0475Timo Sirainen int ret = 0;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (readonly)
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen flags |= MAILBOX_FLAG_READONLY;
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen flags |= MAILBOX_FLAG_DROP_RECENT;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen ctx->box = mailbox_alloc(ctx->ns->list, mailbox, flags);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (mailbox_open(ctx->box) < 0) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client_send_box_error(ctx->cmd, ctx->box);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mailbox_free(&ctx->box);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return -1;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (client->enabled_features != 0)
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen ret = mailbox_enable(ctx->box, client->enabled_features);
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen if (ret < 0 ||
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen mailbox_sync(ctx->box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client_send_box_error(ctx->cmd, ctx->box);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return -1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mailbox_get_open_status(ctx->box, STATUS_MESSAGES | STATUS_RECENT |
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen STATUS_FIRST_UNSEEN_SEQ | STATUS_UIDVALIDITY |
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen STATUS_UIDNEXT | STATUS_KEYWORDS |
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen STATUS_HIGHESTMODSEQ, &status);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen client->mailbox = ctx->box;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client->mailbox_examined = readonly;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client->messages_count = status.messages;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client->recent_count = status.recent;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client->uidvalidity = status.uidvalidity;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen client->notify_uidnext = status.uidnext;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client_update_mailbox_flags(client, status.keywords);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client_send_mailbox_flags(client, TRUE);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen client_send_line(client,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen t_strdup_printf("* %u EXISTS", status.messages));
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen client_send_line(client,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen t_strdup_printf("* %u RECENT", status.recent));
if (status.first_unseen_seq != 0) {
client_send_line(client,
t_strdup_printf("* OK [UNSEEN %u] First unseen.",
status.first_unseen_seq));
}
client_send_line(client,
t_strdup_printf("* OK [UIDVALIDITY %u] UIDs valid",
status.uidvalidity));
client_send_line(client,
t_strdup_printf("* OK [UIDNEXT %u] Predicted next UID",
status.uidnext));
client->nonpermanent_modseqs = status.nonpermanent_modseqs;
if (status.nonpermanent_modseqs) {
client_send_line(client,
"* OK [NOMODSEQ] No permanent modsequences");
} else if (!status.no_modseq_tracking) {
client_send_line(client,
t_strdup_printf("* OK [HIGHESTMODSEQ %llu] Highest",
(unsigned long long)status.highest_modseq));
client->sync_last_full_modseq = status.highest_modseq;
}
if (ctx->qresync_uid_validity == status.uidvalidity &&
status.uidvalidity != 0 && !client->nonpermanent_modseqs) {
if ((ret = select_qresync(ctx)) < 0) {
client_send_box_error(ctx->cmd, ctx->box);
return -1;
}
} else {
ret = 1;
}
return ret;
}
static void close_selected_mailbox(struct client *client)
{
struct mailbox *box;
if (client->mailbox == NULL)
return;
client_search_updates_free(client);
box = client->mailbox;
client->mailbox = NULL;
mailbox_free(&box);
/* CLOSED response is required by QRESYNC */
client_send_line(client, "* OK [CLOSED] Previous mailbox closed.");
}
bool cmd_select_full(struct client_command_context *cmd, bool readonly)
{
struct client *client = cmd->client;
struct imap_select_context *ctx;
const struct imap_arg *args, *list_args;
const char *mailbox, *error;
int ret;
/* <mailbox> [(optional parameters)] */
if (!client_read_args(cmd, 0, 0, &args))
return FALSE;
if (!imap_arg_get_astring(args, &mailbox)) {
close_selected_mailbox(client);
client_send_command_error(cmd, "Invalid arguments.");
return FALSE;
}
ctx = p_new(cmd->pool, struct imap_select_context, 1);
ctx->cmd = cmd;
ctx->ns = client_find_namespace_full(cmd->client, &mailbox, &error);
if (ctx->ns == NULL) {
close_selected_mailbox(client);
client_send_tagline(cmd, error);
return TRUE;
}
(void)gettimeofday(&ctx->start_time, NULL);
if (imap_arg_get_list(&args[1], &list_args)) {
if (!select_parse_options(ctx, list_args)) {
select_context_free(ctx);
close_selected_mailbox(client);
return TRUE;
}
}
i_assert(client->mailbox_change_lock == NULL);
client->mailbox_change_lock = cmd;
close_selected_mailbox(client);
if (ctx->condstore) {
/* Enable while no mailbox is opened to avoid sending
HIGHESTMODSEQ for previously opened mailbox */
(void)client_enable(client, MAILBOX_FEATURE_CONDSTORE);
}
ret = select_open(ctx, mailbox, readonly);
if (ret == 0)
return FALSE;
cmd_select_finish(ctx, ret);
return TRUE;
}
bool cmd_select(struct client_command_context *cmd)
{
return cmd_select_full(cmd, FALSE);
}