mbox-sync.c revision fa09eae7ccb899ae8ee791435e0a2cfca57cd76d
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (C) 2004 Timo Sirainen */
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen Modifying mbox can be slow, so we try to do it all at once minimizing the
fab850a6aee4aaef4f4795bd7946807a3ba45041Timo Sirainen required disk I/O. We may need to:
a6ab8f00351265e35b79f3a22b1f5a4978ae5c35Timo Sirainen - Update message flags in Status, X-Status and X-Keywords headers
4909421ac41e143fe07a235c0d11e9f0452d716bTimo Sirainen - Write missing X-UID and X-IMAPbase headers
a6ab8f00351265e35b79f3a22b1f5a4978ae5c35Timo Sirainen - Write missing or broken Content-Length header if there's space
4909421ac41e143fe07a235c0d11e9f0452d716bTimo Sirainen - Expunge specified messages
a6ab8f00351265e35b79f3a22b1f5a4978ae5c35Timo Sirainen Here's how we do it:
a6ab8f00351265e35b79f3a22b1f5a4978ae5c35Timo Sirainen - Start reading the mails from the beginning
a6ab8f00351265e35b79f3a22b1f5a4978ae5c35Timo Sirainen - X-Keywords, X-UID and X-IMAPbase headers may contain padding at the end
068357123aba2906c17a4e3bbe57417570be1958Timo Sirainen of them, remember how much each message has and offset to beginning of the
5296198635718c9bf5b2f972c9d5be52092d3d58Timo Sirainen - If header needs to be rewritten and there's enough space, do it
5296198635718c9bf5b2f972c9d5be52092d3d58Timo Sirainen - If we didn't have enough space, remember how much was missing
4909421ac41e143fe07a235c0d11e9f0452d716bTimo Sirainen - Continue reading and counting the padding in each message. If available
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen padding is enough to rewrite all the previous messages needing it, do it
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen - When we encounter expunged message, treat all of it as padding and
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen rewrite previous messages if needed (and there's enough space).
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen Afterwards keep moving messages backwards to fill the expunged space.
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen Moving is done by rewriting each message's headers, with possibly adding
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen missing Content-Length header and padding. Message bodies are moved
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen without modifications.
a6ab8f00351265e35b79f3a22b1f5a4978ae5c35Timo Sirainen - If we encounter end of file, grow the file and rewrite needed messages
a6ab8f00351265e35b79f3a22b1f5a4978ae5c35Timo Sirainen - Rewriting is done by moving message body forward, rewriting message's
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen header and doing the same for previous message, until all of them are
068357123aba2906c17a4e3bbe57417570be1958Timo Sirainen/* The text below was taken exactly as c-client wrote it to my mailbox,
068357123aba2906c17a4e3bbe57417570be1958Timo Sirainen so it's probably copyrighted by University of Washington. */
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen"This text is part of the internal format of your mail folder, and is not\n" \
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen"a real message. It is created automatically by the mail system software.\n" \
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen"If deleted, important folder data will be lost, and it will be re-created\n" \
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen"with the data reset to initial values.\n"
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainenint mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset)
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen if (istream_raw_mbox_seek(sync_ctx->input, from_offset) < 0) {
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen mail_storage_set_critical(STORAGE(sync_ctx->mbox->storage),
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen "Unexpectedly lost From-line at offset %"PRIuUOFF_T
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainenstatic void mbox_sync_array_delete_to(array_t *syncs_arr, uint32_t last_uid)
fab850a6aee4aaef4f4795bd7946807a3ba45041Timo Sirainen ARRAY_SET_TYPE(syncs_arr, struct mail_index_sync_rec);
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen syncs = array_get_modifyable(syncs_arr, &count);
fab850a6aee4aaef4f4795bd7946807a3ba45041Timo Sirainen /* keep it */
0f9a8663b0ff6fe30389d02284a2b002c40914ebTimo Sirainenmbox_sync_read_next_mail(struct mbox_sync_context *sync_ctx,
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen /* get EOF */
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen (void)istream_raw_mbox_get_header_offset(sync_ctx->input);
542a32ee5f4ca72626ec93b6313f909811c01534Timo Sirainen istream_raw_mbox_get_start_offset(sync_ctx->input);
542a32ee5f4ca72626ec93b6313f909811c01534Timo Sirainen istream_raw_mbox_get_header_offset(sync_ctx->input);
542a32ee5f4ca72626ec93b6313f909811c01534Timo Sirainen mbox_sync_parse_next_mail(sync_ctx->input, mail_ctx);
542a32ee5f4ca72626ec93b6313f909811c01534Timo Sirainen i_assert(sync_ctx->input->v_offset != mail_ctx->mail.from_offset ||
542a32ee5f4ca72626ec93b6313f909811c01534Timo Sirainen istream_raw_mbox_get_body_size(sync_ctx->input,
542a32ee5f4ca72626ec93b6313f909811c01534Timo Sirainen i_assert(mail_ctx->mail.body_size < OFF_T_MAX);
542a32ee5f4ca72626ec93b6313f909811c01534Timo Sirainen if ((mail_ctx->mail.flags & MAIL_RECENT) != 0 && !mail_ctx->pseudo) {
542a32ee5f4ca72626ec93b6313f909811c01534Timo Sirainen /* need to add 'O' flag to Status-header */
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainenstatic int mbox_sync_buf_have_expunges(array_t *syncs_arr)
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen ARRAY_SET_TYPE(syncs_arr, struct mail_index_sync_rec);
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen unsigned int i, count;
542a32ee5f4ca72626ec93b6313f909811c01534Timo Sirainen for (i = 0; i < count; i++) {
542a32ee5f4ca72626ec93b6313f909811c01534Timo Sirainen if (syncs[i].type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
542a32ee5f4ca72626ec93b6313f909811c01534Timo Sirainenstatic int mbox_sync_read_index_syncs(struct mbox_sync_context *sync_ctx,
acc039dfc0b0f4588cf2feec04727b61e1c672a1Timo Sirainen struct mail_index_sync_rec *sync_rec = &sync_ctx->sync_rec;
4909421ac41e143fe07a235c0d11e9f0452d716bTimo Sirainen /* nothing for this or the future ones */
4909421ac41e143fe07a235c0d11e9f0452d716bTimo Sirainen mbox_sync_array_delete_to(&sync_ctx->syncs, uid);
78ab753927acf4466f38e4a50694be3f4c4cc9abTimo Sirainen sync_rec->type != MAIL_INDEX_SYNC_TYPE_APPEND &&
4909421ac41e143fe07a235c0d11e9f0452d716bTimo Sirainen (sync_rec->type != MAIL_INDEX_SYNC_TYPE_EXPUNGE ||
4909421ac41e143fe07a235c0d11e9f0452d716bTimo Sirainen if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
ff3337516aad9843599905aeeb29812ea67c09d1Timo Sirainen ret = mail_index_sync_next(sync_ctx->index_sync_ctx, sync_rec);
ff3337516aad9843599905aeeb29812ea67c09d1Timo Sirainen mail_storage_set_index_error(&sync_ctx->mbox->ibox);
a6ab8f00351265e35b79f3a22b1f5a4978ae5c35Timo Sirainen if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_APPEND) {
a672f99363d5f37060c1331d00d2ee3c4626310fTimo Sirainen *sync_expunge_r = mbox_sync_buf_have_expunges(&sync_ctx->syncs);
5296198635718c9bf5b2f972c9d5be52092d3d58Timo Sirainenvoid mbox_sync_apply_index_syncs(struct mbox_sync_context *sync_ctx,
5296198635718c9bf5b2f972c9d5be52092d3d58Timo Sirainen unsigned int i, count;
5296198635718c9bf5b2f972c9d5be52092d3d58Timo Sirainen for (i = 0; i < count; i++) {
5296198635718c9bf5b2f972c9d5be52092d3d58Timo Sirainen mail_index_sync_flags_apply(&syncs[i], &mail->flags);
4909421ac41e143fe07a235c0d11e9f0452d716bTimo Sirainen /* no existing keywords */
706c55b9e97b7e4b9018f70b672895572a584a35Timo Sirainen /* adding, create the array */
4909421ac41e143fe07a235c0d11e9f0452d716bTimo Sirainen unsigned int,
a6ab8f00351265e35b79f3a22b1f5a4978ae5c35Timo Sirainenmbox_sync_read_index_rec(struct mbox_sync_context *sync_ctx,
dbcc7e1e5eaaad8a8cac6ee74076772c42a2649aTimo Sirainen uint32_t uid, const struct mail_index_record **rec_r)
aee3e2f7ab2b27572a90b9e7fd8fe60f13c6637eTimo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
a6ab8f00351265e35b79f3a22b1f5a4978ae5c35Timo Sirainen mail_storage_set_index_error(&sync_ctx->mbox->ibox);
return ret;
unsigned char hdr_md5_sum[],
const void *data;
int ret;
if (ret < 0) {
&data) < 0) {
int nocheck)
const void *data;
if (!nocheck) {
&data) < 0) {
int keywords_changed;
t_push();
t_pop();
MAIL_INDEX_MAIL_FLAG_DIRTY) != 0;
t_pop();
const unsigned char *data;
if (from_line_size == 0)
const char *str;
unsigned int i, count;
for (i = 0; i < count; i++) {
int ret;
if (ret < 0)
if (ret > 0) {
move_diff = 0;
if (seq == 0) {
seq++;
if (ret < 0)
if (ret == 0) {
old_offset) < 0) {
uid = 0;
if (seq1 == 0) {
int *skipped_mails)
int ret;
if (ret == 0) {
return ret;
int partial)
if (ret <= 0)
return ret;
uid = 0;
if (uid != 0) {
if (ret < 0)
if (ret == 0) {
uid = 0;
&rec) < 0)
&expunged) < 0)
if (!expunged) {
if (!expunged) {
if (!expunged) {
} else if (partial) {
&partial,
if (ret <= 0) {
if (ret < 0)
if (!skipped_mails)
unsigned int uid_validity;
trailer_size = 0;
trailer_size) < 0)
if (offset == 0) {
if (ret <= 0) {
if (ret < 0)
if (ret <= 0) {
unsigned int lock_id = 0;
if (!changed)
lock_id = 0;
if (changed) {
if (ret <= 0) {
if (ret < 0)
if (lock_id != 0)
return ret;
if (lock_id != 0)
if (lock_id == 0) {
goto __again;
if (ret < 0)
if (ret < 0)
unsigned int read_lock_id = 0;
return ret;
struct mailbox_sync_context *
int ret = 0;
ioloop_time) {