mbox-sync.c revision abe8230dd1dd37d7ccf0163100e934bb5e658c20
0N/A/* Copyright (C) 2004 Timo Sirainen */ 0N/A Modifying mbox can be slow, so we try to do it all at once minimizing the 0N/A required disk I/O. We may need to: 0N/A - Update message flags in Status, X-Status and X-Keywords headers 0N/A - Write missing X-UID and X-IMAPbase headers 0N/A - Write missing or broken Content-Length header if there's space 0N/A - Expunge specified messages 0N/A Here's how we do it: 0N/A - Start reading the mails mail headers from the beginning 0N/A - X-Keywords and X-UID headers may contain extra spaces at the end of them, 0N/A remember how much extra each message has and offset to beginning of the 0N/A - If message flags are dirty and there's enough space to write them, do it 1472N/A - If we didn't have enough space, remember how much was missing and keep 1472N/A - When we encounter expunged message, check if the amount of empty space in 0N/A previous messages plus size of expunged message is enough to cover the 0N/A missing space. If yes, 0N/A - execute the rewrite plan 0N/A - forget all the messages before the expunged message. only remember 0N/A how much data we still have to move to cover the expunged message 0N/A - If we encounter end of file, grow the file and execute the rewrite plan 0N/A - Start from the first message that needs more space 0N/A - If there's expunged messages before us, we have to write over them. 0N/A - Move all messages after it backwards to fill it 0N/A - Each moved message's X-Keywords header should have n bytes extra 0N/A space, unless there's not enough space to do it. 0N/A - If there's no expunged messages, we can move data either forward or 0N/A backward to get it. Calculate which requires less moving. Forward 0N/A counting may encounter more messages which require extra space, count 0N/A - If we decide to move forwards and we had to go through dirty 0N/A messages, do the moving from last to first dirty message 0N/A - If we encounter end of file, grow the file enough to get the required 0N/A amount of space plus enough space to fill X-Keywords headers full of 0N/A/* returns -1 = error, 0 = mbox changed since previous lock, 1 = didn't */ 0N/A /* we didn't have the file open before -> it changed */ 0N/A /* same as before. we'll have to fix mbox stream to contain 0N/A correct from_offset, hdr_offset and body_offset. so, seek 0N/A to from_offset and read through the header. */ 0N/A /* put the extra space between last message's header and body */ /* First message was expunged and this is the next one. /* save the offset permanently with recent flag state */ /* need to add 'O' flag to Status-header */ // FIXME: save it somewhere for (i = 0; i <
size; i++)
/* externally expunged message, remove from index */ /* new UID in the middle of the mailbox - shouldn't happen */ "mbox sync: UID inserted in the middle of mailbox " /* see if from_offset needs updating */ /* see if flags changed */ /* update from_offsets, but not if we're going to rewrite this message. rewriting would just move it anyway. */ const unsigned char *
data;
/* expunging first message, fix space to contain next message's \n header too since it will be removed. */ /* move the header backwards to fill expunged space */ /* read the From-line before rewriting overwrites it */ /* rewrite successful, write From-line to /* first mail with no space to write it */ /* create dummy message to describe the expunged data */ /* we have enough space now */ /* don't waste too much on extra spacing */ /* mail_ctx may contain wrong data after rewrite, so make sure we don't try to access it */ /* set to -1, since they're always increased later */ /* we sync only what we need to. jump to first record that /* get all sync records related to this message */ /* -1 = error, -2 = need to restart */ /* if there's no sync records left, /* we can skip forward to next record which /* rest of the messages in index don't exist -> expunge them */ /* we didn't go through everything. fake the headers and all */ /* copy trailer, then truncate the file */ /* initially we had mbox read-locked, but later we needed a write-lock. doing it required dropping the read lock. we're here because mbox was modified before we got the write-lock. so, restart the whole syncing. */ /* rewrite X-IMAPbase header */ /* only syncs left should be just appends (and their updates) which weren't synced yet for some reason (crash). we'll just ignore them, as we've overwritten them above. */ /* FIXME: drop to read locking and keep it MBOX_SYNC_SECS+1 to make sure we notice changes made by others */