mbox-sync.c revision fcc2880f80385e29924aa926a1eefc5f0f41fa45
be2e4e54da3c8054525321422f7f290d45b32a6cStéphane Graber/* Copyright (c) 2004-2015 Dovecot authors, see the included COPYING file */
be2e4e54da3c8054525321422f7f290d45b32a6cStéphane Graber Modifying mbox can be slow, so we try to do it all at once minimizing the
be2e4e54da3c8054525321422f7f290d45b32a6cStéphane Graber required disk I/O. We may need to:
be2e4e54da3c8054525321422f7f290d45b32a6cStéphane Graber - Update message flags in Status, X-Status and X-Keywords headers
be2e4e54da3c8054525321422f7f290d45b32a6cStéphane Graber - Write missing X-UID and X-IMAPbase headers
be2e4e54da3c8054525321422f7f290d45b32a6cStéphane Graber - Write missing or broken Content-Length header if there's space
d79067a726f1b4a06828220cc11dd3cfbc244856Daniel Miranda - Expunge specified messages
be2e4e54da3c8054525321422f7f290d45b32a6cStéphane Graber Here's how we do it:
d4f6fa926d92803d8b8217468be483ac2f7e270eStéphane Graber - Start reading the mails from the beginning
d4f6fa926d92803d8b8217468be483ac2f7e270eStéphane Graber - X-Keywords, X-UID and X-IMAPbase headers may contain padding at the end
d4f6fa926d92803d8b8217468be483ac2f7e270eStéphane Graber of them, remember how much each message has and offset to beginning of the
be2e4e54da3c8054525321422f7f290d45b32a6cStéphane Graber - If header needs to be rewritten and there's enough space, do it
9a42db48e0bcf4f34b05a3de1cda23e06f51d131Stéphane Graber - If we didn't have enough space, remember how much was missing
be2e4e54da3c8054525321422f7f290d45b32a6cStéphane Graber - Continue reading and counting the padding in each message. If available
be2e4e54da3c8054525321422f7f290d45b32a6cStéphane Graber padding is enough to rewrite all the previous messages needing it, do it
be2e4e54da3c8054525321422f7f290d45b32a6cStéphane Graber - When we encounter expunged message, treat all of it as padding and
c13c0e08da7dbfecb52e85233ac6cd17afa5d818Stéphane Graber rewrite previous messages if needed (and there's enough space).
c13c0e08da7dbfecb52e85233ac6cd17afa5d818Stéphane Graber Afterwards keep moving messages backwards to fill the expunged space.
c13c0e08da7dbfecb52e85233ac6cd17afa5d818Stéphane Graber Moving is done by rewriting each message's headers, with possibly adding
f10e04e36170dbd0faae3a667d53f0af1ef6a13aStéphane Graber missing Content-Length header and padding. Message bodies are moved
f10e04e36170dbd0faae3a667d53f0af1ef6a13aStéphane Graber without modifications.
f10e04e36170dbd0faae3a667d53f0af1ef6a13aStéphane Graber - If we encounter end of file, grow the file and rewrite needed messages
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "buffer.h"
#include "hostpid.h"
#include "istream.h"
#include "file-set-size.h"
#include "str.h"
#include "read-full.h"
#include "write-full.h"
#include "message-date.h"
#include "istream-raw-mbox.h"
#include "mbox-storage.h"
#include "index-sync-changes.h"
#include "mailbox-uidvalidity.h"
#include "mbox-from.h"
#include "mbox-file.h"
#include "mbox-lock.h"
#include "mbox-sync-private.h"
#include <stddef.h>
#include <stdlib.h>
#include <utime.h>
#define PSEUDO_MESSAGE_BODY \
const char *fmt, ...)
if (dirty) {
return TRUE;
return ret;
unsigned char hdr_md5_sum[],
const void *data;
bool nocheck)
const void *data;
if (!nocheck) {
const void *ext_data;
&idx_keywords);
MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
bool dirty;
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;
int ret;
if (ret < 0) {
size) < 0) {
bool *skipped_mails)
int ret;
if (uid != 0) {
if (ret == 0) {
return ret;
return TRUE;
return FALSE;
bool partial)
int ret;
if (ret <= 0)
return ret;
uid = 0;
if (uid != 0) {
ret = 0;
if (ret == 0) {
uid = 0;
} else if (uid == 0 &&
&expunged);
if (!expunged) {
} T_END;
} T_END;
if (!expunged) {
} else if (partial) {
&partial,
if (ret <= 0)
if (ret < 0)
if (!skipped_mails)
unsigned int uid_validity;
while (count > 0) {
if (ret < 0)
if (ret < 0) {
int ret;
if (ret < 0) {
if (ret == 0) {
trailer_size = 0;
trailer_size = 0;
trailer_size) < 0)
if (offset == 0) {
const void *data;
sizeof(uint64_t),
sizeof(uint64_t));
const char *path;
if (ret < 0)
ret = 0;
return ret;
const void *data;
if (data_size == 0) {
unsigned int lock_id;
int ret;
if (ret == 0) {
return ret;
bool empty;
bool *empty_r)
unsigned int *lock_id)
if (!changed)
*lock_id = 0;
if (changed) {
if (ret <= 0) {
if (ret < 0)
return ret;
bool expunged;
if (uid == 0) {
goto nothing_to_do;
if (*lock_id == 0) {
goto again;
if (ret < 0)
!readonly) {
return ret;
unsigned int lock_id = 0;
int ret;
if (lock_id != 0) {
if (ret < 0) {
unsigned int read_lock_id = 0;
return ret;
struct mailbox_sync_context *
int ret = 0;