imap-sync.c revision 1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen#include "common.h"
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen#include "str.h"
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen#include "imap-util.h"
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen#include "mail-storage.h"
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen#include "imap-sync.h"
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen#include "commands.h"
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenstruct cmd_sync_context {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen const char *tagline;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct imap_sync_context *sync_ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen};
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenstruct imap_sync_context {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct client *client;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mailbox *box;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mailbox_transaction_context *t;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mailbox_sync_context *sync_ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mailbox_sync_rec sync_rec;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen uint32_t seq;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen unsigned int messages_count;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen int failed;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen};
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenstruct imap_sync_context *
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenimap_sync_init(struct client *client, struct mailbox *box,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen enum mailbox_sync_flags flags)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct imap_sync_context *ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen i_assert(client->mailbox == box);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx = i_new(struct imap_sync_context, 1);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->client = client;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->box = box;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->sync_ctx = mailbox_sync_init(box, flags);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen ctx->t = mailbox_transaction_begin(box, FALSE);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->messages_count = client->messages_count;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenint imap_sync_deinit(struct imap_sync_context *ctx)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen{
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen struct mailbox_status status;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (mailbox_sync_deinit(ctx->sync_ctx, &status) < 0 || ctx->failed) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen mailbox_transaction_rollback(ctx->t);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen i_free(ctx);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return -1;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
b2c1349cf07410aefab0f5b17153af9e5cfcf48fTimo Sirainen mailbox_transaction_commit(ctx->t, 0);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen t_push();
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->client->messages_count = status.messages;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (status.messages != ctx->messages_count) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen client_send_line(ctx->client,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen t_strdup_printf("* %u EXISTS", status.messages));
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (status.recent != ctx->client->recent_count) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->client->recent_count = status.recent;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen client_send_line(ctx->client,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen t_strdup_printf("* %u RECENT", status.recent));
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /*FIXME:client_save_keywords(&client->keywords, keywords, keywords_count);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen client_send_mailbox_flags(client, mailbox, keywords, keywords_count);*/
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen t_pop();
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen i_free(ctx);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return 0;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenint imap_sync_more(struct imap_sync_context *ctx)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen struct mail *mail;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen const struct mail_full_flags *mail_flags;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen string_t *str;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen t_push();
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen str = t_str_new(256);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen for (;;) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (ctx->seq == 0) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /* get next one */
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (mailbox_sync_next(ctx->sync_ctx,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen &ctx->sync_rec) <= 0)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen break;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen switch (ctx->sync_rec.type) {
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen case MAILBOX_SYNC_TYPE_FLAGS:
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (ctx->seq == 0)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->seq = ctx->sync_rec.seq1;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen for (; ctx->seq <= ctx->sync_rec.seq2; ctx->seq++) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen mail = mailbox_fetch(ctx->t, ctx->seq,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen MAIL_FETCH_FLAGS);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen mail_flags = mail->get_flags(mail);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen if (mail_flags == NULL)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen continue;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen str_truncate(str, 0);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen str_printfa(str, "* %u FETCH (FLAGS (",
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->seq);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen imap_write_flags(str, mail_flags);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen str_append(str, "))");
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (!client_send_line(ctx->client,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen str_c(str))) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen t_pop();
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return 0;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen break;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen case MAILBOX_SYNC_TYPE_EXPUNGE:
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (ctx->seq == 0) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->seq = ctx->sync_rec.seq2;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->messages_count -=
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->sync_rec.seq2 -
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->sync_rec.seq1 + 1;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen for (; ctx->seq >= ctx->sync_rec.seq1; ctx->seq--) {
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen str_truncate(str, 0);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen str_printfa(str, "* %u EXPUNGE", ctx->seq);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (!client_send_line(ctx->client,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen str_c(str))) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen t_pop();
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return 0;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen break;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->seq = 0;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen t_pop();
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return 1;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenint imap_sync_nonselected(struct mailbox *box, enum mailbox_sync_flags flags)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mailbox_sync_context *ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mailbox_sync_rec sync_rec;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mailbox_status status;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx = mailbox_sync_init(box, flags);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen while (mailbox_sync_next(ctx, &sync_rec) > 0)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return mailbox_sync_deinit(ctx, &status);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenstatic int cmd_sync_continue(struct client *client)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct cmd_sync_context *ctx = client->cmd_context;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (imap_sync_more(ctx->sync_ctx) == 0)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return FALSE;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (imap_sync_deinit(ctx->sync_ctx) < 0) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen client_send_untagged_storage_error(client,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen mailbox_get_storage(client->mailbox));
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen client_send_tagline(client, ctx->tagline);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return TRUE;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenint cmd_sync(struct client *client, enum mailbox_sync_flags flags,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen const char *tagline)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct cmd_sync_context *ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (client->mailbox == NULL) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen client_send_tagline(client, tagline);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return TRUE;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx = p_new(client->cmd_pool, struct cmd_sync_context, 1);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->tagline = p_strdup(client->cmd_pool, tagline);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->sync_ctx = imap_sync_init(client, client->mailbox, flags);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen client->cmd_func = cmd_sync_continue;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen client->cmd_context = ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen client->command_pending = TRUE;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return cmd_sync_continue(client);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen}