mbox-sync.c revision 2d39dc1a453546892109b35c0d9770369011a13d
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco/* Copyright (C) 2004 Timo Sirainen */
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco Modifying mbox can be slow, so we try to do it all at once minimizing the
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco required disk I/O. We may need to:
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco - Update message flags in Status, X-Status and X-Keywords headers
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco - Write missing X-UID and X-IMAPbase headers
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco - Write missing or broken Content-Length header if there's space
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco - Expunge specified messages
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco Here's how we do it:
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco - Start reading the mails from the beginning
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco - X-Keywords, X-UID and X-IMAPbase headers may contain padding at the end
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco of them, remember how much each message has and offset to beginning of the
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco - If header needs to be rewritten and there's enough space, do it
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco - If we didn't have enough space, remember how much was missing
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco - Continue reading and counting the padding in each message. If available
4750e1be4c1b2ba11705d5b73b86dd1b9dd4e1acKnut Anders Hatlen padding is enough to rewrite all the previous messages needing it, do it
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco - When we encounter expunged message, treat all of it as padding and
4750e1be4c1b2ba11705d5b73b86dd1b9dd4e1acKnut Anders Hatlen rewrite previous messages if needed (and there's enough space).
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco Afterwards keep moving messages backwards to fill the expunged space.
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco Moving is done by rewriting each message's headers, with possibly adding
4750e1be4c1b2ba11705d5b73b86dd1b9dd4e1acKnut Anders Hatlen missing Content-Length header and padding. Message bodies are moved
bfc104f8240fac5b59d4347db4c27be705f6dfc2Knut Anders Hatlen without modifications.
4750e1be4c1b2ba11705d5b73b86dd1b9dd4e1acKnut Anders Hatlen - If we encounter end of file, grow the file and rewrite needed messages
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco - Rewriting is done by moving message body forward, rewriting message's
b645988bdc1cf4f2f82b8c00ed041ddddd822c24Lubos Kosco header and doing the same for previous message, until all of them are
4750e1be4c1b2ba11705d5b73b86dd1b9dd4e1acKnut Anders Hatlen/* The text below was taken exactly as c-client wrote it to my mailbox,
4750e1be4c1b2ba11705d5b73b86dd1b9dd4e1acKnut Anders Hatlen so it's probably copyrighted by University of Washington. */
4750e1be4c1b2ba11705d5b73b86dd1b9dd4e1acKnut Anders Hatlen"This text is part of the internal format of your mail folder, and is not\n" \
4750e1be4c1b2ba11705d5b73b86dd1b9dd4e1acKnut Anders Hatlen"a real message. It is created automatically by the mail system software.\n" \
bfc104f8240fac5b59d4347db4c27be705f6dfc2Knut Anders Hatlen"If deleted, important folder data will be lost, and it will be re-created\n" \
bfc104f8240fac5b59d4347db4c27be705f6dfc2Knut Anders Hatlen"with the data reset to initial values.\n"
bfc104f8240fac5b59d4347db4c27be705f6dfc2Knut Anders Hatlenvoid mbox_sync_set_critical(struct mbox_sync_context *sync_ctx,
bfc104f8240fac5b59d4347db4c27be705f6dfc2Knut Anders Hatlen const char *fmt, ...)
eb32a77fdb57f20c042b7b79b28a4fb4060cb949Lubos Kosco mail_storage_set_critical(&sync_ctx->mbox->storage->storage,
b645988bdc1cf4f2f82b8c00ed041ddddd822c24Lubos Kosco "mbox file %s was modified while we were syncing, "
b645988bdc1cf4f2f82b8c00ed041ddddd822c24Lubos Kosco "check your locking settings", sync_ctx->mbox->path);
b645988bdc1cf4f2f82b8c00ed041ddddd822c24Lubos Kosco mail_storage_set_critical(&sync_ctx->mbox->storage->storage,
be5cdf850da5383468637c6937c016f26bd339cfLubos Koscoint mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset)
817883e9f0d419428e8236a09b77cdeeaa034df7Knut Anders Hatlen if (istream_raw_mbox_seek(sync_ctx->input, from_offset) < 0) {
b645988bdc1cf4f2f82b8c00ed041ddddd822c24Lubos Kosco "Unexpectedly lost From-line at offset %"PRIuUOFF_T
#ifdef HAVE_STAT_TV_NSEC
if (dirty) {
dest++;
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 (seq1 == 0)
(enum mail_flags)
if (!*sync_expunge_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) {
bool nocheck)
const void *data;
if (!nocheck) {
&data) < 0) {
const void *ext_data;
&ext_data) < 0) {
t_push();
t_pop();
&sync_type);
MAIL_RECENT) != 0) {
MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
MAIL_INDEX_MAIL_FLAG_DIRTY) != 0;
(enum mail_flags)
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);
move_diff = 0;
int ret;
bool deleted;
if (seq == 0) {
seq++;
if (ret < 0) {
if (deleted) {
if (ret == 0) {
old_offset) < 0) {
uid = 0;
if (seq1 == 0) {
bool *skipped_mails)
int ret;
if (ret == 0) {
return ret;
bool partial)
int ret;
if (ret <= 0)
return ret;
uid = 0;
if (uid != 0) {
if (ret < 0)
if (ret == 0) {
uid = 0;
} else if (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)
unsigned int lock_id = 0;
bool delay_writes;
if (!changed)
lock_id = 0;
if (changed) {
sync_flags = 0;
if (ret <= 0) {
if (ret < 0)
if (lock_id != 0)
return ret;
if (lock_id != 0)
bool expunged;
goto __nothing_to_do;
if (lock_id == 0) {
goto __again;
if (ret < 0)
unsigned int read_lock_id = 0;
return ret;
int ret;
return ret;
struct mailbox_sync_context *
int ret = 0;
ioloop_time) {