mbox-sync-rewrite.c revision 313fe89df4d91cd0cd7f3558dc6d7fd21ad39eee
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch#include "lib.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "buffer.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "istream.h"
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen#include "ostream.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "str.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "write-full.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "message-parser.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "mbox-storage.h"
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen#include "mbox-sync-private.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "istream-raw-mbox.h"
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenint mbox_move(struct mbox_sync_context *sync_ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uoff_t dest, uoff_t source, uoff_t size)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct istream *input;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct ostream *output;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen off_t ret;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen istream_raw_mbox_flush(sync_ctx->input);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen output = o_stream_create_file(sync_ctx->fd, default_pool, 4096, FALSE);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen i_stream_seek(sync_ctx->file_input, source);
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen o_stream_seek(output, dest);
12d38e76ba7f70d6219c89ec7416fea0d5de7e02Timo Sirainen
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen if (size == (uoff_t)-1) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen input = sync_ctx->file_input;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return o_stream_send_istream(output, input) < 0 ? -1 : 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen } else {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen input = i_stream_create_limit(default_pool,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen sync_ctx->file_input,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen source, size);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ret = o_stream_send_istream(output, input);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_stream_unref(input);
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen return ret == (off_t)size ? 0 : -1;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen }
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen}
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainenstatic void mbox_sync_headers_add_space(struct mbox_sync_mail_context *ctx,
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen size_t size)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen size_t data_size, pos;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const unsigned char *data;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen void *p;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* Append at the end of X-Keywords header,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen or X-UID if it doesn't exist */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen pos = ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] != (size_t)-1 ?
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] :
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen ctx->hdr_pos[MBOX_HDR_X_UID];
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen data = buffer_get_data(ctx->header, &data_size);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen while (pos < data_size && data[pos] != '\n')
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen pos++;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen buffer_copy(ctx->header, pos + size,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen ctx->header, pos, (size_t)-1);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen p = buffer_get_space_unsafe(ctx->header, pos, size);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen memset(p, ' ', size);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen ctx->mail.offset = ctx->hdr_offset + pos;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen ctx->mail.space += size;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (ctx->header_first_change > pos)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen ctx->header_first_change = pos;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen ctx->header_last_change = (size_t)-1;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void mbox_sync_header_remove_space(struct mbox_sync_mail_context *ctx,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen size_t pos, size_t *size)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const unsigned char *data;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen size_t data_size, end, nonspace;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek /* find the end of the lwsp */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen nonspace = pos-1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data = str_data(ctx->header);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data_size = str_len(ctx->header);
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi for (end = pos; end < data_size; end++) {
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi if (data[end] == '\n') {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (end+1 == data_size || !IS_LWSP(data[end+1]))
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen break;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen } else {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!IS_LWSP(data[end]))
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen nonspace = end;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* and remove what we can */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen nonspace++;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if (end-nonspace < *size) {
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen str_delete(ctx->header, nonspace, end-nonspace);
83d2e37f065eabe38dc92db485c5ca39ee43ce05Timo Sirainen *size -= end-nonspace;
026d971be5201aed5ccf60138900770e42cf0de5Timo Sirainen } else {
83d2e37f065eabe38dc92db485c5ca39ee43ce05Timo Sirainen str_delete(ctx->header, nonspace, *size);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen end -= *size;
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen *size = 0;
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ctx->mail.space < end-nonspace) {
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi ctx->mail.space = end-nonspace;
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi ctx->mail.offset = ctx->hdr_offset + nonspace;
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi }
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi }
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi}
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainenstatic void mbox_sync_headers_remove_space(struct mbox_sync_mail_context *ctx,
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen size_t size)
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen{
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen static enum header_position space_positions[] = {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen MBOX_HDR_X_KEYWORDS,
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen MBOX_HDR_X_UID,
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi MBOX_HDR_X_IMAPBASE
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi };
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi enum header_position pos;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen int i;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen ctx->header_last_change = (size_t)-1;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen ctx->mail.space = 0;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen ctx->mail.offset = ctx->hdr_offset;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen for (i = 0; i < 3 && size > 0; i++) {
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen pos = space_positions[i];
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen if (ctx->hdr_pos[pos] != (size_t)-1) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (ctx->header_first_change > ctx->hdr_pos[pos])
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen ctx->header_first_change = ctx->hdr_pos[pos];
d1ba8ecbb936ace90179d2292952546708d68f71Timo Sirainen mbox_sync_header_remove_space(ctx, ctx->hdr_pos[pos],
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen &size);
4b1781e4c64be52e25b5994e5242dbe696cc7d29Timo Sirainen }
4b1781e4c64be52e25b5994e5242dbe696cc7d29Timo Sirainen }
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen i_assert(size == 0);
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen}
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainenint mbox_sync_try_rewrite(struct mbox_sync_mail_context *ctx)
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen{
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen size_t old_hdr_size, new_hdr_size;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen const unsigned char *data;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen old_hdr_size = ctx->body_offset - ctx->hdr_offset;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen new_hdr_size = str_len(ctx->header);
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen /* do we have enough space? */
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen if (new_hdr_size < old_hdr_size)
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen mbox_sync_headers_add_space(ctx, old_hdr_size - new_hdr_size);
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen else if (new_hdr_size > old_hdr_size) {
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen size_t needed = new_hdr_size - old_hdr_size;
e0a84bcd487b05872da59781452168609b5c1f2cTimo Sirainen if (ctx->mail.space < needed)
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen return 0;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen mbox_sync_headers_remove_space(ctx, needed);
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen }
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen i_assert(ctx->header_first_change != (size_t)-1);
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen if (ctx->header_last_change != (size_t)-1)
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen str_truncate(ctx->header, ctx->header_last_change);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data = str_data(ctx->header);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen new_hdr_size = str_len(ctx->header);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (pwrite_full(ctx->sync_ctx->fd, data + ctx->header_first_change,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen new_hdr_size - ctx->header_first_change,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->hdr_offset + ctx->header_first_change) < 0) {
31633d676642b83305b8d46da495d9bb4e2d1ff8Timo Sirainen // FIXME: error handling
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen return -1;
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen }
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen istream_raw_mbox_flush(ctx->sync_ctx->input);
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen return 1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomistatic void mbox_sync_fix_from_offset(struct mbox_sync_context *sync_ctx,
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi uint32_t idx, off_t diff)
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi{
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi uoff_t *offset_p;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen offset_p = buffer_get_space_unsafe(sync_ctx->ibox->mbox_data_buf,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen idx * sizeof(*offset_p),
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen sizeof(*offset_p));
865a82c1e9bba11609835a36674964649025bf77Timo Sirainen *offset_p = (*offset_p & 1) | (((*offset_p >> 1) + diff) << 1);
865a82c1e9bba11609835a36674964649025bf77Timo Sirainen}
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainenstatic int mbox_sync_read_and_move(struct mbox_sync_context *sync_ctx,
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen struct mbox_sync_mail *mails, uint32_t idx,
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen uint32_t extra_per_mail,
5d4855d7b4dcffb6975ed8e3c9c376dac74e5c8aTimo Sirainen uoff_t *end_offset)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen struct mbox_sync_mail_context mail_ctx;
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen uoff_t offset;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen i_stream_seek(sync_ctx->file_input, mails[idx].offset);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen memset(&mail_ctx, 0, sizeof(mail_ctx));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_ctx.sync_ctx = sync_ctx;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen mail_ctx.seq = idx+1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_ctx.header = sync_ctx->header;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_ctx.mail.offset = mails[idx].offset;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_ctx.mail.body_size = mails[idx].body_size;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen mbox_sync_parse_next_mail(sync_ctx->file_input, &mail_ctx);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mbox_sync_update_header_from(&mail_ctx, &mails[idx]);
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_assert(mail_ctx.mail.space == mails[idx].space);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen /* we're moving next message - update it's from_offset */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen mbox_sync_fix_from_offset(sync_ctx, idx+1, mails[idx+1].space);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (mail_ctx.mail.space <= 0) {
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen mail_ctx.mail.space = 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mbox_sync_headers_add_space(&mail_ctx, extra_per_mail);
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi } else if (mail_ctx.mail.space <= extra_per_mail) {
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi mbox_sync_headers_add_space(&mail_ctx, extra_per_mail -
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen mail_ctx.mail.space);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen } else {
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi mbox_sync_headers_remove_space(&mail_ctx, mail_ctx.mail.space -
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi extra_per_mail);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen /* now we have to move it. first move the body of the message,
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen then write the header and leave the extra space to beginning of
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen headers. */
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen offset = sync_ctx->file_input->v_offset;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen if (mbox_move(sync_ctx, offset + mails[idx+1].space, offset,
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen *end_offset - offset - mails[idx+1].space)) {
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen // FIXME: error handling
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen return -1;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen }
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen *end_offset = offset + mails[idx+1].space - str_len(mail_ctx.header);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen if (pwrite_full(sync_ctx->fd, str_data(mail_ctx.header),
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen str_len(mail_ctx.header), *end_offset) < 0) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen // FIXME: error handling
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return -1;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen }
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen mails[idx].space += mails[idx+1].space - extra_per_mail;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen return 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainenint mbox_sync_rewrite(struct mbox_sync_context *sync_ctx, buffer_t *mails_buf,
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen uint32_t first_seq, uint32_t last_seq, off_t extra_space)
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct mbox_sync_mail *mails;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen size_t size;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen uoff_t offset, end_offset;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen uint32_t idx, extra_per_mail;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen int ret = 0;
31633d676642b83305b8d46da495d9bb4e2d1ff8Timo Sirainen
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen mails = buffer_get_modifyable_data(mails_buf, &size);
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen size /= sizeof(*mails);
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen /* FIXME: see if we can be faster by going back a few mails
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen (update first_seq and last_seq). */
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen extra_per_mail = (extra_space / (last_seq - first_seq + 1));
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi mails[last_seq-1].space -= extra_per_mail;
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi i_assert(mails[last_seq-1].space > 0);
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi end_offset = mails[last_seq-1].offset + mails[last_seq-1].space;
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi
865a82c1e9bba11609835a36674964649025bf77Timo Sirainen /* start moving backwards */
865a82c1e9bba11609835a36674964649025bf77Timo Sirainen while (--last_seq >= first_seq) {
3db05c8c00faca6ab9ac8391e1d6977365f4d1b3Timo Sirainen idx = last_seq-1;
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen if (mails[idx].space <= 0) {
3db05c8c00faca6ab9ac8391e1d6977365f4d1b3Timo Sirainen /* offset points to beginning of headers. read the
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen header again, update it and give enough space to
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen it */
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen if (mbox_sync_read_and_move(sync_ctx, mails, idx,
f0ecd925c7feb815c4b9acf84772fcd56c02319bTimo Sirainen extra_per_mail,
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen &end_offset) < 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ret = -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen break;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen }
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen } else {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen /* X-Keywords: xx [offset] \n
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen ...
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen X-Keywords: xx [end_offset] \n
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen move data forward so mails before us gets the extra
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen space (ie. we temporarily get more space to us) */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen offset = mails[idx].offset + mails[idx].space;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if (mbox_move(sync_ctx, offset + mails[idx+1].space,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen offset, end_offset - offset)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen // FIXME: error handling
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ret = -1;
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen break;
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen mbox_sync_fix_from_offset(sync_ctx, idx+1,
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen mails[idx+1].space);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen mails[idx].space += mails[idx+1].space - extra_per_mail;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_assert(mails[idx].space > 0);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen end_offset = mails[idx].offset + mails[idx].space;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen istream_raw_mbox_flush(sync_ctx->input);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return ret;
50168536f8d04626d71860c73b2efc18d407d083Aki Tuomi}
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen