mail-index-view-sync.c revision bf91bed88d4e294b4577ba2a3b14d87cf35ae135
/* Copyright (C) 2003-2004 Timo Sirainen */
#include "lib.h"
#include "array.h"
#include "buffer.h"
#include "mail-index-view-private.h"
#include "mail-index-sync-private.h"
#include "mail-transaction-log.h"
struct mail_index_view_sync_ctx {
struct mail_index_view *view;
struct mail_index_sync_map_ctx sync_map_ctx;
const struct mail_transaction_header *hdr;
const void *data;
unsigned int sync_map_update:1;
unsigned int skipped_expunges:1;
unsigned int last_read:1;
};
static int
{
/* Note that all the sequences are actually still UIDs at this point */
unsigned int first, i, dest_count;
/* @UNSAFE */
if (dest_count == 0) {
return 0;
}
/* src[] must be sorted. */
return -1;
for (; i < dest_count; i++) {
break;
}
first = i;
i++;
}
/* continue previous record */
} else if (i == first) {
i++; first++;
} else {
/* use next record */
first++;
}
if (i > first) {
i = first;
}
}
return 0;
}
static int
{
bool reset;
int ret;
for (;;) {
/* the view begins from the first non-synced transaction */
&reset);
if (ret <= 0) {
if (ret < 0)
return -1;
/* FIXME: use the new index to get needed
changes */
"Transaction log got desynced for index %s",
return -1;
}
if (!reset || sync_expunges)
break;
/* we can't do this. sync only up to reset. */
&end_seq, &end_offset);
/* we have only this reset log */
break;
}
}
return 0;
}
static int
{
const struct mail_transaction_header *hdr;
const void *data;
unsigned int count;
int ret;
return -1;
/* get a list of expunge transactions. there may be some that we have
already synced, but it doesn't matter because they'll get dropped
out when converting to sequences */
continue;
/* this is simply a request for expunge */
continue;
}
"Corrupted expunge record");
ret = -1;
break;
}
}
if (ret < 0) {
return -1;
}
/* convert UIDs to sequences */
count--;
else
dest++;
}
return 0;
}
{
return -1;
if (seq1 != 0)
return 1;
}
return 0;
}
{
const struct mail_transaction_header *hdr;
const void *data;
int ret = 0;
continue;
/* this is simply a request for expunge */
continue;
}
/* we have an expunge. see if it still exists. */
if (ret != 0)
break;
}
/* handle failures as having expunges (which is safer).
we'll probably fail later. */
return ret != 0;
}
struct mail_index_view_sync_ctx **ctx_r)
{
struct mail_index_view_sync_ctx *ctx;
struct mail_index_map *map;
bool sync_expunges;
return -1;
if (sync_expunges) {
/* get list of all expunges first */
return -1;
}
if (array_is_created(&expunges))
return -1;
}
/* keep the old mapping without expunges until we're
fully synced */
} else {
/* We need a private copy of the map if we don't want to
sync expunges.
If view's map is the head map, it means that it contains
already all the latest changes and there's no need for us
to apply any changes to it. This can only happen if there
hadn't been any expunges. */
/* Using non-head mapping. We have to apply
transactions to it to get latest changes into it. */
}
} else {
}
}
#ifdef DEBUG
#endif
/* Syncing the view invalidates all previous looked up records.
Unreference the mappings this view keeps because of them. */
return 0;
}
static bool
{
const struct mail_index_view_log_sync_area *syncs;
unsigned int i, count;
return FALSE;
for (i = 0; i < count; i++) {
return TRUE;
}
return FALSE;
}
static bool
const struct mail_transaction_header *hdr)
{
if (!ctx->skipped_expunges) {
}
return FALSE;
}
/* already synced */
return FALSE;
}
}
view->log_file_head_offset)) {
/* already synced */
return FALSE;
}
return TRUE;
}
static int
{
const struct mail_transaction_header *hdr;
int ret;
bool synced_to_map;
for (;;) {
/* Get the next transaction from log. */
if (ret <= 0) {
if (ret < 0)
return -1;
return 0;
}
/* This is a visible record that we don't want to
sync. */
continue;
}
/* If we started from a map that we didn't create ourself,
some of the transactions may already be synced. at the end
of this view sync we'll update file_seq=0 so that this check
always becomes FALSE for subsequent syncs. */
/* Apply transaction to view's mapping if needed (meaning we
didn't just re-map the view to head mapping). */
return -1;
}
/* skip changes committed by hidden transactions (eg. in IMAP
store +flags.silent command) */
continue;
break;
}
return 1;
}
#define FLAG_UPDATE_IS_INTERNAL(u) \
((((u)->add_flags | (u)->remove_flags) & \
~(MAIL_INDEX_MAIL_FLAG_DIRTY | MAIL_RECENT)) == 0)
static bool
struct mail_index_view_sync_rec *rec)
{
case MAIL_TRANSACTION_APPEND: {
/* data contains the appended records, but we don't care */
break;
}
case MAIL_TRANSACTION_EXPUNGE: {
const struct mail_transaction_expunge *exp =
/* this is simply a request for expunge */
return 0;
}
/* data contains mail_transaction_expunge[] */
break;
}
case MAIL_TRANSACTION_FLAG_UPDATE: {
const struct mail_transaction_flag_update *update =
/* data contains mail_transaction_flag_update[] */
for (;;) {
if (!FLAG_UPDATE_IS_INTERNAL(update))
break;
/* skip internal flag changes */
return 0;
}
break;
}
case MAIL_TRANSACTION_KEYWORD_UPDATE: {
/* data contains mail_transaction_keyword_update header,
the keyword name and an array of { uint32_t uid1, uid2; } */
if (ctx->data_offset == 0) {
/* skip over the header and name */
}
break;
}
case MAIL_TRANSACTION_KEYWORD_RESET: {
const struct mail_transaction_keyword_reset *reset =
/* data contains mail_transaction_keyword_reset[] */
break;
}
default:
return FALSE;
}
return TRUE;
}
struct mail_index_view_sync_rec *sync_rec)
{
int ret;
do {
if (ret <= 0)
return ret;
ctx->data_offset = 0;
}
return 1;
}
{
}
static void
{
const struct mail_index_view_log_sync_area *syncs;
unsigned int i, count;
return;
/* Clean up to view's tail */
for (i = 0; i < count; i++) {
if ((syncs[i].log_file_offset +
break;
}
if (i > 0)
}
{
/* we didn't sync everything */
}
}
if (!ctx->skipped_expunges) {
}
if (ctx->sync_map_update) {
/* log offsets have no meaning in views. make sure they're not
tried to be used wrong by setting them to zero. */
}
#ifdef DEBUG
#endif
/* set log view to empty range so unneeded memory gets freed */
}
unsigned int length)
{
struct mail_index_view_log_sync_area *area;
}