Saved UIDs are no longer necessarily in a simple x:y range.
--HG--
branch : HEAD
#include "istream.h"
#include "ostream.h"
#include "str.h"
-#include "imap-commands.h"
#include "imap-parser.h"
#include "imap-date.h"
+#include "imap-util.h"
+#include "imap-commands.h"
#include <sys/time.h>
/* last message */
enum mailbox_sync_flags sync_flags;
enum imap_sync_flags imap_flags;
- uint32_t uid_validity, uid1, uid2;
- const char *msg;
+ struct mail_transaction_commit_changes changes;
+ string_t *msg;
/* eat away the trailing CRLF */
client->input_skip_line = TRUE;
return TRUE;
}
- ret = mailbox_transaction_commit_get_uids(&ctx->t,
- &uid_validity,
- &uid1, &uid2);
+ ret = mailbox_transaction_commit_get_changes(&ctx->t, &changes);
if (ret < 0) {
client_send_storage_error(cmd, ctx->storage);
cmd_append_finish(ctx);
return TRUE;
}
- i_assert(ctx->count == uid2 - uid1 + 1);
-
- if (uid1 == 0)
- msg = "OK Append completed.";
- else if (uid1 == uid2) {
- msg = t_strdup_printf("OK [APPENDUID %u %u] "
- "Append completed.",
- uid_validity, uid1);
- } else {
- msg = t_strdup_printf("OK [APPENDUID %u %u:%u] "
- "Append completed.",
- uid_validity, uid1, uid2);
- }
+ i_assert(ctx->count == seq_range_count(&changes.saved_uids));
+
+ msg = t_str_new(256);
+ str_printfa(msg, "OK [APPENDUID %u ", changes.uid_validity);
+ imap_write_seq_range(msg, &changes.saved_uids);
+ str_append(msg, "] Append completed.");
+ pool_unref(&changes.pool);
if (ctx->box == cmd->client->mailbox) {
sync_flags = 0;
}
cmd_append_finish(ctx);
- return cmd_sync(cmd, sync_flags, imap_flags, msg);
+ return cmd_sync(cmd, sync_flags, imap_flags, str_c(msg));
}
if (!validate_args(args, &flags_list, &internal_date_str,
#include "str.h"
#include "ostream.h"
#include "imap-resp-code.h"
+#include "imap-util.h"
#include "imap-commands.h"
#include "imap-search-args.h"
struct mailbox *destbox;
struct mailbox_transaction_context *t;
struct mail_search_args *search_args;
- const char *messageset, *mailbox, *src_uidset, *msg = NULL;
+ const char *messageset, *mailbox, *src_uidset;
enum mailbox_sync_flags sync_flags = 0;
enum imap_sync_flags imap_flags = 0;
+ struct mail_transaction_commit_changes changes;
unsigned int copy_count;
- uint32_t uid_validity, uid1, uid2;
+ string_t *msg;
int ret;
/* <message set> <mailbox> */
ret = fetch_and_copy(client, t, search_args, &src_uidset, ©_count);
mail_search_args_unref(&search_args);
+ msg = t_str_new(256);
if (ret <= 0)
mailbox_transaction_rollback(&t);
- else if (mailbox_transaction_commit_get_uids(&t, &uid_validity,
- &uid1, &uid2) < 0)
+ else if (mailbox_transaction_commit_get_changes(&t, &changes) < 0)
ret = -1;
else if (copy_count == 0)
- msg = "OK No messages copied.";
+ str_append(msg, "OK No messages copied.");
else {
- i_assert(copy_count == uid2 - uid1 + 1);
-
- if (uid1 == 0)
- msg = "OK Copy completed.";
- if (uid1 == uid2) {
- msg = t_strdup_printf("OK [COPYUID %u %s %u] "
- "Copy completed.",
- uid_validity, src_uidset, uid1);
- } else {
- msg = t_strdup_printf("OK [COPYUID %u %s %u:%u] "
- "Copy completed.",
- uid_validity, src_uidset,
- uid1, uid2);
- }
+ i_assert(copy_count == seq_range_count(&changes.saved_uids));
+
+ str_printfa(msg, "OK [COPYUID %u %s ", changes.uid_validity,
+ src_uidset);
+ imap_write_seq_range(msg, &changes.saved_uids);
+ str_append(msg, "] Copy completed.");
+ pool_unref(&changes.pool);
}
dest_storage = mailbox_get_storage(destbox);
}
if (ret > 0)
- return cmd_sync(cmd, sync_flags, imap_flags, msg);
+ return cmd_sync(cmd, sync_flags, imap_flags, str_c(msg));
else if (ret == 0) {
/* some messages were expunged, sync them */
return cmd_sync(cmd, 0, 0,
#include "lib.h"
#include "ioloop.h"
+#include "array.h"
#include "str.h"
#include "str-sanitize.h"
#include "var-expand.h"
struct mail_keywords *kw;
enum mail_error error;
const char *mailbox_name, *errstr;
- uint32_t uid_validity, uid1 = 0, uid2 = 0;
+ struct mail_transaction_commit_changes changes;
+ const struct seq_range *range;
bool default_save;
int ret = 0;
if (ret < 0)
mailbox_transaction_rollback(&t);
- else {
- ret = mailbox_transaction_commit_get_uids(&t, &uid_validity,
- &uid1, &uid2);
- }
+ else
+ ret = mailbox_transaction_commit_get_changes(&t, &changes);
if (ret == 0) {
ctx->saved_mail = TRUE;
mail_deliver_log(ctx, "saved mail to %s", mailbox_name);
if (ctx->save_dest_mail && mailbox_sync(box, 0, 0, NULL) == 0) {
- i_assert(uid1 == uid2);
+ range = array_idx(&changes.saved_uids, 0);
+ i_assert(range[0].seq1 == range[0].seq2);
t = mailbox_transaction_begin(box, 0);
ctx->dest_mail = mail_alloc(t, MAIL_FETCH_STREAM_BODY,
NULL);
- if (mail_set_uid(ctx->dest_mail, uid1) < 0) {
+ if (mail_set_uid(ctx->dest_mail, range[0].seq1) < 0) {
mail_free(&ctx->dest_mail);
mailbox_transaction_rollback(&t);
}
}
+ pool_unref(&changes.pool);
} else {
mail_deliver_log(ctx, "save failed to %s: %s", mailbox_name,
mail_storage_get_last_error(*storage_r, &error));
/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
+#include "array.h"
#include "hostpid.h"
#include "istream.h"
#include "istream-crlf.h"
int cydir_transaction_save_commit_pre(struct cydir_save_context *ctx)
{
- struct cydir_transaction_context *t =
- (struct cydir_transaction_context *)ctx->ctx.transaction;
+ struct mailbox_transaction_context *_t = ctx->ctx.transaction;
const struct mail_index_header *hdr;
+ struct seq_range *range;
uint32_t i, uid, next_uid;
const char *dir;
string_t *src_path, *dest_path;
uid = hdr->next_uid;
mail_index_append_assign_uids(ctx->trans, uid, &next_uid);
- *t->ictx.saved_uid_validity = ctx->sync_ctx->uid_validity;
- *t->ictx.first_saved_uid = uid;
- *t->ictx.last_saved_uid = next_uid - 1;
+ _t->changes->uid_validity = ctx->sync_ctx->uid_validity;
+ range = array_append_space(&_t->changes->saved_uids);
+ range->seq1 = uid;
+ range->seq2 = next_uid - 1;
dir = mailbox_list_get_path(ctx->mbox->ibox.box.list,
ctx->mbox->ibox.box.name,
int dbox_transaction_save_commit_pre(struct dbox_save_context *ctx)
{
- struct dbox_transaction_context *t =
- (struct dbox_transaction_context *)ctx->ctx.transaction;
+ struct mailbox_transaction_context *_t = ctx->ctx.transaction;
const struct mail_index_header *hdr;
+ struct seq_range *range;
uint32_t uid, first_map_uid, last_map_uid, next_uid;
i_assert(ctx->finished);
if (ctx->mail != NULL)
mail_free(&ctx->mail);
- *t->ictx.saved_uid_validity = hdr->uid_validity;
- *t->ictx.first_saved_uid = uid;
- *t->ictx.last_saved_uid = next_uid - 1;
+ _t->changes->uid_validity = hdr->uid_validity;
+ range = array_append_space(&_t->changes->saved_uids);
+ range->seq1 = uid;
+ range->seq2 = next_uid - 1;
return 0;
}
struct mail_cache_view *cache_view;
struct mail_cache_transaction_ctx *cache_trans;
- uint32_t *saved_uid_validity;
- uint32_t *first_saved_uid, *last_saved_uid;
-
unsigned int cache_trans_failed:1;
};
index_transaction_begin(struct mailbox *box,
enum mailbox_transaction_flags flags);
int index_transaction_commit(struct mailbox_transaction_context *t,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r,
- uint32_t *last_saved_uid_r);
+ struct mail_transaction_commit_changes *changes_r);
void index_transaction_rollback(struct mailbox_transaction_context *t);
void index_save_context_free(struct mail_save_context *ctx);
}
int index_transaction_commit(struct mailbox_transaction_context *_t,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r,
- uint32_t *last_saved_uid_r)
+ struct mail_transaction_commit_changes *changes_r)
{
struct index_transaction_context *t =
(struct index_transaction_context *)_t;
struct mail_index_transaction *itrans = t->trans;
- *uid_validity_r = 0;
- *first_saved_uid_r = *last_saved_uid_r = 0;
-
- t->saved_uid_validity = uid_validity_r;
- t->first_saved_uid = first_saved_uid_r;
- t->last_saved_uid = last_saved_uid_r;
+ memset(changes_r, 0, sizeof(*changes_r));
+ changes_r->pool = pool_alloconly_create("transaction changes", 1024);
+ p_array_init(&changes_r->saved_uids, changes_r->pool, 32);
+ _t->changes = changes_r;
return mail_index_transaction_commit(&itrans);
}
struct maildir_transaction_context *t =
(struct maildir_transaction_context *)ctx->ctx.transaction;
struct maildir_mailbox *mbox = ctx->mbox;
+ struct seq_range *range;
uint32_t uid, first_uid, next_uid;
int ret;
}
/* this will work even if index isn't updated */
- *t->ictx.first_saved_uid = first_uid;
- *t->ictx.last_saved_uid = next_uid - 1;
+ range = array_append_space(&t->ictx.mailbox_ctx.changes->saved_uids);
+ range->seq1 = first_uid;
+ range->seq2 = next_uid - 1;
return 0;
}
ret = -1;
}
- *t->ictx.saved_uid_validity =
+ t->ictx.mailbox_ctx.changes->uid_validity =
maildir_uidlist_get_uid_validity(ctx->mbox->uidlist);
if (ctx->mail != NULL) {
int mbox_transaction_save_commit(struct mbox_save_context *ctx)
{
- struct mbox_transaction_context *t =
- (struct mbox_transaction_context *)ctx->ctx.transaction;
+ struct mailbox_transaction_context *_t = ctx->ctx.transaction;
struct mbox_mailbox *mbox = ctx->mbox;
+ struct seq_range *range;
struct stat st;
int ret = 0;
}
if (ctx->synced) {
- *t->ictx.saved_uid_validity = ctx->uid_validity;
- *t->ictx.first_saved_uid = ctx->first_saved_uid;
- *t->ictx.last_saved_uid = ctx->next_uid - 1;
+ _t->changes->uid_validity = ctx->uid_validity;
+ range = array_append_space(&_t->changes->saved_uids);
+ range->seq1 = ctx->first_saved_uid;
+ range->seq2 = ctx->next_uid - 1;
mail_index_update_header(ctx->trans,
offsetof(struct mail_index_header, next_uid),
(*transaction_begin)(struct mailbox *box,
enum mailbox_transaction_flags flags);
int (*transaction_commit)(struct mailbox_transaction_context *t,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r,
- uint32_t *last_saved_uid_r);
+ struct mail_transaction_commit_changes *changes_r);
void (*transaction_rollback)(struct mailbox_transaction_context *t);
void (*transaction_set_max_modseq)(struct mailbox_transaction_context *t,
uint64_t max_modseq,
struct mailbox *box;
enum mailbox_transaction_flags flags;
+ struct mail_transaction_commit_changes *changes;
ARRAY_DEFINE(module_contexts,
union mailbox_transaction_module_context *);
};
int mailbox_transaction_commit(struct mailbox_transaction_context **t)
{
- uint32_t uidvalidity, uid1, uid2;
+ struct mail_transaction_commit_changes changes;
+ int ret;
- /* Store the return values to separate temporary variables so that
- plugins overriding transaction_commit() can look at them. */
- return mailbox_transaction_commit_get_uids(t, &uidvalidity,
- &uid1, &uid2);
+ /* Store changes temporarily so that plugins overriding
+ transaction_commit() can look at them. */
+ ret = mailbox_transaction_commit_get_changes(t, &changes);
+ pool_unref(&changes.pool);
+ return ret;
}
-int mailbox_transaction_commit_get_uids(struct mailbox_transaction_context **_t,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r,
- uint32_t *last_saved_uid_r)
+int mailbox_transaction_commit_get_changes(
+ struct mailbox_transaction_context **_t,
+ struct mail_transaction_commit_changes *changes_r)
{
struct mailbox_transaction_context *t = *_t;
t->box->transaction_count--;
*_t = NULL;
- return t->box->v.transaction_commit(t, uid_validity_r,
- first_saved_uid_r,
- last_saved_uid_r);
+ return t->box->v.transaction_commit(t, changes_r);
}
void mailbox_transaction_rollback(struct mailbox_transaction_context **_t)
uint64_t min_highest_modseq;
};
+struct mail_transaction_commit_changes {
+ /* Unreference the pool to free memory used by these changes. */
+ pool_t pool;
+
+ /* UIDVALIDITY for assigned UIDs. */
+ uint32_t uid_validity;
+ /* UIDs assigned to saved messages. Not necessarily ascending. */
+ ARRAY_TYPE(seq_range) saved_uids;
+};
+
struct mailbox_sync_rec {
uint32_t seq1, seq2;
enum mailbox_sync_type type;
mailbox_transaction_begin(struct mailbox *box,
enum mailbox_transaction_flags flags);
int mailbox_transaction_commit(struct mailbox_transaction_context **t);
-/* If no messages were saved/copied, first/last_saved_uid_r are 0. */
-int mailbox_transaction_commit_get_uids(struct mailbox_transaction_context **t,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r,
- uint32_t *last_saved_uid_r);
+int mailbox_transaction_commit_get_changes(
+ struct mailbox_transaction_context **t,
+ struct mail_transaction_commit_changes *changes_r);
void mailbox_transaction_rollback(struct mailbox_transaction_context **t);
/* Return the number of active transactions for the mailbox. */
unsigned int mailbox_transaction_get_count(const struct mailbox *box) ATTR_PURE;
static int
test_mailbox_transaction_commit(struct mailbox_transaction_context *t,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r,
- uint32_t *last_saved_uid_r)
+ struct mail_transaction_commit_changes *changes_r)
{
- *uid_validity_r = TEST_UID_VALIDITY;
- *first_saved_uid_r = *last_saved_uid_r = 0;
+ changes_r->uid_validity = TEST_UID_VALIDITY;
test_mailbox_transaction_rollback(t);
return 0;
}
static int
acl_transaction_commit(struct mailbox_transaction_context *ctx,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r, uint32_t *last_saved_uid_r)
+ struct mail_transaction_commit_changes *changes_r)
{
struct acl_mailbox *abox = ACL_CONTEXT(ctx->box);
void *at = ACL_CONTEXT(ctx);
return -1;
}
- return abox->module_ctx.super.
- transaction_commit(ctx, uid_validity_r,
- first_saved_uid_r, last_saved_uid_r);
+ return abox->module_ctx.super.transaction_commit(ctx, changes_r);
}
static int
static int
expire_mailbox_transaction_commit(struct mailbox_transaction_context *t,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r,
- uint32_t *last_saved_uid_r)
+ struct mail_transaction_commit_changes *changes_r)
{
struct expire_mail_user *euser =
EXPIRE_USER_CONTEXT(t->box->storage->user);
update_dict = TRUE;
}
- if (xpr_box->module_ctx.super.
- transaction_commit(t, uid_validity_r,
- first_saved_uid_r, last_saved_uid_r) < 0) {
+ if (xpr_box->module_ctx.super.transaction_commit(t, changes_r) < 0) {
i_free(xt);
return -1;
}
fts_transaction_finish(box, ft, FALSE);
}
-static int fts_transaction_commit(struct mailbox_transaction_context *t,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r,
- uint32_t *last_saved_uid_r)
+static int
+fts_transaction_commit(struct mailbox_transaction_context *t,
+ struct mail_transaction_commit_changes *changes_r)
{
struct mailbox *box = t->box;
struct fts_mailbox *fbox = FTS_CONTEXT(box);
if (ft->free_mail)
mail_free(&ft->mail);
- ret = fbox->module_ctx.super.transaction_commit(t,
- uid_validity_r,
- first_saved_uid_r,
- last_saved_uid_r);
+ ret = fbox->module_ctx.super.transaction_commit(t, changes_r);
fts_transaction_finish(box, ft, ret == 0);
return ret;
}
static int
lazy_expunge_transaction_commit(struct mailbox_transaction_context *ctx,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r,
- uint32_t *last_saved_uid_r)
+ struct mail_transaction_commit_changes *changes_r)
{
union mailbox_module_context *mbox = LAZY_EXPUNGE_CONTEXT(ctx->box);
struct lazy_expunge_transaction *lt = LAZY_EXPUNGE_CONTEXT(ctx);
mbox->super.transaction_rollback(ctx);
ret = -1;
} else {
- ret = mbox->super.transaction_commit(ctx, uid_validity_r,
- first_saved_uid_r,
- last_saved_uid_r);
+ ret = mbox->super.transaction_commit(ctx, changes_r);
}
lazy_expunge_transaction_free(lt);
return ret;
static int
mail_log_transaction_commit(struct mailbox_transaction_context *t,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r,
- uint32_t *last_saved_uid_r)
+ struct mail_transaction_commit_changes *changes_r)
{
struct mail_log_transaction_context *lt = MAIL_LOG_CONTEXT(t);
union mailbox_module_context *lbox = MAIL_LOG_CONTEXT(t->box);
mail_free(<->tmp_mail);
pool_unref(<->pool);
- return lbox->super.transaction_commit(t, uid_validity_r,
- first_saved_uid_r,
- last_saved_uid_r);
+ return lbox->super.transaction_commit(t, changes_r);
}
static void
static int
quota_mailbox_transaction_commit(struct mailbox_transaction_context *ctx,
- uint32_t *uid_validity_r,
- uint32_t *first_saved_uid_r,
- uint32_t *last_saved_uid_r)
+ struct mail_transaction_commit_changes *changes_r)
{
struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
struct quota_transaction_context *qt = QUOTA_CONTEXT(ctx);
if (qt->tmp_mail != NULL)
mail_free(&qt->tmp_mail);
- if (qbox->module_ctx.super.transaction_commit(ctx,
- uid_validity_r,
- first_saved_uid_r,
- last_saved_uid_r) < 0) {
+ if (qbox->module_ctx.super.transaction_commit(ctx, changes_r) < 0) {
quota_transaction_rollback(&qt);
return -1;
} else {