mbox-sync.c revision 6a1e4eb2c6a267bec1e8704ce9137bebb7792702
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen Modifying mbox can be slow, so we try to do it all at once minimizing the
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen required disk I/O. We may need to:
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - Update message flags in Status, X-Status and X-Keywords headers
6246b93fb37890dcb2f4df9896438f3f376ab284Timo Sirainen - Write missing X-UID and X-IMAPbase headers
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen - Write missing or broken Content-Length header if there's space
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - Expunge specified messages
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen Here's how we do it:
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - Start reading the mails from the beginning
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - X-Keywords, X-UID and X-IMAPbase headers may contain padding at the end
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen of them, remember how much each message has and offset to beginning of the
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - If header needs to be rewritten and there's enough space, do it
660b4d36110c44b1e4b4b45a78c22d1569ccdb54Timo Sirainen - If we didn't have enough space, remember how much was missing
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - Continue reading and counting the padding in each message. If available
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen padding is enough to rewrite all the previous messages needing it, do it
283ccfe110ed62e48f36e0d84e47da8cae5106beTimo Sirainen - When we encounter expunged message, treat all of it as padding and
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen rewrite previous messages if needed (and there's enough space).
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen Afterwards keep moving messages backwards to fill the expunged space.
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen Moving is done by rewriting each message's headers, with possibly adding
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen missing Content-Length header and padding. Message bodies are moved
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen without modifications.
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen - If we encounter end of file, grow the file and rewrite needed messages
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen - Rewriting is done by moving message body forward, rewriting message's
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen header and doing the same for previous message, until all of them are
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainenint mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset)
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen if (istream_raw_mbox_seek(sync_ctx->input, from_offset) < 0) {
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen mail_storage_set_critical(sync_ctx->ibox->box.storage,
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen "Unexpectedly lost From-line at offset %"PRIuUOFF_T
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainenstatic void mbox_sync_buffer_delete_old(buffer_t *syncs_buf, uint32_t uid)
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen sync = buffer_get_modifyable_data(syncs_buf, &size);
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen /* keep it */
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen buffer_set_used_size(syncs_buf, dest * sizeof(*sync));
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainenmbox_sync_read_next_mail(struct mbox_sync_context *sync_ctx,
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen /* get EOF */
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen (void)istream_raw_mbox_get_header_offset(sync_ctx->input);
d514e6e6ea2320c18c58e0ade9184f5aa67d491bTimo Sirainen istream_raw_mbox_get_start_offset(sync_ctx->input);
36d2b3dc8766ef336a289a51075ca2f3236ef1efTimo Sirainen istream_raw_mbox_get_header_offset(sync_ctx->input);
5561fe7754843250d0f2701332f63467f77f71dbTimo Sirainen if (mail_ctx->seq > 1 && sync_ctx->dest_first_mail) {
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen /* First message was expunged and this is the next one.
0a3d3ca7db7cbdc947ccabe740c40561b3f5c066Timo Sirainen Skip \n header */
d6500661eb699ff335ac570c8646b6e067e1aac6Timo Sirainen mbox_sync_parse_next_mail(sync_ctx->input, mail_ctx);
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen i_assert(sync_ctx->input->v_offset != mail_ctx->mail.from_offset ||
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainen istream_raw_mbox_get_body_size(sync_ctx->input,
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen i_assert(mail_ctx->mail.body_size < OFF_T_MAX);
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen if ((mail_ctx->mail.flags & MBOX_NONRECENT) == 0 && !mail_ctx->pseudo) {
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen /* need to add 'O' flag to Status-header */
1964dbea138cb4a213b1bce1eeee68992b18829aTimo Sirainenstatic int mbox_sync_buf_have_expunges(buffer_t *syncs_buf)
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen for (i = 0; i < size; i++) {
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen if (sync[i].type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainenstatic int mbox_sync_read_index_syncs(struct mbox_sync_context *sync_ctx,
6246b93fb37890dcb2f4df9896438f3f376ab284Timo Sirainen struct mail_index_sync_rec *sync_rec = &sync_ctx->sync_rec;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen /* nothing for this or the future ones */
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen mbox_sync_buffer_delete_old(sync_ctx->syncs, uid);
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen sync_rec->type != MAIL_INDEX_SYNC_TYPE_APPEND &&
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen (sync_rec->type != MAIL_INDEX_SYNC_TYPE_EXPUNGE ||
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
9d7451b57769988f7e3e41cd8790e65429ffc5c7Timo Sirainen ret = mail_index_sync_next(sync_ctx->index_sync_ctx, sync_rec);
if (ret == 0) {
if (!*sync_expunge_r)
for (i = 0; i < size; i++) {
int ret = 0;
if (ret < 0) {
ret = 0;
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) {
INDEX_KEYWORDS_BYTE_COUNT) == 0) {
MAIL_INDEX_MAIL_FLAG_DIRTY) != 0;
INDEX_KEYWORDS_BYTE_COUNT) != 0) {
const unsigned char *data;
if (from_line_size == 0)
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;
messages_count : 0);
&expunged) < 0)
if (size == 0)
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) {
rec) < 0)
if (!expunged) {
if (!partial)
trailer_size) < 0)
min_msg_count = 0;
if (ret <= 0) {
if (ret < 0)
FALSE);
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)
if (ret < 0)
&seq,
&offset) < 0) {
index_sync_ctx) < 0) {
unsigned int read_lock_id = 0;
return ret;
struct mailbox_sync_context *
int ret = 0;