imap-sync.c revision 294f1a51763015cda0e2d874c5027d6fe7a2cd54
39ed514f9d401b3cb589595c6a2f532050254d77Timo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
39ed514f9d401b3cb589595c6a2f532050254d77Timo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "common.h"
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "str.h"
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "mail-storage.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "imap-util.h"
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "imap-sync.h"
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#include "commands.h"
39ed514f9d401b3cb589595c6a2f532050254d77Timo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstruct cmd_sync_context {
2bfa4f4e042def419b7b80b05f7d2cf5d0f9f6a0Timo Sirainen const char *tagline;
5f9231534fd15b9aed2676a3d6cd07158f8e2a39Timo Sirainen struct imap_sync_context *sync_ctx;
5f9231534fd15b9aed2676a3d6cd07158f8e2a39Timo Sirainen};
2bfa4f4e042def419b7b80b05f7d2cf5d0f9f6a0Timo Sirainen
a966016e605eea27e02d73ff1412632cd684d770Timo Sirainenstruct imap_sync_context {
9d1526ac8bcec9aff3c3a32f092ee2f3da2760b7Timo Sirainen struct client *client;
39ed514f9d401b3cb589595c6a2f532050254d77Timo Sirainen struct mailbox *box;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen struct mailbox_transaction_context *t;
9d1526ac8bcec9aff3c3a32f092ee2f3da2760b7Timo Sirainen struct mailbox_sync_context *sync_ctx;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
db9ad8c821c01a18a520c2a07b2d6dc501b4017aTimo Sirainen struct mailbox_sync_rec sync_rec;
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen uint32_t seq;
2ce5b1d19cba4654239116a34e3ad9d5b6af8551Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen unsigned int messages_count;
5f9231534fd15b9aed2676a3d6cd07158f8e2a39Timo Sirainen
db9ad8c821c01a18a520c2a07b2d6dc501b4017aTimo Sirainen int failed;
5f9231534fd15b9aed2676a3d6cd07158f8e2a39Timo Sirainen};
5f9231534fd15b9aed2676a3d6cd07158f8e2a39Timo Sirainen
db9ad8c821c01a18a520c2a07b2d6dc501b4017aTimo Sirainenstruct imap_sync_context *
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainenimap_sync_init(struct client *client, struct mailbox *box,
f90c6ff1ae3d5675abfc6ae05574924fda8dca9eTimo Sirainen enum mailbox_sync_flags flags)
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen{
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen struct imap_sync_context *ctx;
9d1526ac8bcec9aff3c3a32f092ee2f3da2760b7Timo Sirainen
2bfa4f4e042def419b7b80b05f7d2cf5d0f9f6a0Timo Sirainen i_assert(client->mailbox == box);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
9d1526ac8bcec9aff3c3a32f092ee2f3da2760b7Timo Sirainen ctx = i_new(struct imap_sync_context, 1);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen ctx->client = client;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen ctx->box = box;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
2ce5b1d19cba4654239116a34e3ad9d5b6af8551Timo Sirainen ctx->sync_ctx = mailbox_sync_init(box, flags);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen ctx->t = mailbox_transaction_begin(box, FALSE);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen ctx->messages_count = client->messages_count;
fc3489208bdd322f594fefb1883473410e868c50Timo Sirainen return ctx;
f55d355a545747cb26b18b00b4707b56e26260caTimo Sirainen}
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenint imap_sync_deinit(struct imap_sync_context *ctx)
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen{
db9ad8c821c01a18a520c2a07b2d6dc501b4017aTimo Sirainen struct mailbox_status status;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen if (mailbox_sync_deinit(ctx->sync_ctx, &status) < 0 || ctx->failed) {
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen mailbox_transaction_rollback(ctx->t);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen i_free(ctx);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen return -1;
39ed514f9d401b3cb589595c6a2f532050254d77Timo Sirainen }
39ed514f9d401b3cb589595c6a2f532050254d77Timo Sirainen
39ed514f9d401b3cb589595c6a2f532050254d77Timo Sirainen mailbox_transaction_commit(ctx->t, 0);
39ed514f9d401b3cb589595c6a2f532050254d77Timo Sirainen
39ed514f9d401b3cb589595c6a2f532050254d77Timo Sirainen t_push();
39ed514f9d401b3cb589595c6a2f532050254d77Timo Sirainen
ctx->client->messages_count = status.messages;
if (status.messages != ctx->messages_count) {
client_send_line(ctx->client,
t_strdup_printf("* %u EXISTS", status.messages));
}
if (status.recent != ctx->client->recent_count) {
ctx->client->recent_count = status.recent;
client_send_line(ctx->client,
t_strdup_printf("* %u RECENT", status.recent));
}
/*FIXME:client_save_keywords(&client->keywords, keywords, keywords_count);
client_send_mailbox_flags(client, mailbox, keywords, keywords_count);*/
t_pop();
i_free(ctx);
return 0;
}
int imap_sync_more(struct imap_sync_context *ctx)
{
struct mail *mail;
enum mail_flags flags;
const char *const *keywords;
string_t *str;
int ret = 1;
t_push();
str = t_str_new(256);
for (;;) {
if (ctx->seq == 0) {
/* get next one */
ret = mailbox_sync_next(ctx->sync_ctx,
&ctx->sync_rec);
if (ret <= 0) {
if (ret == 0) {
/* all finished ok */
ret = 1;
}
break;
}
}
switch (ctx->sync_rec.type) {
case MAILBOX_SYNC_TYPE_FLAGS:
case MAILBOX_SYNC_TYPE_KEYWORDS:
if (ctx->seq == 0)
ctx->seq = ctx->sync_rec.seq1;
for (; ctx->seq <= ctx->sync_rec.seq2; ctx->seq++) {
mail = mailbox_fetch(ctx->t, ctx->seq,
MAIL_FETCH_FLAGS);
flags = mail->get_flags(mail);
keywords = mail->get_keywords(mail);
str_truncate(str, 0);
str_printfa(str, "* %u FETCH (FLAGS (",
ctx->seq);
imap_write_flags(str, flags, keywords);
str_append(str, "))");
ret = client_send_line(ctx->client, str_c(str));
if (ret <= 0) {
t_pop();
return ret;
}
}
break;
case MAILBOX_SYNC_TYPE_EXPUNGE:
if (ctx->seq == 0) {
ctx->seq = ctx->sync_rec.seq2;
ctx->messages_count -=
ctx->sync_rec.seq2 -
ctx->sync_rec.seq1 + 1;
}
for (; ctx->seq >= ctx->sync_rec.seq1; ctx->seq--) {
str_truncate(str, 0);
str_printfa(str, "* %u EXPUNGE", ctx->seq);
ret = client_send_line(ctx->client, str_c(str));
if (ret <= 0) {
t_pop();
return ret;
}
}
break;
}
ctx->seq = 0;
}
t_pop();
return ret;
}
int imap_sync_nonselected(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct mailbox_sync_context *ctx;
struct mailbox_sync_rec sync_rec;
struct mailbox_status status;
ctx = mailbox_sync_init(box, flags);
while (mailbox_sync_next(ctx, &sync_rec) > 0)
;
return mailbox_sync_deinit(ctx, &status);
}
static int cmd_sync_continue(struct client_command_context *cmd)
{
struct cmd_sync_context *ctx = cmd->context;
if (imap_sync_more(ctx->sync_ctx) == 0)
return FALSE;
if (imap_sync_deinit(ctx->sync_ctx) < 0) {
client_send_untagged_storage_error(cmd->client,
mailbox_get_storage(cmd->client->mailbox));
}
client_send_tagline(cmd, ctx->tagline);
return TRUE;
}
int cmd_sync(struct client_command_context *cmd, enum mailbox_sync_flags flags,
const char *tagline)
{
struct cmd_sync_context *ctx;
if (cmd->client->mailbox == NULL) {
client_send_tagline(cmd, tagline);
return TRUE;
}
if ((client_workarounds & WORKAROUND_DELAY_NEWMAIL) != 0 &&
(flags & MAILBOX_SYNC_FLAG_FAST) != 0)
flags |= MAILBOX_SYNC_FLAG_NO_NEWMAIL;
ctx = p_new(cmd->pool, struct cmd_sync_context, 1);
ctx->tagline = p_strdup(cmd->pool, tagline);
ctx->sync_ctx = imap_sync_init(cmd->client, cmd->client->mailbox,
flags);
cmd->func = cmd_sync_continue;
cmd->context = ctx;
cmd->client->command_pending = TRUE;
return cmd_sync_continue(cmd);
}