mbox-sync.c revision aa38d1a0945f0bc13a225d043f53fad2eec666b1
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (C) 2004 Timo Sirainen */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen Modifying mbox can be slow, so we try to do it all at once minimizing the
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen required disk I/O. We may need to:
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen - Update message flags in Status, X-Status and X-Keywords headers
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen - Write missing X-UID and X-IMAPbase headers
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen - Write missing or broken Content-Length header if there's space
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen - Expunge specified messages
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen Here's how we do it:
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen - Start reading the mails from the beginning
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen - X-Keywords, X-UID and X-IMAPbase headers may contain padding at the end
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen of them, remember how much each message has and offset to beginning of the
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen - If header needs to be rewritten and there's enough space, do it
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen - If we didn't have enough space, remember how much was missing
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen - Continue reading and counting the padding in each message. If available
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen padding is enough to rewrite all the previous messages needing it, do it
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen - When we encounter expunged message, treat all of it as padding and
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen rewrite previous messages if needed (and there's enough space).
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen Afterwards keep moving messages backwards to fill the expunged space.
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen Moving is done by rewriting each message's headers, with possibly adding
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen missing Content-Length header and padding. Message bodies are moved
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen without modifications.
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen - If we encounter end of file, grow the file and rewrite needed messages
9b7eeffb5752b500ac62ba1fd01c4a8c4ada14e9Timo Sirainen - Rewriting is done by moving message body forward, rewriting message's
9b7eeffb5752b500ac62ba1fd01c4a8c4ada14e9Timo Sirainen header and doing the same for previous message, until all of them are
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen/* The text below was taken exactly as c-client wrote it to my mailbox,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen so it's probably copyrighted by University of Washington. */
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen"This text is part of the internal format of your mail folder, and is not\n" \
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen"a real message. It is created automatically by the mail system software.\n" \
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen"If deleted, important folder data will be lost, and it will be re-created\n" \
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen"with the data reset to initial values.\n"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenint mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (istream_raw_mbox_seek(sync_ctx->input, from_offset) < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_storage_set_critical(STORAGE(sync_ctx->mbox->storage),
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen "Unexpectedly lost From-line at offset %"PRIuUOFF_T
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic void mbox_sync_array_delete_to(array_t *syncs_arr, uint32_t last_uid)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen ARRAY_SET_TYPE(syncs_arr, struct mail_index_sync_rec);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen syncs = array_get_modifyable(syncs_arr, &count);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* keep it */
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainenmbox_sync_read_next_mail(struct mbox_sync_context *sync_ctx,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* get EOF */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen (void)istream_raw_mbox_get_header_offset(sync_ctx->input);
unsigned int i, count;
for (i = 0; i < count; i++) {
return TRUE;
return FALSE;
int ret;
if (uid == 0) {
if (ret < 0) {
if (ret == 0) {
if (!*sync_expunge_r)
int *keywords_changed_r)
unsigned int i, count;
for (i = 0; i < count; i++) {
int ret = 0;
if (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) {
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;
int ret;
if (ret < 0) {
if (ret == 0) {
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;
if (uidvalidity_changed) {
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) {
(unsigned int)ioloop_time;
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) {