mbox-fsck.c revision d14de73e30d5d0e06a5b28508b6a44e888edd2d1
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "lib.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "iobuffer.h"
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#include "hex-binary.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "message-parser.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "message-part-serialize.h"
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include "mbox-index.h"
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen#include "mbox-lock.h"
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen#include "mail-index-util.h"
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen#include <unistd.h>
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen#include <fcntl.h>
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainenstatic void skip_line(IOBuffer *inbuf)
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned char *msg;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen size_t i, size;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen while (io_buffer_read_data_blocking(inbuf, &msg, &size, 0) > 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < size; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (msg[i] == '\n') {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen io_buffer_skip(inbuf, i+1);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen io_buffer_skip(inbuf, i);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen}
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic int verify_header_md5sum(MailIndex *index, MailIndexRecord *rec,
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen unsigned char current_digest[16])
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen{
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen const unsigned char *old_digest;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen size_t size;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* MD5 sums must match */
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen old_digest = index->lookup_field_raw(index, rec, FIELD_TYPE_MD5, &size);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return old_digest != NULL && size >= 16 &&
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen memcmp(old_digest, current_digest, 16) == 0;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic int verify_end_of_body(IOBuffer *inbuf, uoff_t end_offset)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen unsigned char *data;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen size_t size;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen /* don't bother parsing the whole body, just make
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen sure it ends properly */
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen io_buffer_seek(inbuf, end_offset);
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen
b87436ebb957a9eb182be72ba00e2c8eae59a2e4Timo Sirainen if (inbuf->offset == inbuf->size) {
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen /* end of file. a bit unexpected though,
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen since \n is missing. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return TRUE;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* read forward a bit */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (io_buffer_read_data_blocking(inbuf, &data, &size, 6) < 0)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return FALSE;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen /* either there should be the next From-line,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen or [\r]\n at end of file */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (size > 0 && data[0] == '\r') {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen data++; size--;
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen }
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen if (size > 0) {
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen if (data[0] != '\n')
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return FALSE;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen data++; size--;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return size == 0 || (size >= 5 && strncmp(data, "From ", 5) == 0);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic int mail_update_header_size(MailIndex *index, MailIndexRecord *rec,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen MailIndexUpdate *update,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen MessageSize *hdr_size)
fd1f0e9ef52b3e157cfd1a01c464c2ac7458ab17Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const void *part_data;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen void *part_data_copy;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen size_t size;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* update index record */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen rec->header_size = hdr_size->physical_size;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if ((rec->cached_fields & FIELD_TYPE_MESSAGEPART) == 0)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen /* update FIELD_TYPE_MESSAGEPART */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen part_data = index->lookup_field_raw(index, rec, FIELD_TYPE_MESSAGEPART,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen &size);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (part_data == NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* well, this wasn't expected but don't bother failing */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* copy & update the part data */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen part_data_copy = t_malloc(size);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen memcpy(part_data_copy, part_data, size);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (!message_part_serialize_update_header(part_data_copy, size,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen hdr_size))
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return FALSE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen index->update_field_raw(update, FIELD_TYPE_MESSAGEPART,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen part_data_copy, size);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return TRUE;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int match_next_record(MailIndex *index, MailIndexRecord *rec,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int seq, IOBuffer *inbuf,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen MailIndexRecord **next_rec, int *dirty)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen MailIndexUpdate *update;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen MessageSize hdr_size;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen MboxHeaderContext ctx;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uoff_t header_offset, body_offset, offset;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned char current_digest[16];
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *next_rec = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* skip the From-line */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen skip_line(inbuf);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen header_offset = inbuf->offset;
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen if (rec->body_size == 0) {
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen /* possibly broken message, find the From-line to make sure
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen header parser won't pass it. */
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen mbox_skip_message(inbuf);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen io_buffer_set_read_limit(inbuf, inbuf->offset);
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainen io_buffer_seek(inbuf, header_offset);
26a8b7deb3a5b6f26f9c4d71538e1248f680e4beTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* get the MD5 sum of fixed headers and the current message flags
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen in Status and X-Status fields */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mbox_header_init_context(&ctx, index);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen message_parse_header(NULL, inbuf, &hdr_size, mbox_header_func, &ctx);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen md5_final(&ctx.md5, current_digest);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mbox_header_free_context(&ctx);
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen io_buffer_set_read_limit(inbuf, 0);
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen body_offset = inbuf->offset;
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen do {
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen if (verify_header_md5sum(index, rec, current_digest) &&
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen verify_end_of_body(inbuf, body_offset + rec->body_size)) {
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen /* valid message */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen update = index->update_begin(index, rec);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* update flags, unless we've changed them */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if ((rec->index_flags & INDEX_MAIL_FLAG_DIRTY) == 0) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (!index->update_flags(index, rec, seq,
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen ctx.flags, TRUE))
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen return FALSE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* update_flags() sets dirty flag, remove it */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen rec->index_flags &= ~INDEX_MAIL_FLAG_DIRTY;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen } else {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (rec->msg_flags != ctx.flags)
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen *dirty = TRUE;
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* update location */
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen if (!mbox_mail_get_start_offset(index, rec, &offset))
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return FALSE;
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen if (offset != header_offset) {
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen index->update_field_raw(update,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen FIELD_TYPE_LOCATION,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen &header_offset,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen sizeof(uoff_t));
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* update size */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (rec->header_size != hdr_size.physical_size ) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (!mail_update_header_size(index, rec,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen update, &hdr_size))
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return FALSE;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen }
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if (!index->update_end(update))
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return FALSE;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *next_rec = rec;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* try next message */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen (void)index->expunge(index, rec, seq, TRUE);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen rec = index->next(index, rec);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } while (rec != NULL);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic int mbox_index_fsck_buf(MailIndex *index, IOBuffer *inbuf)
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen{
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen MailIndexRecord *rec;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen uoff_t from_offset;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen unsigned char *data;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen size_t size;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen unsigned int seq;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen int dirty;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return FALSE;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen mbox_skip_empty_lines(inbuf);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen /* first make sure we start with a "From " line. If file is too
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen small, we'll just treat it as empty mbox file. */
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (io_buffer_read_data_blocking(inbuf, &data, &size, 5) > 0 &&
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen strncmp(data, "From ", 5) != 0) {
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen index_set_error(index, "File isn't in mbox format: %s",
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen index->mbox_path);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return FALSE;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen /* we'll go through the mailbox and index in order matching the
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen messages by their size and Message-ID. old mails aren't remembered,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen so we handle well only the cases when mail has been deleted. if
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen mails have been reordered (eg. sorted by someone) most of the mails
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen will show up as being new. if we really wanted to support that well,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen we could save the message-ids into hash but I don't know if it's
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen worth the trouble. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen seq = 1;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen rec = index->lookup(index, 1);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen dirty = FALSE;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen while (rec != NULL) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen from_offset = inbuf->offset;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (inbuf->offset != 0) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* we're at the [\r]\n before the From-line,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen skip it */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (!mbox_skip_crlf(inbuf)) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* they just went and broke it, even while
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen we had it locked. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return FALSE;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (inbuf->offset == inbuf->size)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen break;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (!match_next_record(index, rec, seq, inbuf, &rec, &dirty))
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return FALSE;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (rec == NULL) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* Get back to line before From */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen io_buffer_seek(inbuf, from_offset);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen break;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen seq++;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen rec = index->next(index, rec);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* delete the rest of the records */
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen while (rec != NULL) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen (void)index->expunge(index, rec, seq, TRUE);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen rec = index->next(index, rec);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (!dirty && (index->header->flags & MAIL_INDEX_FLAG_DIRTY_MESSAGES)) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen /* no flags were dirty anymore, no need to rewrite */
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen index->header->flags &= ~MAIL_INDEX_FLAG_DIRTY_MESSAGES;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (inbuf->offset == inbuf->size)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return TRUE;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen else
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return mbox_index_append(index, inbuf);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen}
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainenint mbox_index_fsck(MailIndex *index)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen{
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen IOBuffer *inbuf;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen int fd, failed;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen /* open the mbox file. we don't really need to open it read-write,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen but fcntl() locking requires it. */
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen fd = open(index->mbox_path, O_RDWR);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (fd == -1)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return mbox_set_syscall_error(index, "open()");
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen inbuf = io_buffer_create_mmap(fd, default_pool,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen MAIL_MMAP_BLOCK_SIZE, 0);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (!mbox_lock(index, index->mbox_path, fd, FALSE))
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen failed = TRUE;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen else {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen failed = !mbox_index_fsck_buf(index, inbuf);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen (void)mbox_unlock(index, index->mbox_path, fd);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (close(fd) < 0)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen mbox_set_syscall_error(index, "close()");
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen io_buffer_destroy(inbuf);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (failed)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return FALSE;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* check the header */
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return mail_index_fsck(index);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen}
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen