imap-state.c revision f3fa33be556fd5199dcc856b02b58128bdf693a5
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2014-2015 Dovecot authors, see the included COPYING file */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "imap-common.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "crc32.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "numpack.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "net.h"
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen#include "ostream.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "str.h"
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen#include "str-sanitize.h"
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen#include "imap-util.h"
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen#include "mail-search-build.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "mail-storage.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "mailbox-recent-flags.h"
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen#include "imap-client.h"
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen#include "imap-fetch.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "imap-search-args.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "imap-state.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenenum imap_state_type_public {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen IMAP_STATE_TYPE_MAILBOX = 'B',
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen IMAP_STATE_TYPE_ENABLED_FEATURES = 'F',
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen IMAP_STATE_TYPE_SEARCHRES = '1',
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen};
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainenenum imap_state_type_internal {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen IMAP_STATE_TYPE_ID_LOGGED = 'I',
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen IMAP_STATE_TYPE_TLS_COMPRESSION = 'C',
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen IMAP_STATE_TYPE_IDLE_CMD_TAG = 'T'
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen};
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenenum imap_state_feature {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen IMAP_STATE_FEATURE_CONDSTORE = 'C',
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen IMAP_STATE_FEATURE_QRESYNC = 'Q'
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen};
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstruct mailbox_import_state {
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen const char *vname;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen guid_128_t mailbox_guid;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen bool examined;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uint32_t keywords_count, keywords_crc32, uids_crc32;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uint32_t uidvalidity, uidnext, messages;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uint64_t highest_modseq;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ARRAY_TYPE(seq_range) recent_uids;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen};
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic void
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenexport_seq_range(buffer_t *dest, const ARRAY_TYPE(seq_range) *range)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const struct seq_range *uids;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen unsigned int i, count;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uint32_t next_uid;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uids = array_get(range, &count);
2200adee458ca662d32b5ec0e01d8c5cba0cc0a8Timo Sirainen numpack_encode(dest, count);
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen next_uid = 1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0; i < count; i++) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(uids[i].seq1 >= next_uid);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (uids[i].seq1 == uids[i].seq2) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen numpack_encode(dest, (uids[i].seq1 - next_uid) << 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else {
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen numpack_encode(dest, 1 | ((uids[i].seq1 - next_uid) << 1));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen numpack_encode(dest, uids[i].seq2 - uids[i].seq1 - 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen next_uid = uids[i].seq2 + 1;
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen }
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainenimport_seq_range(const unsigned char **data, const unsigned char *end,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ARRAY_TYPE(seq_range) *range)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
35ef661bd85c64834e3e34eeeb3c393b81108760Timo Sirainen uint32_t i, count, next_uid, num, uid1, uid2;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (numpack_decode32(data, end, &count) < 0)
35ef661bd85c64834e3e34eeeb3c393b81108760Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen next_uid = 1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0; i < count; i++) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (numpack_decode32(data, end, &num) < 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uid1 = next_uid + (num >> 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if ((num & 1) == 0) {
c39c3d8089fbdd8eb34646c25167aa4551064cf4Timo Sirainen uid2 = uid1;
c39c3d8089fbdd8eb34646c25167aa4551064cf4Timo Sirainen seq_range_array_add(range, uid1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else {
bd63b5b860658b01b1f46f26d406e1e4a9dc019aTimo Sirainen if (numpack_decode32(data, end, &num) < 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uid2 = uid1 + num + 1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen seq_range_array_add_range(range, uid1, uid2);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen next_uid = uid2 + 1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenint imap_state_export_internal(struct client *client, buffer_t *dest,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* the only IMAP command we allow running is IDLE or X-STATE */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (client->command_queue_size > 1) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Multiple commands in progress";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (client->command_queue == NULL ||
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen strcasecmp(client->command_queue->name, "IDLE") != 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* this would require saving the seq <-> uid mapping
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen and restore it on import. quite a lot of trouble if
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen messages have been expunged in the mean time. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Non-IDLE connections not supported currently";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return client->v.state_export(client, TRUE, dest, error_r);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenint imap_state_export_external(struct client *client, buffer_t *dest,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (client->command_queue_size > 1) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Multiple commands in progress";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(client->command_queue_size == 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(strcmp(client->command_queue->name, "X-STATE") == 0);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen return client->v.state_export(client, FALSE, dest, error_r);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen}
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenstatic int
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenimap_state_import(struct client *client, bool internal,
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen const unsigned char *data, size_t size, const char **error_r)
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen{
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen ssize_t ret;
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen while (size > 0) {
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen ret = client->v.state_import(client, internal,
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen data, size, error_r);
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen if (ret <= 0) {
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen i_assert(*error_r != NULL);
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen return ret < 0 ? -1 : 0;
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen }
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen i_assert((size_t)ret <= size);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen data += ret;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen size -= ret;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 1;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen}
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenint imap_state_import_internal(struct client *client,
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen const unsigned char *data, size_t size,
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen const char **error_r)
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen{
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen return imap_state_import(client, TRUE, data, size, error_r);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen}
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenint imap_state_import_external(struct client *client,
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen const unsigned char *data, size_t size,
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen const char **error_r)
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen{
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen return imap_state_import(client, FALSE, data, size, error_r);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen}
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenstatic int
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenimap_state_export_mailbox_mails(buffer_t *dest, struct mailbox *box,
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen const char **error_r)
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen{
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen struct mailbox_transaction_context *trans;
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen struct mail_search_args *search_args;
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen struct mail_search_context *search_ctx;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen struct mail *mail;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen ARRAY_TYPE(seq_range) recent_uids;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen uint32_t crc = 0;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen int ret = 1;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen search_args = mail_search_build_init();
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen mail_search_build_add_all(search_args);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen trans = mailbox_transaction_begin(box, 0);
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen mail_search_args_unref(&search_args);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen t_array_init(&recent_uids, 8);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen while (mailbox_search_next(search_ctx, &mail)) {
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen crc = crc32_data_more(crc, &mail->uid, sizeof(mail->uid));
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if ((mail_get_flags(mail) & MAIL_RECENT) != 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen seq_range_array_add(&recent_uids, mail->uid);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (mailbox_search_deinit(&search_ctx) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = mailbox_get_last_error(box, NULL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = -1;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen }
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen (void)mailbox_transaction_commit(&trans);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen numpack_encode(dest, crc);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen export_seq_range(dest, &recent_uids);
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen return ret;
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen}
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainenstatic uint32_t
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainenmailbox_status_keywords_crc32(const struct mailbox_status *status)
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen{
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen const char *const *strp;
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen uint32_t crc = 0;
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen array_foreach(status->keywords, strp)
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen crc = crc32_str(*strp);
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen return crc;
30f6ac0eaf2be81072ee078ba5b232c368b89ff1Timo Sirainen}
30f6ac0eaf2be81072ee078ba5b232c368b89ff1Timo Sirainen
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainenstatic int
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainenimap_state_export_mailbox(buffer_t *dest, struct client *client,
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen struct mailbox *box, const char **error_r)
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen{
8c3872c26b18421d62c52cbfe0b81b1d79239f89Timo Sirainen struct mailbox_status status;
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen struct mailbox_metadata metadata;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char *vname = mailbox_get_vname(box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen enum mail_error mail_error;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen mailbox_get_open_status(box, STATUS_UIDVALIDITY | STATUS_UIDNEXT |
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen STATUS_MESSAGES | STATUS_HIGHESTMODSEQ |
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen STATUS_KEYWORDS,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen &status);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (status.nonpermanent_modseqs) {
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen *error_r = "Nonpermanent modseqs";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen }
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = mailbox_get_last_error(box, &mail_error);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* if the selected mailbox can't have a GUID, fail silently */
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen return mail_error == MAIL_ERROR_NOTPOSSIBLE ? 0 : -1;
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen }
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append_c(dest, IMAP_STATE_TYPE_MAILBOX);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append(dest, vname, strlen(vname)+1);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append(dest, metadata.guid, sizeof(metadata.guid));
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append_c(dest, client->mailbox_examined ? 1 : 0);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen numpack_encode(dest, status.uidvalidity);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen numpack_encode(dest, status.uidnext);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen numpack_encode(dest, status.messages);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0 &&
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen !client->nonpermanent_modseqs)
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen numpack_encode(dest, client->sync_last_full_modseq);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen else
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen numpack_encode(dest, status.highest_modseq);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen /* keywords count + CRC32 should be enough to figure out if it
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen needs to be resent */
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen numpack_encode(dest, array_count(status.keywords));
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen numpack_encode(dest, mailbox_status_keywords_crc32(&status));
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen /* we're now basically done, but just in case there's a bug add a
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen checksum of the currently existing UIDs and verify it when
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen importing. this also writes the list of recent UIDs. */
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen return imap_state_export_mailbox_mails(dest, box, error_r);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen}
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenint imap_state_export_base(struct client *client, bool internal,
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen buffer_t *dest, const char **error_r)
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen{
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen int ret;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen str_append(dest, "base\n");
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if (array_is_created(&client->search_updates) &&
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen array_count(&client->search_updates) > 0) {
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen /* these could be tricky */
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen *error_r = "SEARCH=CONTEXT updates not supported currently";
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen return 0;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen }
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if (client->notify_ctx != NULL) {
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen /* FIXME: this really should be supported. also IDLE wouldn't
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen be needed if NOTIFY allows sending EXPUNGEs to selected
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen mailbox. */
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen *error_r = "NOTIFY not supported currently";
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen return 0;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen }
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen if (client->mailbox != NULL) {
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen ret = imap_state_export_mailbox(dest, client,
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen client->mailbox, error_r);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if (ret <= 0)
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen return ret;
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen }
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen /* IMAP features */
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if (client->enabled_features != 0) {
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen i_assert((client->enabled_features & ~(MAILBOX_FEATURE_CONDSTORE |
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen MAILBOX_FEATURE_QRESYNC)) == 0);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen buffer_append_c(dest, IMAP_STATE_TYPE_ENABLED_FEATURES);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_CONDSTORE) != 0)
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen buffer_append_c(dest, IMAP_STATE_FEATURE_CONDSTORE);
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0)
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen buffer_append_c(dest, IMAP_STATE_FEATURE_QRESYNC);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append_c(dest, '\0');
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen }
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen if (internal) {
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen if (client->id_logged)
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append_c(dest, IMAP_STATE_TYPE_ID_LOGGED);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen if (client->tls_compression)
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append_c(dest, IMAP_STATE_TYPE_TLS_COMPRESSION);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen if (client->command_queue != NULL) {
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen i_assert(strcasecmp(client->command_queue->name, "IDLE") == 0);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append_c(dest, IMAP_STATE_TYPE_IDLE_CMD_TAG);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append(dest, client->command_queue->tag,
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen strlen(client->command_queue->tag) + 1);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen }
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen }
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen /* IMAP SEARCHRES extension */
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen if (array_is_created(&client->search_saved_uidset) &&
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen array_count(&client->search_saved_uidset) > 0) {
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append_c(dest, IMAP_STATE_TYPE_SEARCHRES);
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen export_seq_range(dest, &client->search_saved_uidset);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_string(const unsigned char **data, const unsigned char *end,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **str_r)
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen{
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen const unsigned char *p;
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen p = memchr(*data, '\0', end - *data);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (p == NULL)
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *str_r = (const void *)*data;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *data = p + 1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_send_expunges(struct client *client,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const struct mailbox_import_state *state,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int *expunge_count_r,
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox_transaction_context *trans;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_search_args *search_args;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_search_context *search_ctx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail *mail;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen uint32_t crc = 0, seq, expunged_uid;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ARRAY_TYPE(seq_range) uids_filter, expunged_uids;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ARRAY_TYPE(uint32_t) expunged_seqs;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct seq_range_iter iter;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const uint32_t *seqs;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int i, expunge_count, n = 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen string_t *str;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen int ret = 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *expunge_count_r = 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (state->messages == 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* the mailbox was empty originally - there couldn't be any
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen pending expunges. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen }
b3070aca2aa0dbdcc7f30e6e2bb1f0455127a343Timo Sirainen if (state->uidnext <= 1) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Invalid UIDNEXT";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
7e8bfb5b0af9606f131fc440e61f3752da335ac9Timo Sirainen
7e8bfb5b0af9606f131fc440e61f3752da335ac9Timo Sirainen /* get all the message UIDs expunged since the last known modseq */
7e8bfb5b0af9606f131fc440e61f3752da335ac9Timo Sirainen t_array_init(&uids_filter, 1);
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen t_array_init(&expunged_uids, 128);
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen seq_range_array_add_range(&uids_filter, 1, state->uidnext-1);
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen if (!mailbox_get_expunged_uids(client->mailbox, state->highest_modseq,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen &uids_filter, &expunged_uids)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = t_strdup_printf(
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "Couldn't get recently expunged UIDs "
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "(uidnext=%u highest_modseq=%llu)", state->uidnext,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen (unsigned long long)state->highest_modseq);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen seq_range_array_iter_init(&iter, &expunged_uids);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen search_args = mail_search_build_init();
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_search_build_add_all(search_args);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen trans = mailbox_transaction_begin(client->mailbox, 0);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_search_args_unref(&search_args);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* find sequence numbers for the expunged UIDs */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen t_array_init(&expunged_seqs, array_count(&expunged_uids)+1); seq = 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen while (mailbox_search_next(search_ctx, &mail)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen while (seq_range_array_iter_nth(&iter, n, &expunged_uid) &&
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen expunged_uid < mail->uid) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen seq++; n++;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen array_append(&expunged_seqs, &seq, 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen crc = crc32_data_more(crc, &expunged_uid,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen sizeof(expunged_uid));
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen }
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen if (seq == state->messages)
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen break;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen crc = crc32_data_more(crc, &mail->uid, sizeof(mail->uid));
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen if (++seq == state->messages)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen break;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen while (seq_range_array_iter_nth(&iter, n, &expunged_uid)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen seq++; n++;
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen array_append(&expunged_seqs, &seq, 1);
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen crc = crc32_data_more(crc, &expunged_uid,
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen sizeof(expunged_uid));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (mailbox_search_deinit(&search_ctx) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = mailbox_get_last_error(client->mailbox, NULL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else if (seq != state->messages) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Message count mismatch after handling expunges";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = -1;
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen (void)mailbox_transaction_commit(&trans);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (ret < 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen seqs = array_get(&expunged_seqs, &expunge_count);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (client->messages_count + expunge_count < state->messages) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Message count too low after handling expunges";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (crc != state->uids_crc32) {
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen *error_r = "Message UIDs CRC32 mismatch";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) == 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen str = t_str_new(32);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = expunge_count; i > 0; i--) {
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen str_truncate(str, 0);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen str_printfa(str, "* %u EXPUNGE", seqs[i-1]);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client_send_line(client, str_c(str));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen str = str_new(default_pool, 128);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen str_append(str, "* VANISHED ");
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen imap_write_seq_range(str, &expunged_uids);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen str_append(str, "\r\n");
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen o_stream_nsend(client->output, str_data(str), str_len(str));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen str_free(&str);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen *expunge_count_r = expunge_count;
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen return 0;
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainenstatic int
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_send_flag_changes(struct client *client,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const struct mailbox_import_state *state)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct imap_fetch_context *fetch_ctx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_search_args *search_args;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ARRAY_TYPE(seq_range) old_uids;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen pool_t pool;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen int ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen if (state->messages == 0)
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen t_array_init(&old_uids, 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen seq_range_array_add_range(&old_uids, 1, state->uidnext-1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen search_args = mail_search_build_init();
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen search_args->args->type = SEARCH_UIDSET;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen search_args->args->value.seqset = old_uids;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen imap_search_add_changed_since(search_args, state->highest_modseq);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen pool = pool_alloconly_create("imap state flag changes", 1024);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen fetch_ctx = imap_fetch_alloc(client, pool);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen pool_unref(&pool);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_flags_init);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_uid_init);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen imap_fetch_init_nofail_handler(fetch_ctx, imap_fetch_modseq_init);
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen }
c8c4bbf6b1415e9d0845bc8f1cd6d19b76ab0392Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen imap_fetch_begin(fetch_ctx, client->mailbox, search_args);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_search_args_unref(&search_args);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen /* FIXME: ideally do this asynchronously.. */
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen while (imap_fetch_more_no_lock_update(fetch_ctx) == 0) ;
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = imap_fetch_end(fetch_ctx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen imap_fetch_free(&fetch_ctx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic ssize_t
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_state_mailbox_struct(const unsigned char *data, size_t size,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox_import_state *state_r,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const unsigned char *p = data, *end = data + size;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen memset(state_r, 0, sizeof(*state_r));
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen t_array_init(&state_r->recent_uids, 8);
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* vname */
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen if (import_string(&p, end, &state_r->vname) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Mailbox state truncated at name";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* GUID */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (end-p < (int)sizeof(state_r->mailbox_guid)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Mailbox state truncated at GUID";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen memcpy(state_r->mailbox_guid, p, sizeof(state_r->mailbox_guid));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen p += sizeof(state_r->mailbox_guid);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen if (guid_128_is_empty(state_r->mailbox_guid)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Empty GUID";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* EXAMINEd vs SELECTed */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (p == end) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Mailbox state truncated at examined-flag";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen state_r->examined = p[0] != 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen p++;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* mailbox state */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (numpack_decode32(&p, end, &state_r->uidvalidity) < 0 ||
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen numpack_decode32(&p, end, &state_r->uidnext) < 0 ||
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen numpack_decode32(&p, end, &state_r->messages) < 0 ||
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen numpack_decode(&p, end, &state_r->highest_modseq) < 0 ||
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen numpack_decode32(&p, end, &state_r->keywords_count) < 0 ||
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen numpack_decode32(&p, end, &state_r->keywords_crc32) < 0 ||
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen numpack_decode32(&p, end, &state_r->uids_crc32) < 0 ||
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen import_seq_range(&p, end, &state_r->recent_uids) < 0) {
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen *error_r = "Mailbox state truncated";
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen if (state_r->uidvalidity == 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Empty UIDVALIDITY";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (state_r->uidnext == 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Empty UIDNEXT";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return p - data;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_state_mailbox_open(struct client *client,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const struct mailbox_import_state *state,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_namespace *ns;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox *box;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox_metadata metadata;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox_status status;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const struct seq_range *range;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen enum mailbox_flags flags = 0;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen unsigned int expunge_count;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen uint32_t uid;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen int ret = 0;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ns = mail_namespace_find(client->user->namespaces, state->vname);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen if (ns == NULL) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Namespace not found for mailbox";
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen if (state->examined)
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen flags |= MAILBOX_FLAG_READONLY;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen else
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen flags |= MAILBOX_FLAG_DROP_RECENT;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box = mailbox_alloc(ns->list, state->vname, flags);
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen if (mailbox_open(box) < 0) {
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen *error_r = t_strdup_printf("Couldn't open mailbox: %s",
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox_get_last_error(box, NULL));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox_free(&box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (client->enabled_features != 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = mailbox_enable(box, client->enabled_features);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (ret < 0 || mailbox_sync(box, 0) < 0) {
7faf475a2faea9ac291898a6593870b01fbc30d4Timo Sirainen *error_r = t_strdup_printf("Couldn't sync mailbox: %s",
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox_get_last_error(box, NULL));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox_free(&box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* verify that this still looks like the same mailbox */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = mailbox_get_last_error(box, NULL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (!guid_128_equals(metadata.guid, state->mailbox_guid)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Mailbox GUID has changed";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox_get_open_status(box, STATUS_UIDVALIDITY | STATUS_UIDNEXT |
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen STATUS_HIGHESTMODSEQ | STATUS_RECENT |
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen STATUS_KEYWORDS, &status);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen if (status.uidvalidity != state->uidvalidity) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Mailbox UIDVALIDITY has changed";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (status.uidnext < state->uidnext) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Mailbox UIDNEXT shrank";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (status.highest_modseq < state->highest_modseq) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Mailbox HIGHESTMODSEQ shrank";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client->mailbox = box;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client->mailbox_examined = state->examined;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client->messages_count = status.messages;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client->recent_count = status.recent;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen client->uidvalidity = status.uidvalidity;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client->notify_uidnext = status.uidnext;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen if (import_send_expunges(client, state, &expunge_count, error_r) < 0)
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(expunge_count <= state->messages);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (state->messages - expunge_count > client->messages_count) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Mailbox message count shrank";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
7faf475a2faea9ac291898a6593870b01fbc30d4Timo Sirainen }
7faf475a2faea9ac291898a6593870b01fbc30d4Timo Sirainen if (state->messages - expunge_count < client->messages_count) {
12e32734b3fe762c647c1ae5552185517a988cf8Timo Sirainen /* new messages arrived */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client_send_line(client,
7faf475a2faea9ac291898a6593870b01fbc30d4Timo Sirainen t_strdup_printf("* %u EXISTS", client->messages_count));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client_send_line(client,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen t_strdup_printf("* %u RECENT", client->recent_count));
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen }
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen client_update_mailbox_flags(client, status.keywords);
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen array_foreach(&state->recent_uids, range) {
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen for (uid = range->seq1; uid <= range->seq2; uid++)
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen mailbox_recent_flags_set_uid_forced(box, uid);
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen }
e9d659ad49a3cf2190606a62289c86347608bffaTimo Sirainen if (array_count(status.keywords) == state->keywords_count &&
e9d659ad49a3cf2190606a62289c86347608bffaTimo Sirainen mailbox_status_keywords_crc32(&status) == state->keywords_crc32) {
e9d659ad49a3cf2190606a62289c86347608bffaTimo Sirainen /* no changes to keywords */
e9d659ad49a3cf2190606a62289c86347608bffaTimo Sirainen client->keywords.announce_count = state->keywords_count;
2200adee458ca662d32b5ec0e01d8c5cba0cc0a8Timo Sirainen } else {
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen client_send_mailbox_flags(client, TRUE);
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen }
2200adee458ca662d32b5ec0e01d8c5cba0cc0a8Timo Sirainen if (import_send_flag_changes(client, state) < 0) {
2200adee458ca662d32b5ec0e01d8c5cba0cc0a8Timo Sirainen *error_r = "Couldn't send flag changes";
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen return -1;
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen }
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0 &&
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen !client->nonpermanent_modseqs &&
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen status.highest_modseq != state->highest_modseq) {
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen client_send_line(client, t_strdup_printf(
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "* OK [HIGHESTMODSEQ %llu] Highest",
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen (unsigned long long)status.highest_modseq));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client->sync_last_full_modseq = status.highest_modseq;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainenstatic ssize_t
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainenimport_state_mailbox(struct client *client, const unsigned char *data,
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen size_t size, const char **error_r)
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen{
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen struct mailbox_import_state state;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ssize_t ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (client->mailbox != NULL) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Duplicate mailbox state";
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen return 0;
0e7d5ff38f28d8c85e197a031bbb66b322ff89e6Timo Sirainen }
0e7d5ff38f28d8c85e197a031bbb66b322ff89e6Timo Sirainen
0e7d5ff38f28d8c85e197a031bbb66b322ff89e6Timo Sirainen ret = import_state_mailbox_struct(data, size, &state, error_r);
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen if (ret <= 0) {
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen i_assert(*error_r != NULL);
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen return ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen if (import_state_mailbox_open(client, &state, error_r) < 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainenstatic ssize_t
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainenimport_state_enabled_features(struct client *client, const unsigned char *data,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen size_t size, const char **error_r)
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen enum imap_state_feature feature;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen size_t i = 0;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen for (i = 0; i < size; i++) {
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen if (data[i] == '\0')
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen return i+1;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen feature = data[i];
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen switch (feature) {
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen case IMAP_STATE_FEATURE_CONDSTORE:
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen client->enabled_features |= MAILBOX_FEATURE_CONDSTORE;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen break;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen case IMAP_STATE_FEATURE_QRESYNC:
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen client->enabled_features |= MAILBOX_FEATURE_QRESYNC;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen break;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen default:
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen *error_r = t_strdup_printf(
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen "Unknown feature '%c'", feature);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Non-terminated features list";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic ssize_t
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_state_searchres(struct client *client, const unsigned char *data,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen size_t size, const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const unsigned char *p = data;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen i_array_init(&client->search_saved_uidset, 128);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen if (import_seq_range(&p, data+size, &client->search_saved_uidset) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Invalid SEARCHRES seq-range";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return p - data;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic ssize_t
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_state_id_logged(struct client *client,
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen const unsigned char *data ATTR_UNUSED,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen size_t size ATTR_UNUSED,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **error_r ATTR_UNUSED)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client->id_logged = TRUE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen}
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainenstatic ssize_t
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainenimport_state_tls_compression(struct client *client,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const unsigned char *data ATTR_UNUSED,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen size_t size ATTR_UNUSED,
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen const char **error_r ATTR_UNUSED)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client->tls_compression = TRUE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic ssize_t
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_state_idle_cmd_tag(struct client *client, const unsigned char *data,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen size_t size, const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const unsigned char *p = data, *end = data + size;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char *tag;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (import_string(&p, end, &tag) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Missing idle tag";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (client->state_import_idle_continue) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* IDLE command continues */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct client_command_context *cmd;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct command *command;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen cmd = client_command_alloc(client);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen cmd->tag = p_strdup(cmd->pool, tag);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen cmd->name = "IDLE";
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen command = command_find("IDLE");
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(command != NULL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen cmd->func = command->func;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen cmd->cmd_flags = command->flags;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (command_exec(cmd)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* IDLE terminated because of an external change, but
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen DONE was already buffered */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client_command_free(&cmd);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client_add_missing_io(client);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(cmd->state == CLIENT_COMMAND_STATE_WAIT_INPUT);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* we're finishing IDLE command */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client_send_line(client, t_strdup_printf(
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "%s %s Idle completed.", tag,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client->state_import_bad_idle_done ? "BAD" : "OK"));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return p - data;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic struct {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen enum imap_state_type_public type;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ssize_t (*import)(struct client *client, const unsigned char *data,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen size_t size, const char **error_r);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen} imap_states_public[] = {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen { IMAP_STATE_TYPE_MAILBOX, import_state_mailbox },
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen { IMAP_STATE_TYPE_ENABLED_FEATURES, import_state_enabled_features },
c6afd726060aae56b6622c6c52aec10231c4bf1cTimo Sirainen { IMAP_STATE_TYPE_SEARCHRES, import_state_searchres }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen};
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic struct {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen enum imap_state_type_internal type;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ssize_t (*import)(struct client *client, const unsigned char *data,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen size_t size, const char **error_r);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen} imap_states_internal[] = {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen { IMAP_STATE_TYPE_ID_LOGGED, import_state_id_logged },
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen { IMAP_STATE_TYPE_TLS_COMPRESSION, import_state_tls_compression },
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen { IMAP_STATE_TYPE_IDLE_CMD_TAG, import_state_idle_cmd_tag },
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen};
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainenstatic ssize_t
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimap_state_try_import_public(struct client *client, const unsigned char *data,
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen size_t size, const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int i;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ssize_t ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(size > 0);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0; i < N_ELEMENTS(imap_states_public); i++) {
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen if (imap_states_public[i].type == data[0]) {
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen ret = imap_states_public[i].
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen import(client, data+1, size-1, error_r);
2200adee458ca662d32b5ec0e01d8c5cba0cc0a8Timo Sirainen return ret < 0 ? -1 : ret+1;
2200adee458ca662d32b5ec0e01d8c5cba0cc0a8Timo Sirainen }
2200adee458ca662d32b5ec0e01d8c5cba0cc0a8Timo Sirainen }
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen return -2;
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen}
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic ssize_t
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimap_state_try_import_internal(struct client *client, const unsigned char *data,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen size_t size, const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int i;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ssize_t ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(size > 0);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0; i < N_ELEMENTS(imap_states_internal); i++) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (imap_states_internal[i].type == data[0]) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = imap_states_internal[i].
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen import(client, data+1, size-1, error_r);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return ret < 0 ? -1 : ret+1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -2;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
ssize_t imap_state_import_base(struct client *client, bool internal,
const unsigned char *data, size_t size,
const char **error_r)
{
const unsigned char *p;
ssize_t ret;
size_t pos;
i_assert(client->mailbox == NULL);
*error_r = NULL;
if (size < 5 || memcmp(data, "base\n", 5) != 0) {
p = memchr(data, '\n', size);
if (p == NULL)
p = data + I_MIN(size, 20);
*error_r = t_strdup_printf("Unknown state block '%s'",
str_sanitize(t_strdup_until(data, p), 20));
return 0;
}
pos = 5;
while (pos < size) {
ret = imap_state_try_import_public(client, data+pos,
size-pos, error_r);
if (ret == -2 && internal) {
ret = imap_state_try_import_internal(client, data+pos,
size-pos, error_r);
}
if (ret < 0 || *error_r != NULL) {
if (ret == -2) {
*error_r = t_strdup_printf("Unknown type '%c'",
data[pos]);
}
i_assert(*error_r != NULL);
return ret < 0 ? -1 : 0;
}
i_assert(size - pos >= (size_t)ret);
pos += ret;
}
return pos;
}