int failed = FALSE;
fetch_ctx = box->fetch_init(box, MAIL_FETCH_STREAM_HEADER |
- MAIL_FETCH_STREAM_BODY, FALSE,
- messageset, uidset);
+ MAIL_FETCH_STREAM_BODY, messageset, uidset);
if (fetch_ctx == NULL)
return FALSE;
return TRUE;
}
- /* FIXME: copying from mailbox to itself is kind of kludgy here.
- currently it works simply because copy_init() will lock mbox
- exclusively and fetching wont drop it. */
- copy_ctx = destbox->copy_init(destbox);
+ if (destbox == client->mailbox) {
+ /* copying inside same mailbox, make sure we get the
+ locking right */
+ if (!destbox->lock(destbox, MAILBOX_LOCK_READ |
+ MAILBOX_LOCK_SAVE))
+ failed = TRUE;
+ }
+
+ copy_ctx = failed ? NULL : destbox->copy_init(destbox);
if (copy_ctx == NULL)
failed = TRUE;
else {
failed = TRUE;
}
+ (void)destbox->lock(destbox, MAILBOX_LOCK_UNLOCK);
+
if (failed)
client_send_storage_error(client);
else if (!all_found) {
client_send_tagline(client,
"NO Some of the requested messages no longer exist.");
} else {
- client_sync_full_fast(client);
+ if (destbox == client->mailbox)
+ client_sync_full(client);
+ else
+ client_sync_full_fast(client);
client_send_tagline(client, "OK Copy completed.");
}
/* and update the flags */
box = client->mailbox;
- fetch_ctx = box->fetch_init(box, MAIL_FETCH_FLAGS, TRUE,
- messageset, client->cmd_uid);
+
+ failed = !box->lock(box, MAILBOX_LOCK_FLAGS | MAILBOX_LOCK_READ);
+ fetch_ctx = failed ? NULL :
+ box->fetch_init(box, MAIL_FETCH_FLAGS,
+ messageset, client->cmd_uid);
if (fetch_ctx == NULL)
failed = TRUE;
else {
if (!box->fetch_deinit(fetch_ctx, &all_found))
failed = TRUE;
+ (void)box->lock(box, MAILBOX_LOCK_UNLOCK);
+
if (!failed) {
if (client->cmd_uid)
client_sync_full_fast(client);
struct imap_fetch_body_data *bodies,
const char *messageset, int uidset)
{
+ struct mailbox *box = client->mailbox;
struct imap_fetch_context ctx;
struct mail *mail;
int all_found;
ctx.select_counter = client->select_counter;
ctx.seen_flag.flags = MAIL_SEEN;
- if (!client->mailbox->readonly) {
+ if (!box->readonly) {
/* If we have any BODY[..] sections, \Seen flag is added for
all messages */
struct imap_fetch_body_data *body;
ctx.update_seen = TRUE;
}
- ctx.fetch_ctx = client->mailbox->
- fetch_init(client->mailbox, fetch_data, ctx.update_seen,
- messageset, uidset);
+ if (ctx.update_seen) {
+ if (!box->lock(box, MAILBOX_LOCK_FLAGS | MAILBOX_LOCK_READ))
+ return -1;
+ }
+
+ ctx.fetch_ctx = box->fetch_init(box, fetch_data, messageset, uidset);
if (ctx.fetch_ctx == NULL)
- return -1;
+ ctx.failed = TRUE;
+ else {
+ ctx.str = str_new(default_pool, 8192);
+ while ((mail = box->fetch_next(ctx.fetch_ctx)) != NULL) {
+ if (!fetch_mail(&ctx, mail)) {
+ ctx.failed = TRUE;
+ break;
+ }
+ }
+ str_free(ctx.str);
- ctx.str = str_new(default_pool, 8192);
- while ((mail = client->mailbox->fetch_next(ctx.fetch_ctx)) != NULL) {
- if (!fetch_mail(&ctx, mail)) {
+ if (!box->fetch_deinit(ctx.fetch_ctx, &all_found))
ctx.failed = TRUE;
- break;
- }
}
- str_free(ctx.str);
- if (!client->mailbox->fetch_deinit(ctx.fetch_ctx, &all_found))
- return -1;
+ (void)box->lock(box, MAILBOX_LOCK_UNLOCK);
+
return ctx.failed ? -1 : all_found;
}
struct mail_fetch_context *
index_storage_fetch_init(struct mailbox *box,
- enum mail_fetch_field wanted_fields, int update_flags,
+ enum mail_fetch_field wanted_fields,
const char *messageset, int uidset)
{
struct index_mailbox *ibox = (struct index_mailbox *) box;
ctx = i_new(struct mail_fetch_context, 1);
ctx->old_lock = ibox->index->lock_type;
- /* need exclusive lock to update the \Seen flags */
- if (update_flags && !box->readonly) {
- if (!index_storage_lock(ibox, MAIL_LOCK_EXCLUSIVE))
- return NULL;
- }
-
check_mail = (client_workarounds &
WORKAROUND_OE6_FETCH_NO_NEWMAIL) == 0;
if (!index_storage_sync_and_lock(ibox, check_mail, TRUE,
{
int ret;
+ if (lock_type == MAIL_LOCK_UNLOCK) {
+ if (ibox->lock_type != MAILBOX_LOCK_UNLOCK)
+ return TRUE;
+ } else {
+ if (ibox->index->lock_type == MAIL_LOCK_EXCLUSIVE)
+ return TRUE;
+ }
+
/* we have to set/reset this every time, because the same index
may be used by multiple IndexMailboxes. */
index_storage_init_lock_notify(ibox);
void (*mail_init)(struct index_mail *mail);
struct mail_index *index;
+ enum mailbox_lock_type lock_type;
struct timeout *autosync_to;
struct index_autosync_file *autosync_files;
struct mail_fetch_context *
index_storage_fetch_init(struct mailbox *box,
- enum mail_fetch_field wanted_fields, int update_flags,
+ enum mail_fetch_field wanted_fields,
const char *messageset, int uidset);
int index_storage_fetch_deinit(struct mail_fetch_context *ctx, int *all_found);
struct mail *index_storage_fetch_next(struct mail_fetch_context *ctx);
}
}
+static int maildir_storage_lock(struct mailbox *box,
+ enum mailbox_lock_type lock_type)
+{
+ struct index_mailbox *ibox = (struct index_mailbox *) box;
+
+ if (lock_type == MAIL_LOCK_UNLOCK) {
+ ibox->lock_type = MAIL_LOCK_UNLOCK;
+ if (!index_storage_lock(ibox, MAIL_LOCK_UNLOCK))
+ return FALSE;
+ return TRUE;
+ }
+
+ i_assert(ibox->lock_type == MAIL_LOCK_UNLOCK);
+
+ if ((lock_type & (MAILBOX_LOCK_EXPUNGE | MAILBOX_LOCK_FLAGS)) != 0) {
+ if (!index_storage_lock(ibox, MAIL_LOCK_EXCLUSIVE))
+ return FALSE;
+ } else if ((lock_type & MAILBOX_LOCK_READ) != 0) {
+ if (!index_storage_lock(ibox, MAIL_LOCK_SHARED))
+ return FALSE;
+ }
+
+ ibox->lock_type = lock_type;
+ return TRUE;
+}
struct mail_storage maildir_storage = {
"maildir", /* name */
NULL, /* storage */
maildir_storage_close,
+ maildir_storage_lock,
index_storage_get_status,
index_storage_sync,
maildir_storage_auto_sync,
index_mailbox_check_add(ibox, ibox->index->mailbox_path);
}
+static int mbox_storage_lock(struct mailbox *box,
+ enum mailbox_lock_type lock_type)
+{
+ struct index_mailbox *ibox = (struct index_mailbox *) box;
+
+ if (lock_type == MAIL_LOCK_UNLOCK) {
+ ibox->lock_type = MAIL_LOCK_UNLOCK;
+ if (!index_storage_lock(ibox, MAIL_LOCK_UNLOCK))
+ return FALSE;
+ return TRUE;
+ }
+
+ i_assert(ibox->lock_type == MAIL_LOCK_UNLOCK);
+
+ if ((lock_type & (MAILBOX_LOCK_EXPUNGE | MAILBOX_LOCK_FLAGS)) != 0) {
+ if (!index_storage_lock(ibox, MAIL_LOCK_EXCLUSIVE))
+ return FALSE;
+ } else if ((lock_type & MAILBOX_LOCK_READ) != 0) {
+ if (!index_storage_lock(ibox, MAIL_LOCK_SHARED))
+ return FALSE;
+ }
+
+ if ((lock_type & (MAILBOX_LOCK_EXPUNGE | MAILBOX_LOCK_SAVE)) != 0) {
+ /* FIXME: saving doesn't have to sync it, just lock it */
+ if (!index_storage_sync_and_lock(ibox, FALSE, TRUE,
+ MAIL_LOCK_EXCLUSIVE))
+ return FALSE;
+ }
+
+ ibox->lock_type = lock_type;
+ return TRUE;
+}
+
struct mail_storage mbox_storage = {
"mbox", /* name */
NULL, /* storage */
mbox_storage_close,
+ mbox_storage_lock,
index_storage_get_status,
index_storage_sync,
mbox_storage_auto_sync,
MAILBOX_SYNC_NO_EXPUNGES
};
+enum mailbox_lock_type {
+ MAILBOX_LOCK_UNLOCK = 0x00,
+ MAILBOX_LOCK_READ = 0x01,
+ MAILBOX_LOCK_FLAGS = 0x02,
+ MAILBOX_LOCK_EXPUNGE = 0x04,
+ MAILBOX_LOCK_SAVE = 0x08
+};
+
enum modify_type {
MODIFY_ADD,
MODIFY_REMOVE,
the mailbox was closed anyway. */
int (*close)(struct mailbox *box);
+ /* Explicitly lock the mailbox. If not used, all the methods below
+ use the minimum locking requirements. This allows you to for
+ example use the expunge() and update_flags() methods in
+ struct mail. The mailbox stays locked until you unlock it.
+ Note that if you call a method which wants more locks than you've
+ given here, the call will fail (to avoid deadlocks). */
+ int (*lock)(struct mailbox *box, enum mailbox_lock_type lock_type);
+
/* Gets the mailbox status information. */
int (*get_status)(struct mailbox *box, enum mailbox_status_items items,
struct mailbox_status *status);
struct mail_fetch_context *
(*fetch_init)(struct mailbox *box,
enum mail_fetch_field wanted_fields,
- int update_flags,
const char *messageset, int uidset);
/* Deinitialize fetch request. all_found is set to TRUE if all of the
fetched messages were found (ie. not just deleted). */
enum mail_fetch_field wanted_fields);
/* Modify sort_program to specify a sort program acceptable for
- search_init(). If server supports no sorting, it's simply set to
+ search_init(). If mailbox supports no sorting, it's simply set to
{MAIL_SORT_END}. */
int (*search_get_sorting)(struct mailbox *box,
enum mail_sort_type *sort_program);
const struct mail_full_flags *flags,
enum modify_type modify_type);
- /* Copy this mail to another mailbox. */
+ /* Copy this message to another mailbox. */
int (*copy)(struct mail *mail, struct mail_copy_context *ctx);
};