mbox-sync-full.c revision 99b621cc5076398c5d780d2ea33dd7391341d630
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen
46552a931924c2d743f045e95b08c3ce6beda91aTimo Sirainen#include "lib.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "istream.h"
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen#include "hex-binary.h"
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen#include "message-parser.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "message-part-serialize.h"
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen#include "mbox-index.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "mbox-lock.h"
45155bb1250cf5a120278f349465aded513a100fTimo Sirainen#include "mail-index-util.h"
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include <unistd.h>
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include <fcntl.h>
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include <sys/stat.h>
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainenstatic void skip_line(struct istream *input)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen{
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen const unsigned char *msg;
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen size_t i, size;
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen while (i_stream_read_data(input, &msg, &size, 0) > 0) {
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen for (i = 0; i < size; i++) {
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen if (msg[i] == '\n') {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen i_stream_skip(input, i+1);
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen return;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen }
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen }
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen i_stream_skip(input, i);
b8cd2f2f99351605725b7260f5da89cff76d0a3aTimo Sirainen }
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen}
9508ac436fff0e1dcea975855c139cd251deb703Timo Sirainen
01cd9d4a8050a1dbf1da2c830f9755a45d6d004aTimo Sirainenstatic int verify_header(struct mail_index *index,
01cd9d4a8050a1dbf1da2c830f9755a45d6d004aTimo Sirainen struct mail_index_record *rec,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen unsigned int uid, unsigned char current_digest[16])
ed16ab579bd058ec5e2b5d02bb41fdadd9e05b31Timo Sirainen{
01cd9d4a8050a1dbf1da2c830f9755a45d6d004aTimo Sirainen const unsigned char *old_digest;
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen size_t size;
ed16ab579bd058ec5e2b5d02bb41fdadd9e05b31Timo Sirainen
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen /* MD5 sums must match */
ab45534d66792946b5794ab99a843d2f2b1d556fTimo Sirainen old_digest = index->lookup_field_raw(index, rec, DATA_FIELD_MD5, &size);
ab45534d66792946b5794ab99a843d2f2b1d556fTimo Sirainen if (old_digest == NULL)
ab45534d66792946b5794ab99a843d2f2b1d556fTimo Sirainen return uid == rec->uid;
01cd9d4a8050a1dbf1da2c830f9755a45d6d004aTimo Sirainen
01cd9d4a8050a1dbf1da2c830f9755a45d6d004aTimo Sirainen return size >= 16 && memcmp(old_digest, current_digest, 16) == 0 &&
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen (uid == 0 || uid == rec->uid);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen}
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainenstatic int mail_update_header_size(struct mail_index *index,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct mail_index_record *rec,
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen struct mail_index_update *update,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen struct message_size *hdr_size)
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen{
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen const void *part_data;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen const char *error;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen void *part_data_copy;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen uoff_t virtual_size;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen size_t size;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* update FIELD_HDR_HEADER_SIZE */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen index->update_field_raw(update, DATA_HDR_HEADER_SIZE,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen &hdr_size->physical_size,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen sizeof(hdr_size->physical_size));
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* reset FIELD_HDR_VIRTUAL_SIZE - we don't know it anymore */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen virtual_size = (uoff_t)-1;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen index->update_field_raw(update, DATA_HDR_VIRTUAL_SIZE,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen &virtual_size, sizeof(virtual_size));
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* update DATA_FIELD_MESSAGEPART */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if ((rec->data_fields & DATA_FIELD_MESSAGEPART) == 0)
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen return TRUE;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen part_data = index->lookup_field_raw(index, rec, DATA_FIELD_MESSAGEPART,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen &size);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (part_data == NULL) {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* well, this wasn't expected but don't bother failing */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen return TRUE;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen }
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen t_push();
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* copy & update the part data */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen part_data_copy = t_malloc(size);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen memcpy(part_data_copy, part_data, size);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (!message_part_serialize_update_header(part_data_copy, size,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen hdr_size, &error)) {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen index_set_corrupted(index,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen "Corrupted cached message_part data (%s)",
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen error);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen t_pop();
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen return FALSE;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen }
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen index->update_field_raw(update, DATA_FIELD_MESSAGEPART,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen part_data_copy, size);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen t_pop();
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen return TRUE;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen}
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainenstatic int mbox_check_uidvalidity(struct mail_index *index,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen unsigned int uid_validity)
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen{
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (uid_validity == index->header->uid_validity)
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen return TRUE;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen index->header->flags |= MAIL_INDEX_FLAG_DIRTY_MESSAGES |
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen MAIL_INDEX_FLAG_DIRTY_CUSTOMFLAGS;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (uid_validity == 0) {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* X-IMAPbase header isn't written yet */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen } else {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* UID validity has changed - rebuild whole index */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen index->set_flags |= MAIL_INDEX_FLAG_REBUILD;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen return FALSE;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen return TRUE;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen}
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int match_next_record(struct mail_index *index,
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen struct mail_index_record *rec,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen unsigned int seq, struct istream *input,
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen struct mail_index_record **next_rec, int *dirty)
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen{
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen struct mail_index_update *update;
d7cd49f01fad7c87c5a0865ebf54a548275e9feeTimo Sirainen struct message_size hdr_parsed_size;
d7cd49f01fad7c87c5a0865ebf54a548275e9feeTimo Sirainen struct mbox_header_context ctx;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen uoff_t header_offset, body_offset, offset;
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen uoff_t hdr_size, body_size;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen unsigned char current_digest[16];
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen int hdr_size_fixed;
b8cd2f2f99351605725b7260f5da89cff76d0a3aTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *next_rec = NULL;
45155bb1250cf5a120278f349465aded513a100fTimo Sirainen
45155bb1250cf5a120278f349465aded513a100fTimo Sirainen /* skip the From-line */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen skip_line(input);
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen header_offset = input->v_offset;
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen
01cd9d4a8050a1dbf1da2c830f9755a45d6d004aTimo Sirainen hdr_size = 0; body_offset = 0; hdr_size_fixed = FALSE;
01cd9d4a8050a1dbf1da2c830f9755a45d6d004aTimo Sirainen do {
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen if (!mbox_mail_get_location(index, rec, NULL, NULL, &body_size))
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen i_stream_seek(input, header_offset);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (body_size == 0 && !hdr_size_fixed) {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* possibly broken message, find the next From-line
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen and make sure header parser won't pass it. */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen mbox_skip_header(input);
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen i_stream_set_read_limit(input, input->v_offset);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen i_stream_seek(input, header_offset);
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen hdr_size_fixed = TRUE;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen hdr_size = 0;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen if (hdr_size == 0) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* get the MD5 sum of fixed headers and the current
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen message flags in Status and X-Status fields */
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen mbox_header_init_context(&ctx, index, input);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen message_parse_header(NULL, input, &hdr_parsed_size,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mbox_header_cb, &ctx);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen md5_final(&ctx.md5, current_digest);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen if (seq == 1) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen if (!mbox_check_uidvalidity(index,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ctx.uid_validity)) {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* uidvalidity changed, abort */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen break;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen }
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen if (ctx.uid_last >= index->header->next_uid) {
ab45534d66792946b5794ab99a843d2f2b1d556fTimo Sirainen /* last_uid larger than ours */
ab45534d66792946b5794ab99a843d2f2b1d556fTimo Sirainen index->header->next_uid =
ab45534d66792946b5794ab99a843d2f2b1d556fTimo Sirainen ctx.uid_last+1;
ab45534d66792946b5794ab99a843d2f2b1d556fTimo Sirainen }
ab45534d66792946b5794ab99a843d2f2b1d556fTimo Sirainen }
ab45534d66792946b5794ab99a843d2f2b1d556fTimo Sirainen
ab45534d66792946b5794ab99a843d2f2b1d556fTimo Sirainen mbox_header_free_context(&ctx);
ab45534d66792946b5794ab99a843d2f2b1d556fTimo Sirainen i_stream_set_read_limit(input, 0);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen body_offset = input->v_offset;
ac84cb764c3a6f4b4b9ded2510d425fb5744dfe8Timo Sirainen }
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (verify_header(index, rec, ctx.uid, current_digest) &&
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen mbox_verify_end_of_body(input, body_offset + body_size)) {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* valid message */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen update = index->update_begin(index, rec);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* update flags, unless we've changed them */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if ((rec->index_flags & INDEX_MAIL_FLAG_DIRTY) == 0) {
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen if (!index->update_flags(index, rec, seq,
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen ctx.flags, TRUE))
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen return FALSE;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* update_flags() sets dirty flag, remove it */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen rec->index_flags &= ~INDEX_MAIL_FLAG_DIRTY;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen } else {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (rec->msg_flags != ctx.flags)
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen *dirty = TRUE;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen }
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* update location */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (!mbox_mail_get_location(index, rec, &offset,
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen NULL, NULL))
b8422738d3c891c7c93294b027a5cfe7d520e378Timo Sirainen return FALSE;
b8422738d3c891c7c93294b027a5cfe7d520e378Timo Sirainen if (offset != header_offset) {
b8422738d3c891c7c93294b027a5cfe7d520e378Timo Sirainen index->update_field_raw(update,
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen DATA_FIELD_LOCATION,
8e50329e2c5e3a199674ae9f6d3dfcddab02487bTimo Sirainen &header_offset,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen sizeof(uoff_t));
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
f8a78c816b4dbfda42f13d8ee152e0cdb28c6a4aTimo Sirainen /* update size */
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen if (hdr_size != hdr_parsed_size.physical_size ) {
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen if (!mail_update_header_size(index, rec, update,
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen &hdr_parsed_size))
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen return FALSE;
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen }
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen if (!index->update_end(update))
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen return FALSE;
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen *next_rec = rec;
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen break;
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen }
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen /* try next message */
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen (void)index->expunge(index, rec, seq, TRUE);
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen rec = index->next(index, rec);
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen } while (rec != NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return TRUE;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainenstatic int mbox_sync_from_stream(struct mail_index *index,
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen struct istream *input)
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen{
ac45ba9c603b67cc43fa7bceffdef0a19100720bTimo Sirainen struct mail_index_record *rec;
6e8ad595d0603295f57bef576da8a3a00b55c5e2Timo Sirainen uoff_t from_offset;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const unsigned char *data;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t size;
6e8ad595d0603295f57bef576da8a3a00b55c5e2Timo Sirainen unsigned int seq;
80980955bb1bbcc1bd73623fe0912f334194ddd2Timo Sirainen int dirty;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen mbox_skip_empty_lines(input);
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen /* first make sure we start with a "From " line. If file is too
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen small, we'll just treat it as empty mbox file. */
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen if (i_stream_read_data(input, &data, &size, 5) > 0 &&
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen memcmp(data, "From ", 5) != 0) {
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen index_set_error(index, "File isn't in mbox format: %s",
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen index->mailbox_path);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return FALSE;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* we'll go through the mailbox and index in order matching the
messages by their size and Message-ID. old mails aren't remembered,
so we handle well only the cases when mail has been deleted. if
mails have been reordered (eg. sorted by someone) most of the mails
will show up as being new. if we really wanted to support that well,
we could save the message-ids into hash but I don't know if it's
worth the trouble. */
seq = 1;
rec = index->lookup(index, 1);
dirty = FALSE;
while (rec != NULL) {
from_offset = input->v_offset;
if (input->v_offset != 0) {
/* we're at the [\r]\n before the From-line,
skip it */
if (!mbox_skip_crlf(input)) {
/* they just went and broke it, even while
we had it locked. */
index_set_error(index,
"Error syncing mbox file %s: "
"LF not found where expected",
index->mailbox_path);
return FALSE;
}
}
if (input->v_offset == input->v_size)
break;
if (!match_next_record(index, rec, seq, input, &rec, &dirty))
return FALSE;
if (rec == NULL) {
/* Get back to line before From */
i_stream_seek(input, from_offset);
break;
}
seq++;
rec = index->next(index, rec);
}
/* delete the rest of the records */
while (rec != NULL) {
(void)index->expunge(index, rec, seq, TRUE);
rec = index->next(index, rec);
}
if (!dirty && (index->header->flags & MAIL_INDEX_FLAG_DIRTY_MESSAGES)) {
/* no flags are dirty anymore, no need to rewrite */
index->header->flags &= ~MAIL_INDEX_FLAG_DIRTY_MESSAGES;
}
if (input->v_offset == input->v_size ||
(index->set_flags & MAIL_INDEX_FLAG_REBUILD))
return TRUE;
else
return mbox_index_append(index, input);
}
int mbox_sync_full(struct mail_index *index)
{
struct istream *input;
struct stat orig_st, st;
uoff_t continue_offset;
int failed;
i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
input = mbox_get_stream(index, 0, MAIL_LOCK_SHARED);
if (input == NULL)
return FALSE;
if (fstat(index->mbox_fd, &orig_st) < 0) {
mbox_set_syscall_error(index, "fstat()");
continue_offset = (uoff_t)-1;
failed = TRUE;
} else {
failed = !mbox_sync_from_stream(index, input);
continue_offset = failed || input->v_offset == input->v_size ||
(index->set_flags & MAIL_INDEX_FLAG_REBUILD) ?
(uoff_t)-1 : input->v_offset;
i_stream_unref(input);
}
if (continue_offset != (uoff_t)-1) {
/* mbox_index_append() stopped, which means that it wants
write access to mbox. if mbox hasn't changed after
unlock+lock, we should be able to safely continue where we
were left off last time. otherwise do full resync. */
if (!mbox_unlock(index))
return FALSE;
input = mbox_get_stream(index, 0, MAIL_LOCK_EXCLUSIVE);
if (input == NULL)
return FALSE;
if (fstat(index->mbox_fd, &st) < 0) {
mbox_set_syscall_error(index, "fstat()");
failed = TRUE;
} else if (st.st_mtime == orig_st.st_mtime &&
st.st_size == orig_st.st_size) {
i_stream_seek(input, continue_offset);
failed = !mbox_index_append(index, input);
} else {
failed = !mbox_sync_from_stream(index, input);
}
i_stream_unref(input);
}
return !failed;
}