mbox-rewrite.c revision 99b621cc5076398c5d780d2ea33dd7391341d630
/* Copyright (C) 2002 Timo Sirainen */
#include "lib.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "file-set-size.h"
#include "str.h"
#include "write-full.h"
#include "mbox-index.h"
#include "mbox-lock.h"
#include "mail-index-util.h"
#include "mail-custom-flags.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
struct mbox_rewrite_context {
int failed;
unsigned int msg_flags;
const char **custom_flags;
unsigned int uid_validity;
unsigned int uid_last;
unsigned int ximapbase_found:1;
unsigned int xkeywords_found:1;
unsigned int xuid_found:1;
unsigned int status_found:1;
unsigned int xstatus_found:1;
unsigned int content_length_found:1;
};
/* Remove dirty flag from all messages */
{
struct mail_index_record *rec;
}
}
{
int failed;
/* fsck should have noticed it.. */
} else {
}
return !failed;
}
{
const char *str;
int i;
return FALSE;
for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
return FALSE;
ctx->custom_flags[i]) < 0)
return FALSE;
}
}
return FALSE;
return TRUE;
}
{
const char *str;
return FALSE;
return TRUE;
}
const char *x_keywords)
{
unsigned int field;
int i;
x_keywords == NULL)
return TRUE;
return FALSE;
return FALSE;
ctx->custom_flags[i]) < 0)
return FALSE;
}
}
if (x_keywords != NULL) {
/* X-Keywords that aren't custom flags */
return FALSE;
return FALSE;
}
return FALSE;
return TRUE;
}
const char *status)
{
const char *str;
return FALSE;
return FALSE;
return TRUE;
}
const char *x_status)
{
const char *str;
/* X-Status field */
return TRUE;
return FALSE;
return FALSE;
return TRUE;
}
{
return FALSE;
return TRUE;
}
const char *list)
{
/* @UNSAFE: leave only unknown flags, very likely none */
char *ret, *p;
size_t i;
for (i = 0; i < value_len; i++) {
*p++ = value[i];
}
if (ret == p)
return NULL;
*p = '\0';
return ret;
}
{
if (index < 0) {
/* not found, keep it */
}
}
struct mbox_rewrite_context *ctx)
{
}
void *context)
{
const char *str;
return;
(void)mbox_write_ximapbase(ctx);
}
(void)mbox_write_xuid(ctx);
} else if (name_len == 14 &&
(void)mbox_write_content_length(ctx);
} else if (name_len > 0) {
/* save this header */
}
}
{
/* We need to update fields that define message flags. Standard fields
are stored in Status and X-Status. For custom flags we use
uw-imapd compatible format, by first listing them in first message's
X-IMAPbase field and actually defining them in X-Keywords field.
Format of X-IMAPbase is: <UID validity> <last used UID> <flag names>
We don't want to sync our UIDs with the mbox file, so the UID
validity is always kept different from our internal UID validity.
Last used UID is also not updated, and set to 0 initially.
*/
struct mbox_rewrite_context ctx;
struct message_size hdr_parsed_size;
/* fsck should have noticed it.. */
return FALSE;
}
t_push();
/* parse the header, write the fields we don't want to change */
/* append the flag fields */
/* write X-IMAPbase header to first message */
(void)mbox_write_ximapbase(&ctx);
}
if (!ctx.status_found)
if (!ctx.xstatus_found)
if (!ctx.xkeywords_found)
if (!ctx.xuid_found)
(void)mbox_write_xuid(&ctx);
if (!ctx.content_length_found)
(void)mbox_write_content_length(&ctx);
t_pop();
/* empty line ends headers */
return TRUE;
}
{
int ret;
/* first grow the file to wanted size, to make sure we don't run out
of disk space */
return -1;
}
return -1;
}
}
return -1;
}
t_push();
if (ret < 0) {
}
t_pop();
return ret;
}
{
return TRUE;
if (o_stream_flush(output) < 0) {
return FALSE;
}
/* POSSIBLE DATA LOSS HERE. We're writing to the mbox file,
so if we get killed here before finished, we'll lose some
bytes. I can't really think of any way to fix this,
rename() is problematic too especially because of file
locking issues (new mail could be lost).
Usually we're moving the data by just a few bytes, so
the data loss should never be more than those few bytes..
If we moved more, we could have written the file from end
to beginning in blocks (it'd be a bit slow to do it in
blocks of ~1-10 bytes which is the usual case, so we don't
bother).
Also, we might as well be shrinking the file, in which
case we can't lose data. */
return FALSE;
/* All ok. Just make sure the timestamps of index and
mbox differ, so index will be updated at next sync */
if (o_stream_seek(output, 0) < 0) {
return FALSE;
}
return TRUE;
}
#define INDEX_DIRTY_FLAGS \
{
/* Write messages beginning from the first dirty one to temp file,
then copy it over the mbox file. This may create data loss if
interrupted (see below). This rewriting relies quite a lot on
struct mail_index_record *rec;
const char *path;
unsigned int seq;
if (!no_locking) {
return FALSE;
}
if (!no_locking) {
return FALSE;
}
if (!rewrite) {
/* no need to rewrite */
return TRUE;
}
do {
if (!no_locking) {
break;
NULL))
break;
}
break;
/* fsck() figured out there's no dirty messages
after all */
break;
}
if (tmp_fd == -1)
break;
} while (0);
if (!rewrite) {
if (!no_locking) {
}
return !failed;
}
/* need to update X-IMAPbase in first message */
dirty_found = TRUE;
} else {
dirty_found = FALSE;
}
dirty_offset = 0;
/* note: we can't use data_stack_pool with output stream because it's
being written to inside t_push() .. t_pop() calls */
/* get offset to beginning of mail headers */
/* fsck should have fixed it */
break;
}
"Invalid message offset");
break;
}
"Invalid message size");
break;
}
}
if (!dirty_found &&
/* first dirty message */
dirty_found = TRUE;
}
if (dirty_found) {
/* write the From-line */
break;
}
/* write header, updating flag fields */
break;
}
if (dirty_found &&
/* no need to write more, flush */
break;
}
dirty_found = FALSE;
} else {
/* write body */
break;
}
}
}
seq++;
}
if (!failed && dirty_found) {
/* end with \n */
}
}
if (!failed && dirty_found) {
else {
/* we may have shrinked the file */
}
}
}
if (!failed)
if (!no_locking) {
}
return !failed;
}