imap-state.c revision f3fa33be556fd5199dcc856b02b58128bdf693a5
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2014-2015 Dovecot authors, see the included COPYING file */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen uint32_t keywords_count, keywords_crc32, uids_crc32;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenexport_seq_range(buffer_t *dest, const ARRAY_TYPE(seq_range) *range)
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen unsigned int i, count;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0; i < count; i++) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen numpack_encode(dest, (uids[i].seq1 - next_uid) << 1);
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen numpack_encode(dest, 1 | ((uids[i].seq1 - next_uid) << 1));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen numpack_encode(dest, uids[i].seq2 - uids[i].seq1 - 1);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainenimport_seq_range(const unsigned char **data, const unsigned char *end,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0; i < count; i++) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenint imap_state_export_internal(struct client *client, buffer_t *dest,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* the only IMAP command we allow running is IDLE or X-STATE */
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 client->v.state_export(client, TRUE, dest, error_r);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenint imap_state_export_external(struct client *client, buffer_t *dest,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **error_r)
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 Sirainenimap_state_import(struct client *client, bool internal,
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen const unsigned char *data, size_t size, const char **error_r)
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen while (size > 0) {
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen ret = client->v.state_import(client, internal,
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenint imap_state_import_internal(struct client *client,
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen const char **error_r)
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen return imap_state_import(client, TRUE, data, size, error_r);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenint imap_state_import_external(struct client *client,
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen const char **error_r)
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainen return imap_state_import(client, FALSE, data, size, error_r);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenimap_state_export_mailbox_mails(buffer_t *dest, struct mailbox *box,
5fa253bd316540ec280ca76b39d62a9e32da228bTimo Sirainen const char **error_r)
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
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)
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainenmailbox_status_keywords_crc32(const struct mailbox_status *status)
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainen const char *const *strp;
2f19f8ff906a0017b906763e0f7675d49ab0e58fTimo Sirainenimap_state_export_mailbox(buffer_t *dest, struct client *client,
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen mailbox_get_open_status(box, STATUS_UIDVALIDITY | STATUS_UIDNEXT |
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 buffer_append_c(dest, IMAP_STATE_TYPE_MAILBOX);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append(dest, metadata.guid, sizeof(metadata.guid));
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append_c(dest, client->mailbox_examined ? 1 : 0);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0 &&
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen numpack_encode(dest, client->sync_last_full_modseq);
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 /* 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);
e18e90938ffd9e31c796c405404be0b7dcd5c807Timo Sirainenint imap_state_export_base(struct client *client, bool internal,
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen if (array_is_created(&client->search_updates) &&
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen /* these could be tricky */
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen *error_r = "SEARCH=CONTEXT updates not supported currently";
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 /* IMAP features */
31fd39a3a3d544b1a8afb9aef07f180d0d40fda2Timo Sirainen i_assert((client->enabled_features & ~(MAILBOX_FEATURE_CONDSTORE |
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, IMAP_STATE_TYPE_ID_LOGGED);
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen buffer_append_c(dest, IMAP_STATE_TYPE_TLS_COMPRESSION);
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 /* 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 Sirainenimport_string(const unsigned char **data, const unsigned char *end,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **str_r)
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen const unsigned char *p;
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ARRAY_TYPE(seq_range) uids_filter, expunged_uids;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int i, expunge_count, n = 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* the mailbox was empty originally - there couldn't be any
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen pending expunges. */
7e8bfb5b0af9606f131fc440e61f3752da335ac9Timo Sirainen /* get all the message UIDs expunged since the last known modseq */
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 "Couldn't get recently expunged UIDs "
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "(uidnext=%u highest_modseq=%llu)", state->uidnext,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen seq_range_array_iter_init(&iter, &expunged_uids);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen trans = mailbox_transaction_begin(client->mailbox, 0);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
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 crc = crc32_data_more(crc, &mail->uid, sizeof(mail->uid));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen while (seq_range_array_iter_nth(&iter, n, &expunged_uid)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = mailbox_get_last_error(client->mailbox, NULL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Message count mismatch after handling expunges";
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 if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) == 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = expunge_count; i > 0; i--) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen o_stream_nsend(client->output, str_data(str), str_len(str));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_send_flag_changes(struct client *client,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen seq_range_array_add_range(&old_uids, 1, state->uidnext-1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen imap_search_add_changed_since(search_args, state->highest_modseq);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen pool = pool_alloconly_create("imap state flag changes", 1024);
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);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen imap_fetch_begin(fetch_ctx, client->mailbox, search_args);
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen /* FIXME: ideally do this asynchronously.. */
b215322367dbd94df3e2e4bb643b53460e6adc51Timo Sirainen while (imap_fetch_more_no_lock_update(fetch_ctx) == 0) ;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_state_mailbox_struct(const unsigned char *data, size_t size,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const unsigned char *p = data, *end = data + size;
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen if (import_string(&p, end, &state_r->vname) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (end-p < (int)sizeof(state_r->mailbox_guid)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen memcpy(state_r->mailbox_guid, p, sizeof(state_r->mailbox_guid));
57e1fdc2f8f2bf1c6fcd9523f93459404c2359c8Timo Sirainen if (guid_128_is_empty(state_r->mailbox_guid)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* EXAMINEd vs SELECTed */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *error_r = "Mailbox state truncated at examined-flag";
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) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_state_mailbox_open(struct client *client,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **error_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ns = mail_namespace_find(client->user->namespaces, state->vname);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box = mailbox_alloc(ns->list, state->vname, flags);
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen *error_r = t_strdup_printf("Couldn't open mailbox: %s",
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ret = mailbox_enable(box, client->enabled_features);
7faf475a2faea9ac291898a6593870b01fbc30d4Timo Sirainen *error_r = t_strdup_printf("Couldn't sync mailbox: %s",
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 if (!guid_128_equals(metadata.guid, state->mailbox_guid)) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox_get_open_status(box, STATUS_UIDVALIDITY | STATUS_UIDNEXT |
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen if (status.uidvalidity != state->uidvalidity) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (status.highest_modseq < state->highest_modseq) {
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen if (import_send_expunges(client, state, &expunge_count, error_r) < 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (state->messages - expunge_count > client->messages_count) {
7faf475a2faea9ac291898a6593870b01fbc30d4Timo Sirainen if (state->messages - expunge_count < client->messages_count) {
12e32734b3fe762c647c1ae5552185517a988cf8Timo Sirainen /* new messages arrived */
7faf475a2faea9ac291898a6593870b01fbc30d4Timo Sirainen t_strdup_printf("* %u EXISTS", client->messages_count));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen t_strdup_printf("* %u RECENT", client->recent_count));
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen client_update_mailbox_flags(client, status.keywords);
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen for (uid = range->seq1; uid <= range->seq2; uid++)
af99ca825f4b7674ec6dd0269bbca665775205aaTimo Sirainen mailbox_recent_flags_set_uid_forced(box, uid);
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 if (import_send_flag_changes(client, state) < 0) {
ba57ea2c696f9e9aae909f073069848876a641f4Timo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0 &&
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen status.highest_modseq != state->highest_modseq) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "* OK [HIGHESTMODSEQ %llu] Highest",
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client->sync_last_full_modseq = status.highest_modseq;
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainenimport_state_mailbox(struct client *client, const unsigned char *data,
0e7d5ff38f28d8c85e197a031bbb66b322ff89e6Timo Sirainen ret = import_state_mailbox_struct(data, size, &state, error_r);
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainen if (import_state_mailbox_open(client, &state, error_r) < 0)
1c3dc4c08ced3948f52c3c6c171ed77310b2cbfdTimo Sirainenimport_state_enabled_features(struct client *client, const unsigned char *data,
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen for (i = 0; i < size; i++) {
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen client->enabled_features |= MAILBOX_FEATURE_CONDSTORE;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen client->enabled_features |= MAILBOX_FEATURE_QRESYNC;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_state_searchres(struct client *client, const unsigned char *data,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const unsigned char *p = data;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen i_array_init(&client->search_saved_uidset, 128);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen if (import_seq_range(&p, data+size, &client->search_saved_uidset) < 0) {
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainenimport_state_tls_compression(struct client *client,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimport_state_idle_cmd_tag(struct client *client, const unsigned char *data,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const unsigned char *p = data, *end = data + size;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char *tag;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* IDLE command continues */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* IDLE terminated because of an external change, but
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen DONE was already buffered */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(cmd->state == CLIENT_COMMAND_STATE_WAIT_INPUT);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* we're finishing IDLE command */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen client->state_import_bad_idle_done ? "BAD" : "OK"));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic struct {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ssize_t (*import)(struct client *client, const unsigned char *data,
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 Sirainenstatic struct {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ssize_t (*import)(struct client *client, const unsigned char *data,
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 },
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimap_state_try_import_public(struct client *client, const unsigned char *data,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int i;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0; i < N_ELEMENTS(imap_states_public); i++) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenimap_state_try_import_internal(struct client *client, const unsigned char *data,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int i;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0; i < N_ELEMENTS(imap_states_internal); i++) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (imap_states_internal[i].type == data[0]) {
const char **error_r)
if (p == NULL)
return pos;