Mercurial > dovecot > core-2.2
changeset 12575:c39557b7662d
Merged fixes from v2.0 tree.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 01 Jan 2011 15:59:02 +0200 |
parents | 917f3699af5b (diff) c1e71f579adc (current diff) |
children | 1e425fe18dea |
files | TODO src/imap/imap-search.c src/lib-storage/index/maildir/maildir-sync.c src/lib-storage/mail-storage.h src/plugins/acl/acl-mailbox-list.c |
diffstat | 126 files changed, 2277 insertions(+), 2438 deletions(-) [+] |
line wrap: on
line diff
--- a/TODO Sat Jan 01 14:34:14 2011 +0200 +++ b/TODO Sat Jan 01 15:59:02 2011 +0200 @@ -1,3 +1,23 @@ + - notify_sync() could have "what changed" struct with old/new flags + - mailbox deletion could really be "rmdir", which fails if everything isn't + already expunged. IMAP DELETE could fail with "mailbox changed during + deletion, aborting" if new messages arrive + - if doing any changes, figure out how to handle symlinked mailboxes + - maildir: copy dovecot-shared file from parent mailbox, not root. + - is mail_index_sync_have_any() really necessary? especially that it returns + TRUE for ext rec changes ... why?... + - mailbox listing to use UTF8 everywhere + - move namespace sep vs. real_sep check from imap client_find_namespace() + to lib-storage mailbox name validity check + - rewrite autocreate plugin by making it list virtual mailbox names and only + lazily autocreate create them when mailbox is opened + - login-common API change to fix compiling with + LDFLAGS="-Wl,--as-needed -Wl,--no-undefined" + - if global ACL path points to a file instead of a directory, read all of + them from there. support wildcards in names. + - remove 3 unnecessary stat() calls when opening mailbox. they all come from + mailbox_list_get_permissions_full() + - master passdb preserves userdb_* extra fields. should it preserve non-userdb_* extra fields too? - imap, pop3: if client init fails, wait a second or two before disconnecting
--- a/src/doveadm/doveadm-mail-fetch.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/doveadm/doveadm-mail-fetch.c Sat Jan 01 15:59:02 2011 +0200 @@ -63,11 +63,12 @@ static int fetch_mailbox_guid(struct fetch_cmd_context *ctx) { - uint8_t guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; - if (mailbox_get_guid(ctx->mail->box, guid) < 0) + if (mailbox_get_metadata(ctx->mail->box, MAILBOX_METADATA_GUID, + &metadata) < 0) return -1; - doveadm_print(mail_guid_128_to_string(guid)); + doveadm_print(mail_guid_128_to_string(metadata.guid)); return 0; }
--- a/src/doveadm/doveadm-mail-mailbox-status.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/doveadm/doveadm-mail-mailbox-status.c Sat Jan 01 15:59:02 2011 +0200 @@ -12,18 +12,24 @@ #define ALL_STATUS_ITEMS \ (STATUS_MESSAGES | STATUS_RECENT | \ STATUS_UIDNEXT | STATUS_UIDVALIDITY | \ - STATUS_UNSEEN | STATUS_HIGHESTMODSEQ | STATUS_VIRTUAL_SIZE) + STATUS_UNSEEN | STATUS_HIGHESTMODSEQ) +#define ALL_METADATA_ITEMS \ + (MAILBOX_METADATA_VIRTUAL_SIZE | MAILBOX_METADATA_GUID) #define TOTAL_STATUS_ITEMS \ - (STATUS_MESSAGES | STATUS_RECENT | STATUS_UNSEEN | STATUS_VIRTUAL_SIZE) + (STATUS_MESSAGES | STATUS_RECENT | STATUS_UNSEEN) +#define TOTAL_METADATA_ITEMS \ + (MAILBOX_METADATA_VIRTUAL_SIZE) struct status_cmd_context { struct doveadm_mail_cmd_context ctx; struct mail_search_args *search_args; - enum mailbox_status_items items; + + enum mailbox_status_items status_items; + enum mailbox_metadata_items metadata_items; struct mailbox_status total_status; + struct mailbox_metadata total_metadata; - unsigned int guid:1; unsigned int total_sum:1; }; @@ -37,40 +43,42 @@ const char *field = *fields; if (strcmp(field, "all") == 0) { - if (ctx->total_sum) - ctx->items |= TOTAL_STATUS_ITEMS; - else { - ctx->items |= ALL_STATUS_ITEMS; - ctx->guid = TRUE; + if (ctx->total_sum) { + ctx->status_items |= TOTAL_STATUS_ITEMS; + ctx->metadata_items |= TOTAL_METADATA_ITEMS; + } else { + ctx->status_items |= ALL_STATUS_ITEMS; + ctx->metadata_items |= ALL_METADATA_ITEMS; } } else if (strcmp(field, "messages") == 0) - ctx->items |= STATUS_MESSAGES; + ctx->status_items |= STATUS_MESSAGES; else if (strcmp(field, "recent") == 0) - ctx->items |= STATUS_RECENT; + ctx->status_items |= STATUS_RECENT; else if (strcmp(field, "uidnext") == 0) - ctx->items |= STATUS_UIDNEXT; + ctx->status_items |= STATUS_UIDNEXT; else if (strcmp(field, "uidvalidity") == 0) - ctx->items |= STATUS_UIDVALIDITY; + ctx->status_items |= STATUS_UIDVALIDITY; else if (strcmp(field, "unseen") == 0) - ctx->items |= STATUS_UNSEEN; + ctx->status_items |= STATUS_UNSEEN; else if (strcmp(field, "highestmodseq") == 0) - ctx->items |= STATUS_HIGHESTMODSEQ; + ctx->status_items |= STATUS_HIGHESTMODSEQ; else if (strcmp(field, "vsize") == 0) - ctx->items |= STATUS_VIRTUAL_SIZE; + ctx->metadata_items |= MAILBOX_METADATA_VIRTUAL_SIZE; else if (strcmp(field, "guid") == 0) - ctx->guid = TRUE; + ctx->metadata_items |= MAILBOX_METADATA_GUID; else i_fatal("Unknown status field: %s", field); if (ctx->total_sum && - ((ctx->items & ~TOTAL_STATUS_ITEMS) != 0 || ctx->guid)) + ((ctx->status_items & ~TOTAL_STATUS_ITEMS) != 0 || + (ctx->metadata_items & ~TOTAL_METADATA_ITEMS) != 0)) i_fatal("Status field %s can't be used with -t", field); } } static void status_output(struct status_cmd_context *ctx, struct mailbox *box, const struct mailbox_status *status, - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]) + const struct mailbox_metadata *metadata) { string_t *name; @@ -83,34 +91,35 @@ doveadm_print(str_c(name)); } - if ((ctx->items & STATUS_MESSAGES) != 0) + if ((ctx->status_items & STATUS_MESSAGES) != 0) doveadm_print_num(status->messages); - if ((ctx->items & STATUS_RECENT) != 0) + if ((ctx->status_items & STATUS_RECENT) != 0) doveadm_print_num(status->recent); - if ((ctx->items & STATUS_UIDNEXT) != 0) + if ((ctx->status_items & STATUS_UIDNEXT) != 0) doveadm_print_num(status->uidnext); - if ((ctx->items & STATUS_UIDVALIDITY) != 0) + if ((ctx->status_items & STATUS_UIDVALIDITY) != 0) doveadm_print_num(status->uidvalidity); - if ((ctx->items & STATUS_UNSEEN) != 0) + if ((ctx->status_items & STATUS_UNSEEN) != 0) doveadm_print_num(status->unseen); - if ((ctx->items & STATUS_HIGHESTMODSEQ) != 0) + if ((ctx->status_items & STATUS_HIGHESTMODSEQ) != 0) doveadm_print_num(status->highest_modseq); - if ((ctx->items & STATUS_VIRTUAL_SIZE) != 0) - doveadm_print_num(status->virtual_size); - if (ctx->guid) - doveadm_print(mail_guid_128_to_string(mailbox_guid)); + if ((ctx->metadata_items & MAILBOX_METADATA_VIRTUAL_SIZE) != 0) + doveadm_print_num(metadata->virtual_size); + if ((ctx->metadata_items & MAILBOX_METADATA_GUID) != 0) + doveadm_print(mail_guid_128_to_string(metadata->guid)); } static void status_sum(struct status_cmd_context *ctx, - const struct mailbox_status *status) + const struct mailbox_status *status, + const struct mailbox_metadata *metadata) { struct mailbox_status *dest = &ctx->total_status; dest->messages += status->messages; dest->recent += status->recent; dest->unseen += status->unseen; - dest->virtual_size += status->virtual_size; + ctx->total_metadata.virtual_size += metadata->virtual_size; } static void @@ -118,7 +127,7 @@ { struct mailbox *box; struct mailbox_status status; - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; string_t *mailbox_name = t_str_new(128); if (imap_utf7_to_utf8(info->name, mailbox_name) < 0) { @@ -126,20 +135,17 @@ str_append(mailbox_name, info->name); } - if (doveadm_mailbox_find_and_sync(ctx->ctx.cur_mail_user, - str_c(mailbox_name), &box) < 0) { + box = doveadm_mailbox_find(ctx->ctx.cur_mail_user, str_c(mailbox_name)); + if (mailbox_get_status(box, ctx->status_items, &status) < 0 || + mailbox_get_metadata(box, ctx->metadata_items, &metadata) < 0) { ctx->ctx.failed = TRUE; + mailbox_free(&box); return; } - mailbox_get_status(box, ctx->items, &status); - if (ctx->guid) { - if (mailbox_get_guid(box, mailbox_guid) < 0) - memset(mailbox_guid, 0, sizeof(mailbox_guid)); - } if (!ctx->total_sum) - status_output(ctx, box, &status, mailbox_guid); + status_output(ctx, box, &status, &metadata); else - status_sum(ctx, &status); + status_sum(ctx, &status, &metadata); mailbox_free(&box); } @@ -165,8 +171,10 @@ } doveadm_mail_list_iter_deinit(&iter); - if (ctx->total_sum) - status_output(ctx, NULL, &ctx->total_status, NULL); + if (ctx->total_sum) { + status_output(ctx, NULL, &ctx->total_status, + &ctx->total_metadata); + } } static void cmd_mailbox_status_init(struct doveadm_mail_cmd_context *_ctx, @@ -185,21 +193,21 @@ doveadm_print_header("mailbox", "mailbox", DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); } - if ((ctx->items & STATUS_MESSAGES) != 0) + if ((ctx->status_items & STATUS_MESSAGES) != 0) doveadm_print_header_simple("messages"); - if ((ctx->items & STATUS_RECENT) != 0) + if ((ctx->status_items & STATUS_RECENT) != 0) doveadm_print_header_simple("recent"); - if ((ctx->items & STATUS_UIDNEXT) != 0) + if ((ctx->status_items & STATUS_UIDNEXT) != 0) doveadm_print_header_simple("uidnext"); - if ((ctx->items & STATUS_UIDVALIDITY) != 0) + if ((ctx->status_items & STATUS_UIDVALIDITY) != 0) doveadm_print_header_simple("uidvalidity"); - if ((ctx->items & STATUS_UNSEEN) != 0) + if ((ctx->status_items & STATUS_UNSEEN) != 0) doveadm_print_header_simple("unseen"); - if ((ctx->items & STATUS_HIGHESTMODSEQ) != 0) + if ((ctx->status_items & STATUS_HIGHESTMODSEQ) != 0) doveadm_print_header_simple("highestmodseq"); - if ((ctx->items & STATUS_VIRTUAL_SIZE) != 0) + if ((ctx->metadata_items & MAILBOX_METADATA_VIRTUAL_SIZE) != 0) doveadm_print_header_simple("vsize"); - if (ctx->guid) + if ((ctx->metadata_items & MAILBOX_METADATA_GUID) != 0) doveadm_print_header_simple("guid"); }
--- a/src/doveadm/doveadm-mail-search.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/doveadm/doveadm-mail-search.c Sat Jan 01 15:59:02 2011 +0200 @@ -16,7 +16,7 @@ struct doveadm_mail_iter *iter; struct mailbox_transaction_context *trans; struct mail *mail; - uint8_t guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; const char *guid_str; int ret = 0; @@ -24,10 +24,12 @@ return -1; mail = mail_alloc(trans, 0, NULL); - if (mailbox_get_guid(mail->box, guid) < 0) + + if (mailbox_get_metadata(mail->box, MAILBOX_METADATA_GUID, + &metadata) < 0) ret = -1; else { - guid_str = mail_guid_128_to_string(guid); + guid_str = mail_guid_128_to_string(metadata.guid); while (doveadm_mail_iter_next(iter, mail)) { doveadm_print(guid_str); T_BEGIN {
--- a/src/doveadm/doveadm-mail.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/doveadm/doveadm-mail.c Sat Jan 01 15:59:02 2011 +0200 @@ -71,13 +71,11 @@ return ctx; } -static int mailbox_find_and_open(struct mail_user *user, const char *mailbox, - struct mailbox **box_r) +struct mailbox * +doveadm_mailbox_find(struct mail_user *user, const char *mailbox) { struct mail_namespace *ns; - struct mailbox *box; string_t *str; - const char *orig_mailbox = mailbox; str = t_str_new(128); if (imap_utf8_to_utf7(mailbox, str) < 0) @@ -88,10 +86,19 @@ if (ns == NULL) i_fatal("Can't find namespace for mailbox %s", mailbox); - box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_KEEP_RECENT | - MAILBOX_FLAG_IGNORE_ACLS); + return mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_KEEP_RECENT | + MAILBOX_FLAG_IGNORE_ACLS); +} + +static int +doveadm_mailbox_find_and_open(struct mail_user *user, const char *mailbox, + struct mailbox **box_r) +{ + struct mailbox *box; + + box = doveadm_mailbox_find(user, mailbox); if (mailbox_open(box) < 0) { - i_error("Opening mailbox %s failed: %s", orig_mailbox, + i_error("Opening mailbox %s failed: %s", mailbox, mail_storage_get_last_error(mailbox_get_storage(box), NULL)); mailbox_free(&box); @@ -104,12 +111,13 @@ int doveadm_mailbox_find_and_sync(struct mail_user *user, const char *mailbox, struct mailbox **box_r) { - if (mailbox_find_and_open(user, mailbox, box_r) < 0) + if (doveadm_mailbox_find_and_open(user, mailbox, box_r) < 0) return -1; if (mailbox_sync(*box_r, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { i_error("Syncing mailbox %s failed: %s", mailbox, mail_storage_get_last_error(mailbox_get_storage(*box_r), NULL)); + mailbox_free(box_r); return -1; } return 0; @@ -143,7 +151,7 @@ struct mail_storage *storage; struct mailbox *box; - if (mailbox_find_and_open(user, ctx->mailbox, &box) < 0) { + if (doveadm_mailbox_find_and_open(user, ctx->mailbox, &box) < 0) { _ctx->failed = TRUE; return; }
--- a/src/doveadm/doveadm-mail.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/doveadm/doveadm-mail.h Sat Jan 01 15:59:02 2011 +0200 @@ -89,6 +89,8 @@ const char **error_r); void doveadm_mail_server_flush(void); +struct mailbox * +doveadm_mailbox_find(struct mail_user *user, const char *mailbox); int doveadm_mailbox_find_and_sync(struct mail_user *user, const char *mailbox, struct mailbox **box_r); struct mail_search_args *
--- a/src/dsync/dsync-worker-local.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/dsync/dsync-worker-local.c Sat Jan 01 15:59:02 2011 +0200 @@ -510,13 +510,18 @@ (struct local_dsync_worker_mailbox_iter *)_iter; struct local_dsync_worker *worker = (struct local_dsync_worker *)_iter->worker; - enum mailbox_flags flags = + const enum mailbox_flags flags = MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT; + const enum mailbox_status_items status_items = + STATUS_UIDNEXT | STATUS_UIDVALIDITY | + STATUS_HIGHESTMODSEQ; + const enum mailbox_metadata_items metadata_items = + MAILBOX_METADATA_CACHE_FIELDS | MAILBOX_METADATA_GUID; const struct mailbox_info *info; const char *storage_name; struct mailbox *box; struct mailbox_status status; - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; struct local_dsync_mailbox_change *change; struct local_dsync_dir_change *dir_change, change_lookup; struct local_dsync_mailbox *old_lbox; @@ -554,8 +559,8 @@ } box = mailbox_alloc(info->ns->list, storage_name, flags); - if (mailbox_sync(box, 0) < 0 || - mailbox_get_guid(box, mailbox_guid) < 0) { + if (mailbox_get_status(box, status_items, &status) < 0 || + mailbox_get_metadata(box, metadata_items, &metadata) < 0) { struct mail_storage *storage = mailbox_get_storage(box); i_error("Failed to sync mailbox %s: %s", info->name, @@ -565,16 +570,13 @@ return -1; } - mailbox_get_status(box, STATUS_UIDNEXT | STATUS_UIDVALIDITY | - STATUS_HIGHESTMODSEQ | STATUS_CACHE_FIELDS, &status); - - change = hash_table_lookup(worker->mailbox_changes_hash, mailbox_guid); + change = hash_table_lookup(worker->mailbox_changes_hash, metadata.guid); if (change != NULL) { /* it shouldn't be marked as deleted, but drop it to be sure */ change->deleted_mailbox = FALSE; } - memcpy(dsync_box_r->mailbox_guid.guid, mailbox_guid, + memcpy(dsync_box_r->mailbox_guid.guid, metadata.guid, sizeof(dsync_box_r->mailbox_guid.guid)); dsync_box_r->uid_validity = status.uidvalidity; dsync_box_r->uid_next = status.uidnext; @@ -582,7 +584,7 @@ dsync_box_r->highest_modseq = status.highest_modseq; p_clear(iter->ret_pool); - fields = array_get(status.cache_fields, &field_count); + fields = array_get(metadata.cache_fields, &field_count); p_array_init(&dsync_box_r->cache_fields, iter->ret_pool, field_count); for (i = 0; i < field_count; i++) { const char *field_name = p_strdup(iter->ret_pool, fields[i]); @@ -787,7 +789,7 @@ enum mailbox_flags flags = MAILBOX_FLAG_KEEP_RECENT; struct local_dsync_mailbox *lbox; struct mailbox *box; - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; lbox = hash_table_lookup(worker->mailbox_hash, guid); if (lbox == NULL) { @@ -798,7 +800,7 @@ box = mailbox_alloc(lbox->ns->list, lbox->storage_name, flags); if (mailbox_sync(box, 0) < 0 || - mailbox_get_guid(box, mailbox_guid) < 0) { + mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) { struct mail_storage *storage = mailbox_get_storage(box); i_error("Failed to sync mailbox %s: %s", lbox->storage_name, @@ -807,10 +809,10 @@ return -1; } - if (memcmp(mailbox_guid, guid->guid, sizeof(guid->guid)) != 0) { + if (memcmp(metadata.guid, guid->guid, sizeof(guid->guid)) != 0) { i_error("Mailbox %s changed its GUID (%s -> %s)", lbox->storage_name, dsync_guid_to_str(guid), - mail_guid_128_to_string(mailbox_guid)); + mail_guid_128_to_string(metadata.guid)); mailbox_free(&box); return -1; } @@ -935,7 +937,7 @@ array_clear(&iter->expunges); iter->expunges_set = TRUE; - mailbox_get_status(box, STATUS_UIDNEXT, &status); + mailbox_get_open_status(box, STATUS_UIDNEXT, &status); if (prev_uid + 1 >= status.uidnext) { /* no expunged messages at the end of mailbox */ return FALSE; @@ -1523,7 +1525,7 @@ keywords = mailbox_keywords_create_valid(worker->mail->box, msg->keywords); mail_update_keywords(worker->mail, MODIFY_REPLACE, keywords); - mailbox_keywords_unref(worker->mail->box, &keywords); + mailbox_keywords_unref(&keywords); mail_update_modseq(worker->mail, msg->modseq); } } @@ -1574,7 +1576,7 @@ mailbox_keywords_create_valid(box, msg->keywords); mailbox_save_set_flags(save_ctx, msg->flags, keywords); if (keywords != NULL) - mailbox_keywords_unref(box, &keywords); + mailbox_keywords_unref(&keywords); mailbox_save_set_uid(save_ctx, msg->uid); mailbox_save_set_save_date(save_ctx, msg->save_date); mailbox_save_set_min_modseq(save_ctx, msg->modseq);
--- a/src/imap/cmd-append.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/cmd-append.c Sat Jan 01 15:59:02 2011 +0200 @@ -351,7 +351,7 @@ ret = mailbox_save_begin(&ctx->save_ctx, ctx->input); if (keywords != NULL) - mailbox_keywords_unref(ctx->box, &keywords); + mailbox_keywords_unref(&keywords); if (ret < 0) { /* save initialization failed */ @@ -445,47 +445,6 @@ return FALSE; } -static struct mailbox * -get_mailbox(struct client_command_context *cmd, const char *name) -{ - struct mail_namespace *ns; - struct mailbox *box; - enum mailbox_name_status status; - const char *storage_name; - - ns = client_find_namespace(cmd, name, &storage_name, &status); - if (ns == NULL) - return NULL; - - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - break; - case MAILBOX_NAME_EXISTS_DIR: - status = MAILBOX_NAME_VALID; - /* fall through */ - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, name, "TRYCREATE", status); - return NULL; - } - - if (cmd->client->mailbox != NULL && - mailbox_equals(cmd->client->mailbox, ns, storage_name)) - return cmd->client->mailbox; - - box = mailbox_alloc(ns->list, storage_name, MAILBOX_FLAG_SAVEONLY | - MAILBOX_FLAG_KEEP_RECENT); - if (mailbox_open(box) < 0) { - client_send_storage_error(cmd, mailbox_get_storage(box)); - mailbox_free(&box); - return NULL; - } - if (cmd->client->enabled_features != 0) - mailbox_enable(box, cmd->client->enabled_features); - return box; -} - bool cmd_append(struct client_command_context *cmd) { struct client *client = cmd->client; @@ -509,8 +468,7 @@ ctx = p_new(cmd->pool, struct cmd_append_context, 1); ctx->cmd = cmd; ctx->client = client; - ctx->box = get_mailbox(cmd, mailbox); - if (ctx->box == NULL) + if (client_open_save_dest_box(cmd, mailbox, &ctx->box) < 0) ctx->failed = TRUE; else { ctx->storage = mailbox_get_storage(ctx->box);
--- a/src/imap/cmd-copy.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/cmd-copy.c Sat Jan 01 15:59:02 2011 +0200 @@ -85,13 +85,11 @@ bool cmd_copy(struct client_command_context *cmd) { struct client *client = cmd->client; - struct mail_namespace *dest_ns; struct mail_storage *dest_storage; struct mailbox *destbox; struct mailbox_transaction_context *t; struct mail_search_args *search_args; - const char *messageset, *mailbox, *storage_name, *src_uidset; - enum mailbox_name_status status; + 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; @@ -110,41 +108,9 @@ if (ret <= 0) return ret < 0; - /* open the destination mailbox */ - dest_ns = client_find_namespace(cmd, mailbox, &storage_name, &status); - if (dest_ns == NULL) + if (client_open_save_dest_box(cmd, mailbox, &destbox) < 0) return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - break; - case MAILBOX_NAME_EXISTS_DIR: - status = MAILBOX_NAME_VALID; - /* fall through */ - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, - "TRYCREATE", status); - return NULL; - } - - if (mailbox_equals(client->mailbox, dest_ns, storage_name)) - destbox = client->mailbox; - else { - destbox = mailbox_alloc(dest_ns->list, storage_name, - MAILBOX_FLAG_SAVEONLY | - MAILBOX_FLAG_KEEP_RECENT); - if (mailbox_open(destbox) < 0) { - client_send_storage_error(cmd, - mailbox_get_storage(destbox)); - mailbox_free(&destbox); - return TRUE; - } - if (client->enabled_features != 0) - mailbox_enable(destbox, client->enabled_features); - } - t = mailbox_transaction_begin(destbox, MAILBOX_TRANSACTION_FLAG_EXTERNAL | MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS);
--- a/src/imap/cmd-create.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/cmd-create.c Sat Jan 01 15:59:02 2011 +0200 @@ -7,7 +7,6 @@ bool cmd_create(struct client_command_context *cmd) { - enum mailbox_name_status status; struct mail_namespace *ns; const char *mailbox, *storage_name; struct mailbox *box; @@ -18,7 +17,7 @@ if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; - ns = client_find_namespace(cmd, mailbox, &storage_name, NULL); + ns = client_find_namespace(cmd, mailbox, &storage_name); if (ns == NULL) return TRUE; @@ -34,26 +33,18 @@ informing us that it wants to create children under this mailbox. */ directory = TRUE; - storage_name = t_strndup(storage_name, strlen(storage_name)-1); mailbox = t_strndup(mailbox, len-1); + + /* drop also from storage_name. it's already dropped when + WORKAROUND_TB_EXTRA_MAILBOX_SEP is enabled */ + len = strlen(storage_name); + if (storage_name[len-1] == ns->real_sep) + storage_name = t_strndup(storage_name, len-1); } - ns = client_find_namespace(cmd, mailbox, &storage_name, &status); + ns = client_find_namespace(cmd, mailbox, &storage_name); if (ns == NULL) return TRUE; - switch (status) { - case MAILBOX_NAME_VALID: - break; - case MAILBOX_NAME_EXISTS_DIR: - if (!directory) - break; - /* fall through */ - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, NULL, status); - return TRUE; - } box = mailbox_alloc(ns->list, storage_name, 0); if (mailbox_create(box, NULL, directory) < 0)
--- a/src/imap/cmd-delete.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/cmd-delete.c Sat Jan 01 15:59:02 2011 +0200 @@ -6,7 +6,6 @@ bool cmd_delete(struct client_command_context *cmd) { struct client *client = cmd->client; - enum mailbox_name_status status; struct mail_namespace *ns; struct mailbox *box; const char *name, *storage_name; @@ -21,19 +20,9 @@ return TRUE; } - ns = client_find_namespace(cmd, name, &storage_name, &status); + ns = client_find_namespace(cmd, name, &storage_name); if (ns == NULL) return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - break; - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, name, NULL, status); - return TRUE; - } box = mailbox_alloc(ns->list, storage_name, 0); if (client->mailbox != NULL &&
--- a/src/imap/cmd-enable.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/cmd-enable.c Sat Jan 01 15:59:02 2011 +0200 @@ -21,13 +21,13 @@ } str = t_str_ucase(str); if (strcmp(str, "CONDSTORE") == 0) { - client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE); - str_append(reply, " CONDSTORE"); - } - else if (strcmp(str, "QRESYNC") == 0) { - client_enable(cmd->client, MAILBOX_FEATURE_QRESYNC | - MAILBOX_FEATURE_CONDSTORE); - str_append(reply, " QRESYNC"); + if (client_enable(cmd->client, + MAILBOX_FEATURE_CONDSTORE) == 0) + str_append(reply, " CONDSTORE"); + } else if (strcmp(str, "QRESYNC") == 0) { + if (client_enable(cmd->client, MAILBOX_FEATURE_QRESYNC | + MAILBOX_FEATURE_CONDSTORE) == 0) + str_append(reply, " QRESYNC"); } } if (str_len(reply) > 9)
--- a/src/imap/cmd-rename.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/cmd-rename.c Sat Jan 01 15:59:02 2011 +0200 @@ -6,7 +6,6 @@ bool cmd_rename(struct client_command_context *cmd) { - enum mailbox_name_status status; struct mail_namespace *old_ns, *new_ns; struct mailbox *old_box, *new_box; const char *oldname, *newname, *storage_oldname, *storage_newname; @@ -16,33 +15,12 @@ if (!client_read_string_args(cmd, 2, &oldname, &newname)) return FALSE; - old_ns = client_find_namespace(cmd, oldname, &storage_oldname, &status); + old_ns = client_find_namespace(cmd, oldname, &storage_oldname); if (old_ns == NULL) return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - break; - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, oldname, NULL, status); - return TRUE; - } - - new_ns = client_find_namespace(cmd, newname, &storage_newname, &status); + new_ns = client_find_namespace(cmd, newname, &storage_newname); if (new_ns == NULL) return TRUE; - switch (status) { - case MAILBOX_NAME_VALID: - break; - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, newname, NULL, status); - return TRUE; - } if (old_ns == new_ns) { /* disallow box -> box/child, because it may break clients and
--- a/src/imap/cmd-select.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/cmd-select.c Sat Jan 01 15:59:02 2011 +0200 @@ -276,7 +276,7 @@ struct client *client = ctx->cmd->client; struct mailbox_status status; enum mailbox_flags flags = 0; - int ret; + int ret = 0; if (readonly) flags |= MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT; @@ -289,16 +289,17 @@ } if (client->enabled_features != 0) - mailbox_enable(ctx->box, client->enabled_features); - if (mailbox_sync(ctx->box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { + ret = mailbox_enable(ctx->box, client->enabled_features); + if (ret < 0 || + mailbox_sync(ctx->box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { client_send_storage_error(ctx->cmd, mailbox_get_storage(ctx->box)); return -1; } - mailbox_get_status(ctx->box, STATUS_MESSAGES | STATUS_RECENT | - STATUS_FIRST_UNSEEN_SEQ | STATUS_UIDVALIDITY | - STATUS_UIDNEXT | STATUS_KEYWORDS | - STATUS_HIGHESTMODSEQ, &status); + mailbox_get_open_status(ctx->box, STATUS_MESSAGES | STATUS_RECENT | + STATUS_FIRST_UNSEEN_SEQ | STATUS_UIDVALIDITY | + STATUS_UIDNEXT | STATUS_KEYWORDS | + STATUS_HIGHESTMODSEQ, &status); client->mailbox = ctx->box; client->select_counter++; @@ -372,7 +373,6 @@ struct client *client = cmd->client; struct imap_select_context *ctx; const struct imap_arg *args, *list_args; - enum mailbox_name_status status; const char *mailbox, *storage_name; int ret; @@ -388,24 +388,11 @@ ctx = p_new(cmd->pool, struct imap_select_context, 1); ctx->cmd = cmd; - ctx->ns = client_find_namespace(cmd, mailbox, &storage_name, &status); + ctx->ns = client_find_namespace(cmd, mailbox, &storage_name); if (ctx->ns == NULL) { close_selected_mailbox(client); return TRUE; } - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - break; - case MAILBOX_NAME_EXISTS_DIR: - status = MAILBOX_NAME_VALID; - /* fall through */ - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, NULL, status); - close_selected_mailbox(client); - return TRUE; - } if (imap_arg_get_list(&args[1], &list_args)) { if (!select_parse_options(ctx, list_args)) { @@ -423,7 +410,7 @@ if (ctx->condstore) { /* Enable while no mailbox is opened to avoid sending HIGHESTMODSEQ for previously opened mailbox */ - client_enable(client, MAILBOX_FEATURE_CONDSTORE); + (void)client_enable(client, MAILBOX_FEATURE_CONDSTORE); } ret = select_open(ctx, storage_name, readonly);
--- a/src/imap/cmd-status.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/cmd-status.c Sat Jan 01 15:59:02 2011 +0200 @@ -9,7 +9,6 @@ bool cmd_status(struct client_command_context *cmd) { struct client *client = cmd->client; - enum mailbox_name_status status; const struct imap_arg *args, *list_args; struct imap_status_items items; struct imap_status_result result; @@ -31,21 +30,9 @@ if (imap_status_parse_items(cmd, list_args, &items) < 0) return TRUE; - ns = client_find_namespace(cmd, mailbox, &storage_name, &status); + ns = client_find_namespace(cmd, mailbox, &storage_name); if (ns == NULL) return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - break; - case MAILBOX_NAME_EXISTS_DIR: - status = MAILBOX_NAME_VALID; - /* fall through */ - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, NULL, status); - return TRUE; - } selected_mailbox = client->mailbox != NULL && mailbox_equals(client->mailbox, ns, storage_name);
--- a/src/imap/cmd-store.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/cmd-store.c Sat Jan 01 15:59:02 2011 +0200 @@ -62,8 +62,8 @@ "Invalid modseq"); return FALSE; } - client_enable(ctx->cmd->client, - MAILBOX_FEATURE_CONDSTORE); + (void)client_enable(ctx->cmd->client, + MAILBOX_FEATURE_CONDSTORE); } else { client_send_command_error(ctx->cmd, "Unknown STORE modifier"); @@ -201,7 +201,7 @@ mail_free(&mail); if (ctx.keywords != NULL) - mailbox_keywords_unref(client->mailbox, &ctx.keywords); + mailbox_keywords_unref(&ctx.keywords); ret = mailbox_search_deinit(&search_ctx); if (ret < 0)
--- a/src/imap/cmd-subscribe.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/cmd-subscribe.c Sat Jan 01 15:59:02 2011 +0200 @@ -26,9 +26,39 @@ return FALSE; } +static bool +subscribe_is_valid_name(struct client_command_context *cmd, const char *mailbox) +{ + enum mailbox_name_status name_status; + struct mail_namespace *ns; + const char *storage_name; + + if (have_listable_namespace_prefix(cmd->client->user->namespaces, + mailbox)) { + /* subscribing to a listable namespace prefix, allow it. */ + return TRUE; + } + + /* see if the mailbox exists */ + ns = client_find_namespace(cmd, mailbox, &storage_name); + if (ns == NULL) + return FALSE; + + if (mailbox_list_get_mailbox_name_status(ns->list, storage_name, + &name_status) < 0) { + client_send_list_error(cmd, ns->list); + return FALSE; + } + if (name_status == MAILBOX_NAME_NONEXISTENT) { + client_send_tagline(cmd, t_strdup_printf( + "NO "MAIL_ERRSTR_MAILBOX_NOT_FOUND, mailbox)); + return FALSE; + } + return TRUE; +} + bool cmd_subscribe_full(struct client_command_context *cmd, bool subscribe) { - enum mailbox_name_status status; struct mail_namespace *ns, *box_ns; const char *mailbox, *storage_name, *subs_name, *subs_name2 = NULL; bool unsubscribed_mailbox2; @@ -37,9 +67,13 @@ if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; - box_ns = client_find_namespace(cmd, mailbox, &storage_name, NULL); + box_ns = client_find_namespace(cmd, mailbox, &storage_name); if (box_ns == NULL) return TRUE; + if (!mailbox_list_is_valid_existing_name(box_ns->list, storage_name)) { + client_send_tagline(cmd, "NO [CANNOT] Invalid mailbox name"); + return TRUE; + } /* now find a namespace where the subscription can be added to */ subs_name = mailbox; @@ -69,39 +103,9 @@ subs_name = t_strndup(subs_name, strlen(subs_name)-1); } - if (have_listable_namespace_prefix(cmd->client->user->namespaces, - mailbox)) { - /* subscribing to a listable namespace prefix, allow it. */ - } else if (subscribe) { - if (client_find_namespace(cmd, mailbox, - &storage_name, &status) == NULL) - return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - break; - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, - NULL, status); + if (subscribe) { + if (!subscribe_is_valid_name(cmd, mailbox)) return TRUE; - } - } else { - if (client_find_namespace(cmd, mailbox, - &storage_name, &status) == NULL) - return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - case MAILBOX_NAME_VALID: - break; - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, - NULL, status); - return TRUE; - } } unsubscribed_mailbox2 = FALSE;
--- a/src/imap/imap-client.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/imap-client.c Sat Jan 01 15:59:02 2011 +0200 @@ -911,27 +911,35 @@ return TRUE; } -void client_enable(struct client *client, enum mailbox_feature features) +int client_enable(struct client *client, enum mailbox_feature features) { struct mailbox_status status; + int ret; if ((client->enabled_features & features) == features) - return; + return 0; client->enabled_features |= features; if (client->mailbox == NULL) - return; + return 0; - mailbox_enable(client->mailbox, features); - if ((features & MAILBOX_FEATURE_CONDSTORE) != 0) { + ret = mailbox_enable(client->mailbox, features); + if ((features & MAILBOX_FEATURE_CONDSTORE) != 0 && ret == 0) { /* CONDSTORE being enabled while mailbox is selected. Notify client of the latest HIGHESTMODSEQ. */ - mailbox_get_status(client->mailbox, - STATUS_HIGHESTMODSEQ, &status); - client_send_line(client, t_strdup_printf( - "* OK [HIGHESTMODSEQ %llu] Highest", - (unsigned long long)status.highest_modseq)); + ret = mailbox_get_status(client->mailbox, + STATUS_HIGHESTMODSEQ, &status); + if (ret == 0) { + client_send_line(client, t_strdup_printf( + "* OK [HIGHESTMODSEQ %llu] Highest", + (unsigned long long)status.highest_modseq)); + } } + if (ret < 0) { + client_send_untagged_storage_error(client, + mailbox_get_storage(client->mailbox)); + } + return ret; } struct imap_search_update *
--- a/src/imap/imap-client.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/imap-client.h Sat Jan 01 15:59:02 2011 +0200 @@ -192,7 +192,7 @@ have to wait for an existing SEARCH SAVE to finish. */ bool client_handle_search_save_ambiguity(struct client_command_context *cmd); -void client_enable(struct client *client, enum mailbox_feature features); +int client_enable(struct client *client, enum mailbox_feature features); struct imap_search_update * client_search_update_lookup(struct client *client, const char *tag,
--- a/src/imap/imap-commands-util.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/imap-commands-util.c Sat Jan 01 15:59:02 2011 +0200 @@ -13,16 +13,9 @@ #include "mail-namespace.h" #include "imap-commands-util.h" -/* Maximum length for mailbox name, including it's path. This isn't fully - exact since the user can create folder hierarchy with small names, then - rename them to larger names. Mail storages should set more strict limits - to them, mbox/maildir currently allow paths only up to PATH_MAX. */ -#define MAILBOX_MAX_NAME_LEN 512 - struct mail_namespace * client_find_namespace(struct client_command_context *cmd, const char *mailbox, - const char **storage_name_r, - enum mailbox_name_status *mailbox_status_r) + const char **storage_name_r) { struct mail_namespace *namespaces = cmd->client->user->namespaces; struct mail_namespace *ns; @@ -39,17 +32,6 @@ return NULL; } - if (mailbox_status_r == NULL) { - *storage_name_r = storage_name; - return ns; - } - - /* make sure it even looks valid */ - if (*storage_name == '\0' && !(*mailbox != '\0' && ns->list)) { - client_send_tagline(cmd, "NO Empty mailbox name."); - return NULL; - } - storage_name_len = strlen(storage_name); if ((cmd->client->set->parsed_workarounds & WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 && @@ -74,66 +56,10 @@ } } - /* make sure two hierarchy separators aren't next to each others */ - for (p = storage_name+1; *p != '\0'; p++) { - if (p[0] == ns->real_sep && p[-1] == ns->real_sep) { - client_send_tagline(cmd, "NO Invalid mailbox name."); - return NULL; - } - } - - if (storage_name_len > MAILBOX_MAX_NAME_LEN) { - client_send_tagline(cmd, "NO Mailbox name too long."); - return NULL; - } - - /* check what our storage thinks of it */ - if (mailbox_list_get_mailbox_name_status(ns->list, storage_name, - mailbox_status_r) < 0) { - client_send_list_error(cmd, ns->list); - return NULL; - } *storage_name_r = storage_name; return ns; } -void client_fail_mailbox_name_status(struct client_command_context *cmd, - const char *mailbox_name, - const char *resp_code, - enum mailbox_name_status status) -{ - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - client_send_tagline(cmd, t_strconcat( - "NO [", IMAP_RESP_CODE_ALREADYEXISTS, - "] Mailbox already exists: ", - str_sanitize(mailbox_name, MAILBOX_MAX_NAME_LEN), - NULL)); - break; - case MAILBOX_NAME_VALID: - if (resp_code == NULL) - resp_code = ""; - else - resp_code = t_strconcat("[", resp_code, "] ", NULL); - client_send_tagline(cmd, t_strconcat( - "NO ", resp_code, "Mailbox doesn't exist: ", - str_sanitize(mailbox_name, MAILBOX_MAX_NAME_LEN), - NULL)); - break; - case MAILBOX_NAME_INVALID: - client_send_tagline(cmd, t_strconcat( - "NO Invalid mailbox name: ", - str_sanitize(mailbox_name, MAILBOX_MAX_NAME_LEN), - NULL)); - break; - case MAILBOX_NAME_NOINFERIORS: - client_send_tagline(cmd, - "NO Parent mailbox doesn't allow child mailboxes."); - break; - } -} - bool client_verify_open_mailbox(struct client_command_context *cmd) { if (cmd->client->mailbox != NULL) @@ -144,6 +70,49 @@ } } +int client_open_save_dest_box(struct client_command_context *cmd, + const char *name, struct mailbox **destbox_r) +{ + struct mail_namespace *ns; + struct mailbox *box; + const char *storage_name, *error_string; + enum mail_error error; + + ns = client_find_namespace(cmd, name, &storage_name); + if (ns == NULL) + return -1; + + if (cmd->client->mailbox != NULL && + mailbox_equals(cmd->client->mailbox, ns, storage_name)) { + *destbox_r = cmd->client->mailbox; + return 0; + } + box = mailbox_alloc(ns->list, storage_name, + MAILBOX_FLAG_SAVEONLY | MAILBOX_FLAG_KEEP_RECENT); + if (mailbox_open(box) < 0) { + struct mail_storage *storage = mailbox_get_storage(box); + + error_string = mail_storage_get_last_error(storage, &error); + if (error == MAIL_ERROR_NOTFOUND) { + client_send_tagline(cmd, t_strdup_printf( + "NO [TRYCREATE] %s", error_string)); + } else { + client_send_storage_error(cmd, storage); + } + mailbox_free(&box); + return -1; + } + if (cmd->client->enabled_features != 0) { + if (mailbox_enable(box, cmd->client->enabled_features) < 0) { + client_send_storage_error(cmd, mailbox_get_storage(box)); + mailbox_free(&box); + return -1; + } + } + *destbox_r = box; + return 0; +} + const char * imap_get_error_string(struct client_command_context *cmd, const char *error_string, enum mail_error error)
--- a/src/imap/imap-commands-util.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/imap-commands-util.h Sat Jan 01 15:59:02 2011 +0200 @@ -13,19 +13,16 @@ or mailbox name is invalid, sends a tagged NO reply to client. */ struct mail_namespace * client_find_namespace(struct client_command_context *cmd, const char *mailbox, - const char **storage_name_r, - enum mailbox_name_status *mailbox_status_r); - -/* Send tagged NO reply based on mailbox name status. */ -void client_fail_mailbox_name_status(struct client_command_context *cmd, - const char *mailbox_name, - const char *resp_code, - enum mailbox_name_status status); + const char **storage_name_r); /* Returns TRUE if mailbox is selected. If not, sends "No mailbox selected" error message to client. */ bool client_verify_open_mailbox(struct client_command_context *cmd); +/* Open APPEND/COPY destination mailbox. */ +int client_open_save_dest_box(struct client_command_context *cmd, + const char *name, struct mailbox **destbox_r); + const char * imap_get_error_string(struct client_command_context *cmd, const char *error_string, enum mail_error error);
--- a/src/imap/imap-fetch.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/imap-fetch.c Sat Jan 01 15:59:02 2011 +0200 @@ -159,7 +159,7 @@ i_assert(array_count(ctx->qresync_sample_uidset) == count); i_assert(count > 0); - mailbox_get_status(ctx->box, STATUS_MESSAGES, &status); + mailbox_get_open_status(ctx->box, STATUS_MESSAGES, &status); /* FIXME: we could do removals from the middle as well */ for (i = 0; i < count && seqs[i] <= status.messages; i++) { @@ -245,7 +245,7 @@ uid_filter[i].seq2); } - mailbox_get_status(ctx->box, STATUS_UIDNEXT, &status); + mailbox_get_open_status(ctx->box, STATUS_UIDNEXT, &status); seq_range_array_remove_range(expunged_uids, status.uidnext, (uint32_t)-1); @@ -751,7 +751,7 @@ fetch_modseq_init(struct imap_fetch_context *ctx, const char *name, const struct imap_arg **args ATTR_UNUSED) { - client_enable(ctx->client, MAILBOX_FEATURE_CONDSTORE); + (void)client_enable(ctx->client, MAILBOX_FEATURE_CONDSTORE); imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL, fetch_modseq, NULL); return TRUE;
--- a/src/imap/imap-search.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/imap-search.c Sat Jan 01 15:59:02 2011 +0200 @@ -528,7 +528,7 @@ if (ctx->have_modseqs) { ctx->return_options |= SEARCH_RETURN_MODSEQ; - client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE); + (void)client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE); } ctx->box = cmd->client->mailbox;
--- a/src/imap/imap-status.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/imap-status.c Sat Jan 01 15:59:02 2011 +0200 @@ -11,7 +11,8 @@ struct imap_status_items *items_r) { const char *item; - enum mailbox_status_items items; + enum mailbox_status_items status = 0; + enum mailbox_metadata_items metadata = 0; if (IMAP_ARG_IS_EOL(args)) { client_send_command_error(cmd, "Empty status list."); @@ -19,7 +20,6 @@ } memset(items_r, 0, sizeof(*items_r)); - items = 0; for (; !IMAP_ARG_IS_EOL(args); args++) { if (!imap_arg_get_atom(args, &item)) { /* list may contain only atoms */ @@ -30,21 +30,21 @@ item = t_str_ucase(item); if (strcmp(item, "MESSAGES") == 0) - items |= STATUS_MESSAGES; + status |= STATUS_MESSAGES; else if (strcmp(item, "RECENT") == 0) - items |= STATUS_RECENT; + status |= STATUS_RECENT; else if (strcmp(item, "UIDNEXT") == 0) - items |= STATUS_UIDNEXT; + status |= STATUS_UIDNEXT; else if (strcmp(item, "UIDVALIDITY") == 0) - items |= STATUS_UIDVALIDITY; + status |= STATUS_UIDVALIDITY; else if (strcmp(item, "UNSEEN") == 0) - items |= STATUS_UNSEEN; + status |= STATUS_UNSEEN; else if (strcmp(item, "HIGHESTMODSEQ") == 0) - items |= STATUS_HIGHESTMODSEQ; + status |= STATUS_HIGHESTMODSEQ; else if (strcmp(item, "X-SIZE") == 0) - items |= STATUS_VIRTUAL_SIZE; + metadata |= MAILBOX_METADATA_VIRTUAL_SIZE; else if (strcmp(item, "X-GUID") == 0) - items_r->guid = TRUE; + metadata |= MAILBOX_METADATA_GUID; else { client_send_tagline(cmd, t_strconcat( "BAD Invalid status item ", item, NULL)); @@ -52,7 +52,8 @@ } } - items_r->mailbox_items = items; + items_r->status = status; + items_r->metadata = metadata; return 0; } @@ -75,19 +76,19 @@ box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT); - if (client->enabled_features != 0) - mailbox_enable(box, client->enabled_features); + if (client->enabled_features != 0) { + if (mailbox_enable(box, client->enabled_features) < 0) + ret = -1; + } } - if ((items->mailbox_items & STATUS_HIGHESTMODSEQ) != 0) - client_enable(client, MAILBOX_FEATURE_CONDSTORE); + if ((items->status & STATUS_HIGHESTMODSEQ) != 0) + (void)client_enable(client, MAILBOX_FEATURE_CONDSTORE); - ret = box == client->mailbox ? 0 : mailbox_sync(box, 0); - if (ret == 0) { - mailbox_get_status(box, items->mailbox_items, - &result_r->status); - if (items->guid) - ret = mailbox_get_guid(box, result_r->mailbox_guid); + ret = mailbox_get_status(box, items->status, &result_r->status); + if (items->metadata != 0 && ret == 0) { + ret = mailbox_get_metadata(box, items->metadata, + &result_r->metadata); } if (ret < 0) { @@ -115,27 +116,27 @@ str_append(str, " ("); prefix_len = str_len(str); - if ((items->mailbox_items & STATUS_MESSAGES) != 0) + if ((items->status & STATUS_MESSAGES) != 0) str_printfa(str, "MESSAGES %u ", status->messages); - if ((items->mailbox_items & STATUS_RECENT) != 0) + if ((items->status & STATUS_RECENT) != 0) str_printfa(str, "RECENT %u ", status->recent); - if ((items->mailbox_items & STATUS_UIDNEXT) != 0) + if ((items->status & STATUS_UIDNEXT) != 0) str_printfa(str, "UIDNEXT %u ", status->uidnext); - if ((items->mailbox_items & STATUS_UIDVALIDITY) != 0) + if ((items->status & STATUS_UIDVALIDITY) != 0) str_printfa(str, "UIDVALIDITY %u ", status->uidvalidity); - if ((items->mailbox_items & STATUS_UNSEEN) != 0) + if ((items->status & STATUS_UNSEEN) != 0) str_printfa(str, "UNSEEN %u ", status->unseen); - if ((items->mailbox_items & STATUS_HIGHESTMODSEQ) != 0) { + if ((items->status & STATUS_HIGHESTMODSEQ) != 0) { str_printfa(str, "HIGHESTMODSEQ %llu ", (unsigned long long)status->highest_modseq); } - if ((items->mailbox_items & STATUS_VIRTUAL_SIZE) != 0) { + if ((items->metadata & MAILBOX_METADATA_VIRTUAL_SIZE) != 0) { str_printfa(str, "X-SIZE %llu ", - (unsigned long long)status->virtual_size); + (unsigned long long)result->metadata.virtual_size); } - if (items->guid) { + if ((items->metadata & MAILBOX_METADATA_GUID) != 0) { str_printfa(str, "X-GUID %s ", - mail_guid_128_to_string(result->mailbox_guid)); + mail_guid_128_to_string(result->metadata.guid)); } if (str_len(str) != prefix_len)
--- a/src/imap/imap-status.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/imap-status.h Sat Jan 01 15:59:02 2011 +0200 @@ -2,14 +2,13 @@ #define IMAP_STATUS_H struct imap_status_items { - enum mailbox_status_items mailbox_items; - - unsigned int guid:1; + enum mailbox_status_items status; + enum mailbox_metadata_items metadata; }; struct imap_status_result { struct mailbox_status status; - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; }; int imap_status_parse_items(struct client_command_context *cmd,
--- a/src/imap/imap-sync.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/imap/imap-sync.c Sat Jan 01 15:59:02 2011 +0200 @@ -226,9 +226,9 @@ i_free(ctx); return -1; } - mailbox_get_status(ctx->box, STATUS_UIDVALIDITY | - STATUS_MESSAGES | STATUS_RECENT | - STATUS_HIGHESTMODSEQ, &status); + mailbox_get_open_status(ctx->box, STATUS_UIDVALIDITY | + STATUS_MESSAGES | STATUS_RECENT | + STATUS_HIGHESTMODSEQ, &status); ret = mailbox_transaction_commit(&ctx->t);
--- a/src/lib-imap/imap-bodystructure.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-imap/imap-bodystructure.c Sat Jan 01 15:59:02 2011 +0200 @@ -360,6 +360,7 @@ static void part_write_body(const struct message_part *part, string_t *str, bool extended) { +#define NVL(str, nullstr) ((str) != NULL ? (str) : (nullstr)) struct message_part_body_data *data = part->context; bool text;
--- a/src/lib-imap/imap-envelope.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-imap/imap-envelope.c Sat Jan 01 15:59:02 2011 +0200 @@ -182,6 +182,7 @@ void imap_envelope_write_part_data(struct message_part_envelope_data *data, string_t *str) { +#define NVL(str, nullstr) ((str) != NULL ? (str) : (nullstr)) static const char *empty_envelope = "NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL";
--- a/src/lib-lda/duplicate.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-lda/duplicate.c Sat Jan 01 15:59:02 2011 +0200 @@ -232,15 +232,15 @@ pool_unref(&file->pool); } -int duplicate_check(struct duplicate_context *ctx, - const void *id, size_t id_size, const char *user) +bool duplicate_check(struct duplicate_context *ctx, + const void *id, size_t id_size, const char *user) { struct duplicate d; if (ctx->file == NULL) { if (ctx->path == NULL) { /* duplicate database disabled */ - return 0; + return FALSE; } ctx->file = duplicate_file_new(ctx); }
--- a/src/lib-lda/duplicate.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-lda/duplicate.h Sat Jan 01 15:59:02 2011 +0200 @@ -6,8 +6,8 @@ #define DUPLICATE_DEFAULT_KEEP (3600 * 24) -int duplicate_check(struct duplicate_context *ctx, - const void *id, size_t id_size, const char *user); +bool duplicate_check(struct duplicate_context *ctx, + const void *id, size_t id_size, const char *user); void duplicate_mark(struct duplicate_context *ctx, const void *id, size_t id_size, const char *user, time_t timestamp);
--- a/src/lib-lda/mail-deliver.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-lda/mail-deliver.c Sat Jan 01 15:59:02 2011 +0200 @@ -253,7 +253,7 @@ else mail_deliver_log_cache_var_expand_table(ctx); if (kw != NULL) - mailbox_keywords_unref(box, &kw); + mailbox_keywords_unref(&kw); mail_free(&ctx->dest_mail); if (ret < 0)
--- a/src/lib-storage/Makefile.am Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/Makefile.am Sat Jan 01 15:59:02 2011 +0200 @@ -5,6 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-test \ -I$(top_srcdir)/src/lib-auth \ -I$(top_srcdir)/src/lib-dict \ -I$(top_srcdir)/src/lib-master \ @@ -33,6 +34,9 @@ mail-storage-settings.c \ mail-thread.c \ mail-user.c \ + mailbox-get.c \ + mailbox-header.c \ + mailbox-keywords.c \ mailbox-list.c \ mailbox-search-result.c \ mailbox-tree.c \ @@ -86,6 +90,25 @@ test_headers = \ test-mail-storage.h +test_programs = \ + test-mailbox-get + +noinst_PROGRAMS = $(test_programs) + +test_libs = \ + $(top_builddir)/src/lib-test/libtest.la \ + $(top_builddir)/src/lib/liblib.la + +test_mailbox_get_SOURCES = test-mailbox-get.c +test_mailbox_get_LDADD = mailbox-get.lo $(test_libs) +test_mailbox_get_DEPENDENCIES = mailbox-get.lo $(test_libs) + +check: check-am check-test +check-test: all-am + for bin in $(test_programs); do \ + if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \ + done + pkginc_libdir=$(pkgincludedir) pkginc_lib_HEADERS = $(headers) noinst_HEADERS = $(test_headers)
--- a/src/lib-storage/index/Makefile.am Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/Makefile.am Sat Jan 01 15:59:02 2011 +0200 @@ -15,7 +15,6 @@ istream-attachment.c \ istream-mail-stats.c \ index-attachment.c \ - index-fetch.c \ index-mail.c \ index-mail-headers.c \ index-mailbox-check.c \ @@ -49,24 +48,5 @@ index-sync-private.h \ index-thread-private.h -test_programs = \ - test-index-fetch - -noinst_PROGRAMS = $(test_programs) - -test_libs = \ - $(top_builddir)/src/lib-test/libtest.la \ - $(top_builddir)/src/lib/liblib.la - -test_index_fetch_SOURCES = test-index-fetch.c -test_index_fetch_LDADD = index-fetch.lo $(test_libs) -test_index_fetch_DEPENDENCIES = index-fetch.lo $(test_libs) - -check: check-am check-test -check-test: all-am - for bin in $(test_programs); do \ - if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \ - done - pkginc_libdir=$(pkgincludedir) pkginc_lib_HEADERS = $(headers)
--- a/src/lib-storage/index/cydir/cydir-storage.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/cydir/cydir-storage.c Sat Jan 01 15:59:02 2011 +0200 @@ -55,10 +55,6 @@ index_storage_mailbox_alloc(&mbox->box, name, flags, CYDIR_INDEX_PREFIX); - mail_index_set_fsync_mode(mbox->box.index, - storage->set->parsed_fsync_mode, - MAIL_INDEX_SYNC_TYPE_APPEND | - MAIL_INDEX_SYNC_TYPE_EXPUNGE); ibox = INDEX_STORAGE_CONTEXT(&mbox->box); ibox->save_commit_pre = cydir_transaction_save_commit_pre; @@ -71,9 +67,10 @@ static int cydir_mailbox_open(struct mailbox *box) { + const char *box_path = mailbox_get_path(box); struct stat st; - if (stat(box->path, &st) == 0) { + if (stat(box_path, &st) == 0) { /* exists, open it */ } else if (errno == ENOENT) { mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND, @@ -81,14 +78,20 @@ return -1; } else if (errno == EACCES) { mail_storage_set_critical(box->storage, "%s", - mail_error_eacces_msg("stat", box->path)); + mail_error_eacces_msg("stat", box_path)); return -1; } else { mail_storage_set_critical(box->storage, "stat(%s) failed: %m", - box->path); + box_path); return -1; } - return index_storage_mailbox_open(box, FALSE); + if (index_storage_mailbox_open(box, FALSE) < 0) + return -1; + mail_index_set_fsync_mode(box->index, + box->storage->set->parsed_fsync_mode, + MAIL_INDEX_SYNC_TYPE_APPEND | + MAIL_INDEX_SYNC_TYPE_EXPUNGE); + return 0; } static int @@ -105,12 +108,10 @@ static void cydir_notify_changes(struct mailbox *box) { - struct cydir_mailbox *mbox = (struct cydir_mailbox *)box; - if (box->notify_callback == NULL) - index_mailbox_check_remove_all(&mbox->box); + index_mailbox_check_remove_all(box); else - index_mailbox_check_add(&mbox->box, mbox->box.path); + index_mailbox_check_add(box, mailbox_get_path(box)); } struct mail_storage cydir_storage = { @@ -154,21 +155,8 @@ index_transaction_begin, index_transaction_commit, index_transaction_rollback, - index_transaction_set_max_modseq, - index_keywords_create, - index_keywords_create_from_indexes, - index_keywords_ref, - index_keywords_unref, - index_keyword_is_valid, - index_storage_get_seq_range, - index_storage_get_uid_range, - index_storage_get_expunges, - NULL, - NULL, NULL, index_mail_alloc, - index_header_lookup_init, - index_header_lookup_deinit, index_storage_search_init, index_storage_search_deinit, index_storage_search_next_nonblock, @@ -179,7 +167,6 @@ cydir_save_finish, cydir_save_cancel, mail_storage_copy, - NULL, index_storage_is_inconsistent } };
--- a/src/lib-storage/index/dbox-common/dbox-mail.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-common/dbox-mail.c Sat Jan 01 15:59:02 2011 +0200 @@ -167,8 +167,8 @@ string_t *str; str = str_new(imail->data_pool, 64); - if (mail_cache_lookup_field(imail->trans->cache_view, str, - imail->mail.mail.seq, + if (mail_cache_lookup_field(imail->mail.mail.transaction->cache_view, + str, imail->mail.mail.seq, ibox->cache_fields[cache_field].idx) > 0) { *value_r = str_c(str); return 0;
--- a/src/lib-storage/index/dbox-common/dbox-storage.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-common/dbox-storage.c Sat Jan 01 15:59:02 2011 +0200 @@ -113,21 +113,31 @@ int dbox_mailbox_open(struct mailbox *box) { - if (dbox_cleanup_if_exists(box->list, box->path)) { - return index_storage_mailbox_open(box, FALSE); - } else if (errno == ENOENT) { + const char *box_path = mailbox_get_path(box); + + if (dbox_cleanup_if_exists(box->list, box_path)) + ; + else if (errno == ENOENT) { mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND, T_MAIL_ERR_MAILBOX_NOT_FOUND(box->name)); return -1; } else if (errno == EACCES) { mail_storage_set_critical(box->storage, "%s", - mail_error_eacces_msg("stat", box->path)); + mail_error_eacces_msg("stat", box_path)); return -1; } else { mail_storage_set_critical(box->storage, - "stat(%s) failed: %m", box->path); + "stat(%s) failed: %m", box_path); return -1; } + + if (index_storage_mailbox_open(box, FALSE) < 0) + return -1; + mail_index_set_fsync_mode(box->index, + box->storage->set->parsed_fsync_mode, + MAIL_INDEX_SYNC_TYPE_APPEND | + MAIL_INDEX_SYNC_TYPE_EXPUNGE); + return 0; } static int dir_is_empty(struct mail_storage *storage, const char *path)
--- a/src/lib-storage/index/dbox-multi/mdbox-mail.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-multi/mdbox-mail.c Sat Jan 01 15:59:02 2011 +0200 @@ -29,7 +29,7 @@ mail_index_lookup_uid(view, seq, &uid); mail_storage_set_critical(&mbox->storage->storage.storage, "mdbox %s: map uid lost for uid %u", - mbox->box.path, uid); + mailbox_get_path(&mbox->box), uid); mdbox_storage_set_corrupted(mbox->storage); return -1; } @@ -48,7 +48,7 @@ if (cur_map_uid_validity != mbox->map_uid_validity) { mail_storage_set_critical(&mbox->storage->storage.storage, "mdbox %s: map uidvalidity mismatch (%u vs %u)", - mbox->box.path, mbox->map_uid_validity, + mailbox_get_path(&mbox->box), mbox->map_uid_validity, cur_map_uid_validity); mdbox_storage_set_corrupted(mbox->storage); return -1;
--- a/src/lib-storage/index/dbox-multi/mdbox-map.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-multi/mdbox-map.c Sat Jan 01 15:59:02 2011 +0200 @@ -77,8 +77,9 @@ map->ref_ext_id = mail_index_ext_register(map->index, "ref", 0, sizeof(uint16_t), sizeof(uint16_t)); - mailbox_list_get_permissions(root_list, NULL, &map->create_mode, - &map->create_gid, &map->create_gid_origin); + mailbox_list_get_root_permissions(root_list, &map->create_mode, + &map->create_gid, + &map->create_gid_origin); mail_index_set_permissions(map->index, map->create_mode, map->create_gid, map->create_gid_origin); return map;
--- a/src/lib-storage/index/dbox-multi/mdbox-save.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-multi/mdbox-save.c Sat Jan 01 15:59:02 2011 +0200 @@ -364,10 +364,11 @@ (void)mdbox_map_atomic_finish(&ctx->atomic); if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) { - if (fdatasync_path(ctx->mbox->box.path) < 0) { + const char *box_path = mailbox_get_path(&ctx->mbox->box); + + if (fdatasync_path(box_path) < 0) { mail_storage_set_critical(storage, - "fdatasync_path(%s) failed: %m", - ctx->mbox->box.path); + "fdatasync_path(%s) failed: %m", box_path); } } mdbox_transaction_save_rollback(_ctx);
--- a/src/lib-storage/index/dbox-multi/mdbox-storage.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-multi/mdbox-storage.c Sat Jan 01 15:59:02 2011 +0200 @@ -101,10 +101,6 @@ mbox->box.mail_vfuncs = &mdbox_mail_vfuncs; index_storage_mailbox_alloc(&mbox->box, name, flags, DBOX_INDEX_PREFIX); - mail_index_set_fsync_mode(mbox->box.index, - storage->set->parsed_fsync_mode, - MAIL_INDEX_SYNC_TYPE_APPEND | - MAIL_INDEX_SYNC_TYPE_EXPUNGE); ibox = INDEX_STORAGE_CONTEXT(&mbox->box); ibox->save_commit_pre = mdbox_transaction_save_commit_pre; @@ -114,6 +110,16 @@ MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY; mbox->storage = (struct mdbox_storage *)storage; + return &mbox->box; +} + +static int mdbox_mailbox_open(struct mailbox *box) +{ + struct mdbox_mailbox *mbox = (struct mdbox_mailbox *)box; + + if (dbox_mailbox_open(box) < 0) + return -1; + mbox->ext_id = mail_index_ext_register(mbox->box.index, "mdbox", 0, sizeof(struct mdbox_mail_index_record), @@ -124,7 +130,7 @@ mbox->guid_ext_id = mail_index_ext_register(mbox->box.index, "guid", 0, MAIL_GUID_128_SIZE, 1); - return &mbox->box; + return 0; } static void mdbox_mailbox_close(struct mailbox *box) @@ -149,7 +155,7 @@ (!mbox->creating || data_size != 0)) { mail_storage_set_critical(&mbox->storage->storage.storage, "mdbox %s: Invalid dbox header size: %"PRIuSIZE_T, - mbox->box.path, data_size); + mailbox_get_path(&mbox->box), data_size); mdbox_storage_set_corrupted(mbox->storage); return -1; } @@ -294,9 +300,9 @@ } static int -mdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) +mdbox_mailbox_get_guid(struct mdbox_mailbox *mbox, + uint8_t guid[MAIL_GUID_128_SIZE]) { - struct mdbox_mailbox *mbox = (struct mdbox_mailbox *)box; struct mdbox_index_header hdr; if (mdbox_read_header(mbox, &hdr) < 0) @@ -304,7 +310,7 @@ if (mail_guid_128_is_empty(hdr.mailbox_guid)) { /* regenerate it */ - if (mdbox_write_index_header(box, NULL, NULL) < 0 || + if (mdbox_write_index_header(&mbox->box, NULL, NULL) < 0 || mdbox_read_header(mbox, &hdr) < 0) return -1; } @@ -313,6 +319,20 @@ } static int +mdbox_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) +{ + struct mdbox_mailbox *mbox = (struct mdbox_mailbox *)box; + + if ((items & MAILBOX_METADATA_GUID) != 0) { + if (mdbox_mailbox_get_guid(mbox, metadata_r->guid) < 0) + return -1; + } + return index_mailbox_get_metadata(box, items, metadata_r); +} + +static int mdbox_mailbox_update(struct mailbox *box, const struct mailbox_update *update) { if (!box->opened) { @@ -389,7 +409,7 @@ index_storage_is_readonly, index_storage_allow_new_keywords, index_storage_mailbox_enable, - dbox_mailbox_open, + mdbox_mailbox_open, mdbox_mailbox_close, index_storage_mailbox_free, dbox_mailbox_create, @@ -397,7 +417,7 @@ mdbox_mailbox_delete, index_storage_mailbox_rename, index_storage_get_status, - mdbox_mailbox_get_guid, + mdbox_mailbox_get_metadata, NULL, NULL, mdbox_storage_sync_init, @@ -408,21 +428,8 @@ index_transaction_begin, index_transaction_commit, index_transaction_rollback, - index_transaction_set_max_modseq, - index_keywords_create, - index_keywords_create_from_indexes, - index_keywords_ref, - index_keywords_unref, - index_keyword_is_valid, - index_storage_get_seq_range, - index_storage_get_uid_range, - index_storage_get_expunges, - NULL, - NULL, NULL, dbox_mail_alloc, - index_header_lookup_init, - index_header_lookup_deinit, index_storage_search_init, index_storage_search_deinit, index_storage_search_next_nonblock, @@ -433,7 +440,6 @@ mdbox_save_finish, mdbox_save_cancel, mdbox_copy, - NULL, index_storage_is_inconsistent } };
--- a/src/lib-storage/index/dbox-multi/mdbox-sync.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-multi/mdbox-sync.c Sat Jan 01 15:59:02 2011 +0200 @@ -264,7 +264,7 @@ if (storage_rebuilt) { mail_storage_set_critical(storage, "mdbox %s: Storage keeps breaking", - mbox->box.path); + mailbox_get_path(&mbox->box)); return -1; }
--- a/src/lib-storage/index/dbox-single/sdbox-file.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-single/sdbox-file.c Sat Jan 01 15:59:02 2011 +0200 @@ -22,7 +22,7 @@ i_free(file->file.primary_path); i_free(file->file.alt_path); file->file.primary_path = - i_strdup_printf("%s/%s", box->path, fname); + i_strdup_printf("%s/%s", mailbox_get_path(box), fname); alt_path = mailbox_list_get_path(box->list, box->name, MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX); @@ -46,7 +46,7 @@ } else { file->file.primary_path = i_strdup_printf("%s/%s", - file->mbox->box.path, + mailbox_get_path(&mbox->box), dbox_generate_tmp_filename()); } } T_END; @@ -151,7 +151,7 @@ old_path = file->file.cur_path; new_fname = t_strdup_printf(SDBOX_MAIL_FILE_FORMAT, uid); - new_path = t_strdup_printf("%s/%s", file->mbox->box.path, + new_path = t_strdup_printf("%s/%s", mailbox_get_path(&file->mbox->box), new_fname); if (rename(old_path, new_path) < 0) { mail_storage_set_critical(&file->file.storage->storage, @@ -221,43 +221,44 @@ { struct sdbox_file *sfile = (struct sdbox_file *)file; struct mailbox *box = &sfile->mbox->box; + const struct mailbox_permissions *perm = mailbox_get_permissions(box); const char *p, *dir; mode_t old_mask; int fd; - old_mask = umask(0666 & ~box->file_create_mode); + old_mask = umask(0666 & ~perm->file_create_mode); fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666); umask(old_mask); if (fd == -1 && errno == ENOENT && parents && (p = strrchr(path, '/')) != NULL) { dir = t_strdup_until(path, p); - if (mkdir_parents_chgrp(dir, box->dir_create_mode, - box->file_create_gid, - box->file_create_gid_origin) < 0) { + if (mkdir_parents_chgrp(dir, perm->dir_create_mode, + perm->file_create_gid, + perm->file_create_gid_origin) < 0) { mail_storage_set_critical(box->storage, "mkdir_parents(%s) failed: %m", dir); return -1; } /* try again */ - old_mask = umask(0666 & ~box->file_create_mode); + old_mask = umask(0666 & ~perm->file_create_mode); fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666); umask(old_mask); } if (fd == -1) { mail_storage_set_critical(box->storage, "open(%s, O_CREAT) failed: %m", path); - } else if (box->file_create_gid == (gid_t)-1) { + } else if (perm->file_create_gid == (gid_t)-1) { /* no group change */ - } else if (fchown(fd, (uid_t)-1, box->file_create_gid) < 0) { + } else if (fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) { if (errno == EPERM) { mail_storage_set_critical(box->storage, "%s", eperm_error_get_chgrp("fchown", path, - box->file_create_gid, - box->file_create_gid_origin)); + perm->file_create_gid, + perm->file_create_gid_origin)); } else { mail_storage_set_critical(box->storage, "fchown(%s, -1, %ld) failed: %m", - path, (long)box->file_create_gid); + path, (long)perm->file_create_gid); } /* continue anyway */ }
--- a/src/lib-storage/index/dbox-single/sdbox-save.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-single/sdbox-save.c Sat Jan 01 15:59:02 2011 +0200 @@ -307,10 +307,11 @@ ctx->ctx.failed = TRUE; if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) { - if (fdatasync_path(ctx->mbox->box.path) < 0) { + const char *box_path = mailbox_get_path(&ctx->mbox->box); + + if (fdatasync_path(box_path) < 0) { mail_storage_set_critical(storage, - "fdatasync_path(%s) failed: %m", - ctx->mbox->box.path); + "fdatasync_path(%s) failed: %m", box_path); } } sdbox_transaction_save_rollback(_ctx);
--- a/src/lib-storage/index/dbox-single/sdbox-storage.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-single/sdbox-storage.c Sat Jan 01 15:59:02 2011 +0200 @@ -48,10 +48,6 @@ mbox->box.mail_vfuncs = &sdbox_mail_vfuncs; index_storage_mailbox_alloc(&mbox->box, name, flags, DBOX_INDEX_PREFIX); - mail_index_set_fsync_mode(mbox->box.index, - storage->set->parsed_fsync_mode, - MAIL_INDEX_SYNC_TYPE_APPEND | - MAIL_INDEX_SYNC_TYPE_EXPUNGE); ibox = INDEX_STORAGE_CONTEXT(&mbox->box); ibox->save_commit_pre = sdbox_transaction_save_commit_pre; @@ -61,9 +57,6 @@ MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY; mbox->storage = (struct sdbox_storage *)storage; - mbox->hdr_ext_id = - mail_index_ext_register(mbox->box.index, "dbox-hdr", - sizeof(struct sdbox_index_header), 0, 0); return &mbox->box; } @@ -84,7 +77,7 @@ mail_storage_set_critical( &mbox->storage->storage.storage, "sdbox %s: Invalid dbox header size", - mbox->box.path); + mailbox_get_path(&mbox->box)); } ret = -1; } else { @@ -226,6 +219,9 @@ if (dbox_mailbox_open(box) < 0) return -1; + mbox->hdr_ext_id = + mail_index_ext_register(box->index, "dbox-hdr", + sizeof(struct sdbox_index_header), 0, 0); /* get/generate mailbox guid */ if (sdbox_read_header(mbox, &hdr, FALSE) < 0) { @@ -307,12 +303,17 @@ } static int -sdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) +sdbox_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) { struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)box; - memcpy(guid, mbox->mailbox_guid, MAIL_GUID_128_SIZE); - return 0; + if ((items & MAILBOX_METADATA_GUID) != 0) { + memcpy(metadata_r->guid, mbox->mailbox_guid, + MAIL_GUID_128_SIZE); + } + return index_mailbox_get_metadata(box, items, metadata_r); } static int @@ -374,7 +375,7 @@ sdbox_mailbox_delete, index_storage_mailbox_rename, index_storage_get_status, - sdbox_mailbox_get_guid, + sdbox_mailbox_get_metadata, NULL, NULL, sdbox_storage_sync_init, @@ -385,21 +386,8 @@ index_transaction_begin, index_transaction_commit, index_transaction_rollback, - index_transaction_set_max_modseq, - index_keywords_create, - index_keywords_create_from_indexes, - index_keywords_ref, - index_keywords_unref, - index_keyword_is_valid, - index_storage_get_seq_range, - index_storage_get_uid_range, - index_storage_get_expunges, - NULL, - NULL, NULL, dbox_mail_alloc, - index_header_lookup_init, - index_header_lookup_deinit, index_storage_search_init, index_storage_search_deinit, index_storage_search_next_nonblock, @@ -410,7 +398,6 @@ sdbox_save_finish, sdbox_save_cancel, sdbox_copy, - NULL, index_storage_is_inconsistent } };
--- a/src/lib-storage/index/dbox-single/sdbox-sync-rebuild.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-single/sdbox-sync-rebuild.c Sat Jan 01 15:59:02 2011 +0200 @@ -73,7 +73,7 @@ if (str_to_uint32(fname, &uid) < 0 || uid == 0) { i_warning("sdbox %s: Ignoring invalid filename %s", - ctx->box->path, fname); + mailbox_get_path(ctx->box), fname); return 0; } @@ -146,14 +146,15 @@ static int sdbox_sync_index_rebuild_singles(struct dbox_sync_rebuild_context *ctx) { - const char *alt_path; + const char *path, *alt_path; int ret = 0; + path = mailbox_get_path(ctx->box); alt_path = mailbox_list_get_path(ctx->box->list, ctx->box->name, MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX); sdbox_sync_set_uidvalidity(ctx); - if (sdbox_sync_index_rebuild_dir(ctx, ctx->box->path, TRUE) < 0) + if (sdbox_sync_index_rebuild_dir(ctx, path, TRUE) < 0) ret = -1; else if (alt_path != NULL) ret = sdbox_sync_index_rebuild_dir(ctx, alt_path, FALSE);
--- a/src/lib-storage/index/dbox-single/sdbox-sync.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/dbox-single/sdbox-sync.c Sat Jan 01 15:59:02 2011 +0200 @@ -202,12 +202,12 @@ if (i >= SDBOX_REBUILD_COUNT) { mail_storage_set_critical(storage, "sdbox %s: Index keeps breaking", - ctx->mbox->box.path); + mailbox_get_path(&ctx->mbox->box)); ret = -1; } else { /* do a full resync and try again. */ i_warning("sdbox %s: Rebuilding index", - ctx->mbox->box.path); + mailbox_get_path(&ctx->mbox->box)); rebuild = FALSE; ret = sdbox_sync_index_rebuild(mbox, force_rebuild);
--- a/src/lib-storage/index/index-attachment.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/index-attachment.c Sat Jan 01 15:59:02 2011 +0200 @@ -147,7 +147,6 @@ static bool save_is_attachment(struct mail_save_context *ctx, struct message_part *part) { - struct mailbox *box = ctx->transaction->box; struct mail_attachment_part apart; if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0) { @@ -155,14 +154,14 @@ but they're never themselves */ return FALSE; } - if (box->v.save_is_attachment == NULL) + if (ctx->part_is_attachment == NULL) return TRUE; memset(&apart, 0, sizeof(apart)); apart.part = part; apart.content_type = ctx->attach->part.content_type; apart.content_disposition = ctx->attach->part.content_disposition; - return box->v.save_is_attachment(ctx, &apart); + return ctx->part_is_attachment(ctx, &apart); } static int index_attachment_save_temp_open_fd(struct mail_storage *storage)
--- a/src/lib-storage/index/index-fetch.c Sat Jan 01 14:34:14 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "array.h" -#include "mail-index-modseq.h" -#include "index-storage.h" -#include "index-mail.h" - -void index_storage_get_seq_range(struct mailbox *box, - uint32_t uid1, uint32_t uid2, - uint32_t *seq1_r, uint32_t *seq2_r) -{ - mail_index_lookup_seq_range(box->view, uid1, uid2, seq1_r, seq2_r); -} - -void index_storage_get_uid_range(struct mailbox *box, - const ARRAY_TYPE(seq_range) *seqs, - ARRAY_TYPE(seq_range) *uids) -{ - const struct seq_range *range; - unsigned int i, count; - uint32_t seq, uid; - - range = array_get(seqs, &count); - for (i = 0; i < count; i++) { - if (range[i].seq2 == (uint32_t)-1) { - i_assert(count == i-1); - mail_index_lookup_uid(box->view, range[i].seq1, &uid); - seq_range_array_add_range(uids, uid, (uint32_t)-1); - break; - } - for (seq = range[i].seq1; seq <= range[i].seq2; seq++) { - mail_index_lookup_uid(box->view, seq, &uid); - seq_range_array_add(uids, 0, uid); - } - } -} - -static void -add_expunges(ARRAY_TYPE(mailbox_expunge_rec) *expunges, - const struct mail_transaction_expunge *src, size_t src_size, - const ARRAY_TYPE(seq_range) *uids_filter) -{ - const struct mail_transaction_expunge *end; - struct mailbox_expunge_rec *expunge; - uint32_t uid; - - end = src + src_size / sizeof(*src); - for (; src != end; src++) { - for (uid = src->uid1; uid <= src->uid2; uid++) { - if (seq_range_exists(uids_filter, uid)) { - expunge = array_append_space(expunges); - expunge->uid = uid; - } - } - } -} - -static void -add_guid_expunges(ARRAY_TYPE(mailbox_expunge_rec) *expunges, - const struct mail_transaction_expunge_guid *src, - size_t src_size, const ARRAY_TYPE(seq_range) *uids_filter) -{ - const struct mail_transaction_expunge_guid *end; - struct mailbox_expunge_rec *expunge; - - end = src + src_size / sizeof(*src); - for (; src != end; src++) { - if (seq_range_exists(uids_filter, src->uid)) { - expunge = array_append_space(expunges); - expunge->uid = src->uid; - memcpy(expunge->guid_128, src->guid_128, - sizeof(expunge->guid_128)); - } - } -} - -bool index_storage_get_expunges(struct mailbox *box, uint64_t prev_modseq, - const ARRAY_TYPE(seq_range) *uids_filter, - ARRAY_TYPE(mailbox_expunge_rec) *expunges) -{ - struct mail_transaction_log_view *log_view; - const struct mail_transaction_header *thdr; - const void *tdata; - uint32_t log_seq, tail_seq = 0; - uoff_t log_offset; - bool reset; - int ret; - - if (!mail_index_modseq_get_next_log_offset(box->view, prev_modseq, - &log_seq, &log_offset)) { - log_seq = 1; - log_offset = 0; - } - if (log_seq > box->view->log_file_head_seq || - (log_seq == box->view->log_file_head_seq && - log_offset >= box->view->log_file_head_offset)) { - /* we haven't seen this high expunges at all */ - return TRUE; - } - - log_view = mail_transaction_log_view_open(box->index->log); - ret = mail_transaction_log_view_set(log_view, log_seq, log_offset, - box->view->log_file_head_seq, - box->view->log_file_head_offset, - &reset); - if (ret == 0) { - mail_transaction_log_get_tail(box->index->log, &tail_seq); - i_assert(tail_seq > log_seq); - ret = mail_transaction_log_view_set(log_view, tail_seq, 0, - box->view->log_file_head_seq, - box->view->log_file_head_offset, - &reset); - i_assert(ret != 0); - } - if (ret <= 0) { - mail_transaction_log_view_close(&log_view); - return FALSE; - } - - while ((ret = mail_transaction_log_view_next(log_view, - &thdr, &tdata)) > 0) { - if ((thdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) { - /* skip expunge requests */ - continue; - } - switch (thdr->type & MAIL_TRANSACTION_TYPE_MASK) { - case MAIL_TRANSACTION_EXPUNGE: - add_expunges(expunges, tdata, thdr->size, uids_filter); - break; - case MAIL_TRANSACTION_EXPUNGE_GUID: - add_guid_expunges(expunges, tdata, thdr->size, - uids_filter); - break; - } - } - - mail_transaction_log_view_close(&log_view); - return ret < 0 || tail_seq != 0 ? FALSE : TRUE; -}
--- a/src/lib-storage/index/index-mail-headers.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/index-mail-headers.c Sat Jan 01 15:59:02 2011 +0200 @@ -15,17 +15,6 @@ #include "index-storage.h" #include "index-mail.h" -#include <stdlib.h> - -struct index_header_lookup_ctx { - struct mailbox_header_lookup_ctx ctx; - pool_t pool; - - unsigned int count; - unsigned int *idx; - const char **name; -}; - static const enum message_header_parser_flags hdr_parser_flags = MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP | MESSAGE_HEADER_PARSER_FLAG_DROP_CR; @@ -44,6 +33,7 @@ static void index_mail_parse_header_finish(struct index_mail *mail) { + struct mail *_mail = &mail->mail.mail; const struct index_mail_line *lines; const unsigned char *header, *data; const uint8_t *match; @@ -68,9 +58,8 @@ while (match_idx < lines[i].field_idx && match_idx < match_count) { if (HEADER_MATCH_USABLE(mail, match[match_idx]) && - mail_cache_field_can_add(mail->trans->cache_trans, - mail->data.seq, - match_idx)) { + mail_cache_field_can_add(_mail->transaction->cache_trans, + _mail->seq, match_idx)) { /* this header doesn't exist. remember that. */ i_assert((match[match_idx] & HEADER_MATCH_FLAG_FOUND) == 0); @@ -87,9 +76,8 @@ match_idx++; } - if (!mail_cache_field_can_add(mail->trans->cache_trans, - mail->data.seq, - lines[i].field_idx)) { + if (!mail_cache_field_can_add(_mail->transaction->cache_trans, + _mail->seq, lines[i].field_idx)) { /* header is already cached */ j = i + 1; continue; @@ -132,9 +120,8 @@ for (; match_idx < match_count; match_idx++) { if (HEADER_MATCH_USABLE(mail, match[match_idx]) && - mail_cache_field_can_add(mail->trans->cache_trans, - mail->data.seq, - match_idx)) { + mail_cache_field_can_add(_mail->transaction->cache_trans, + _mail->seq, match_idx)) { /* this header doesn't exist. remember that. */ i_assert((match[match_idx] & HEADER_MATCH_FLAG_FOUND) == 0); @@ -176,17 +163,18 @@ static void index_mail_parse_header_register_all_wanted(struct index_mail *mail) { + struct mail *_mail = &mail->mail.mail; const struct mail_cache_field *all_cache_fields; unsigned int i, count; all_cache_fields = - mail_cache_register_get_list(mail->mail.mail.box->cache, + mail_cache_register_get_list(_mail->box->cache, pool_datastack_create(), &count); for (i = 0; i < count; i++) { if (strncasecmp(all_cache_fields[i].name, "hdr.", 4) != 0) continue; - if (!mail_cache_field_want_add(mail->trans->cache_trans, - mail->data.seq, i)) + if (!mail_cache_field_want_add(_mail->transaction->cache_trans, + _mail->seq, i)) continue; array_idx_set(&mail->header_match, all_cache_fields[i].idx, @@ -195,10 +183,8 @@ } void index_mail_parse_header_init(struct index_mail *mail, - struct mailbox_header_lookup_ctx *_headers) + struct mailbox_header_lookup_ctx *headers) { - struct index_header_lookup_ctx *headers = - (struct index_header_lookup_ctx *)_headers; const uint8_t *match; unsigned int i, field_idx, match_count; @@ -265,6 +251,7 @@ static void index_mail_parse_finish_imap_envelope(struct index_mail *mail) { + struct mail *_mail = &mail->mail.mail; const unsigned int cache_field_envelope = mail->ibox->cache_fields[MAIL_CACHE_IMAP_ENVELOPE].idx; string_t *str; @@ -273,8 +260,8 @@ imap_envelope_write_part_data(mail->data.envelope_data, str); mail->data.envelope = str_c(str); - if (mail_cache_field_can_add(mail->trans->cache_trans, - mail->data.seq, cache_field_envelope)) { + if (mail_cache_field_can_add(_mail->transaction->cache_trans, + _mail->seq, cache_field_envelope)) { index_mail_cache_add_idx(mail, cache_field_envelope, str_data(str), str_len(str)); } @@ -596,6 +583,7 @@ index_mail_get_raw_headers(struct index_mail *mail, const char *field, const char *const **value_r) { + struct mail *_mail = &mail->mail.mail; const char *headers[2], *value; struct mailbox_header_lookup_ctx *headers_ctx; unsigned char *data; @@ -607,12 +595,12 @@ i_assert(field != NULL); - field_idx = get_header_field_idx(mail->mail.mail.box, field, + field_idx = get_header_field_idx(_mail->box, field, MAIL_CACHE_DECISION_TEMP); dest = str_new(mail->data_pool, 128); - if (mail_cache_lookup_headers(mail->trans->cache_view, dest, - mail->data.seq, &field_idx, 1) <= 0) { + if (mail_cache_lookup_headers(_mail->transaction->cache_view, dest, + _mail->seq, &field_idx, 1) <= 0) { /* not in cache / error - first see if it's already parsed */ p_free(mail->data_pool, dest); @@ -620,8 +608,8 @@ index_mail_header_is_parsed(mail, field_idx) < 0) { /* parse */ headers[0] = field; headers[1] = NULL; - headers_ctx = mailbox_header_lookup_init( - mail->mail.mail.box, headers); + headers_ctx = mailbox_header_lookup_init(_mail->box, + headers); ret = index_mail_parse_headers(mail, headers_ctx); mailbox_header_lookup_unref(&headers_ctx); if (ret < 0) @@ -800,26 +788,24 @@ } int index_mail_get_header_stream(struct mail *_mail, - struct mailbox_header_lookup_ctx *_headers, + struct mailbox_header_lookup_ctx *headers, struct istream **stream_r) { struct index_mail *mail = (struct index_mail *)_mail; - struct index_header_lookup_ctx *headers = - (struct index_header_lookup_ctx *)_headers; struct istream *input; string_t *dest; - i_assert(_headers->box == _mail->box); + i_assert(headers->box == _mail->box); if (mail->data.save_bodystructure_header) { /* we have to parse the header. */ - if (index_mail_parse_headers(mail, _headers) < 0) + if (index_mail_parse_headers(mail, headers) < 0) return -1; } dest = str_new(mail->data_pool, 256); - if (mail_cache_lookup_headers(mail->trans->cache_view, dest, - mail->data.seq, headers->idx, + if (mail_cache_lookup_headers(_mail->transaction->cache_view, dest, + _mail->seq, headers->idx, headers->count) > 0) { mail->mail.stats_cache_hit_count++; if (mail->data.filter_stream != NULL) @@ -833,13 +819,13 @@ /* not in cache / error */ p_free(mail->data_pool, dest); - if (mail_get_stream(&mail->mail.mail, NULL, NULL, &input) < 0) + if (mail_get_stream(_mail, NULL, NULL, &input) < 0) return -1; if (mail->data.filter_stream != NULL) i_stream_destroy(&mail->data.filter_stream); - index_mail_parse_header_init(mail, _headers); + index_mail_parse_header_init(mail, headers); mail->data.filter_stream = i_stream_create_header_filter(mail->data.stream, HEADER_FILTER_INCLUDE | @@ -849,73 +835,3 @@ *stream_r = mail->data.filter_stream; return 0; } - -static struct mailbox_header_lookup_ctx * -index_header_lookup_init_real(struct mailbox *box, const char *const headers[]) -{ - struct mail_cache_field *fields, header_field = { - NULL, 0, MAIL_CACHE_FIELD_HEADER, 0, - MAIL_CACHE_DECISION_TEMP - }; - struct index_header_lookup_ctx *ctx; - const char *const *name; - const char **sorted_headers; - pool_t pool; - unsigned int i, count; - - i_assert(*headers != NULL); - - for (count = 0, name = headers; *name != NULL; name++) - count++; - - /* @UNSAFE: headers need to be sorted for filter stream. */ - sorted_headers = t_new(const char *, count); - memcpy(sorted_headers, headers, count * sizeof(*sorted_headers)); - qsort(sorted_headers, count, sizeof(*sorted_headers), i_strcasecmp_p); - headers = sorted_headers; - - /* @UNSAFE */ - fields = t_new(struct mail_cache_field, count); - for (i = 0; i < count; i++) { - header_field.name = t_strconcat("hdr.", headers[i], NULL); - fields[i] = header_field; - } - mail_cache_register_fields(box->cache, fields, count); - - pool = pool_alloconly_create("index_header_lookup_ctx", 1024); - ctx = p_new(pool, struct index_header_lookup_ctx, 1); - ctx->ctx.box = box; - ctx->ctx.refcount = 1; - ctx->pool = pool; - ctx->count = count; - - ctx->idx = p_new(pool, unsigned int, count); - ctx->name = p_new(pool, const char *, count + 1); - - /* @UNSAFE */ - for (i = 0; i < count; i++) { - ctx->idx[i] = fields[i].idx; - ctx->name[i] = p_strdup(pool, headers[i]); - } - ctx->ctx.headers = ctx->name; - return &ctx->ctx; -} - -struct mailbox_header_lookup_ctx * -index_header_lookup_init(struct mailbox *box, const char *const headers[]) -{ - struct mailbox_header_lookup_ctx *ctx; - - T_BEGIN { - ctx = index_header_lookup_init_real(box, headers); - } T_END; - return ctx; -} - -void index_header_lookup_deinit(struct mailbox_header_lookup_ctx *_ctx) -{ - struct index_header_lookup_ctx *ctx = - (struct index_header_lookup_ctx *)_ctx; - - pool_unref(&ctx->pool); -}
--- a/src/lib-storage/index/index-mail.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/index-mail.c Sat Jan 01 15:59:02 2011 +0200 @@ -45,8 +45,8 @@ { int ret; - ret = mail_cache_lookup_field(mail->trans->cache_view, buf, - mail->data.seq, field_idx); + ret = mail_cache_lookup_field(mail->mail.mail.transaction->cache_view, + buf, mail->data.seq, field_idx); if (ret > 0) mail->mail.stats_cache_hit_count++; return ret; @@ -54,7 +54,7 @@ static struct message_part *get_unserialized_parts(struct index_mail *mail) { - unsigned int field_idx = + const unsigned int field_idx = mail->ibox->cache_fields[MAIL_CACHE_MESSAGE_PARTS].idx; struct message_part *parts; buffer_t *part_buf; @@ -102,7 +102,7 @@ enum index_cache_field field, void *data, size_t data_size) { - unsigned int field_idx = mail->ibox->cache_fields[field].idx; + const unsigned int field_idx = mail->ibox->cache_fields[field].idx; buffer_t buf; int ret; @@ -421,21 +421,21 @@ void index_mail_cache_add_idx(struct index_mail *mail, unsigned int field_idx, const void *data, size_t data_size) { - const struct mail_storage_settings *set = - mail->mail.mail.box->storage->set; + struct mail *_mail = &mail->mail.mail; + const struct mail_storage_settings *set = _mail->box->storage->set; const struct mail_index_header *hdr; if (set->mail_cache_min_mail_count > 0) { /* First check if we've configured caching not to be used with low enough message count. */ - hdr = mail_index_get_header(mail->mail.mail.box->view); + hdr = mail_index_get_header(_mail->box->view); if (hdr->messages_count < set->mail_cache_min_mail_count) return; } if (!mail->data.no_caching && mail->data.dont_cache_field_idx != field_idx) { - mail_cache_add(mail->trans->cache_trans, mail->data.seq, + mail_cache_add(_mail->transaction->cache_trans, _mail->seq, field_idx, data, data_size); } } @@ -449,29 +449,36 @@ static bool want_plain_bodystructure_cached(struct index_mail *mail) { + const unsigned int cache_field_body = + mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODY].idx; + const unsigned int cache_field_bodystructure = + mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; + struct mail *_mail = &mail->mail.mail; + if ((mail->wanted_fields & (MAIL_FETCH_IMAP_BODY | MAIL_FETCH_IMAP_BODYSTRUCTURE)) != 0) return TRUE; - if (mail_cache_field_want_add(mail->trans->cache_trans, mail->data.seq, - mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODY].idx)) + if (mail_cache_field_want_add(_mail->transaction->cache_trans, + _mail->seq, cache_field_body)) return TRUE; - if (mail_cache_field_want_add(mail->trans->cache_trans, mail->data.seq, - mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx)) + if (mail_cache_field_want_add(_mail->transaction->cache_trans, + _mail->seq, cache_field_bodystructure)) return TRUE; return FALSE; } static void index_mail_body_parsed_cache_flags(struct index_mail *mail) { + struct mail *_mail = &mail->mail.mail; struct index_mail_data *data = &mail->data; unsigned int cache_flags_idx; uint32_t cache_flags = data->cache_flags; bool want_cached; cache_flags_idx = mail->ibox->cache_fields[MAIL_CACHE_FLAGS].idx; - want_cached = mail_cache_field_want_add(mail->trans->cache_trans, - data->seq, cache_flags_idx); + want_cached = mail_cache_field_want_add(_mail->transaction->cache_trans, + _mail->seq, cache_flags_idx); if (data->parsed_bodystructure && imap_bodystructure_is_plain_7bit(data->parts) && @@ -490,12 +497,12 @@ MAIL_CACHE_FLAG_HAS_NULS | MAIL_CACHE_FLAG_HAS_NO_NULS); if ((data->parts->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) { - mail->mail.mail.has_nuls = TRUE; - mail->mail.mail.has_no_nuls = FALSE; + _mail->has_nuls = TRUE; + _mail->has_no_nuls = FALSE; cache_flags |= MAIL_CACHE_FLAG_HAS_NULS; } else { - mail->mail.mail.has_nuls = FALSE; - mail->mail.mail.has_no_nuls = TRUE; + _mail->has_nuls = FALSE; + _mail->has_no_nuls = TRUE; cache_flags |= MAIL_CACHE_FLAG_HAS_NO_NULS; } @@ -513,20 +520,21 @@ static void index_mail_body_parsed_cache_message_parts(struct index_mail *mail) { + struct mail *_mail = &mail->mail.mail; struct index_mail_data *data = &mail->data; - unsigned int cache_field = + const unsigned int cache_field = mail->ibox->cache_fields[MAIL_CACHE_MESSAGE_PARTS].idx; enum mail_cache_decision_type decision; buffer_t *buffer; if (data->messageparts_saved_to_cache || - mail_cache_field_exists(mail->trans->cache_view, mail->data.seq, + mail_cache_field_exists(_mail->transaction->cache_view, _mail->seq, cache_field) != 0) { /* already cached */ return; } - decision = mail_cache_field_get_decision(mail->mail.mail.box->cache, + decision = mail_cache_field_get_decision(_mail->box->cache, cache_field); if (decision == (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED)) { /* we never want it cached */ @@ -554,12 +562,13 @@ index_mail_body_parsed_cache_bodystructure(struct index_mail *mail, enum index_cache_field field) { + struct mail *_mail = &mail->mail.mail; struct index_mail_data *data = &mail->data; - unsigned int cache_field_parts = + const unsigned int cache_field_parts = mail->ibox->cache_fields[MAIL_CACHE_MESSAGE_PARTS].idx; - unsigned int cache_field_body = + const unsigned int cache_field_body = mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODY].idx; - unsigned int cache_field_bodystructure = + const unsigned int cache_field_bodystructure = mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; enum mail_cache_decision_type dec; string_t *str; @@ -569,8 +578,8 @@ if ((data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0) { if (data->messageparts_saved_to_cache || - mail_cache_field_exists(mail->trans->cache_view, data->seq, - cache_field_parts) > 0) { + mail_cache_field_exists(_mail->transaction->cache_view, + _mail->seq, cache_field_parts) > 0) { /* cached it as flag + message_parts */ plain_bodystructure = TRUE; } @@ -587,12 +596,12 @@ else if (field == MAIL_CACHE_IMAP_BODYSTRUCTURE || (mail->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0) { cache_bodystructure = - mail_cache_field_can_add(mail->trans->cache_trans, - data->seq, cache_field_bodystructure); + mail_cache_field_can_add(_mail->transaction->cache_trans, + _mail->seq, cache_field_bodystructure); } else { cache_bodystructure = - mail_cache_field_want_add(mail->trans->cache_trans, - data->seq, cache_field_bodystructure); + mail_cache_field_want_add(_mail->transaction->cache_trans, + _mail->seq, cache_field_bodystructure); } if (cache_bodystructure) { str = str_new(mail->data_pool, 128); @@ -604,13 +613,13 @@ bodystructure_cached = TRUE; } else { bodystructure_cached = - mail_cache_field_exists(mail->trans->cache_view, - data->seq, cache_field_bodystructure) > 0; + mail_cache_field_exists(_mail->transaction->cache_view, + _mail->seq, cache_field_bodystructure) > 0; } /* normally don't cache both BODY and BODYSTRUCTURE, but do it if BODY is forced to be cached */ - dec = mail_cache_field_get_decision(mail->mail.mail.box->cache, + dec = mail_cache_field_get_decision(_mail->box->cache, cache_field_body); if (plain_bodystructure || (bodystructure_cached && @@ -618,12 +627,12 @@ cache_body = FALSE; else if (field == MAIL_CACHE_IMAP_BODY) { cache_body = - mail_cache_field_can_add(mail->trans->cache_trans, - data->seq, cache_field_body); + mail_cache_field_can_add(_mail->transaction->cache_trans, + _mail->seq, cache_field_body); } else { cache_body = - mail_cache_field_want_add(mail->trans->cache_trans, - data->seq, cache_field_body); + mail_cache_field_want_add(_mail->transaction->cache_trans, + _mail->seq, cache_field_body); } if (cache_body) { @@ -639,6 +648,7 @@ static bool index_mail_want_cache(struct index_mail *mail, enum index_cache_field field) { + struct mail *_mail = &mail->mail.mail; enum mail_fetch_field fetch_field; unsigned int cache_field; @@ -667,11 +677,11 @@ cache_field = mail->ibox->cache_fields[field].idx; if ((mail->data.cache_fetch_fields & fetch_field) != 0) { - return mail_cache_field_can_add(mail->trans->cache_trans, - mail->data.seq, cache_field); + return mail_cache_field_can_add(_mail->transaction->cache_trans, + _mail->seq, cache_field); } else { - return mail_cache_field_want_add(mail->trans->cache_trans, - mail->data.seq, cache_field); + return mail_cache_field_want_add(_mail->transaction->cache_trans, + _mail->seq, cache_field); } } @@ -804,7 +814,8 @@ enum index_mail_access_part index_mail_get_access_part(struct index_mail *mail) { - struct mail_cache_field *cache_fields = mail->ibox->cache_fields; + struct mail *_mail = &mail->mail.mail; + const struct mail_cache_field *cache_fields = mail->ibox->cache_fields; if ((mail->data.access_part & (READ_HDR | PARSE_HDR)) != 0 && (mail->data.access_part & (READ_BODY | PARSE_BODY)) != 0) @@ -812,12 +823,11 @@ /* lazy virtual size access check */ if ((mail->wanted_fields & MAIL_FETCH_VIRTUAL_SIZE) != 0) { - unsigned int cache_field = + const unsigned int cache_field = cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx; - if (mail_cache_field_exists(mail->trans->cache_view, - mail->mail.mail.seq, - cache_field) <= 0) + if (mail_cache_field_exists(_mail->transaction->cache_view, + _mail->seq, cache_field) <= 0) mail->data.access_part |= READ_HDR | READ_BODY; } return mail->data.access_part; @@ -979,14 +989,14 @@ { struct index_mail *mail = (struct index_mail *)_mail; struct index_mail_data *data = &mail->data; - struct mail_cache_field *cache_fields = mail->ibox->cache_fields; + const struct mail_cache_field *cache_fields = mail->ibox->cache_fields; string_t *str; switch (field) { case MAIL_FETCH_IMAP_BODY: { - unsigned int body_cache_field = + const unsigned int body_cache_field = cache_fields[MAIL_CACHE_IMAP_BODY].idx; - unsigned int bodystructure_cache_field = + const unsigned int bodystructure_cache_field = cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; if (data->body != NULL) { @@ -1036,7 +1046,7 @@ return 0; } case MAIL_FETCH_IMAP_BODYSTRUCTURE: { - unsigned int bodystructure_cache_field = + const unsigned int bodystructure_cache_field = cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; if (data->bodystructure != NULL) { @@ -1109,36 +1119,31 @@ } void index_mail_init(struct index_mail *mail, - struct mailbox_transaction_context *_t, + struct mailbox_transaction_context *t, enum mail_fetch_field wanted_fields, - struct mailbox_header_lookup_ctx *_wanted_headers) + struct mailbox_header_lookup_ctx *wanted_headers) { - struct index_transaction_context *t = - (struct index_transaction_context *)_t; - struct index_header_lookup_ctx *wanted_headers = - (struct index_header_lookup_ctx *)_wanted_headers; const struct mail_index_header *hdr; array_create(&mail->mail.module_contexts, mail->mail.pool, sizeof(void *), 5); - mail->mail.v = *_t->box->mail_vfuncs; - mail->mail.mail.box = _t->box; - mail->mail.mail.transaction = &t->mailbox_ctx; + mail->mail.v = *t->box->mail_vfuncs; + mail->mail.mail.box = t->box; + mail->mail.mail.transaction = t; mail->mail.wanted_fields = wanted_fields; - mail->mail.wanted_headers = _wanted_headers; + mail->mail.wanted_headers = wanted_headers; - hdr = mail_index_get_header(_t->box->view); + hdr = mail_index_get_header(t->box->view); mail->uid_validity = hdr->uid_validity; t->mail_ref_count++; mail->data_pool = pool_alloconly_create("index_mail", 16384); - mail->ibox = INDEX_STORAGE_CONTEXT(_t->box); - mail->trans = t; + mail->ibox = INDEX_STORAGE_CONTEXT(t->box); mail->wanted_fields = wanted_fields; if (wanted_headers != NULL) { mail->wanted_headers = wanted_headers; - mailbox_header_lookup_ref(_wanted_headers); + mailbox_header_lookup_ref(wanted_headers); } } @@ -1198,7 +1203,8 @@ static void check_envelope(struct index_mail *mail) { - unsigned int cache_field_envelope = + struct mail *_mail = &mail->mail.mail; + const unsigned int cache_field_envelope = mail->ibox->cache_fields[MAIL_CACHE_IMAP_ENVELOPE].idx; unsigned int cache_field_hdr; @@ -1208,20 +1214,18 @@ } /* if "imap.envelope" is cached, that's all we need */ - if (mail_cache_field_exists(mail->trans->cache_view, - mail->mail.mail.seq, - cache_field_envelope) > 0) + if (mail_cache_field_exists(_mail->transaction->cache_view, + _mail->seq, cache_field_envelope) > 0) return; /* don't waste time doing full checks for all required headers. assume that if we have "hdr.message-id" cached, we don't need to parse the header. */ - cache_field_hdr = mail_cache_register_lookup(mail->mail.mail.box->cache, + cache_field_hdr = mail_cache_register_lookup(_mail->box->cache, "hdr.message-id"); if (cache_field_hdr == (unsigned int)-1 || - mail_cache_field_exists(mail->trans->cache_view, - mail->mail.mail.seq, - cache_field_hdr) <= 0) + mail_cache_field_exists(_mail->transaction->cache_view, + _mail->seq, cache_field_hdr) <= 0) mail->data.access_part |= PARSE_HDR; mail->data.save_envelope = TRUE; } @@ -1230,8 +1234,8 @@ { struct index_mail *mail = (struct index_mail *)_mail; struct index_mail_data *data = &mail->data; - struct mail_cache_field *cache_fields = mail->ibox->cache_fields; - struct mail_cache_view *cache_view = mail->trans->cache_view; + const struct mail_cache_field *cache_fields = mail->ibox->cache_fields; + struct mail_cache_view *cache_view = _mail->transaction->cache_view; const struct mail_index_header *hdr; struct istream *input; @@ -1266,7 +1270,7 @@ /* see if wanted_fields can tell us if we need to read/parse header/body */ if ((mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) != 0) { - unsigned int cache_field = + const unsigned int cache_field = cache_fields[MAIL_CACHE_MESSAGE_PARTS].idx; if (mail_cache_field_exists(cache_view, seq, @@ -1282,9 +1286,9 @@ if ((mail->wanted_fields & MAIL_FETCH_IMAP_BODY) != 0 && (data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) == 0) { /* we need either imap.body or imap.bodystructure */ - unsigned int cache_field1 = + const unsigned int cache_field1 = cache_fields[MAIL_CACHE_IMAP_BODY].idx; - unsigned int cache_field2 = + const unsigned int cache_field2 = cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; if (mail_cache_field_exists(cache_view, @@ -1299,7 +1303,7 @@ if ((mail->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0 && (data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) == 0) { - unsigned int cache_field = + const unsigned int cache_field = cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; if (mail_cache_field_exists(cache_view, seq, @@ -1311,7 +1315,7 @@ } if ((mail->wanted_fields & MAIL_FETCH_DATE) != 0) { - unsigned int cache_field = + const unsigned int cache_field = cache_fields[MAIL_CACHE_SENT_DATE].idx; if (mail_cache_field_exists(cache_view, seq, @@ -1369,8 +1373,8 @@ mail->mail.v.close(_mail); - i_assert(mail->trans->mail_ref_count > 0); - mail->trans->mail_ref_count--; + i_assert(_mail->transaction->mail_ref_count > 0); + _mail->transaction->mail_ref_count--; if (mail->header_data != NULL) buffer_free(&mail->header_data); @@ -1543,7 +1547,7 @@ } /* make sure we don't cache invalid values */ - mail_cache_transaction_reset(imail->trans->cache_trans); + mail_cache_transaction_reset(mail->transaction->cache_trans); imail->data.no_caching = TRUE; imail->data.forced_no_caching = TRUE; mail_cache_set_corrupted(mail->box->cache,
--- a/src/lib-storage/index/index-mail.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/index-mail.h Sat Jan 01 15:59:02 2011 +0200 @@ -120,11 +120,10 @@ struct index_mailbox_context *ibox; pool_t data_pool; - struct index_transaction_context *trans; uint32_t uid_validity; enum mail_fetch_field wanted_fields; - struct index_header_lookup_ctx *wanted_headers; + struct mailbox_header_lookup_ctx *wanted_headers; int pop3_state;
--- a/src/lib-storage/index/index-search.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/index-search.c Sat Jan 01 15:59:02 2011 +0200 @@ -88,7 +88,7 @@ static void search_init_arg(struct mail_search_arg *arg, struct index_search_context *ctx) { - uint8_t guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; bool match; switch (arg->type) { @@ -105,12 +105,13 @@ ctx->have_index_args = TRUE; break; case SEARCH_MAILBOX_GUID: - if (mailbox_get_guid(ctx->box, guid) < 0) { + if (mailbox_get_metadata(ctx->box, MAILBOX_METADATA_GUID, + &metadata) < 0) { /* result will be unknown */ break; } - match = strcmp(mail_guid_128_to_string(guid), + match = strcmp(mail_guid_128_to_string(metadata.guid), arg->value.str) == 0; if (match != arg->not) arg->match_always = TRUE; @@ -1079,7 +1080,7 @@ if (gettimeofday(&ctx->last_nonblock_timeval, NULL) < 0) i_fatal("gettimeofday() failed: %m"); - mailbox_get_status(t->box, STATUS_MESSAGES, &status); + mailbox_get_open_status(t->box, STATUS_MESSAGES, &status); ctx->mail_ctx.progress_max = status.messages; i_array_init(&ctx->mail_ctx.results, 5);
--- a/src/lib-storage/index/index-status.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/index-status.c Sat Jan 01 15:59:02 2011 +0200 @@ -7,9 +7,54 @@ #include "index-storage.h" #include "mail-index-modseq.h" +int index_storage_get_status(struct mailbox *box, + enum mailbox_status_items items, + struct mailbox_status *status_r) +{ + const struct mail_index_header *hdr; + + memset(status_r, 0, sizeof(struct mailbox_status)); + + if (!box->opened) { + if (mailbox_open(box) < 0) + return -1; + if (mailbox_sync(box, 0) < 0) + return -1; + } + + /* we can get most of the status items without any trouble */ + hdr = mail_index_get_header(box->view); + status_r->messages = hdr->messages_count; + if ((items & STATUS_RECENT) != 0) { + status_r->recent = index_mailbox_get_recent_count(box); + i_assert(status_r->recent <= status_r->messages); + } + status_r->unseen = hdr->messages_count - hdr->seen_messages_count; + status_r->uidvalidity = hdr->uid_validity; + status_r->uidnext = hdr->next_uid; + status_r->nonpermanent_modseqs = mail_index_is_in_memory(box->index); + if ((items & STATUS_HIGHESTMODSEQ) != 0) { + status_r->highest_modseq = + mail_index_modseq_get_highest(box->view); + if (status_r->highest_modseq == 0) { + /* modseqs not enabled yet, but we can't return 0 */ + status_r->highest_modseq = 1; + } + } + + if ((items & STATUS_FIRST_UNSEEN_SEQ) != 0) { + mail_index_lookup_first(box->view, 0, MAIL_SEEN, + &status_r->first_unseen_seq); + } + + if ((items & STATUS_KEYWORDS) != 0) + status_r->keywords = mail_index_get_keywords(box->index); + return 0; +} + static void -index_storage_get_status_cache_fields(struct mailbox *box, - struct mailbox_status *status_r) +get_metadata_cache_fields(struct mailbox *box, + struct mailbox_metadata *metadata_r) { const struct mail_cache_field *fields; enum mail_cache_decision_type dec; @@ -26,12 +71,12 @@ if (dec != MAIL_CACHE_DECISION_NO) array_append(cache_fields, &fields[i].name, 1); } - status_r->cache_fields = cache_fields; + metadata_r->cache_fields = cache_fields; } -static void -index_storage_virtual_size_add_new(struct mailbox *box, - struct index_vsize_header *vsize_hdr) +static int +virtual_size_add_new(struct mailbox *box, + struct index_vsize_header *vsize_hdr) { struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box); const struct mail_index_header *hdr; @@ -94,18 +139,21 @@ mail_index_update_header_ext(trans->itrans, ibox->vsize_hdr_ext_id, 0, vsize_hdr, sizeof(*vsize_hdr)); (void)mailbox_transaction_commit(&trans); - + return ret; } -static void -index_storage_get_status_virtual_size(struct mailbox *box, - struct mailbox_status *status_r) +static int +get_metadata_virtual_size(struct mailbox *box, + struct mailbox_metadata *metadata_r) { struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box); struct index_vsize_header vsize_hdr; + struct mailbox_status status; const void *data; size_t size; + int ret; + mailbox_get_open_status(box, STATUS_MESSAGES | STATUS_UIDNEXT, &status); mail_index_get_header_ext(box->view, ibox->vsize_hdr_ext_id, &data, &size); if (size == sizeof(vsize_hdr)) @@ -119,61 +167,32 @@ memset(&vsize_hdr, 0, sizeof(vsize_hdr)); } - if (vsize_hdr.highest_uid + 1 == status_r->uidnext && - vsize_hdr.message_count == status_r->messages) { + if (vsize_hdr.highest_uid + 1 == status.uidnext && + vsize_hdr.message_count == status.messages) { /* up to date */ - status_r->virtual_size = vsize_hdr.vsize; - return; + metadata_r->virtual_size = vsize_hdr.vsize; + return 0; } - if (vsize_hdr.highest_uid >= status_r->uidnext) { + if (vsize_hdr.highest_uid >= status.uidnext) { mail_storage_set_critical(box->storage, "vsize-hdr has invalid highest-uid (%u >= %u)", - vsize_hdr.highest_uid, status_r->uidnext); + vsize_hdr.highest_uid, status.uidnext); memset(&vsize_hdr, 0, sizeof(vsize_hdr)); } - index_storage_virtual_size_add_new(box, &vsize_hdr); - status_r->virtual_size = vsize_hdr.vsize; + ret = virtual_size_add_new(box, &vsize_hdr); + metadata_r->virtual_size = vsize_hdr.vsize; + return ret; } -void index_storage_get_status(struct mailbox *box, - enum mailbox_status_items items, - struct mailbox_status *status_r) +int index_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) { - const struct mail_index_header *hdr; - - i_assert(box->opened); - - memset(status_r, 0, sizeof(struct mailbox_status)); - - /* we can get most of the status items without any trouble */ - hdr = mail_index_get_header(box->view); - status_r->messages = hdr->messages_count; - if ((items & STATUS_RECENT) != 0) { - status_r->recent = index_mailbox_get_recent_count(box); - i_assert(status_r->recent <= status_r->messages); + if ((items & MAILBOX_METADATA_CACHE_FIELDS) != 0) + get_metadata_cache_fields(box, metadata_r); + if ((items & MAILBOX_METADATA_VIRTUAL_SIZE) != 0) { + if (get_metadata_virtual_size(box, metadata_r) < 0) + return -1; } - status_r->unseen = hdr->messages_count - hdr->seen_messages_count; - status_r->uidvalidity = hdr->uid_validity; - status_r->uidnext = hdr->next_uid; - status_r->nonpermanent_modseqs = mail_index_is_in_memory(box->index); - if ((items & STATUS_HIGHESTMODSEQ) != 0) { - status_r->highest_modseq = - mail_index_modseq_get_highest(box->view); - if (status_r->highest_modseq == 0) { - /* modseqs not enabled yet, but we can't return 0 */ - status_r->highest_modseq = 1; - } - } - - if ((items & STATUS_FIRST_UNSEEN_SEQ) != 0) { - mail_index_lookup_first(box->view, 0, MAIL_SEEN, - &status_r->first_unseen_seq); - } - - if ((items & STATUS_KEYWORDS) != 0) - status_r->keywords = mail_index_get_keywords(box->index); - if ((items & STATUS_CACHE_FIELDS) != 0) - index_storage_get_status_cache_fields(box, status_r); - if ((items & STATUS_VIRTUAL_SIZE) != 0) - index_storage_get_status_virtual_size(box, status_r); + return 0; }
--- a/src/lib-storage/index/index-storage.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/index-storage.c Sat Jan 01 15:59:02 2011 +0200 @@ -5,7 +5,6 @@ #include "istream.h" #include "ioloop.h" #include "str.h" -#include "imap-parser.h" #include "mkdir-parents.h" #include "mail-index-alloc-cache.h" #include "mail-index-private.h" @@ -27,22 +26,6 @@ struct index_storage_module index_storage_module = MODULE_CONTEXT_INIT(&mail_storage_module_register); -static struct mail_index * -index_storage_alloc(struct mailbox_list *list, const char *name, - enum mailbox_flags flags, const char *prefix) -{ - const char *index_dir, *mailbox_path; - - mailbox_path = mailbox_list_get_path(list, name, - MAILBOX_LIST_PATH_TYPE_MAILBOX); - index_dir = (flags & MAILBOX_FLAG_NO_INDEX_FILES) != 0 ? "" : - mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_INDEX); - if (*index_dir == '\0') - index_dir = NULL; - - return mail_index_alloc_cache_get(mailbox_path, index_dir, prefix); -} - static void set_cache_decisions(const char *set, const char *fields, enum mail_cache_decision_type dec) { @@ -150,6 +133,23 @@ ibox->last_notify_type = MAILBOX_LOCK_NOTIFY_NONE; } +static struct mail_index * +index_mailbox_alloc_index(struct mailbox *box) +{ + const char *index_dir, *mailbox_path; + + mailbox_path = mailbox_list_get_path(box->list, box->name, + MAILBOX_LIST_PATH_TYPE_MAILBOX); + index_dir = (box->flags & MAILBOX_FLAG_NO_INDEX_FILES) != 0 ? "" : + mailbox_list_get_path(box->list, box->name, + MAILBOX_LIST_PATH_TYPE_INDEX); + if (*index_dir == '\0') + index_dir = NULL; + + return mail_index_alloc_cache_get(mailbox_path, index_dir, + box->index_prefix); +} + int index_storage_mailbox_open(struct mailbox *box, bool move_to_memory) { struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box); @@ -162,19 +162,21 @@ if (move_to_memory) ibox->index_flags &= ~MAIL_INDEX_OPEN_FLAG_CREATE; - if ((index_flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0) { - if (mail_index_is_in_memory(box->index)) { - mail_storage_set_critical(box->storage, - "Couldn't create index file"); - return -1; - } - } - if (mailbox_list_create_missing_index_dir(box->list, box->name) < 0) { mail_storage_set_internal_error(box->storage); return -1; } + box->index = index_mailbox_alloc_index(box); + mail_index_set_fsync_mode(box->index, + box->storage->set->parsed_fsync_mode, 0); + mail_index_set_lock_method(box->index, + box->storage->set->parsed_lock_method, + mail_storage_get_lock_timeout(box->storage, -1U)); + + /* make sure mail_index_set_permissions() has been called */ + (void)mailbox_get_permissions(box); + ret = mail_index_open(box->index, index_flags); if (ret <= 0 || move_to_memory) { if ((index_flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0) { @@ -191,6 +193,13 @@ i_panic("in-memory index creation failed"); } } + if ((index_flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0) { + if (mail_index_is_in_memory(box->index)) { + mail_storage_set_critical(box->storage, + "Couldn't create index file"); + return -1; + } + } box->cache = mail_index_get_cache(box->index); index_cache_register_defaults(box); @@ -221,7 +230,6 @@ const char *index_prefix) { struct index_mailbox_context *ibox; - const char *path; string_t *vname; i_assert(name != NULL); @@ -230,7 +238,9 @@ vname = t_str_new(128); mail_namespace_get_vname(box->list->ns, vname, name); box->vname = p_strdup(box->pool, str_c(vname)); + box->flags = flags; + box->index_prefix = p_strdup(box->pool, index_prefix); p_array_init(&box->search_results, box->pool, 16); array_create(&box->module_contexts, @@ -242,24 +252,10 @@ ibox->next_lock_notify = time(NULL) + LOCK_NOTIFY_INTERVAL; MODULE_CONTEXT_SET(box, index_storage_module, ibox); - path = mailbox_list_get_path(box->list, name, - MAILBOX_LIST_PATH_TYPE_MAILBOX); - box->path = p_strdup(box->pool, path); - box->index = index_storage_alloc(box->list, name, flags, index_prefix); box->inbox_user = strcmp(name, "INBOX") == 0 && (box->list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0; box->inbox_any = strcmp(name, "INBOX") == 0 && (box->list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0; - if (box->file_create_mode == 0) - mailbox_refresh_permissions(box); - mail_index_set_permissions(box->index, box->file_create_mode, - box->file_create_gid, - box->file_create_gid_origin); - mail_index_set_fsync_mode(box->index, - box->storage->set->parsed_fsync_mode, 0); - mail_index_set_lock_method(box->index, - box->storage->set->parsed_lock_method, - mail_storage_get_lock_timeout(box->storage, -1U)); } int index_storage_mailbox_enable(struct mailbox *box, @@ -301,7 +297,8 @@ void index_storage_mailbox_free(struct mailbox *box) { - mail_index_alloc_cache_unref(&box->index); + if (box->index != NULL) + mail_index_alloc_cache_unref(&box->index); } void index_storage_mailbox_update_cache_fields(struct mailbox *box, @@ -426,7 +423,7 @@ int index_storage_mailbox_delete(struct mailbox *box) { - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; if (!box->opened) { /* \noselect mailbox, try deleting only the directory */ @@ -436,7 +433,7 @@ if (mailbox_mark_index_deleted(box, TRUE) < 0) return -1; - if (mailbox_get_guid(box, mailbox_guid) < 0) + if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) return -1; /* Make sure the indexes are closed before trying to delete the @@ -452,7 +449,7 @@ } mailbox_list_add_change(box->list, MAILBOX_LOG_RECORD_DELETE_MAILBOX, - mailbox_guid); + metadata.guid); return index_storage_mailbox_delete_dir(box, TRUE); } @@ -477,16 +474,7 @@ bool index_storage_is_readonly(struct mailbox *box) { - if ((box->flags & MAILBOX_FLAG_READONLY) != 0) - return TRUE; - - if (box->backend_readonly) { - /* return read-only only if there are no private flags - (that are stored in index files) */ - if (box->private_flags_mask == 0) - return TRUE; - } - return FALSE; + return (box->flags & MAILBOX_FLAG_READONLY) != 0; } bool index_storage_allow_new_keywords(struct mailbox *box) @@ -500,99 +488,6 @@ return mail_index_view_is_inconsistent(box->view); } -bool index_keyword_is_valid(struct mailbox *box, const char *keyword, - const char **error_r) -{ - unsigned int i, idx; - - /* if it already exists, skip validity checks */ - if (mail_index_keyword_lookup(box->index, keyword, &idx)) - return TRUE; - - if (*keyword == '\0') { - *error_r = "Empty keywords not allowed"; - return FALSE; - } - - /* these are IMAP-specific restrictions, but for now IMAP is all we - care about */ - for (i = 0; keyword[i] != '\0'; i++) { - if (IS_ATOM_SPECIAL((unsigned char)keyword[i])) { - *error_r = "Invalid characters in keyword"; - return FALSE; - } - if ((unsigned char)keyword[i] >= 0x80) { - *error_r = "8bit characters in keyword"; - return FALSE; - } - } - if (i > box->storage->set->mail_max_keyword_length) { - *error_r = "Keyword length too long"; - return FALSE; - } - return TRUE; -} - -static struct mail_keywords * -index_keywords_create_skip(struct mailbox *box, - const char *const keywords[]) -{ - ARRAY_DEFINE(valid_keywords, const char *); - const char *error; - - t_array_init(&valid_keywords, 32); - for (; *keywords != NULL; keywords++) { - if (mailbox_keyword_is_valid(box, *keywords, &error)) - array_append(&valid_keywords, keywords, 1); - } - (void)array_append_space(&valid_keywords); /* NULL-terminate */ - return mail_index_keywords_create(box->index, keywords); -} - -int index_keywords_create(struct mailbox *box, const char *const keywords[], - struct mail_keywords **keywords_r, bool skip_invalid) -{ - const char *error; - unsigned int i; - - for (i = 0; keywords[i] != NULL; i++) { - if (mailbox_keyword_is_valid(box, keywords[i], &error)) - continue; - - if (!skip_invalid) { - mail_storage_set_error(box->storage, - MAIL_ERROR_PARAMS, error); - return -1; - } - - /* found invalid keywords, do this the slow way */ - T_BEGIN { - *keywords_r = index_keywords_create_skip(box, keywords); - } T_END; - return 0; - } - - *keywords_r = mail_index_keywords_create(box->index, keywords); - return 0; -} - -struct mail_keywords * -index_keywords_create_from_indexes(struct mailbox *_box, - const ARRAY_TYPE(keyword_indexes) *idx) -{ - return mail_index_keywords_create_from_indexes(_box->index, idx); -} - -void index_keywords_ref(struct mail_keywords *keywords) -{ - mail_index_keywords_ref(keywords); -} - -void index_keywords_unref(struct mail_keywords *keywords) -{ - mail_index_keywords_unref(&keywords); -} - void index_save_context_free(struct mail_save_context *ctx) { i_free_and_null(ctx->from_envelope); @@ -606,10 +501,6 @@ uint32_t dest_seq, const char *name, buffer_t *buf) { struct mailbox_transaction_context *dest_trans = ctx->transaction; - struct index_transaction_context *dest_itrans = - (struct index_transaction_context *)dest_trans; - struct index_transaction_context *src_itrans = - (struct index_transaction_context *)src_mail->transaction; const struct mail_cache_field *dest_field; unsigned int src_field_idx, dest_field_idx; @@ -630,9 +521,9 @@ } buffer_set_used_size(buf, 0); - if (mail_cache_lookup_field(src_itrans->cache_view, buf, + if (mail_cache_lookup_field(src_mail->transaction->cache_view, buf, src_mail->seq, src_field_idx) > 0) { - mail_cache_add(dest_itrans->cache_trans, dest_seq, + mail_cache_add(dest_trans->cache_trans, dest_seq, dest_field_idx, buf->data, buf->used); } } @@ -641,15 +532,17 @@ struct mail *src_mail, uint32_t dest_seq) { T_BEGIN { - struct mailbox_status src_status; + struct mailbox_metadata src_metadata; const char *const *namep; buffer_t *buf; - index_storage_get_status(src_mail->box, STATUS_CACHE_FIELDS, - &src_status); + if (mailbox_get_metadata(src_mail->box, + MAILBOX_METADATA_CACHE_FIELDS, + &src_metadata) < 0) + i_unreached(); buf = buffer_create_dynamic(pool_datastack_create(), 1024); - array_foreach(src_status.cache_fields, namep) { + array_foreach(src_metadata.cache_fields, namep) { mail_copy_cache_field(ctx, src_mail, dest_seq, *namep, buf); }
--- a/src/lib-storage/index/index-storage.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/index-storage.h Sat Jan 01 15:59:02 2011 +0200 @@ -16,17 +16,6 @@ MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE }; -struct index_transaction_context { - struct mailbox_transaction_context mailbox_ctx; - union mail_index_transaction_module_context module_ctx; - - struct mail_index_transaction_vfuncs super; - int mail_ref_count; - - struct mail_cache_view *cache_view; - struct mail_cache_transaction_ctx *cache_trans; -}; - struct index_vsize_header { uint64_t vsize; uint32_t highest_uid; @@ -92,16 +81,6 @@ bool index_storage_allow_new_keywords(struct mailbox *box); bool index_storage_is_inconsistent(struct mailbox *box); -int index_keywords_create(struct mailbox *box, const char *const keywords[], - struct mail_keywords **keywords_r, bool skip_invalid); -struct mail_keywords * -index_keywords_create_from_indexes(struct mailbox *box, - const ARRAY_TYPE(keyword_indexes) *idx); -void index_keywords_ref(struct mail_keywords *keywords); -void index_keywords_unref(struct mail_keywords *keywords); -bool index_keyword_is_valid(struct mailbox *box, const char *keyword, - const char **error_r); - void index_mailbox_set_recent_uid(struct mailbox *box, uint32_t uid); void index_mailbox_set_recent_seq(struct mailbox *box, struct mail_index_view *view, @@ -126,22 +105,12 @@ int index_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags); enum mailbox_sync_type index_sync_type_convert(enum mail_index_sync_type type); -void index_storage_get_status(struct mailbox *box, - enum mailbox_status_items items, - struct mailbox_status *status_r); -void index_storage_get_seq_range(struct mailbox *box, - uint32_t uid1, uint32_t uid2, - uint32_t *seq1_r, uint32_t *seq2_r); -void index_storage_get_uid_range(struct mailbox *box, - const ARRAY_TYPE(seq_range) *seqs, - ARRAY_TYPE(seq_range) *uids); -bool index_storage_get_expunges(struct mailbox *box, uint64_t prev_modseq, - const ARRAY_TYPE(seq_range) *uids_filter, - ARRAY_TYPE(mailbox_expunge_rec) *expunges); - -struct mailbox_header_lookup_ctx * -index_header_lookup_init(struct mailbox *box, const char *const headers[]); -void index_header_lookup_deinit(struct mailbox_header_lookup_ctx *ctx); +int index_storage_get_status(struct mailbox *box, + enum mailbox_status_items items, + struct mailbox_status *status_r); +int index_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r); struct mail_search_context * index_storage_search_init(struct mailbox_transaction_context *t, @@ -152,14 +121,10 @@ struct mail *mail, bool *tryagain_r); bool index_storage_search_next_update_seq(struct mail_search_context *ctx); -void index_transaction_set_max_modseq(struct mailbox_transaction_context *_t, - uint64_t max_modseq, - ARRAY_TYPE(seq_range) *seqs); - struct mailbox_transaction_context * index_transaction_begin(struct mailbox *box, enum mailbox_transaction_flags flags); -void index_transaction_init(struct index_transaction_context *it, +void index_transaction_init(struct mailbox_transaction_context *t, struct mailbox *box, enum mailbox_transaction_flags flags); int index_transaction_commit(struct mailbox_transaction_context *t,
--- a/src/lib-storage/index/index-transaction.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/index-transaction.c Sat Jan 01 15:59:02 2011 +0200 @@ -5,11 +5,11 @@ #include "index-storage.h" #include "index-mail.h" -static void index_transaction_free(struct index_transaction_context *t) +static void index_transaction_free(struct mailbox_transaction_context *t) { mail_cache_view_close(t->cache_view); - mail_index_view_close(&t->mailbox_ctx.view); - array_free(&t->mailbox_ctx.module_contexts); + mail_index_view_close(&t->view); + array_free(&t->module_contexts); i_free(t); } @@ -17,9 +17,8 @@ index_transaction_index_commit(struct mail_index_transaction *index_trans, struct mail_index_transaction_commit_result *result_r) { - struct index_transaction_context *it = + struct mailbox_transaction_context *t = MAIL_STORAGE_CONTEXT(index_trans); - struct mailbox_transaction_context *t = &it->mailbox_ctx; struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(t->box); int ret = 0; @@ -30,11 +29,11 @@ } } - i_assert(it->mail_ref_count == 0); + i_assert(t->mail_ref_count == 0); if (ret < 0) - it->super.rollback(index_trans); + t->super.rollback(index_trans); else { - if (it->super.commit(index_trans, result_r) < 0) { + if (t->super.commit(index_trans, result_r) < 0) { mail_storage_set_index_error(t->box); ret = -1; } @@ -43,29 +42,30 @@ if (t->save_ctx != NULL) ibox->save_commit_post(t->save_ctx, result_r); - index_transaction_free(it); + index_transaction_free(t); return ret; } -static void index_transaction_index_rollback(struct mail_index_transaction *t) +static void +index_transaction_index_rollback(struct mail_index_transaction *index_trans) { - struct index_transaction_context *it = MAIL_STORAGE_CONTEXT(t); + struct mailbox_transaction_context *t = + MAIL_STORAGE_CONTEXT(index_trans); struct index_mailbox_context *ibox = - INDEX_STORAGE_CONTEXT(it->mailbox_ctx.box); + INDEX_STORAGE_CONTEXT(t->box); - if (it->mailbox_ctx.save_ctx != NULL) - ibox->save_rollback(it->mailbox_ctx.save_ctx); + if (t->save_ctx != NULL) + ibox->save_rollback(t->save_ctx); - i_assert(it->mail_ref_count == 0); - it->super.rollback(t); - index_transaction_free(it); + i_assert(t->mail_ref_count == 0); + t->super.rollback(index_trans); + index_transaction_free(t); } -void index_transaction_init(struct index_transaction_context *it, +void index_transaction_init(struct mailbox_transaction_context *t, struct mailbox *box, enum mailbox_transaction_flags flags) { - struct mailbox_transaction_context *t = &it->mailbox_ctx; enum mail_index_transaction_flags trans_flags; i_assert(box->opened); @@ -85,26 +85,26 @@ array_create(&t->module_contexts, default_pool, sizeof(void *), 5); - it->cache_view = mail_cache_view_open(box->cache, t->view); - it->cache_trans = mail_cache_get_transaction(it->cache_view, t->itrans); + t->cache_view = mail_cache_view_open(box->cache, t->view); + t->cache_trans = mail_cache_get_transaction(t->cache_view, t->itrans); /* set up after mail_cache_get_transaction(), so that we'll still have the cache_trans available in _index_commit() */ - it->super = t->itrans->v; + t->super = t->itrans->v; t->itrans->v.commit = index_transaction_index_commit; t->itrans->v.rollback = index_transaction_index_rollback; - MODULE_CONTEXT_SET(t->itrans, mail_storage_mail_index_module, it); + MODULE_CONTEXT_SET(t->itrans, mail_storage_mail_index_module, t); } struct mailbox_transaction_context * index_transaction_begin(struct mailbox *box, enum mailbox_transaction_flags flags) { - struct index_transaction_context *it; + struct mailbox_transaction_context *t; - it = i_new(struct index_transaction_context, 1); - index_transaction_init(it, box, flags); - return &it->mailbox_ctx; + t = i_new(struct mailbox_transaction_context, 1); + index_transaction_init(t, box, flags); + return t; } int index_transaction_commit(struct mailbox_transaction_context *t, @@ -137,10 +137,3 @@ mail_index_transaction_rollback(&itrans); } - -void index_transaction_set_max_modseq(struct mailbox_transaction_context *t, - uint64_t max_modseq, - ARRAY_TYPE(seq_range) *seqs) -{ - mail_index_transaction_set_max_modseq(t->itrans, max_modseq, seqs); -}
--- a/src/lib-storage/index/maildir/Makefile.am Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/Makefile.am Sat Jan 01 15:59:02 2011 +0200 @@ -12,6 +12,7 @@ libstorage_maildir_la_SOURCES = \ maildir-copy.c \ maildir-filename.c \ + maildir-filename-flags.c \ maildir-keywords.c \ maildir-mail.c \ maildir-save.c \ @@ -24,6 +25,7 @@ headers = \ maildir-filename.h \ + maildir-filename-flags.h \ maildir-keywords.h \ maildir-storage.h \ maildir-settings.h \
--- a/src/lib-storage/index/maildir/maildir-copy.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-copy.c Sat Jan 01 15:59:02 2011 +0200 @@ -83,7 +83,8 @@ dest_fname = maildir_filename_generate(); memset(&do_ctx, 0, sizeof(do_ctx)); do_ctx.dest_path = - t_strdup_printf("%s/tmp/%s", dest_mbox->box.path, dest_fname); + t_strdup_printf("%s/tmp/%s", mailbox_get_path(&dest_mbox->box), + dest_fname); if (src_mbox != NULL) { /* maildir */ if (maildir_file_do(src_mbox, mail->uid,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/maildir/maildir-filename-flags.c Sat Jan 01 15:59:02 2011 +0200 @@ -0,0 +1,172 @@ +/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "str.h" +#include "maildir-storage.h" +#include "maildir-keywords.h" +#include "maildir-filename-flags.h" + +#include <stdlib.h> + +void maildir_filename_flags_get(struct maildir_keywords_sync_ctx *ctx, + const char *fname, enum mail_flags *flags_r, + ARRAY_TYPE(keyword_indexes) *keywords_r) +{ + const char *info; + + array_clear(keywords_r); + *flags_r = 0; + + info = strrchr(fname, MAILDIR_INFO_SEP); + if (info == NULL || info[1] != '2' || info[2] != MAILDIR_FLAGS_SEP) + return; + + for (info += 3; *info != '\0' && *info != MAILDIR_FLAGS_SEP; info++) { + switch (*info) { + case 'R': /* replied */ + *flags_r |= MAIL_ANSWERED; + break; + case 'S': /* seen */ + *flags_r |= MAIL_SEEN; + break; + case 'T': /* trashed */ + *flags_r |= MAIL_DELETED; + break; + case 'D': /* draft */ + *flags_r |= MAIL_DRAFT; + break; + case 'F': /* flagged */ + *flags_r |= MAIL_FLAGGED; + break; + default: + if (*info >= MAILDIR_KEYWORD_FIRST && + *info <= MAILDIR_KEYWORD_LAST) { + int idx; + + idx = maildir_keywords_char_idx(ctx, *info); + if (idx < 0) { + /* unknown keyword. */ + break; + } + + array_append(keywords_r, + (unsigned int *)&idx, 1); + break; + } + + /* unknown flag - ignore */ + break; + } + } +} + +static int char_cmp(const void *p1, const void *p2) +{ + const unsigned char *c1 = p1, *c2 = p2; + + return *c1 - *c2; +} + +static void +maildir_filename_append_keywords(struct maildir_keywords_sync_ctx *ctx, + ARRAY_TYPE(keyword_indexes) *keywords, + string_t *fname) +{ + const unsigned int *indexes; + unsigned int i, count, start = str_len(fname); + char chr; + + indexes = array_get(keywords, &count); + for (i = 0; i < count; i++) { + chr = maildir_keywords_idx_char(ctx, indexes[i]); + if (chr != '\0') + str_append_c(fname, chr); + } + + qsort(str_c_modifiable(fname) + start, str_len(fname) - start, 1, + char_cmp); +} + +const char *maildir_filename_flags_set(struct maildir_keywords_sync_ctx *ctx, + const char *fname, enum mail_flags flags, + ARRAY_TYPE(keyword_indexes) *keywords) +{ + string_t *flags_str; + enum mail_flags flags_left; + const char *info, *oldflags; + int nextflag; + + /* remove the old :info from file name, and get the old flags */ + info = strrchr(fname, MAILDIR_INFO_SEP); + if (info != NULL && strrchr(fname, '/') > info) + info = NULL; + + oldflags = ""; + if (info != NULL) { + fname = t_strdup_until(fname, info); + if (info[1] == '2' && info[2] == MAILDIR_FLAGS_SEP) + oldflags = info+3; + } + + /* insert the new flags between old flags. flags must be sorted by + their ASCII code. unknown flags are kept. */ + flags_str = t_str_new(256); + str_append(flags_str, fname); + str_append(flags_str, MAILDIR_FLAGS_FULL_SEP); + flags_left = flags; + for (;;) { + /* skip all known flags */ + while (*oldflags == 'D' || *oldflags == 'F' || + *oldflags == 'R' || *oldflags == 'S' || + *oldflags == 'T' || + (*oldflags >= MAILDIR_KEYWORD_FIRST && + *oldflags <= MAILDIR_KEYWORD_LAST)) + oldflags++; + + nextflag = *oldflags == '\0' || *oldflags == MAILDIR_FLAGS_SEP ? + 256 : (unsigned char) *oldflags; + + if ((flags_left & MAIL_DRAFT) && nextflag > 'D') { + str_append_c(flags_str, 'D'); + flags_left &= ~MAIL_DRAFT; + } + if ((flags_left & MAIL_FLAGGED) && nextflag > 'F') { + str_append_c(flags_str, 'F'); + flags_left &= ~MAIL_FLAGGED; + } + if ((flags_left & MAIL_ANSWERED) && nextflag > 'R') { + str_append_c(flags_str, 'R'); + flags_left &= ~MAIL_ANSWERED; + } + if ((flags_left & MAIL_SEEN) && nextflag > 'S') { + str_append_c(flags_str, 'S'); + flags_left &= ~MAIL_SEEN; + } + if ((flags_left & MAIL_DELETED) && nextflag > 'T') { + str_append_c(flags_str, 'T'); + flags_left &= ~MAIL_DELETED; + } + + if (keywords != NULL && array_is_created(keywords) && + nextflag > MAILDIR_KEYWORD_FIRST) { + maildir_filename_append_keywords(ctx, keywords, + flags_str); + keywords = NULL; + } + + if (*oldflags == '\0' || *oldflags == MAILDIR_FLAGS_SEP) + break; + + str_append_c(flags_str, *oldflags); + oldflags++; + } + + if (*oldflags == MAILDIR_FLAGS_SEP) { + /* another flagset, we don't know about these, just keep them */ + while (*oldflags != '\0') + str_append_c(flags_str, *oldflags++); + } + + return str_c(flags_str); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/maildir/maildir-filename-flags.h Sat Jan 01 15:59:02 2011 +0200 @@ -0,0 +1,12 @@ +#ifndef MAILDIR_FILENAME_FLAGS_H +#define MAILDIR_FILENAME_FLAGS_H + +void maildir_filename_flags_get(struct maildir_keywords_sync_ctx *ctx, + const char *fname, enum mail_flags *flags_r, + ARRAY_TYPE(keyword_indexes) *keywords_r); + +const char *maildir_filename_flags_set(struct maildir_keywords_sync_ctx *ctx, + const char *fname, enum mail_flags flags, + ARRAY_TYPE(keyword_indexes) *keywords); + +#endif
--- a/src/lib-storage/index/maildir/maildir-filename.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-filename.c Sat Jan 01 15:59:02 2011 +0200 @@ -2,16 +2,11 @@ #include "lib.h" #include "ioloop.h" -#include "array.h" -#include "str.h" #include "time-util.h" #include "hostpid.h" #include "maildir-storage.h" -#include "maildir-keywords.h" #include "maildir-filename.h" -#include <stdlib.h> - const char *maildir_filename_generate(void) { static struct timeval last_tv = { 0, 0 }; @@ -34,168 +29,6 @@ my_pid, my_hostname); } -void maildir_filename_get_flags(struct maildir_keywords_sync_ctx *ctx, - const char *fname, enum mail_flags *flags_r, - ARRAY_TYPE(keyword_indexes) *keywords_r) -{ - const char *info; - - array_clear(keywords_r); - *flags_r = 0; - - info = strrchr(fname, MAILDIR_INFO_SEP); - if (info == NULL || info[1] != '2' || info[2] != MAILDIR_FLAGS_SEP) - return; - - for (info += 3; *info != '\0' && *info != MAILDIR_FLAGS_SEP; info++) { - switch (*info) { - case 'R': /* replied */ - *flags_r |= MAIL_ANSWERED; - break; - case 'S': /* seen */ - *flags_r |= MAIL_SEEN; - break; - case 'T': /* trashed */ - *flags_r |= MAIL_DELETED; - break; - case 'D': /* draft */ - *flags_r |= MAIL_DRAFT; - break; - case 'F': /* flagged */ - *flags_r |= MAIL_FLAGGED; - break; - default: - if (*info >= MAILDIR_KEYWORD_FIRST && - *info <= MAILDIR_KEYWORD_LAST) { - int idx; - - idx = maildir_keywords_char_idx(ctx, *info); - if (idx < 0) { - /* unknown keyword. */ - break; - } - - array_append(keywords_r, - (unsigned int *)&idx, 1); - break; - } - - /* unknown flag - ignore */ - break; - } - } -} - -static int char_cmp(const void *p1, const void *p2) -{ - const unsigned char *c1 = p1, *c2 = p2; - - return *c1 - *c2; -} - -static void -maildir_filename_append_keywords(struct maildir_keywords_sync_ctx *ctx, - ARRAY_TYPE(keyword_indexes) *keywords, - string_t *fname) -{ - const unsigned int *indexes; - unsigned int i, count, start = str_len(fname); - char chr; - - indexes = array_get(keywords, &count); - for (i = 0; i < count; i++) { - chr = maildir_keywords_idx_char(ctx, indexes[i]); - if (chr != '\0') - str_append_c(fname, chr); - } - - qsort(str_c_modifiable(fname) + start, str_len(fname) - start, 1, - char_cmp); -} - -const char *maildir_filename_set_flags(struct maildir_keywords_sync_ctx *ctx, - const char *fname, enum mail_flags flags, - ARRAY_TYPE(keyword_indexes) *keywords) -{ - string_t *flags_str; - enum mail_flags flags_left; - const char *info, *oldflags; - int nextflag; - - /* remove the old :info from file name, and get the old flags */ - info = strrchr(fname, MAILDIR_INFO_SEP); - if (info != NULL && strrchr(fname, '/') > info) - info = NULL; - - oldflags = ""; - if (info != NULL) { - fname = t_strdup_until(fname, info); - if (info[1] == '2' && info[2] == MAILDIR_FLAGS_SEP) - oldflags = info+3; - } - - /* insert the new flags between old flags. flags must be sorted by - their ASCII code. unknown flags are kept. */ - flags_str = t_str_new(256); - str_append(flags_str, fname); - str_append(flags_str, MAILDIR_FLAGS_FULL_SEP); - flags_left = flags; - for (;;) { - /* skip all known flags */ - while (*oldflags == 'D' || *oldflags == 'F' || - *oldflags == 'R' || *oldflags == 'S' || - *oldflags == 'T' || - (*oldflags >= MAILDIR_KEYWORD_FIRST && - *oldflags <= MAILDIR_KEYWORD_LAST)) - oldflags++; - - nextflag = *oldflags == '\0' || *oldflags == MAILDIR_FLAGS_SEP ? - 256 : (unsigned char) *oldflags; - - if ((flags_left & MAIL_DRAFT) && nextflag > 'D') { - str_append_c(flags_str, 'D'); - flags_left &= ~MAIL_DRAFT; - } - if ((flags_left & MAIL_FLAGGED) && nextflag > 'F') { - str_append_c(flags_str, 'F'); - flags_left &= ~MAIL_FLAGGED; - } - if ((flags_left & MAIL_ANSWERED) && nextflag > 'R') { - str_append_c(flags_str, 'R'); - flags_left &= ~MAIL_ANSWERED; - } - if ((flags_left & MAIL_SEEN) && nextflag > 'S') { - str_append_c(flags_str, 'S'); - flags_left &= ~MAIL_SEEN; - } - if ((flags_left & MAIL_DELETED) && nextflag > 'T') { - str_append_c(flags_str, 'T'); - flags_left &= ~MAIL_DELETED; - } - - if (keywords != NULL && array_is_created(keywords) && - nextflag > MAILDIR_KEYWORD_FIRST) { - maildir_filename_append_keywords(ctx, keywords, - flags_str); - keywords = NULL; - } - - if (*oldflags == '\0' || *oldflags == MAILDIR_FLAGS_SEP) - break; - - str_append_c(flags_str, *oldflags); - oldflags++; - } - - if (*oldflags == MAILDIR_FLAGS_SEP) { - /* another flagset, we don't know about these, just keep them */ - while (*oldflags != '\0') - str_append_c(flags_str, *oldflags++); - } - - return str_c(flags_str); -} - bool maildir_filename_get_size(const char *fname, char type, uoff_t *size_r) { uoff_t size = 0;
--- a/src/lib-storage/index/maildir/maildir-filename.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-filename.h Sat Jan 01 15:59:02 2011 +0200 @@ -5,14 +5,6 @@ const char *maildir_filename_generate(void); -void maildir_filename_get_flags(struct maildir_keywords_sync_ctx *ctx, - const char *fname, enum mail_flags *flags_r, - ARRAY_TYPE(keyword_indexes) *keywords_r); - -const char *maildir_filename_set_flags(struct maildir_keywords_sync_ctx *ctx, - const char *fname, enum mail_flags flags, - ARRAY_TYPE(keyword_indexes) *keywords); - bool maildir_filename_get_size(const char *fname, char type, uoff_t *size_r); unsigned int maildir_filename_base_hash(const void *p);
--- a/src/lib-storage/index/maildir/maildir-keywords.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-keywords.c Sat Jan 01 15:59:02 2011 +0200 @@ -290,6 +290,7 @@ { struct maildir_mailbox *mbox = mk->mbox; struct mailbox *box = &mbox->box; + const struct mailbox_permissions *perm = mailbox_get_permissions(box); const char *const *keywords; unsigned int i, count; string_t *str; @@ -313,14 +314,14 @@ return -1; } - if (st.st_gid != box->file_create_gid && - box->file_create_gid != (gid_t)-1) { - if (fchown(fd, (uid_t)-1, box->file_create_gid) < 0) { + if (st.st_gid != perm->file_create_gid && + perm->file_create_gid != (gid_t)-1) { + if (fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) { if (errno == EPERM) { mail_storage_set_critical(mk->storage, "%s", eperm_error_get_chgrp("fchown", path, - box->file_create_gid, - box->file_create_gid_origin)); + perm->file_create_gid, + perm->file_create_gid_origin)); } else { mail_storage_set_critical(mk->storage, "fchown(%s) failed: %m", path); @@ -353,6 +354,7 @@ static int maildir_keywords_commit(struct maildir_keywords *mk) { + const struct mailbox_permissions *perm; struct dotlock *dotlock; const char *lock_path; mode_t old_mask; @@ -366,11 +368,12 @@ lock_path = t_strconcat(mk->path, ".lock", NULL); (void)unlink(lock_path); + perm = mailbox_get_permissions(&mk->mbox->box); for (i = 0;; i++) { /* we could just create the temp file directly, but doing it this ways avoids potential problems with overwriting contents in malicious symlinks */ - old_mask = umask(0777 & ~mk->mbox->box.file_create_mode); + old_mask = umask(0777 & ~perm->file_create_mode); fd = file_dotlock_open(&mk->dotlock_settings, mk->path, DOTLOCK_CREATE_FLAG_NONBLOCK, &dotlock); umask(old_mask);
--- a/src/lib-storage/index/maildir/maildir-mail.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-mail.c Sat Jan 01 15:59:02 2011 +0200 @@ -188,7 +188,7 @@ bool exists; int ret; - ret = maildir_uidlist_lookup(mbox->uidlist, mail->uid, &flags, fname_r); + ret = maildir_sync_lookup(mbox, mail->uid, &flags, fname_r); if (ret != 0) return ret; @@ -588,8 +588,7 @@ if (field == MAIL_FETCH_VIRTUAL_SIZE) { /* make sure it gets removed from uidlist. if it's in file name, we can't really do more than log it. */ - ret = maildir_uidlist_lookup(mbox->uidlist, _mail->uid, - &flags, &fname); + ret = maildir_sync_lookup(mbox, _mail->uid, &flags, &fname); if (ret <= 0) return; if (maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE, @@ -599,7 +598,7 @@ "new" : "cur"; mail_storage_set_critical(_mail->box->storage, "Maildir filename has wrong W value: %s/%s/%s", - mbox->box.path, subdir, fname); + mailbox_get_path(&mbox->box), subdir, fname); } else if (maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid, MAILDIR_UIDLIST_REC_EXT_VSIZE) != NULL) { maildir_uidlist_set_ext(mbox->uidlist, _mail->uid,
--- a/src/lib-storage/index/maildir/maildir-save.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-save.c Sat Jan 01 15:59:02 2011 +0200 @@ -15,6 +15,7 @@ #include "maildir-uidlist.h" #include "maildir-keywords.h" #include "maildir-filename.h" +#include "maildir-filename-flags.h" #include "maildir-sync.h" #include <stdio.h> @@ -116,6 +117,7 @@ { struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->box; struct maildir_save_context *ctx; + const char *path; pool_t pool; pool = pool_alloconly_create("maildir_save_context", 4096); @@ -127,9 +129,10 @@ ctx->files_tail = &ctx->files; ctx->fd = -1; - ctx->tmpdir = p_strconcat(pool, mbox->box.path, "/tmp", NULL); - ctx->newdir = p_strconcat(pool, mbox->box.path, "/new", NULL); - ctx->curdir = p_strconcat(pool, mbox->box.path, "/cur", NULL); + path = mailbox_get_path(&mbox->box); + ctx->tmpdir = p_strconcat(pool, path, "/tmp", NULL); + ctx->newdir = p_strconcat(pool, path, "/new", NULL); + ctx->curdir = p_strconcat(pool, path, "/cur", NULL); buffer_create_const_data(&ctx->keywords_buffer, NULL, 0); array_create_from_buffer(&ctx->keywords_array, &ctx->keywords_buffer, @@ -268,7 +271,7 @@ return TRUE; } - *fname_r = maildir_filename_set_flags(NULL, basename, + *fname_r = maildir_filename_flags_set(NULL, basename, mf->flags & MAIL_FLAGS_MASK, NULL); return FALSE; } @@ -276,7 +279,7 @@ i_assert(ctx->keywords_sync_ctx != NULL || mf->keywords_count == 0); buffer_create_const_data(&ctx->keywords_buffer, mf + 1, mf->keywords_count * sizeof(unsigned int)); - *fname_r = maildir_filename_set_flags(ctx->keywords_sync_ctx, basename, + *fname_r = maildir_filename_flags_set(ctx->keywords_sync_ctx, basename, mf->flags & MAIL_FLAGS_MASK, &ctx->keywords_array); return FALSE; @@ -322,6 +325,7 @@ const char **fname_r) { struct mailbox *box = &mbox->box; + const struct mailbox_permissions *perm = mailbox_get_permissions(box); unsigned int prefix_len; const char *tmp_fname; string_t *path; @@ -342,7 +346,7 @@ might return an existing filename is if the time moved backwards. so we'll use O_EXCL anyway, although it's mostly useless. */ - old_mask = umask(0777 & ~box->file_create_mode); + old_mask = umask(0777 & ~perm->file_create_mode); fd = open(str_c(path), O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0777); umask(old_mask); @@ -357,14 +361,14 @@ mail_storage_set_critical(box->storage, "open(%s) failed: %m", str_c(path)); } - } else if (box->file_create_gid != (gid_t)-1) { - if (fchown(fd, (uid_t)-1, box->file_create_gid) < 0) { + } else if (perm->file_create_gid != (gid_t)-1) { + if (fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) { if (errno == EPERM) { mail_storage_set_critical(box->storage, "%s", eperm_error_get_chgrp("fchown", str_c(path), - box->file_create_gid, - box->file_create_gid_origin)); + perm->file_create_gid, + perm->file_create_gid_origin)); } else { mail_storage_set_critical(box->storage, "fchown(%s) failed: %m", str_c(path)); @@ -490,14 +494,12 @@ static void maildir_save_remove_last_filename(struct maildir_save_context *ctx) { - struct index_transaction_context *t = - (struct index_transaction_context *)ctx->ctx.transaction; struct maildir_filename **fm; mail_index_expunge(ctx->trans, ctx->seq); /* currently we can't just drop pending cache updates for this one specific record, so we'll reset the whole cache transaction. */ - mail_cache_transaction_reset(t->cache_trans); + mail_cache_transaction_reset(ctx->ctx.transaction->cache_trans); ctx->seq--; for (fm = &ctx->files; (*fm)->next != NULL; fm = &(*fm)->next) ; @@ -763,8 +765,6 @@ static void maildir_save_rollback_index_changes(struct maildir_save_context *ctx) { - struct index_transaction_context *t = - (struct index_transaction_context *)ctx->ctx.transaction; uint32_t seq; if (ctx->seq == 0) @@ -773,7 +773,7 @@ for (seq = ctx->seq; seq >= ctx->first_seq; seq--) mail_index_expunge(ctx->trans, seq); - mail_cache_transaction_reset(t->cache_trans); + mail_cache_transaction_reset(ctx->ctx.transaction->cache_trans); } static bool maildir_filename_has_conflict(struct maildir_filename *mf,
--- a/src/lib-storage/index/maildir/maildir-storage.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-storage.c Sat Jan 01 15:59:02 2011 +0200 @@ -233,16 +233,18 @@ /* create or fix maildir, ignore if it already exists */ static int create_maildir(struct mailbox *box, bool verify) { + const struct mailbox_permissions *perm = mailbox_get_permissions(box); const char *path; unsigned int i; enum mail_error error; int ret = 0; for (i = 0; i < N_ELEMENTS(maildir_subdirs); i++) { - path = t_strconcat(box->path, "/", maildir_subdirs[i], NULL); + path = t_strconcat(mailbox_get_path(box), "/", + maildir_subdirs[i], NULL); if (mkdir_verify(box->storage, box->list->ns, path, - box->dir_create_mode, box->file_create_gid, - box->file_create_gid_origin, verify) < 0) { + perm->dir_create_mode, perm->file_create_gid, + perm->file_create_gid_origin, verify) < 0) { (void)mail_storage_get_last_error(box->storage, &error); if (error != MAIL_ERROR_EXISTS) return -1; @@ -284,25 +286,16 @@ ibox->save_rollback = maildir_transaction_save_rollback; mbox->storage = (struct maildir_storage *)storage; - mbox->maildir_ext_id = - mail_index_ext_register(mbox->box.index, "maildir", - sizeof(mbox->maildir_hdr), 0, 0); return &mbox->box; } static int maildir_mailbox_open_existing(struct mailbox *box) { struct maildir_mailbox *mbox = (struct maildir_mailbox *)box; - struct stat st; - const char *shared_path; mbox->uidlist = maildir_uidlist_init(mbox); mbox->keywords = maildir_keywords_init(mbox); - shared_path = t_strconcat(box->path, "/dovecot-shared", NULL); - if (stat(shared_path, &st) == 0) - box->private_flags_mask = MAIL_SEEN; - if ((box->flags & MAILBOX_FLAG_KEEP_LOCKED) != 0) { if (maildir_uidlist_lock(mbox->uidlist) <= 0) return -1; @@ -311,21 +304,41 @@ mbox); } - if (access(t_strconcat(box->path, "/cur", NULL), W_OK) < 0 && - errno == EACCES) - mbox->box.backend_readonly = TRUE; - return index_storage_mailbox_open(box, FALSE); + if (index_storage_mailbox_open(box, FALSE) < 0) + return -1; + + mbox->maildir_ext_id = + mail_index_ext_register(mbox->box.index, "maildir", + sizeof(mbox->maildir_hdr), 0, 0); + return 0; +} + +static bool maildir_storage_is_readonly(struct mailbox *box) +{ + struct maildir_mailbox *mbox = (struct maildir_mailbox *)box; + + if (index_storage_is_readonly(box)) + return TRUE; + + if (maildir_is_backend_readonly(mbox)) { + /* return read-only only if there are no private flags + (that are stored in index files) */ + if (mailbox_get_private_flags_mask(box) == 0) + return TRUE; + } + return FALSE; } static int maildir_mailbox_open(struct mailbox *box) { + const char *box_path = mailbox_get_path(box); const char *root_dir; struct stat st; int ret; /* begin by checking if tmp/ directory exists and if it should be cleaned up. */ - ret = maildir_check_tmp(box->storage, box->path); + ret = maildir_check_tmp(box->storage, box_path); if (ret > 0) { /* exists */ return maildir_mailbox_open_existing(box); @@ -336,10 +349,10 @@ /* tmp/ directory doesn't exist. does the maildir? */ root_dir = mailbox_list_get_path(box->list, NULL, MAILBOX_LIST_PATH_TYPE_MAILBOX); - if (strcmp(box->path, root_dir) == 0) { + if (strcmp(box_path, root_dir) == 0) { /* root directory. either INBOX or some other namespace root */ errno = ENOENT; - } else if (stat(box->path, &st) == 0) { + } else if (stat(box_path, &st) == 0) { /* yes, we'll need to create the missing dirs */ if (create_maildir(box, TRUE) < 0) return -1; @@ -353,20 +366,21 @@ return -1; } else { mail_storage_set_critical(box->storage, - "stat(%s) failed: %m", box->path); + "stat(%s) failed: %m", box_path); return -1; } } static int maildir_create_shared(struct mailbox *box) { + const struct mailbox_permissions *perm = mailbox_get_permissions(box); const char *path; mode_t old_mask; int fd; old_mask = umask(0); - path = t_strconcat(box->path, "/dovecot-shared", NULL); - fd = open(path, O_WRONLY | O_CREAT, box->file_create_mode); + path = t_strconcat(mailbox_get_path(box), "/dovecot-shared", NULL); + fd = open(path, O_WRONLY | O_CREAT, perm->file_create_mode); umask(old_mask); if (fd == -1) { @@ -375,12 +389,12 @@ return -1; } - if (fchown(fd, (uid_t)-1, box->file_create_gid) < 0) { + if (fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) { if (errno == EPERM) { mail_storage_set_critical(box->storage, "%s", eperm_error_get_chgrp("fchown", path, - box->file_create_gid, - box->file_create_gid_origin)); + perm->file_create_gid, + perm->file_create_gid_origin)); } else { mail_storage_set_critical(box->storage, "fchown(%s) failed: %m", path); @@ -433,7 +447,7 @@ (box->list->props & MAILBOX_LIST_PROP_NO_NOSELECT) == 0) return 0; - ret = maildir_check_tmp(box->storage, box->path); + ret = maildir_check_tmp(box->storage, mailbox_get_path(box)); if (ret > 0) { mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS, "Mailbox already exists"); @@ -459,11 +473,18 @@ } static int -maildir_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) +maildir_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) { struct maildir_mailbox *mbox = (struct maildir_mailbox *)box; - return maildir_uidlist_get_mailbox_guid(mbox->uidlist, guid); + if ((items & MAILBOX_METADATA_GUID) != 0) { + if (maildir_uidlist_get_mailbox_guid(mbox->uidlist, + metadata_r->guid) < 0) + return -1; + } + return index_mailbox_get_metadata(box, items, metadata_r); } static void maildir_mailbox_close(struct mailbox *box) @@ -486,14 +507,15 @@ static void maildir_notify_changes(struct mailbox *box) { struct maildir_mailbox *mbox = (struct maildir_mailbox *)box; + const char *box_path = mailbox_get_path(box); if (box->notify_callback == NULL) index_mailbox_check_remove_all(&mbox->box); else { index_mailbox_check_add(&mbox->box, - t_strconcat(mbox->box.path, "/new", NULL)); + t_strconcat(box_path, "/new", NULL)); index_mailbox_check_add(&mbox->box, - t_strconcat(mbox->box.path, "/cur", NULL)); + t_strconcat(box_path, "/cur", NULL)); } } @@ -570,6 +592,35 @@ return mailbox_uidvalidity_next(list, path); } +static enum mail_flags maildir_get_private_flags_mask(struct mailbox *box) +{ + struct maildir_mailbox *mbox = (struct maildir_mailbox *)box; + const char *path; + struct stat st; + + if (!mbox->private_flags_mask_set) { + path = t_strconcat(mailbox_get_path(box), "/dovecot-shared", NULL); + if (stat(path, &st) < 0) + mbox->_private_flags_mask = 0; + else + mbox->_private_flags_mask = MAIL_SEEN; + } + return mbox->_private_flags_mask; +} + +bool maildir_is_backend_readonly(struct maildir_mailbox *mbox) +{ + if (!mbox->backend_readonly_set) { + const char *box_path = mailbox_get_path(&mbox->box); + + mbox->backend_readonly_set = TRUE; + if (access(t_strconcat(box_path, "/cur", NULL), W_OK) < 0 && + errno == EACCES) + mbox->backend_readonly = TRUE; + } + return mbox->backend_readonly; +} + struct mail_storage maildir_storage = { .name = MAILDIR_STORAGE_NAME, .class_flags = 0, @@ -589,7 +640,7 @@ struct mailbox maildir_mailbox = { .v = { - index_storage_is_readonly, + maildir_storage_is_readonly, index_storage_allow_new_keywords, index_storage_mailbox_enable, maildir_mailbox_open, @@ -600,7 +651,7 @@ index_storage_mailbox_delete, index_storage_mailbox_rename, index_storage_get_status, - maildir_mailbox_get_guid, + maildir_mailbox_get_metadata, maildir_list_index_has_changed, maildir_list_index_update_sync, maildir_storage_sync_init, @@ -611,21 +662,8 @@ index_transaction_begin, index_transaction_commit, index_transaction_rollback, - index_transaction_set_max_modseq, - index_keywords_create, - index_keywords_create_from_indexes, - index_keywords_ref, - index_keywords_unref, - index_keyword_is_valid, - index_storage_get_seq_range, - index_storage_get_uid_range, - index_storage_get_expunges, - NULL, - NULL, - NULL, + maildir_get_private_flags_mask, index_mail_alloc, - index_header_lookup_init, - index_header_lookup_deinit, index_storage_search_init, index_storage_search_deinit, index_storage_search_next_nonblock, @@ -636,7 +674,6 @@ maildir_save_finish, maildir_save_cancel, maildir_copy, - NULL, index_storage_is_inconsistent } };
--- a/src/lib-storage/index/maildir/maildir-storage.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-storage.h Sat Jan 01 15:59:02 2011 +0200 @@ -78,6 +78,9 @@ struct timeout *keep_lock_to; + /* Filled lazily by mailbox_get_private_flags_mask() */ + enum mail_flags _private_flags_mask; + /* maildir sync: */ struct maildir_uidlist *uidlist; struct maildir_keywords *keywords; @@ -87,6 +90,9 @@ unsigned int synced:1; unsigned int syncing_commit:1; + unsigned int private_flags_mask_set:1; + unsigned int backend_readonly:1; + unsigned int backend_readonly_set:1; }; extern struct mail_vfuncs maildir_mail_vfuncs; @@ -111,6 +117,7 @@ bool maildir_set_deleted(struct mailbox *box); uint32_t maildir_get_uidvalidity_next(struct mailbox_list *list); int maildir_lose_unexpected_dir(struct mail_storage *storage, const char *path); +bool maildir_is_backend_readonly(struct maildir_mailbox *mbox); struct mail_save_context * maildir_save_alloc(struct mailbox_transaction_context *_t);
--- a/src/lib-storage/index/maildir/maildir-sync-index.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-sync-index.c Sat Jan 01 15:59:02 2011 +0200 @@ -8,7 +8,7 @@ #include "index-sync-changes.h" #include "maildir-uidlist.h" #include "maildir-keywords.h" -#include "maildir-filename.h" +#include "maildir-filename-flags.h" #include "maildir-sync.h" #include <stdio.h> @@ -123,7 +123,7 @@ i_assert(*fname != '\0'); /* get the current flags and keywords */ - maildir_filename_get_flags(ctx->keywords_sync_ctx, + maildir_filename_flags_get(ctx->keywords_sync_ctx, fname, &ctx->flags, &ctx->keywords); /* apply changes */ @@ -133,7 +133,7 @@ ctx->flags = flags8; /* and try renaming with the new name */ - newfname = maildir_filename_set_flags(ctx->keywords_sync_ctx, fname, + newfname = maildir_filename_flags_set(ctx->keywords_sync_ctx, fname, ctx->flags, &ctx->keywords); newpath = t_strconcat(dir, newfname, NULL); if (strcmp(path, newpath) == 0) { @@ -206,7 +206,7 @@ maildir_uidlist_sync_finish(ctx->uidlist_sync_ctx); i_warning("Maildir %s: Expunged message reappeared, giving a new UID " - "(old uid=%u, file=%s)%s", ctx->mbox->box.path, + "(old uid=%u, file=%s)%s", mailbox_get_path(&ctx->mbox->box), uid, filename, strncmp(filename, "msg.", 4) != 0 ? "" : " (Your MDA is saving MH files into Maildir?)"); return 0; @@ -244,7 +244,7 @@ maildir_keywords_sync_init(mbox->keywords, _box->index); ctx->sync_changes = index_sync_changes_init(ctx->sync_ctx, ctx->view, ctx->trans, - mbox->box.backend_readonly); + maildir_is_backend_readonly(mbox)); ctx->start_time = time(NULL); *ctx_r = ctx; @@ -278,12 +278,13 @@ maildir_sync_index_update_ext_header(struct maildir_index_sync_context *ctx) { struct maildir_mailbox *mbox = ctx->mbox; + const char *cur_path; const void *data; size_t data_size; struct stat st; - if (ctx->update_maildir_hdr_cur && - stat(t_strconcat(mbox->box.path, "/cur", NULL), &st) == 0) { + cur_path = t_strconcat(mailbox_get_path(&mbox->box), "/cur", NULL); + if (ctx->update_maildir_hdr_cur && stat(cur_path, &st) == 0) { if ((time_t)mbox->maildir_hdr.cur_check_time < st.st_mtime) mbox->maildir_hdr.cur_check_time = st.st_mtime; mbox->maildir_hdr.cur_mtime = st.st_mtime; @@ -312,7 +313,7 @@ i_warning("Maildir %s: Synchronization took %u seconds " "(%u new msgs, %u flag change attempts, " "%u expunge attempts)", - ctx->mbox->box.path, time_diff, + mailbox_get_path(&ctx->mbox->box), time_diff, ctx->new_msgs_count, ctx->flag_change_count, ctx->expunge_count); } @@ -466,6 +467,7 @@ int ret = 0; time_t time_before_sync; uint8_t expunged_guid_128[MAIL_GUID_128_SIZE]; + enum mail_flags private_flags_mask; bool expunged, full_rescan = FALSE; i_assert(!mbox->syncing_commit); @@ -479,7 +481,8 @@ first time, reset the index so we can add all messages as new */ i_warning("Maildir %s: UIDVALIDITY changed (%u -> %u)", - mbox->box.path, hdr->uid_validity, uid_validity); + mailbox_get_path(&ctx->mbox->box), + hdr->uid_validity, uid_validity); mail_index_reset(trans); index_mailbox_reset_uidvalidity(&mbox->box); @@ -490,6 +493,7 @@ } hdr_next_uid = hdr->next_uid; + private_flags_mask = mailbox_get_private_flags_mask(&mbox->box); time_before_sync = time(NULL); mbox->syncing_commit = TRUE; seq = prev_uid = 0; first_recent_uid = I_MAX(hdr->first_recent_uid, 1); @@ -497,7 +501,7 @@ i_array_init(&ctx->idx_keywords, MAILDIR_MAX_KEYWORDS); iter = maildir_uidlist_iter_init(mbox->uidlist); while (maildir_uidlist_iter_next(iter, &uid, &uflags, &filename)) { - maildir_filename_get_flags(ctx->keywords_sync_ctx, filename, + maildir_filename_flags_get(ctx->keywords_sync_ctx, filename, &ctx->flags, &ctx->keywords); i_assert(uid > prev_uid); @@ -505,7 +509,7 @@ /* the private flags are kept only in indexes. don't use them at all even for newly seen mails */ - ctx->flags &= ~mbox->box.private_flags_mask; + ctx->flags &= ~private_flags_mask; again: seq++; @@ -580,7 +584,7 @@ } /* the private flags are stored only in indexes, keep them */ - ctx->flags |= rec->flags & mbox->box.private_flags_mask; + ctx->flags |= rec->flags & private_flags_mask; if (index_sync_changes_have(ctx->sync_changes)) { /* apply flag changes to maildir */
--- a/src/lib-storage/index/maildir/maildir-sync.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-sync.c Sat Jan 01 15:59:02 2011 +0200 @@ -255,8 +255,8 @@ ctx = t_new(struct maildir_sync_context, 1); ctx->mbox = mbox; - ctx->new_dir = t_strconcat(mbox->box.path, "/new", NULL); - ctx->cur_dir = t_strconcat(mbox->box.path, "/cur", NULL); + ctx->new_dir = t_strconcat(mailbox_get_path(&mbox->box), "/new", NULL); + ctx->cur_dir = t_strconcat(mailbox_get_path(&mbox->box), "/cur", NULL); ctx->last_touch = ioloop_time; ctx->last_notify = ioloop_time; ctx->flags = flags; @@ -319,7 +319,8 @@ } new_fname = maildir_filename_generate(); - new_path = t_strconcat(ctx->mbox->box.path, "/new/", new_fname, NULL); + new_path = t_strconcat(mailbox_get_path(&ctx->mbox->box), + "/new/", new_fname, NULL); if (rename(path2, new_path) == 0) i_warning("Fixed a duplicate: %s -> %s", path2, new_fname); @@ -886,8 +887,8 @@ } if (find_uid != NULL && *find_uid != 0) { - ret = maildir_uidlist_lookup_nosync(ctx->mbox->uidlist, - *find_uid, &flags, &fname); + ret = maildir_uidlist_lookup(ctx->mbox->uidlist, + *find_uid, &flags, &fname); if (ret < 0) return -1; if (ret == 0) { @@ -902,6 +903,35 @@ return maildir_uidlist_sync_deinit(&ctx->uidlist_sync_ctx, TRUE); } +int maildir_sync_lookup(struct maildir_mailbox *mbox, uint32_t uid, + enum maildir_uidlist_rec_flag *flags_r, + const char **fname_r) +{ + int ret; + + ret = maildir_uidlist_lookup(mbox->uidlist, uid, flags_r, fname_r); + if (ret <= 0) { + if (ret < 0) + return -1; + if (maildir_uidlist_is_open(mbox->uidlist)) { + /* refresh uidlist and check again in case it was added + after the last mailbox sync */ + if (maildir_uidlist_refresh(mbox->uidlist) < 0) + return -1; + } else { + /* the uidlist doesn't exist. */ + if (maildir_storage_sync_force(mbox, uid) < 0) + return -1; + } + + /* try again */ + ret = maildir_uidlist_lookup(mbox->uidlist, uid, + flags_r, fname_r); + } + + return ret; +} + int maildir_storage_sync_force(struct maildir_mailbox *mbox, uint32_t uid) { struct maildir_sync_context *ctx; @@ -993,10 +1023,11 @@ int ret; T_BEGIN { + const char *box_path = mailbox_get_path(&mbox->box); const char *new_dir, *cur_dir; - new_dir = t_strconcat(mbox->box.path, "/new", NULL); - cur_dir = t_strconcat(mbox->box.path, "/cur", NULL); + new_dir = t_strconcat(box_path, "/new", NULL); + cur_dir = t_strconcat(box_path, "/cur", NULL); ret = maildir_sync_quick_check(mbox, FALSE, new_dir, cur_dir, &new_changed, &cur_changed);
--- a/src/lib-storage/index/maildir/maildir-sync.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-sync.h Sat Jan 01 15:59:02 2011 +0200 @@ -14,8 +14,9 @@ /* If syncing takes longer than this, log a warning. */ #define MAILDIR_SYNC_TIME_WARN_SECS 60 +enum maildir_uidlist_rec_flag; + struct maildir_mailbox; - struct maildir_sync_context; struct maildir_keywords_sync_ctx; struct maildir_index_sync_context; @@ -42,6 +43,10 @@ void maildir_sync_set_new_msgs_count(struct maildir_index_sync_context *ctx, unsigned int count); +int maildir_sync_lookup(struct maildir_mailbox *mbox, uint32_t uid, + enum maildir_uidlist_rec_flag *flags_r, + const char **fname_r); + int maildir_list_index_has_changed(struct mailbox *box, struct mail_index_view *list_view, uint32_t seq);
--- a/src/lib-storage/index/maildir/maildir-uidlist.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-uidlist.c Sat Jan 01 15:59:02 2011 +0200 @@ -36,7 +36,6 @@ #include "nfs-workarounds.h" #include "eacces-error.h" #include "maildir-storage.h" -#include "maildir-sync.h" #include "maildir-filename.h" #include "maildir-uidlist.h" @@ -53,8 +52,6 @@ #define UIDLIST_IS_LOCKED(uidlist) \ ((uidlist)->lock_count > 0) -#define UIDLIST_ALLOW_WRITING(uidlist) \ - (UIDLIST_IS_LOCKED(uidlist) || (uidlist)->mbox == NULL) struct maildir_uidlist_rec { uint32_t uid; @@ -65,8 +62,9 @@ ARRAY_DEFINE_TYPE(maildir_uidlist_rec_p, struct maildir_uidlist_rec *); struct maildir_uidlist { - struct maildir_mailbox *mbox; + struct mailbox *box; char *path; + struct maildir_index_header *mhdr; int fd; dev_t fd_dev; @@ -137,7 +135,8 @@ bool nonblock, bool refresh, bool refresh_when_locked) { - struct mailbox *box = &uidlist->mbox->box; + struct mailbox *box = uidlist->box; + const struct mailbox_permissions *perm = mailbox_get_permissions(box); const char *control_dir, *path; mode_t old_mask; const enum dotlock_create_flags dotlock_flags = @@ -153,14 +152,14 @@ return 1; } - index_storage_lock_notify_reset(&uidlist->mbox->box); + index_storage_lock_notify_reset(uidlist->box); control_dir = mailbox_list_get_path(box->list, box->name, MAILBOX_LIST_PATH_TYPE_CONTROL); path = t_strconcat(control_dir, "/" MAILDIR_UIDLIST_NAME, NULL); for (i = 0;; i++) { - old_mask = umask(0777 & ~box->file_create_mode); + old_mask = umask(0777 & ~perm->file_create_mode); ret = file_dotlock_create(&uidlist->dotlock_settings, path, dotlock_flags, &uidlist->dotlock); umask(old_mask); @@ -173,8 +172,7 @@ MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT); return 0; } - if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT || - uidlist->mbox == NULL) { + if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT) { if (errno == EACCES) { mail_storage_set_critical(box->storage, "%s", eacces_error_get_creating("file_dotlock_create", path)); @@ -187,7 +185,7 @@ } /* the control dir doesn't exist. create it unless the whole mailbox was just deleted. */ - if (!maildir_set_deleted(&uidlist->mbox->box)) + if (!maildir_set_deleted(uidlist->box)) return -1; } @@ -232,6 +230,11 @@ return uidlist->initial_read; } +bool maildir_uidlist_is_open(struct maildir_uidlist *uidlist) +{ + return uidlist->fd != -1; +} + void maildir_uidlist_unlock(struct maildir_uidlist *uidlist) { i_assert(uidlist->lock_count > 0); @@ -256,14 +259,16 @@ struct maildir_uidlist *maildir_uidlist_init(struct maildir_mailbox *mbox) { + struct mailbox *box = &mbox->box; struct maildir_uidlist *uidlist; const char *control_dir; - control_dir = mailbox_list_get_path(mbox->box.list, mbox->box.name, + control_dir = mailbox_list_get_path(box->list, box->name, MAILBOX_LIST_PATH_TYPE_CONTROL); uidlist = i_new(struct maildir_uidlist, 1); - uidlist->mbox = mbox; + uidlist->box = box; + uidlist->mhdr = &mbox->maildir_hdr; uidlist->fd = -1; uidlist->path = i_strconcat(control_dir, "/"MAILDIR_UIDLIST_NAME, NULL); i_array_init(&uidlist->records, 128); @@ -275,23 +280,23 @@ uidlist->dotlock_settings.use_io_notify = TRUE; uidlist->dotlock_settings.use_excl_lock = - mbox->box.storage->set->dotlock_use_excl; + box->storage->set->dotlock_use_excl; uidlist->dotlock_settings.nfs_flush = - mbox->box.storage->set->mail_nfs_storage; + box->storage->set->mail_nfs_storage; uidlist->dotlock_settings.timeout = - mail_storage_get_lock_timeout(&mbox->storage->storage, + mail_storage_get_lock_timeout(box->storage, MAILDIR_UIDLIST_LOCK_STALE_TIMEOUT + 2); uidlist->dotlock_settings.stale_timeout = MAILDIR_UIDLIST_LOCK_STALE_TIMEOUT; uidlist->dotlock_settings.callback = dotlock_callback; - uidlist->dotlock_settings.context = &mbox->box; + uidlist->dotlock_settings.context = box; uidlist->dotlock_settings.temp_prefix = mbox->storage->temp_prefix; return uidlist; } static void maildir_uidlist_close(struct maildir_uidlist *uidlist) { - struct mail_storage *storage = uidlist->mbox->box.storage; + struct mail_storage *storage = uidlist->box->storage; if (uidlist->fd != -1) { if (close(uidlist->fd) < 0) { @@ -347,7 +352,7 @@ maildir_uidlist_set_corrupted(struct maildir_uidlist *uidlist, const char *fmt, ...) { - struct mail_storage *storage = uidlist->mbox->box.storage; + struct mail_storage *storage = uidlist->box->storage; va_list args; va_start(args, fmt); @@ -368,14 +373,8 @@ static void maildir_uidlist_update_hdr(struct maildir_uidlist *uidlist, const struct stat *st) { - struct maildir_index_header *mhdr; + struct maildir_index_header *mhdr = uidlist->mhdr; - if (uidlist->mbox == NULL) { - /* dbox is using this */ - return; - } - - mhdr = &uidlist->mbox->maildir_hdr; if (mhdr->uidlist_mtime == 0 && uidlist->version != UIDLIST_VERSION) { /* upgrading from older verson. don't update the uidlist times until it uses the new format */ @@ -695,7 +694,7 @@ maildir_uidlist_update_read(struct maildir_uidlist *uidlist, bool *retry_r, bool try_retry) { - struct mail_storage *storage = uidlist->mbox->box.storage; + struct mail_storage *storage = uidlist->box->storage; const char *line; uint32_t orig_next_uid, orig_uid_validity; struct istream *input; @@ -838,7 +837,7 @@ static int maildir_uidlist_stat(struct maildir_uidlist *uidlist, struct stat *st_r) { - struct mail_storage *storage = uidlist->mbox->box.storage; + struct mail_storage *storage = uidlist->box->storage; if (storage->set->mail_nfs_storage) { nfs_flush_file_handle_cache(uidlist->path); @@ -858,7 +857,7 @@ static int maildir_uidlist_has_changed(struct maildir_uidlist *uidlist, bool *recreated_r) { - struct mail_storage *storage = uidlist->mbox->box.storage; + struct mail_storage *storage = uidlist->box->storage; struct stat st; int ret; @@ -918,7 +917,7 @@ uidlist->fd = nfs_safe_open(uidlist->path, O_RDWR); if (uidlist->fd == -1 && errno != ENOENT) { - mail_storage_set_critical(uidlist->mbox->box.storage, + mail_storage_set_critical(uidlist->box->storage, "open(%s) failed: %m", uidlist->path); return -1; } @@ -957,8 +956,8 @@ int maildir_uidlist_refresh_fast_init(struct maildir_uidlist *uidlist) { - const struct maildir_index_header *mhdr = &uidlist->mbox->maildir_hdr; - struct mail_index *index = uidlist->mbox->box.index; + const struct maildir_index_header *mhdr = uidlist->mhdr; + struct mail_index *index = uidlist->box->index; struct mail_index_view *view; const struct mail_index_header *hdr; struct stat st; @@ -1028,35 +1027,6 @@ enum maildir_uidlist_rec_flag *flags_r, const char **fname_r) { - int ret; - - ret = maildir_uidlist_lookup_nosync(uidlist, uid, flags_r, fname_r); - if (ret <= 0) { - if (ret < 0) - return -1; - if (uidlist->fd != -1 || uidlist->mbox == NULL) { - /* refresh uidlist and check again in case it was added - after the last mailbox sync */ - if (maildir_uidlist_refresh(uidlist) < 0) - return -1; - } else { - /* the uidlist doesn't exist. */ - if (maildir_storage_sync_force(uidlist->mbox, uid) < 0) - return -1; - } - - /* try again */ - ret = maildir_uidlist_lookup_nosync(uidlist, uid, - flags_r, fname_r); - } - - return ret; -} - -int maildir_uidlist_lookup_nosync(struct maildir_uidlist *uidlist, uint32_t uid, - enum maildir_uidlist_rec_flag *flags_r, - const char **fname_r) -{ struct maildir_uidlist_rec *rec; int ret; @@ -1213,22 +1183,22 @@ { const struct mail_index_header *hdr; - if (uidlist->mbox->box.opened) { - hdr = mail_index_get_header(uidlist->mbox->box.view); + if (uidlist->box->opened) { + hdr = mail_index_get_header(uidlist->box->view); if (hdr->uid_validity != 0) { uidlist->uid_validity = hdr->uid_validity; return; } } uidlist->uid_validity = - maildir_get_uidvalidity_next(uidlist->mbox->box.list); + maildir_get_uidvalidity_next(uidlist->box->list); } static int maildir_uidlist_write_fd(struct maildir_uidlist *uidlist, int fd, const char *path, unsigned int first_idx, uoff_t *file_size_r) { - struct mail_storage *storage = uidlist->mbox->box.storage; + struct mail_storage *storage = uidlist->box->storage; struct maildir_uidlist_iter_ctx *iter; struct ostream *output; struct maildir_uidlist_rec *rec; @@ -1332,11 +1302,11 @@ /* we could get here when opening and locking mailbox, before index files have been opened. */ - if (!uidlist->mbox->box.opened) + if (!uidlist->box->opened) return; - mail_index_refresh(uidlist->mbox->box.index); - view = mail_index_view_open(uidlist->mbox->box.index); + mail_index_refresh(uidlist->box->index); + view = mail_index_view_open(uidlist->box->index); count = array_count(&uidlist->records); hdr = mail_index_get_header(view); if (count * UIDLIST_COMPRESS_PERCENTAGE / 100 <= hdr->messages_count) { @@ -1381,7 +1351,8 @@ static int maildir_uidlist_recreate(struct maildir_uidlist *uidlist) { - struct mailbox *box = &uidlist->mbox->box; + struct mailbox *box = uidlist->box; + const struct mailbox_permissions *perm = mailbox_get_permissions(box); const char *control_dir, *temp_path; struct stat st; mode_t old_mask; @@ -1398,31 +1369,30 @@ "/" MAILDIR_UIDLIST_NAME ".tmp", NULL); for (i = 0;; i++) { - old_mask = umask(0777 & ~box->file_create_mode); + old_mask = umask(0777 & ~perm->file_create_mode); fd = open(temp_path, O_RDWR | O_CREAT | O_TRUNC, 0777); umask(old_mask); if (fd != -1) break; - if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT || - uidlist->mbox == NULL) { + if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT) { mail_storage_set_critical(box->storage, "open(%s, O_CREAT) failed: %m", temp_path); return -1; } /* the control dir doesn't exist. create it unless the whole mailbox was just deleted. */ - if (!maildir_set_deleted(&uidlist->mbox->box)) + if (!maildir_set_deleted(uidlist->box)) return -1; } - if (box->file_create_gid != (gid_t)-1 && - fchown(fd, (uid_t)-1, box->file_create_gid) < 0) { + if (perm->file_create_gid != (gid_t)-1 && + fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) { if (errno == EPERM) { mail_storage_set_critical(box->storage, "%s", eperm_error_get_chgrp("fchown", temp_path, - box->file_create_gid, - box->file_create_gid_origin)); + perm->file_create_gid, + perm->file_create_gid_origin)); } else { mail_storage_set_critical(box->storage, "fchown(%s) failed: %m", temp_path); @@ -1519,7 +1489,7 @@ static int maildir_uidlist_sync_update(struct maildir_uidlist_sync_ctx *ctx) { struct maildir_uidlist *uidlist = ctx->uidlist; - struct mail_storage *storage = uidlist->mbox->box.storage; + struct mail_storage *storage = uidlist->box->storage; struct stat st; uoff_t file_size; @@ -1631,7 +1601,7 @@ *sync_ctx_r = ctx = i_new(struct maildir_uidlist_sync_ctx, 1); ctx->uidlist = uidlist; ctx->sync_flags = sync_flags; - ctx->partial = (!locked && ctx->uidlist->mbox != NULL) || + ctx->partial = !locked || (sync_flags & MAILDIR_UIDLIST_SYNC_PARTIAL) != 0; ctx->locked = locked; ctx->first_unwritten_pos = (unsigned int)-1; @@ -1694,7 +1664,7 @@ } if (uid != 0) { if (rec->uid != uid && rec->uid != (uint32_t)-1) { - mail_storage_set_critical(uidlist->mbox->box.storage, + mail_storage_set_critical(uidlist->box->storage, "Maildir: %s changed UID %u -> %u", filename, rec->uid, uid); return -1; @@ -1761,7 +1731,7 @@ return -1; for (p = filename; *p != '\0'; p++) { if (*p == 13 || *p == 10) { - struct mailbox *box = &uidlist->mbox->box; + struct mailbox *box = uidlist->box; dir = mailbox_list_get_path(box->list, box->name, MAILBOX_LIST_PATH_TYPE_MAILBOX); @@ -1791,7 +1761,7 @@ MAILDIR_UIDLIST_REC_FLAG_MOVED); } else { old_rec = hash_table_lookup(uidlist->files, filename); - i_assert(old_rec != NULL || UIDLIST_ALLOW_WRITING(uidlist)); + i_assert(old_rec != NULL || UIDLIST_IS_LOCKED(uidlist)); rec = p_new(ctx->record_pool, struct maildir_uidlist_rec, 1); @@ -1913,7 +1883,7 @@ struct maildir_uidlist_rec **recs; unsigned int dest, count; - i_assert(UIDLIST_ALLOW_WRITING(ctx->uidlist)); + i_assert(UIDLIST_IS_LOCKED(ctx->uidlist)); i_assert(ctx->first_new_pos != (unsigned int)-1); if (ctx->first_unwritten_pos == (unsigned int)-1) @@ -1996,9 +1966,9 @@ /* mbox=NULL means we're coming from dbox rebuilding code. the dbox is already locked, so allow uidlist recreation */ - i_assert(ctx->locked || !ctx->changed || ctx->uidlist->mbox == NULL); + i_assert(ctx->locked || !ctx->changed); if ((ctx->changed || maildir_uidlist_want_compress(ctx)) && - !ctx->failed && (ctx->locked || ctx->uidlist->mbox == NULL)) { + !ctx->failed && ctx->locked) { T_BEGIN { if (maildir_uidlist_sync_update(ctx) < 0) { /* we couldn't write everything we wanted. make
--- a/src/lib-storage/index/maildir/maildir-uidlist.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-uidlist.h Sat Jan 01 15:59:02 2011 +0200 @@ -56,6 +56,8 @@ void maildir_uidlist_unlock(struct maildir_uidlist *uidlist); bool maildir_uidlist_is_locked(struct maildir_uidlist *uidlist); bool maildir_uidlist_is_read(struct maildir_uidlist *uidlist); +/* Returns TRUE if uidlist file is currently open */ +bool maildir_uidlist_is_open(struct maildir_uidlist *uidlist); struct maildir_uidlist *maildir_uidlist_init(struct maildir_mailbox *mbox); void maildir_uidlist_deinit(struct maildir_uidlist **uidlist); @@ -73,9 +75,6 @@ int maildir_uidlist_lookup(struct maildir_uidlist *uidlist, uint32_t uid, enum maildir_uidlist_rec_flag *flags_r, const char **fname_r); -int maildir_uidlist_lookup_nosync(struct maildir_uidlist *uidlist, uint32_t uid, - enum maildir_uidlist_rec_flag *flags_r, - const char **fname_r); /* Returns extension's value or NULL if it doesn't exist. */ const char * maildir_uidlist_lookup_ext(struct maildir_uidlist *uidlist, uint32_t uid,
--- a/src/lib-storage/index/maildir/maildir-util.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-util.c Sat Jan 01 15:59:02 2011 +0200 @@ -9,7 +9,7 @@ #include "maildir-storage.h" #include "maildir-uidlist.h" #include "maildir-keywords.h" -#include "maildir-filename.h" +#include "maildir-filename-flags.h" #include "maildir-sync.h" #include <stdio.h> @@ -41,12 +41,12 @@ mail_index_lookup_view_flags(view, seq, &flags, &keywords); if (array_count(&keywords) == 0) { *have_flags_r = (flags & MAIL_FLAGS_NONRECENT) != 0; - fname = maildir_filename_set_flags(NULL, fname, flags, NULL); + fname = maildir_filename_flags_set(NULL, fname, flags, NULL); } else { *have_flags_r = TRUE; kw_ctx = maildir_keywords_sync_init_readonly(mbox->keywords, mbox->box.index); - fname = maildir_filename_set_flags(kw_ctx, fname, + fname = maildir_filename_flags_set(kw_ctx, fname, flags, &keywords); maildir_keywords_sync_deinit(&kw_ctx); } @@ -61,7 +61,7 @@ bool have_flags; int ret; - ret = maildir_uidlist_lookup(mbox->uidlist, uid, &flags, &fname); + ret = maildir_sync_lookup(mbox, uid, &flags, &fname); if (ret <= 0) return ret == 0 ? -2 : -1; @@ -76,13 +76,14 @@ if ((flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) { /* probably in new/ dir */ - path = t_strconcat(mbox->box.path, "/new/", fname, NULL); + path = t_strconcat(mailbox_get_path(&mbox->box), + "/new/", fname, NULL); ret = callback(mbox, path, context); if (ret != 0) return ret; } - path = t_strconcat(mbox->box.path, "/cur/", fname, NULL); + path = t_strconcat(mailbox_get_path(&mbox->box), "/cur/", fname, NULL); ret = callback(mbox, path, context); return ret; } @@ -135,10 +136,11 @@ static int maildir_create_path(struct mailbox *box, const char *path, enum mailbox_list_path_type type, bool retry) { + const struct mailbox_permissions *perm = mailbox_get_permissions(box); const char *p, *parent; - if (mkdir_chgrp(path, box->dir_create_mode, box->file_create_gid, - box->file_create_gid_origin) == 0) + if (mkdir_chgrp(path, perm->dir_create_mode, perm->file_create_gid, + perm->file_create_gid_origin) == 0) return 0; switch (errno) { @@ -179,7 +181,8 @@ /* @UNSAFE: get a list of directories we want to create */ for (i = 0; i < N_ELEMENTS(subdirs); i++) { types[i] = MAILBOX_LIST_PATH_TYPE_MAILBOX; - dirs[i] = t_strconcat(box->path, "/", subdirs[i], NULL); + dirs[i] = t_strconcat(mailbox_get_path(box), + "/", subdirs[i], NULL); } types[i] = MAILBOX_LIST_PATH_TYPE_CONTROL; dirs[i++] = mailbox_list_get_path(box->list, box->name, @@ -209,12 +212,12 @@ struct stat st; int ret; - if (stat(box->path, &st) < 0) { + if (stat(mailbox_get_path(box), &st) < 0) { if (errno == ENOENT) mailbox_set_deleted(box); else { mail_storage_set_critical(box->storage, - "stat(%s) failed: %m", box->path); + "stat(%s) failed: %m", mailbox_get_path(box)); } return FALSE; }
--- a/src/lib-storage/index/mbox/mbox-file.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/mbox/mbox-file.c Sat Jan 01 15:59:02 2011 +0200 @@ -21,15 +21,15 @@ if (mbox->mbox_file_stream != NULL) { /* read-only mbox stream */ - i_assert(mbox->box.backend_readonly); + i_assert(mbox_is_backend_readonly(mbox)); return 0; } - fd = open(mbox->box.path, - mbox->box.backend_readonly ? O_RDONLY : O_RDWR); - if (fd == -1 && errno == EACCES && !mbox->box.backend_readonly) { - mbox->box.backend_readonly = TRUE; - fd = open(mbox->box.path, O_RDONLY); + fd = open(mailbox_get_path(&mbox->box), + mbox_is_backend_readonly(mbox) ? O_RDONLY : O_RDWR); + if (fd == -1 && errno == EACCES && !mbox->backend_readonly) { + mbox->backend_readonly = TRUE; + fd = open(mailbox_get_path(&mbox->box), O_RDONLY); } if (fd == -1) { @@ -68,7 +68,7 @@ if (mbox->mbox_file_stream != NULL) { /* read-only mbox stream */ - i_assert(mbox->mbox_fd == -1 && mbox->box.backend_readonly); + i_assert(mbox->mbox_fd == -1 && mbox_is_backend_readonly(mbox)); } else { if (mbox->mbox_fd == -1) { if (mbox_file_open(mbox) < 0) @@ -86,7 +86,8 @@ i_stream_set_init_buffer_size(mbox->mbox_file_stream, MBOX_READ_BLOCK_SIZE); } - i_stream_set_name(mbox->mbox_file_stream, mbox->box.path); + i_stream_set_name(mbox->mbox_file_stream, + mailbox_get_path(&mbox->box)); } mbox->mbox_stream = i_stream_create_raw_mbox(mbox->mbox_file_stream); @@ -103,7 +104,7 @@ if (ibox->recent_flags_count > 0 && (mbox->box.flags & MAILBOX_FLAG_KEEP_RECENT) != 0 && - mbox->mbox_fd != -1 && !mbox->box.backend_readonly) { + mbox->mbox_fd != -1 && !mbox_is_backend_readonly(mbox)) { /* we've seen recent messages which we want to keep recent. keep file's atime lower than mtime so \Marked status gets shown while listing */ @@ -115,7 +116,8 @@ buf.modtime = st.st_mtime; buf.actime = buf.modtime - 1; /* EPERM can happen with shared mailboxes */ - if (utime(mbox->box.path, &buf) < 0 && errno != EPERM) + if (utime(mailbox_get_path(&mbox->box), &buf) < 0 && + errno != EPERM) mbox_set_syscall_error(mbox, "utime()"); } } @@ -131,7 +133,7 @@ if (mbox->mbox_file_stream != NULL) { if (mbox->mbox_fd == -1) { /* read-only mbox stream */ - i_assert(mbox->box.backend_readonly); + i_assert(mbox_is_backend_readonly(mbox)); i_stream_seek(mbox->mbox_file_stream, 0); } else { i_stream_destroy(&mbox->mbox_file_stream); @@ -153,7 +155,7 @@ if (data == NULL) { mail_storage_set_critical(&mbox->storage->storage, "Cached message offset lost for seq %u in mbox file %s", - seq, mbox->box.path); + seq, mailbox_get_path(&mbox->box)); mbox->mbox_hdr.dirty_flag = TRUE; mbox->mbox_broken_offsets = TRUE; return 0; @@ -190,7 +192,7 @@ mail_storage_set_critical(&mbox->storage->storage, "Cached message offset %s is invalid for mbox file %s", - dec2str(offset), mbox->box.path); + dec2str(offset), mailbox_get_path(&mbox->box)); mbox->mbox_hdr.dirty_flag = TRUE; mbox->mbox_broken_offsets = TRUE; return 0;
--- a/src/lib-storage/index/mbox/mbox-lock.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/mbox/mbox-lock.c Sat Jan 01 15:59:02 2011 +0200 @@ -174,7 +174,7 @@ be sure that the file is latest, but mbox files get rarely deleted and the flushing might cause errors (e.g. EBUSY for trying to flush a /var/mail mountpoint) */ - if (nfs_safe_stat(mbox->box.path, &st) < 0) { + if (nfs_safe_stat(mailbox_get_path(&mbox->box), &st) < 0) { if (errno == ENOENT) mailbox_set_deleted(&mbox->box); else @@ -250,7 +250,7 @@ struct dotlock_settings *set, enum mbox_dotlock_op op) { - const char *dir, *fname; + const char *box_path, *dir, *fname; int ret = -1, orig_dir_fd, orig_errno; orig_dir_fd = open(".", O_RDONLY); @@ -268,12 +268,13 @@ privileged group - DoS other users by dotlocking their mailboxes infinitely */ - fname = strrchr(mbox->box.path, '/'); + box_path = mailbox_get_path(&mbox->box); + fname = strrchr(box_path, '/'); if (fname == NULL) { /* already relative */ - fname = mbox->box.path; + fname = box_path; } else { - dir = t_strdup_until(mbox->box.path, fname); + dir = t_strdup_until(box_path, fname); if (chdir(dir) < 0) { mail_storage_set_critical(&mbox->storage->storage, "chdir(%s) failed: %m", dir); @@ -285,7 +286,7 @@ if (op == MBOX_DOTLOCK_OP_LOCK) { if (access(fname, R_OK) < 0) { mail_storage_set_critical(&mbox->storage->storage, - "access(%s) failed: %m", mbox->box.path); + "access(%s) failed: %m", box_path); return -1; } } @@ -415,7 +416,7 @@ set.callback = dotlock_callback; set.context = ctx; - ret = file_dotlock_create(&set, mbox->box.path, 0, + ret = file_dotlock_create(&set, mailbox_get_path(&mbox->box), 0, &mbox->mbox_dotlock); if (ret >= 0) { /* success / timeout */ @@ -425,7 +426,7 @@ ret = mbox_dotlock_privileged_op(mbox, &set, MBOX_DOTLOCK_OP_LOCK); } else if (errno == EACCES) - mbox_dotlock_log_eacces_error(mbox, mbox->box.path); + mbox_dotlock_log_eacces_error(mbox, mailbox_get_path(&mbox->box)); else mbox_set_syscall_error(mbox, "file_dotlock_create()"); @@ -635,7 +636,7 @@ mail_storage_set_critical(&ctx->mbox->storage->storage, "fcntl() failed with mbox file %s: " "File is locked by another process (EACCES)", - ctx->mbox->box.path); + mailbox_get_path(&ctx->mbox->box)); return -1; } @@ -707,7 +708,7 @@ if (mbox->mbox_fd == -1 && mbox->mbox_file_stream != NULL) { /* read-only mbox stream. no need to lock. */ - i_assert(mbox->box.backend_readonly); + i_assert(mbox_is_backend_readonly(mbox)); mbox->mbox_lock_type = lock_type; return 1; } @@ -772,7 +773,7 @@ int mbox_lock(struct mbox_mailbox *mbox, int lock_type, unsigned int *lock_id_r) { - const char *path = mbox->box.path; + const char *path = mailbox_get_path(&mbox->box); int mbox_fd = mbox->mbox_fd; bool fcntl_locked; int ret;
--- a/src/lib-storage/index/mbox/mbox-mail.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/mbox/mbox-mail.c Sat Jan 01 15:59:02 2011 +0200 @@ -33,7 +33,7 @@ static int mbox_mail_seek(struct index_mail *mail) { struct mbox_transaction_context *t = - (struct mbox_transaction_context *)mail->trans; + (struct mbox_transaction_context *)mail->mail.mail.transaction; struct mail *_mail = &mail->mail.mail; struct mbox_mailbox *mbox = (struct mbox_mailbox *)_mail->box; enum mbox_sync_flags sync_flags = 0; @@ -102,7 +102,7 @@ if (ret == 0) { mail_storage_set_critical(&mbox->storage->storage, "Losing sync for mail uid=%u in mbox file %s", - _mail->uid, mbox->box.path); + _mail->uid, mailbox_get_path(&mbox->box)); } return 0; } @@ -324,8 +324,8 @@ ret = mbox_mail_get_next_offset(mail, &next_offset); if (ret < 0) { i_warning("mbox %s: Can't find next message offset " - "for uid=%u", - mbox->box.path, mail->mail.mail.uid); + "for uid=%u", mailbox_get_path(&mbox->box), + mail->mail.mail.uid); } } if (ret <= 0)
--- a/src/lib-storage/index/mbox/mbox-save.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/mbox/mbox-save.c Sat Jan 01 15:59:02 2011 +0200 @@ -255,13 +255,13 @@ mbox_save_init_file(struct mbox_save_context *ctx, struct mbox_transaction_context *t, bool want_mail) { - struct mailbox_transaction_context *_t = &t->ictx.mailbox_ctx; + struct mailbox_transaction_context *_t = &t->t; struct mbox_mailbox *mbox = ctx->mbox; struct mail_storage *storage = &mbox->storage->storage; bool empty = FALSE; int ret; - if (ctx->mbox->box.backend_readonly) { + if (mbox_is_backend_readonly(ctx->mbox)) { mail_storage_set_error(storage, MAIL_ERROR_PERM, "Read-only mbox"); return -1; @@ -770,7 +770,8 @@ buf.modtime = st.st_mtime; buf.actime = ctx->orig_atime; - if (utime(mbox->box.path, &buf) < 0 && errno != EPERM) + if (utime(mailbox_get_path(&mbox->box), &buf) < 0 && + errno != EPERM) mbox_set_syscall_error(mbox, "utime()"); }
--- a/src/lib-storage/index/mbox/mbox-storage.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/mbox/mbox-storage.c Sat Jan 01 15:59:02 2011 +0200 @@ -79,9 +79,8 @@ const char *toobig_error = errno != EFBIG ? "" : " (process was started with ulimit -f limit)"; mail_storage_set_critical(&mbox->storage->storage, - "%s failed with mbox file %s: %m%s", - function, mbox->box.path, - toobig_error); + "%s failed with mbox file %s: %m%s", function, + mailbox_get_path(&mbox->box), toobig_error); } return -1; } @@ -370,13 +369,6 @@ mbox->storage = (struct mbox_storage *)storage; mbox->mbox_fd = -1; mbox->mbox_lock_type = F_UNLCK; - mbox->mbox_ext_idx = - mail_index_ext_register(mbox->box.index, "mbox", - sizeof(mbox->mbox_hdr), - sizeof(uint64_t), sizeof(uint64_t)); - mbox->md5hdr_ext_idx = - mail_index_ext_register(mbox->box.index, "header-md5", - 0, 16, 1); if ((storage->flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) != 0) mbox->mbox_save_md5 = TRUE; @@ -388,27 +380,36 @@ mbox_dotlock_touch(mbox); } +static int +mbox_mailbox_open_finish(struct mbox_mailbox *mbox, bool move_to_memory) +{ + if (index_storage_mailbox_open(&mbox->box, move_to_memory) < 0) + return -1; + + mbox->mbox_ext_idx = + mail_index_ext_register(mbox->box.index, "mbox", + sizeof(mbox->mbox_hdr), + sizeof(uint64_t), sizeof(uint64_t)); + mbox->md5hdr_ext_idx = + mail_index_ext_register(mbox->box.index, "header-md5", + 0, 16, 1); + return 0; +} + static int mbox_mailbox_open_existing(struct mbox_mailbox *mbox) { struct mailbox *box = &mbox->box; - const char *rootdir; + const char *rootdir, *box_path = mailbox_get_path(box); bool move_to_memory; - if (access(box->path, R_OK|W_OK) < 0) { - if (errno != EACCES) { - mbox_set_syscall_error(mbox, "access()"); - return -1; - } - mbox->box.backend_readonly = TRUE; - } - move_to_memory = want_memory_indexes(mbox->storage, box->path); + move_to_memory = want_memory_indexes(mbox->storage, box_path); if (box->inbox_any || strcmp(box->name, "INBOX") == 0) { /* if INBOX isn't under the root directory, it's probably in /var/mail and we want to allow privileged dotlocking */ rootdir = mailbox_list_get_path(box->list, NULL, MAILBOX_LIST_PATH_TYPE_DIR); - if (strncmp(box->path, rootdir, strlen(rootdir)) != 0) + if (strncmp(box_path, rootdir, strlen(rootdir)) != 0) mbox->mbox_privileged_locking = TRUE; } if ((box->flags & MAILBOX_FLAG_KEEP_LOCKED) != 0) { @@ -421,7 +422,23 @@ mbox_lock_touch_timeout, mbox); } } - return index_storage_mailbox_open(box, move_to_memory); + return mbox_mailbox_open_finish(mbox, move_to_memory); +} + +static bool mbox_storage_is_readonly(struct mailbox *box) +{ + struct mbox_mailbox *mbox = (struct mbox_mailbox *)box; + + if (index_storage_is_readonly(box)) + return TRUE; + + if (mbox_is_backend_readonly(mbox)) { + /* return read-only only if there are no private flags + (that are stored in index files) */ + if (mailbox_get_private_flags_mask(box) == 0) + return TRUE; + } + return FALSE; } static int mbox_mailbox_open(struct mailbox *box) @@ -433,14 +450,16 @@ if (box->input != NULL) { i_stream_ref(box->input); mbox->mbox_file_stream = box->input; - mbox->box.backend_readonly = TRUE; + mbox->backend_readonly = TRUE; + mbox->backend_readonly_set = TRUE; mbox->no_mbox_file = TRUE; - return index_storage_mailbox_open(box, FALSE); + return mbox_mailbox_open_finish(mbox, FALSE); } - if ((ret = stat(box->path, &st)) == 0 && !S_ISDIR(st.st_mode)) - return mbox_mailbox_open_existing(mbox); - else if (ret == 0) { + ret = stat(mailbox_get_path(box), &st); + if (ret == 0) { + if (!S_ISDIR(st.st_mode)) + return mbox_mailbox_open_existing(mbox); mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND, "Mailbox isn't selectable"); return -1; @@ -452,7 +471,7 @@ return -1; } else { mail_storage_set_critical(box->storage, - "stat(%s) failed: %m", box->path); + "stat(%s) failed: %m", mailbox_get_path(box)); return -1; } } @@ -523,7 +542,7 @@ return -1; } else { /* create the mbox file */ - ret = mailbox_create_fd(box, box->path, + ret = mailbox_create_fd(box, mailbox_get_path(box), O_RDWR | O_CREAT | O_EXCL, &fd); if (ret < 0) return -1; @@ -552,7 +571,7 @@ if (box->view != NULL) { hdr = mail_index_get_header(box->view); if ((hdr->flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0 && - !mbox->box.backend_readonly) { + !mbox_is_backend_readonly(mbox)) { /* we've done changes to mbox which haven't been written yet. do it now. */ sync_flags |= MBOX_SYNC_REWRITE; @@ -574,12 +593,11 @@ } static int -mbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) +mbox_mailbox_get_guid(struct mbox_mailbox *mbox, + uint8_t guid[MAIL_GUID_128_SIZE]) { - struct mbox_mailbox *mbox = (struct mbox_mailbox *)box; - - if (mail_index_is_in_memory(box->index)) { - mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE, + if (mail_index_is_in_memory(mbox->box.index)) { + mail_storage_set_error(mbox->box.storage, MAIL_ERROR_NOTPOSSIBLE, "Mailbox GUIDs are not permanent without index files"); return -1; } @@ -591,14 +609,28 @@ return 0; } +static int +mbox_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) +{ + struct mbox_mailbox *mbox = (struct mbox_mailbox *)box; + + if ((items & MAILBOX_METADATA_GUID) != 0) { + if (mbox_mailbox_get_guid(mbox, metadata_r->guid) < 0) + return -1; + } + return index_mailbox_get_metadata(box, items, metadata_r); +} + static void mbox_notify_changes(struct mailbox *box) { struct mbox_mailbox *mbox = (struct mbox_mailbox *)box; if (box->notify_callback == NULL) - index_mailbox_check_remove_all(&mbox->box); + index_mailbox_check_remove_all(box); else if (!mbox->no_mbox_file) - index_mailbox_check_add(&mbox->box, mbox->box.path); + index_mailbox_check_add(box, mailbox_get_path(box)); } static bool @@ -641,8 +673,8 @@ struct mbox_transaction_context *mt; mt = i_new(struct mbox_transaction_context, 1); - index_transaction_init(&mt->ictx, box, flags); - return &mt->ictx.mailbox_ctx; + index_transaction_init(&mt->t, box, flags); + return &mt->t; } static void mbox_transaction_unlock(struct mailbox *box, unsigned int lock_id) @@ -687,6 +719,17 @@ mbox_transaction_unlock(box, lock_id); } +bool mbox_is_backend_readonly(struct mbox_mailbox *mbox) +{ + if (!mbox->backend_readonly_set) { + mbox->backend_readonly_set = TRUE; + if (access(mailbox_get_path(&mbox->box), R_OK|W_OK) < 0 && + errno == EACCES) + mbox->backend_readonly = TRUE; + } + return mbox->backend_readonly; +} + struct mail_storage mbox_storage = { .name = MBOX_STORAGE_NAME, .class_flags = MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE | @@ -707,7 +750,7 @@ struct mailbox mbox_mailbox = { .v = { - index_storage_is_readonly, + mbox_storage_is_readonly, index_storage_allow_new_keywords, index_storage_mailbox_enable, mbox_mailbox_open, @@ -718,7 +761,7 @@ index_storage_mailbox_delete, index_storage_mailbox_rename, index_storage_get_status, - mbox_mailbox_get_guid, + mbox_mailbox_get_metadata, NULL, NULL, mbox_storage_sync_init, @@ -729,21 +772,8 @@ mbox_transaction_begin, mbox_transaction_commit, mbox_transaction_rollback, - index_transaction_set_max_modseq, - index_keywords_create, - index_keywords_create_from_indexes, - index_keywords_ref, - index_keywords_unref, - index_keyword_is_valid, - index_storage_get_seq_range, - index_storage_get_uid_range, - index_storage_get_expunges, - NULL, - NULL, NULL, index_mail_alloc, - index_header_lookup_init, - index_header_lookup_deinit, index_storage_search_init, index_storage_search_deinit, index_storage_search_next_nonblock, @@ -754,7 +784,6 @@ mbox_save_finish, mbox_save_cancel, mail_storage_copy, - NULL, index_storage_is_inconsistent } };
--- a/src/lib-storage/index/mbox/mbox-storage.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/mbox/mbox-storage.h Sat Jan 01 15:59:02 2011 +0200 @@ -57,10 +57,14 @@ unsigned int mbox_used_privileges:1; unsigned int mbox_privileged_locking:1; unsigned int syncing:1; + unsigned int backend_readonly:1; + unsigned int backend_readonly_set:1; }; struct mbox_transaction_context { - struct index_transaction_context ictx; + struct mailbox_transaction_context t; + union mail_index_transaction_module_context module_ctx; + unsigned int mbox_lock_id; }; @@ -85,4 +89,6 @@ struct mail_index_transaction_commit_result *result); void mbox_transaction_save_rollback(struct mail_save_context *ctx); +bool mbox_is_backend_readonly(struct mbox_mailbox *mbox); + #endif
--- a/src/lib-storage/index/mbox/mbox-sync.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/mbox/mbox-sync.c Sat Jan 01 15:59:02 2011 +0200 @@ -73,13 +73,13 @@ mail_storage_set_critical(&sync_ctx->mbox->storage->storage, "mbox file %s was modified while we were syncing, " "check your locking settings", - sync_ctx->mbox->box.path); + mailbox_get_path(&sync_ctx->mbox->box)); } va_start(va, fmt); mail_storage_set_critical(&sync_ctx->mbox->storage->storage, "Sync failed for mbox file %s: %s", - sync_ctx->mbox->box.path, + mailbox_get_path(&sync_ctx->mbox->box), t_strdup_vprintf(fmt, va)); va_end(va); } @@ -991,7 +991,7 @@ i_warning("UIDVALIDITY changed (%u -> %u) in mbox file %s", sync_ctx->hdr->uid_validity, sync_ctx->base_uid_validity, - sync_ctx->mbox->box.path); + mailbox_get_path(&sync_ctx->mbox->box)); sync_ctx->index_reset = TRUE; return TRUE; } @@ -1114,7 +1114,7 @@ &sync_ctx->mbox->storage->storage, "Out of UIDs, renumbering them in mbox " "file %s", - sync_ctx->mbox->box.path); + mailbox_get_path(&sync_ctx->mbox->box)); sync_ctx->renumber_uids = TRUE; return 0; } @@ -1429,7 +1429,7 @@ quite minimal (an extra logged error message). */ while (sync_ctx->orig_mtime == st->st_mtime) { usleep(500000); - if (utime(sync_ctx->mbox->box.path, NULL) < 0) { + if (utime(mailbox_get_path(&sync_ctx->mbox->box), NULL) < 0) { mbox_set_syscall_error(sync_ctx->mbox, "utime()"); return -1; @@ -1678,7 +1678,7 @@ return -1; } } else { - if (stat(mbox->box.path, &statbuf) < 0) { + if (stat(mailbox_get_path(&mbox->box), &statbuf) < 0) { if (errno == ENOENT) { mailbox_set_deleted(&mbox->box); return 0; @@ -1733,7 +1733,7 @@ int ret, changed; bool delay_writes, readonly; - readonly = mbox->box.backend_readonly || + readonly = mbox_is_backend_readonly(mbox) || (flags & MBOX_SYNC_READONLY) != 0; delay_writes = readonly || ((flags & MBOX_SYNC_REWRITE) == 0 && @@ -1791,7 +1791,8 @@ /* try as read-only */ if (mbox_lock(mbox, F_RDLCK, lock_id) <= 0) return -1; - mbox->box.backend_readonly = readonly = TRUE; + mbox->backend_readonly = readonly = TRUE; + mbox->backend_readonly_set = TRUE; delay_writes = TRUE; } } @@ -1915,7 +1916,8 @@ else { buf.modtime = st.st_mtime; buf.actime = sync_ctx.orig_atime; - if (utime(mbox->box.path, &buf) < 0 && errno != EPERM) + if (utime(mailbox_get_path(&mbox->box), &buf) < 0 && + errno != EPERM) mbox_set_syscall_error(mbox, "utime()"); } }
--- a/src/lib-storage/index/raw/raw-mail.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/raw/raw-mail.c Sat Jan 01 15:59:02 2011 +0200 @@ -22,7 +22,8 @@ st = i_stream_stat(mail->box->input, TRUE); if (st == NULL) { mail_storage_set_critical(mail->box->storage, - "stat(%s) failed: %m", mail->box->path); + "stat(%s) failed: %m", + i_stream_get_name(mail->box->input)); return -1; } @@ -103,7 +104,8 @@ *value_r = mbox->envelope_sender; return 0; case MAIL_FETCH_UIDL_FILE_NAME: - *value_r = mbox->have_filename ? _mail->box->path : ""; + *value_r = mbox->have_filename ? + mailbox_get_path(_mail->box) : ""; return 0; default: return index_mail_get_special(_mail, field, value_r);
--- a/src/lib-storage/index/raw/raw-storage.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/index/raw/raw-storage.c Sat Jan 01 15:59:02 2011 +0200 @@ -62,6 +62,7 @@ static int raw_mailbox_open(struct mailbox *box) { struct raw_mailbox *mbox = (struct raw_mailbox *)box; + const char *path; int fd; if (box->input != NULL) { @@ -69,9 +70,9 @@ return index_storage_mailbox_open(box, FALSE); } - box->path = box->name; + path = box->_path = box->name; mbox->have_filename = TRUE; - fd = open(box->path, O_RDONLY); + fd = open(path, O_RDONLY); if (fd == -1) { if (ENOTFOUND(errno)) { mail_storage_set_error(box->storage, @@ -79,12 +80,12 @@ T_MAIL_ERR_MAILBOX_NOT_FOUND(box->name)); } else if (!mail_storage_set_error_from_errno(box->storage)) { mail_storage_set_critical(box->storage, - "open(%s) failed: %m", box->path); + "open(%s) failed: %m", path); } return -1; } box->input = i_stream_create_fd(fd, MAIL_READ_FULL_BLOCK_SIZE, TRUE); - i_stream_set_name(box->input, box->path); + i_stream_set_name(box->input, path); i_stream_set_init_buffer_size(box->input, MAIL_READ_FULL_BLOCK_SIZE); return index_storage_mailbox_open(box, FALSE); } @@ -154,21 +155,8 @@ index_transaction_begin, index_transaction_commit, index_transaction_rollback, - index_transaction_set_max_modseq, - index_keywords_create, - index_keywords_create_from_indexes, - index_keywords_ref, - index_keywords_unref, - index_keyword_is_valid, - index_storage_get_seq_range, - index_storage_get_uid_range, - index_storage_get_expunges, - NULL, - NULL, NULL, index_mail_alloc, - index_header_lookup_init, - index_header_lookup_deinit, index_storage_search_init, index_storage_search_deinit, index_storage_search_next_nonblock, @@ -179,7 +167,6 @@ NULL, NULL, mail_storage_copy, - NULL, index_storage_is_inconsistent } };
--- a/src/lib-storage/index/test-index-fetch.c Sat Jan 01 14:34:14 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* Copyright (c) 2009-2010 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "array.h" -#include "test-common.h" -#include "mail-index-modseq.h" -#include "index-storage.h" - -static uint32_t expunge_uids[] = { 25, 15, 7, 3, 11, 1, 53, 33 }; -static uint8_t mail_guids[N_ELEMENTS(expunge_uids)][MAIL_GUID_128_SIZE]; -static unsigned int expunge_idx; -static unsigned int nonexternal_idx; - -void mail_index_lookup_uid(struct mail_index_view *view ATTR_UNUSED, - uint32_t seq, uint32_t *uid_r) -{ - *uid_r = seq; -} - -bool mail_index_lookup_seq_range(struct mail_index_view *view ATTR_UNUSED, - uint32_t first_uid, uint32_t last_uid, - uint32_t *first_seq_r, uint32_t *last_seq_r) -{ - *first_seq_r = first_uid; - *last_seq_r = last_uid; - return TRUE; -} - -bool mail_index_modseq_get_next_log_offset(struct mail_index_view *view ATTR_UNUSED, - uint64_t modseq, uint32_t *log_seq_r, - uoff_t *log_offset_r) -{ - *log_seq_r = modseq >> 32; - *log_offset_r = modseq & 0xfffffff; - return TRUE; -} - -struct mail_transaction_log_view * -mail_transaction_log_view_open(struct mail_transaction_log *log ATTR_UNUSED) { return NULL; } -int mail_transaction_log_view_set(struct mail_transaction_log_view *view ATTR_UNUSED, - uint32_t min_file_seq ATTR_UNUSED, uoff_t min_file_offset ATTR_UNUSED, - uint32_t max_file_seq ATTR_UNUSED, uoff_t max_file_offset ATTR_UNUSED, - bool *reset_r ATTR_UNUSED) { - if (min_file_seq < 99) - return 0; - return 1; -} - -void mail_transaction_log_view_close(struct mail_transaction_log_view **view ATTR_UNUSED) { } - -void mail_transaction_log_get_tail(struct mail_transaction_log *log ATTR_UNUSED, - uint32_t *file_seq_r) -{ - *file_seq_r = 100; -} - -int mail_transaction_log_view_next(struct mail_transaction_log_view *view ATTR_UNUSED, - const struct mail_transaction_header **hdr_r, - const void **data_r) -{ - static struct mail_transaction_header hdr; - static struct mail_transaction_expunge_guid exp; - static struct mail_transaction_expunge old_exp; - - if (expunge_idx == N_ELEMENTS(expunge_uids)) - return 0; - - if (mail_guids[expunge_idx][0] == 0) { - old_exp.uid1 = old_exp.uid2 = expunge_uids[expunge_idx]; - hdr.type = MAIL_TRANSACTION_EXPUNGE; - hdr.size = sizeof(old_exp); - *data_r = &old_exp; - } else { - exp.uid = expunge_uids[expunge_idx]; - memcpy(exp.guid_128, mail_guids[expunge_idx], sizeof(exp.guid_128)); - hdr.type = MAIL_TRANSACTION_EXPUNGE_GUID; - hdr.size = sizeof(exp); - *data_r = &exp; - } - if (expunge_idx != nonexternal_idx) - hdr.type |= MAIL_TRANSACTION_EXTERNAL; - - *hdr_r = &hdr; - expunge_idx++; - return 1; -} - -static void test_index_storage_get_expunges(void) -{ - struct mailbox *box; - ARRAY_TYPE(seq_range) uids_filter; - ARRAY_TYPE(mailbox_expunge_rec) expunges; - const struct mailbox_expunge_rec *exp; - unsigned int i, count; - uint64_t modseq; - - box = t_new(struct mailbox, 1); - box->index = t_new(struct mail_index, 1); - box->view = t_new(struct mail_index_view, 1); - - box->view->log_file_head_seq = 101; - box->view->log_file_head_offset = 1024; - - test_begin("index storage get expunges"); - - nonexternal_idx = 1; - memset(mail_guids + 2, 0, MAIL_GUID_128_SIZE); - memset(mail_guids + 4, 0, MAIL_GUID_128_SIZE); - - t_array_init(&uids_filter, 32); - seq_range_array_add_range(&uids_filter, 1, 20); - seq_range_array_add_range(&uids_filter, 53, 53); - - t_array_init(&expunges, 32); - modseq = 98ULL << 32; - for (i = 0; i < 2; i++) { - test_assert(index_storage_get_expunges(box, modseq, &uids_filter, - &expunges) == i); - - exp = array_get(&expunges, &count); - test_assert(count == 5); - test_assert(exp[0].uid == 7); - test_assert(memcmp(exp[0].guid_128, mail_guids[2], MAIL_GUID_128_SIZE) == 0); - test_assert(exp[1].uid == 3); - test_assert(memcmp(exp[1].guid_128, mail_guids[3], MAIL_GUID_128_SIZE) == 0); - test_assert(exp[2].uid == 11); - test_assert(memcmp(exp[2].guid_128, mail_guids[4], MAIL_GUID_128_SIZE) == 0); - test_assert(exp[3].uid == 1); - test_assert(memcmp(exp[3].guid_128, mail_guids[5], MAIL_GUID_128_SIZE) == 0); - test_assert(exp[4].uid == 53); - test_assert(memcmp(exp[4].guid_128, mail_guids[6], MAIL_GUID_128_SIZE) == 0); - - array_clear(&uids_filter); - expunge_idx = 0; - modseq = 100ULL << 32; - } - - test_end(); -} - -int main(void) -{ - static void (*test_functions[])(void) = { - test_index_storage_get_expunges, - NULL - }; - unsigned int i, j; - - for (i = 0; i < N_ELEMENTS(mail_guids); i++) { - for (j = 0; j < MAIL_GUID_128_SIZE; j++) - mail_guids[i][j] = j + i + 1; - } - return test_run(test_functions); -}
--- a/src/lib-storage/list/index-mailbox-list-sync.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/list/index-mailbox-list-sync.c Sat Jan 01 15:59:02 2011 +0200 @@ -159,7 +159,7 @@ return ret; } -static void +static int index_list_get_status(struct mailbox *box, enum mailbox_status_items items, struct mailbox_status *status) { @@ -167,11 +167,11 @@ if ((items & ~CACHED_STATUS_ITEMS) == 0) { if (index_list_get_cached_status(box, status) > 0) - return; + return 0; /* nonsynced / error, fallback to doing it the slow way */ } - ibox->module_ctx.super.get_status(box, items, status); + return ibox->module_ctx.super.get_status(box, items, status); } static int index_list_lookup_or_create(struct index_mailbox_list *ilist, @@ -340,7 +340,7 @@ view = mail_index_view_open(ilist->mail_index); if (mail_index_lookup_seq(view, uid, &seq)) { - mailbox_get_status(box, CACHED_STATUS_ITEMS, &status); + mailbox_get_open_status(box, CACHED_STATUS_ITEMS, &status); (void)index_list_update(ilist, box, view, seq, &status); } mail_index_view_close(&view);
--- a/src/lib-storage/list/mailbox-list-fs.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/list/mailbox-list-fs.c Sat Jan 01 15:59:02 2011 +0200 @@ -254,16 +254,8 @@ errno = ENOENT; } - if (!mailbox_list_is_valid_create_name(_list, name)) { - *status = MAILBOX_NAME_INVALID; - return 0; - } - if (ENOTFOUND(errno) || errno == EACCES) { - *status = MAILBOX_NAME_VALID; - return 0; - } else if (errno == ENOTDIR) { - *status = MAILBOX_NAME_NOINFERIORS; + *status = MAILBOX_NAME_NONEXISTENT; return 0; } else { mailbox_list_set_critical(_list, "stat(%s) failed: %m", path); @@ -339,8 +331,7 @@ path = t_strdup_until(path, p); } - mailbox_list_get_dir_permissions(list, NULL, &mode, - &gid, &gid_origin); + mailbox_list_get_root_dir_permissions(list, &mode, &gid, &gid_origin); if (mkdir_parents_chgrp(path, mode, gid, gid_origin) == 0) return 0; else if (errno == EEXIST) { @@ -434,7 +425,7 @@ if (fs_list_rmdir(list, name, path) == 0) return 0; - if (errno == ENOENT) { + if (errno == ENOENT || errno == ENOTDIR) { mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND, T_MAIL_ERR_MAILBOX_NOT_FOUND(name)); } else if (errno == ENOTEMPTY || errno == EEXIST) { @@ -541,8 +532,8 @@ /* create the hierarchy */ p = strrchr(newpath, '/'); if (p != NULL) { - mailbox_list_get_dir_permissions(newlist, NULL, &mode, - &gid, &origin); + mailbox_list_get_root_dir_permissions(newlist, &mode, + &gid, &origin); p = t_strdup_until(newpath, p); if (mkdir_parents_chgrp(p, mode, gid, origin) < 0 && errno != EEXIST) {
--- a/src/lib-storage/list/mailbox-list-maildir.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/list/mailbox-list-maildir.c Sat Jan 01 15:59:02 2011 +0200 @@ -240,13 +240,8 @@ return 0; } - if (!mailbox_list_is_valid_create_name(_list, name)) { - *status = MAILBOX_NAME_INVALID; - return 0; - } - if (ENOTFOUND(errno) || errno == EACCES) { - *status = MAILBOX_NAME_VALID; + *status = MAILBOX_NAME_NONEXISTENT; return 0; } else { mailbox_list_set_critical(_list, "stat(%s) failed: %m", path); @@ -289,7 +284,7 @@ /* Maildir++ spec wants that maildirfolder named file is created for all subfolders. */ - mailbox_list_get_permissions(list, NULL, &mode, &gid, &gid_origin); + mailbox_list_get_root_permissions(list, &mode, &gid, &gid_origin); path = t_strconcat(dir, "/" MAILDIR_SUBFOLDER_FILENAME, NULL); old_mask = umask(0); @@ -352,8 +347,8 @@ root_dir = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_MAILBOX); - mailbox_list_get_dir_permissions(list, NULL, &mode, - &gid, &gid_origin); + mailbox_list_get_root_dir_permissions(list, &mode, + &gid, &gid_origin); if (mkdir_parents_chgrp(path, mode, gid, gid_origin) == 0) { /* ok */ } else if (errno == EEXIST) { @@ -440,7 +435,7 @@ if (stat(path, &st) == 0) { mailbox_list_set_error(list, MAIL_ERROR_EXISTS, "Mailbox exists"); - } else if (errno == ENOENT) { + } else if (errno == ENOENT || errno == ENOTDIR) { mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND, T_MAIL_ERR_MAILBOX_NOT_FOUND(name)); } else {
--- a/src/lib-storage/list/mailbox-list-none.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/list/mailbox-list-none.c Sat Jan 01 15:59:02 2011 +0200 @@ -62,7 +62,7 @@ const char *name ATTR_UNUSED, enum mailbox_name_status *status) { - *status = MAILBOX_NAME_VALID; + *status = MAILBOX_NAME_NONEXISTENT; return 0; }
--- a/src/lib-storage/list/subscription-file.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/list/subscription-file.c Sat Jan 01 15:59:02 2011 +0200 @@ -108,7 +108,7 @@ dotlock_set.timeout = SUBSCRIPTION_FILE_LOCK_TIMEOUT; dotlock_set.stale_timeout = SUBSCRIPTION_FILE_CHANGE_TIMEOUT; - mailbox_list_get_permissions(list, NULL, &mode, &gid, &origin); + mailbox_list_get_root_permissions(list, &mode, &gid, &origin); fd_out = file_dotlock_open_group(&dotlock_set, path, 0, mode, gid, origin, &dotlock); if (fd_out == -1 && errno == ENOENT) {
--- a/src/lib-storage/mail-copy.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/mail-copy.c Sat Jan 01 15:59:02 2011 +0200 @@ -64,7 +64,7 @@ /* keywords gets unreferenced twice: first in mailbox_save_cancel()/_finish() and second time in mailbox_copy(). */ - mailbox_keywords_ref(ctx->transaction->box, ctx->keywords); + mailbox_keywords_ref(ctx->keywords); } if (mail_storage_try_copy(&ctx, mail) < 0) { @@ -78,7 +78,12 @@ bool mail_storage_copy_can_use_hardlink(struct mailbox *src, struct mailbox *dest) { - return src->file_create_mode == dest->file_create_mode && - src->file_create_gid == dest->file_create_gid && + const struct mailbox_permissions *src_perm = + mailbox_get_permissions(src); + const struct mailbox_permissions *dest_perm = + mailbox_get_permissions(dest); + + return src_perm->file_create_mode == dest_perm->file_create_mode && + src_perm->file_create_gid == dest_perm->file_create_gid && !dest->disable_reflink_copy_to; }
--- a/src/lib-storage/mail-search.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/mail-search.c Sat Jan 01 15:59:02 2011 +0200 @@ -158,7 +158,7 @@ case SEARCH_KEYWORDS: if (arg->value.keywords == NULL) break; - mailbox_keywords_unref(args->box, &arg->value.keywords); + mailbox_keywords_unref(&arg->value.keywords); break; case SEARCH_MAILBOX_GLOB: if (arg->value.mailbox_glob == NULL) @@ -619,8 +619,8 @@ new_kw = mailbox_keywords_create_from_indexes(box, &new_indexes); } T_END; - mailbox_keywords_unref(box, _kw1); - mailbox_keywords_unref(box, _kw2); + mailbox_keywords_unref(_kw1); + mailbox_keywords_unref(_kw2); return new_kw; }
--- a/src/lib-storage/mail-storage-private.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/mail-storage-private.h Sat Jan 01 15:59:02 2011 +0200 @@ -114,9 +114,11 @@ int (*rename)(struct mailbox *src, struct mailbox *dest, bool rename_children); - void (*get_status)(struct mailbox *box, enum mailbox_status_items items, - struct mailbox_status *status_r); - int (*get_guid)(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]); + int (*get_status)(struct mailbox *box, enum mailbox_status_items items, + struct mailbox_status *status_r); + int (*get_metadata)(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r); /* Lookup sync extension record and figure out if it mailbox has changed since. Returns 1 = yes, 0 = no, -1 = error. */ @@ -150,51 +152,14 @@ int (*transaction_commit)(struct mailbox_transaction_context *t, 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, - ARRAY_TYPE(seq_range) *seqs); - int (*keywords_create)(struct mailbox *box, - const char *const keywords[], - struct mail_keywords **keywords_r, - bool skip_invalid); - struct mail_keywords * - (*keywords_create_from_indexes)(struct mailbox *box, - const ARRAY_TYPE(keyword_indexes) *idx); - void (*keywords_ref)(struct mail_keywords *keywords); - void (*keywords_unref)(struct mail_keywords *keywords); - bool (*keyword_is_valid)(struct mailbox *box, const char *keyword, - const char **error_r); - - void (*get_seq_range)(struct mailbox *box, uint32_t uid1, uint32_t uid2, - uint32_t *seq1_r, uint32_t *seq2_r); - void (*get_uid_range)(struct mailbox *box, - const ARRAY_TYPE(seq_range) *seqs, - ARRAY_TYPE(seq_range) *uids); - bool (*get_expunges)(struct mailbox *box, uint64_t prev_modseq, - const ARRAY_TYPE(seq_range) *uids_filter, - ARRAY_TYPE(mailbox_expunge_rec) *expunges); - bool (*get_virtual_uid)(struct mailbox *box, - const char *backend_mailbox, - uint32_t backend_uidvalidity, - uint32_t backend_uid, uint32_t *uid_r); - void (*get_virtual_backend_boxes)(struct mailbox *box, - ARRAY_TYPE(mailboxes) *mailboxes, - bool only_with_msgs); - void (*get_virtual_box_patterns)(struct mailbox *box, - ARRAY_TYPE(mailbox_virtual_patterns) *includes, - ARRAY_TYPE(mailbox_virtual_patterns) *excludes); + enum mail_flags (*get_private_flags_mask)(struct mailbox *box); struct mail * (*mail_alloc)(struct mailbox_transaction_context *t, enum mail_fetch_field wanted_fields, struct mailbox_header_lookup_ctx *wanted_headers); - struct mailbox_header_lookup_ctx * - (*header_lookup_init)(struct mailbox *box, - const char *const headers[]); - void (*header_lookup_deinit)(struct mailbox_header_lookup_ctx *ctx); - struct mail_search_context * (*search_init)(struct mailbox_transaction_context *t, struct mail_search_args *args, @@ -212,9 +177,6 @@ int (*save_finish)(struct mail_save_context *ctx); void (*save_cancel)(struct mail_save_context *ctx); int (*copy)(struct mail_save_context *ctx, struct mail *mail); - /* returns TRUE if message part is an attachment. */ - bool (*save_is_attachment)(struct mail_save_context *ctx, - const struct mail_attachment_part *part); bool (*is_inconsistent)(struct mailbox *box); }; @@ -224,8 +186,20 @@ struct mail_storage_module_register *reg; }; +struct mailbox_permissions { + /* mode and GID to use for newly created files/dirs */ + mode_t file_create_mode, dir_create_mode; + gid_t file_create_gid; + /* origin (e.g. path) where the file_create_gid was got from */ + const char *file_create_gid_origin; + + bool mail_index_permissions_set; +}; + struct mailbox { const char *name; + /* mailbox's virtual name (from mail_namespace_get_vname()) */ + const char *vname; struct mail_storage *storage; struct mailbox_list *list; @@ -233,31 +207,24 @@ /* private: */ pool_t pool; + /* these won't be set until mailbox is opened: */ struct mail_index *index; struct mail_index_view *view; struct mail_cache *cache; + /* Filled lazily by mailbox_get_permissions() */ + struct mailbox_permissions _perm; + /* Filled lazily by mailbox_get_path() */ + const char *_path; /* default vfuncs for new struct mails. */ const struct mail_vfuncs *mail_vfuncs; - /* mailbox's MAILBOX_LIST_PATH_TYPE_MAILBOX */ - const char *path; - /* mailbox's virtual name (from mail_namespace_get_vname()) */ - const char *vname; struct istream *input; + const char *index_prefix; enum mailbox_flags flags; unsigned int transaction_count; enum mailbox_feature enabled_features; - /* User's private flags if this is a shared mailbox */ - enum mail_flags private_flags_mask; - - /* mode and GID to use for newly created files/dirs */ - mode_t file_create_mode, dir_create_mode; - gid_t file_create_gid; - /* origin (e.g. path) where the file_create_gid was got from */ - const char *file_create_gid_origin; - /* Mailbox notification settings: */ unsigned int notify_min_interval; mailbox_notify_callback_t *notify_callback; @@ -274,8 +241,6 @@ unsigned int opened:1; /* Mailbox was deleted while we had it open. */ unsigned int mailbox_deleted:1; - /* we've discovered there aren't enough permissions to modify mailbox */ - unsigned int backend_readonly:1; /* Mailbox is being deleted */ unsigned int deleting:1; /* Mailbox was already marked as deleted within this allocation. */ @@ -383,10 +348,17 @@ struct mailbox *box; enum mailbox_transaction_flags flags; + union mail_index_transaction_module_context module_ctx; + struct mail_index_transaction_vfuncs super; + int mail_ref_count; + struct mail_index_transaction *itrans; /* view contains all changes done within this transaction */ struct mail_index_view *view; + struct mail_cache_view *cache_view; + struct mail_cache_transaction_ctx *cache_trans; + struct mail_transaction_commit_changes *changes; ARRAY_DEFINE(module_contexts, union mailbox_transaction_module_context *); @@ -438,6 +410,10 @@ struct mail_save_attachment *attach; + /* returns TRUE if message part is an attachment. */ + bool (*part_is_attachment)(struct mail_save_context *ctx, + const struct mail_attachment_part *part); + /* we came here from mailbox_copy() */ unsigned int copying:1; }; @@ -448,8 +424,12 @@ struct mailbox_header_lookup_ctx { struct mailbox *box; - const char *const *headers; + pool_t pool; int refcount; + + unsigned int count; + const char *const *name; + unsigned int *idx; }; /* Modules should use do "my_id = mail_storage_module_id++" and @@ -484,6 +464,11 @@ void mail_set_expunged(struct mail *mail); void mailbox_set_deleted(struct mailbox *box); int mailbox_mark_index_deleted(struct mailbox *box, bool del); +/* Easy wrapper for getting mailbox's MAILBOX_LIST_PATH_TYPE_MAILBOX */ +const char *mailbox_get_path(struct mailbox *box) ATTR_PURE; +/* Get mailbox permissions. */ +const struct mailbox_permissions *mailbox_get_permissions(struct mailbox *box); +/* Force permissions to be refreshed on next lookup */ void mailbox_refresh_permissions(struct mailbox *box); /* Returns -1 if error, 0 if failed with EEXIST, 1 if ok */
--- a/src/lib-storage/mail-storage.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/mail-storage.c Sat Jan 01 15:59:02 2011 +0200 @@ -243,7 +243,7 @@ return ret; /* we need to create the root directory. */ - mailbox_list_get_dir_permissions(list, NULL, &mode, &gid, &origin); + mailbox_list_get_root_dir_permissions(list, &mode, &gid, &origin); if (mkdir_parents_chgrp(root_dir, mode, gid, origin) < 0 && errno != EEXIST) { *error_r = mail_error_create_eacces_msg("mkdir", root_dir); @@ -652,7 +652,6 @@ box->opened = FALSE; box->mailbox_deleted = FALSE; - box->backend_readonly = FALSE; array_clear(&box->search_results); } @@ -905,31 +904,45 @@ return ns1 == ns2; } -void mailbox_get_status(struct mailbox *box, - enum mailbox_status_items items, - struct mailbox_status *status_r) +int mailbox_get_status(struct mailbox *box, + enum mailbox_status_items items, + struct mailbox_status *status_r) { - box->v.get_status(box, items, status_r); + return box->v.get_status(box, items, status_r); } -int mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) +void mailbox_get_open_status(struct mailbox *box, + enum mailbox_status_items items, + struct mailbox_status *status_r) { - if (box->v.get_guid == NULL) { - mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE, - "Storage doesn't support mailbox GUIDs"); - return -1; - } + i_assert(box->opened); + if (box->v.get_status(box, items, status_r) < 0) + i_unreached(); +} + +int mailbox_get_metadata(struct mailbox *box, enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) +{ if (!box->opened) { if (mailbox_open(box) < 0) return -1; } - if (box->v.get_guid(box, guid) < 0) + if (box->v.get_metadata(box, items, metadata_r) < 0) return -1; - i_assert(!mail_guid_128_is_empty(guid)); + i_assert((items & MAILBOX_METADATA_GUID) == 0 || + !mail_guid_128_is_empty(metadata_r->guid)); return 0; } +enum mail_flags mailbox_get_private_flags_mask(struct mailbox *box) +{ + if (box->v.get_private_flags_mask == NULL) + return 0; + else + return box->v.get_private_flags_mask(box); +} + struct mailbox_sync_context * mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags) { @@ -1006,139 +1019,6 @@ mailbox_notify_changes(box, 0, NULL, NULL); } -int mailbox_keywords_create(struct mailbox *box, const char *const keywords[], - struct mail_keywords **keywords_r) -{ - const char *empty_keyword_list = NULL; - - if (keywords == NULL) - keywords = &empty_keyword_list; - return box->v.keywords_create(box, keywords, keywords_r, FALSE); -} - -struct mail_keywords * -mailbox_keywords_create_valid(struct mailbox *box, - const char *const keywords[]) -{ - const char *empty_keyword_list = NULL; - struct mail_keywords *kw; - - if (keywords == NULL) - keywords = &empty_keyword_list; - if (box->v.keywords_create(box, keywords, &kw, TRUE) < 0) - i_unreached(); - return kw; -} - -struct mail_keywords * -mailbox_keywords_create_from_indexes(struct mailbox *box, - const ARRAY_TYPE(keyword_indexes) *idx) -{ - return box->v.keywords_create_from_indexes(box, idx); -} - -void mailbox_keywords_ref(struct mailbox *box, struct mail_keywords *keywords) -{ - box->v.keywords_ref(keywords); -} - -void mailbox_keywords_unref(struct mailbox *box, - struct mail_keywords **_keywords) -{ - struct mail_keywords *keywords = *_keywords; - - *_keywords = NULL; - box->v.keywords_unref(keywords); -} - -bool mailbox_keyword_is_valid(struct mailbox *box, const char *keyword, - const char **error_r) -{ - return box->v.keyword_is_valid(box, keyword, error_r); -} - -void mailbox_get_seq_range(struct mailbox *box, uint32_t uid1, uint32_t uid2, - uint32_t *seq1_r, uint32_t *seq2_r) -{ - box->v.get_seq_range(box, uid1, uid2, seq1_r, seq2_r); -} - -void mailbox_get_uid_range(struct mailbox *box, - const ARRAY_TYPE(seq_range) *seqs, - ARRAY_TYPE(seq_range) *uids) -{ - box->v.get_uid_range(box, seqs, uids); -} - -bool mailbox_get_expunges(struct mailbox *box, uint64_t prev_modseq, - const ARRAY_TYPE(seq_range) *uids_filter, - ARRAY_TYPE(mailbox_expunge_rec) *expunges) -{ - return box->v.get_expunges(box, prev_modseq, - uids_filter, expunges); -} - -bool mailbox_get_virtual_uid(struct mailbox *box, const char *backend_mailbox, - uint32_t backend_uidvalidity, - uint32_t backend_uid, uint32_t *uid_r) -{ - if (box->v.get_virtual_uid == NULL) - return FALSE; - return box->v.get_virtual_uid(box, backend_mailbox, backend_uidvalidity, - backend_uid, uid_r); -} - -void mailbox_get_virtual_backend_boxes(struct mailbox *box, - ARRAY_TYPE(mailboxes) *mailboxes, - bool only_with_msgs) -{ - if (box->v.get_virtual_backend_boxes == NULL) - array_append(mailboxes, &box, 1); - else - box->v.get_virtual_backend_boxes(box, mailboxes, only_with_msgs); -} - -void mailbox_get_virtual_box_patterns(struct mailbox *box, - ARRAY_TYPE(mailbox_virtual_patterns) *includes, - ARRAY_TYPE(mailbox_virtual_patterns) *excludes) -{ - if (box->v.get_virtual_box_patterns == NULL) { - struct mailbox_virtual_pattern pat; - - memset(&pat, 0, sizeof(pat)); - pat.ns = box->list->ns; - pat.pattern = box->name; - array_append(includes, &pat, 1); - } else { - box->v.get_virtual_box_patterns(box, includes, excludes); - } -} - -struct mailbox_header_lookup_ctx * -mailbox_header_lookup_init(struct mailbox *box, const char *const headers[]) -{ - return box->v.header_lookup_init(box, headers); -} - -void mailbox_header_lookup_ref(struct mailbox_header_lookup_ctx *ctx) -{ - i_assert(ctx->refcount > 0); - ctx->refcount++; -} - -void mailbox_header_lookup_unref(struct mailbox_header_lookup_ctx **_ctx) -{ - struct mailbox_header_lookup_ctx *ctx = *_ctx; - - *_ctx = NULL; - - i_assert(ctx->refcount > 0); - if (--ctx->refcount > 0) - return; - - ctx->box->v.header_lookup_deinit(ctx); -} - struct mail_search_context * mailbox_search_init(struct mailbox_transaction_context *t, struct mail_search_args *args, @@ -1274,7 +1154,7 @@ uint64_t max_modseq, ARRAY_TYPE(seq_range) *seqs) { - t->box->v.transaction_set_max_modseq(t, max_modseq, seqs); + mail_index_transaction_set_max_modseq(t->itrans, max_modseq, seqs); } struct mailbox * @@ -1301,7 +1181,7 @@ ctx->flags = flags; ctx->keywords = keywords; if (keywords != NULL) - mailbox_keywords_ref(ctx->transaction->box, keywords); + mailbox_keywords_ref(keywords); } void mailbox_save_copy_flags(struct mail_save_context *ctx, struct mail *mail) @@ -1409,20 +1289,19 @@ *_ctx = NULL; ret = box->v.save_finish(ctx); if (keywords != NULL) - mailbox_keywords_unref(box, &keywords); + mailbox_keywords_unref(&keywords); return ret; } void mailbox_save_cancel(struct mail_save_context **_ctx) { struct mail_save_context *ctx = *_ctx; - struct mailbox *box = ctx->transaction->box; struct mail_keywords *keywords = ctx->keywords; *_ctx = NULL; ctx->transaction->box->v.save_cancel(ctx); if (keywords != NULL) - mailbox_keywords_unref(box, &keywords); + mailbox_keywords_unref(&keywords); } int mailbox_copy(struct mail_save_context **_ctx, struct mail *mail) @@ -1442,7 +1321,7 @@ ret = ctx->transaction->box->v.copy(ctx, mail); if (keywords != NULL) - mailbox_keywords_unref(box, &keywords); + mailbox_keywords_unref(&keywords); return ret; } @@ -1458,42 +1337,76 @@ box->mailbox_deleted = TRUE; } -void mailbox_refresh_permissions(struct mailbox *box) +const char *mailbox_get_path(struct mailbox *box) +{ + const char *path; + + if (box->_path == NULL) { + path = mailbox_list_get_path(box->list, box->name, + MAILBOX_LIST_PATH_TYPE_MAILBOX); + box->_path = p_strdup(box->pool, path); + } + return box->_path; +} + +static void mailbox_get_permissions_if_not_set(struct mailbox *box) { const char *origin, *dir_origin; gid_t dir_gid; + if (box->_perm.file_create_mode != 0) + return; + if (box->input != NULL) { - box->file_create_mode = 0600; - box->dir_create_mode = 0700; - box->file_create_gid = (gid_t)-1; - box->file_create_gid_origin = "defaults"; + box->_perm.file_create_mode = 0600; + box->_perm.dir_create_mode = 0700; + box->_perm.file_create_gid = (gid_t)-1; + box->_perm.file_create_gid_origin = "defaults"; return; } mailbox_list_get_permissions(box->list, box->name, - &box->file_create_mode, - &box->file_create_gid, &origin); + &box->_perm.file_create_mode, + &box->_perm.file_create_gid, &origin); + box->_perm.file_create_gid_origin = p_strdup(box->pool, origin); + mailbox_list_get_dir_permissions(box->list, box->name, + &box->_perm.dir_create_mode, + &dir_gid, &dir_origin); +} + +const struct mailbox_permissions *mailbox_get_permissions(struct mailbox *box) +{ + mailbox_get_permissions_if_not_set(box); - box->file_create_gid_origin = p_strdup(box->pool, origin); - mailbox_list_get_dir_permissions(box->list, box->name, - &box->dir_create_mode, - &dir_gid, &dir_origin); + if (!box->_perm.mail_index_permissions_set && box->index != NULL) { + box->_perm.mail_index_permissions_set = TRUE; + mail_index_set_permissions(box->index, + box->_perm.file_create_mode, + box->_perm.file_create_gid, + box->_perm.file_create_gid_origin); + } + return &box->_perm; +} + +void mailbox_refresh_permissions(struct mailbox *box) +{ + memset(&box->_perm, 0, sizeof(box->_perm)); + (void)mailbox_get_permissions(box); } int mailbox_create_fd(struct mailbox *box, const char *path, int flags, int *fd_r) { + const struct mailbox_permissions *perm = mailbox_get_permissions(box); mode_t old_mask; int fd; - i_assert(box->file_create_mode != 0); i_assert((flags & O_CREAT) != 0); *fd_r = -1; old_mask = umask(0); - fd = open(path, flags, box->file_create_mode); + fd = open(path, flags, perm->file_create_mode); umask(old_mask); if (fd != -1) { @@ -1504,6 +1417,10 @@ } else if (errno == ENOENT) { mailbox_set_deleted(box); return -1; + } else if (errno == ENOTDIR) { + mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE, + "Mailbox doesn't allow inferior mailboxes"); + return -1; } else if (mail_storage_set_error_from_errno(box->storage)) { return -1; } else { @@ -1512,14 +1429,14 @@ return -1; } - if (box->file_create_gid != (gid_t)-1) { - if (fchown(fd, (uid_t)-1, box->file_create_gid) == 0) { + if (perm->file_create_gid != (gid_t)-1) { + if (fchown(fd, (uid_t)-1, perm->file_create_gid) == 0) { /* ok */ } else if (errno == EPERM) { mail_storage_set_critical(box->storage, "%s", eperm_error_get_chgrp("fchown", path, - box->file_create_gid, - box->file_create_gid_origin)); + perm->file_create_gid, + perm->file_create_gid_origin)); } else { mail_storage_set_critical(box->storage, "fchown(%s) failed: %m", path);
--- a/src/lib-storage/mail-storage.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/mail-storage.h Sat Jan 01 15:59:02 2011 +0200 @@ -64,9 +64,13 @@ STATUS_UNSEEN = 0x10, STATUS_FIRST_UNSEEN_SEQ = 0x20, STATUS_KEYWORDS = 0x40, - STATUS_HIGHESTMODSEQ = 0x80, - STATUS_CACHE_FIELDS = 0x100, - STATUS_VIRTUAL_SIZE = 0x200 + STATUS_HIGHESTMODSEQ = 0x80 +}; + +enum mailbox_metadata_items { + MAILBOX_METADATA_GUID = 0x01, + MAILBOX_METADATA_VIRTUAL_SIZE = 0x02, + MAILBOX_METADATA_CACHE_FIELDS = 0x04 }; enum mailbox_search_result_flags { @@ -185,17 +189,21 @@ uint32_t first_unseen_seq; uint64_t highest_modseq; - /* sum of virtual size of all messages in mailbox */ - uint64_t virtual_size; const ARRAY_TYPE(keywords) *keywords; - /* Fields that have "temp" or "yes" caching decision. */ - const ARRAY_TYPE(const_string) *cache_fields; /* Modseqs aren't permanent (index is in memory) */ unsigned int nonpermanent_modseqs:1; }; +struct mailbox_metadata { + uint8_t guid[MAIL_GUID_128_SIZE]; + /* sum of virtual size of all messages in mailbox */ + uint64_t virtual_size; + /* Fields that have "temp" or "yes" caching decision. */ + const ARRAY_TYPE(const_string) *cache_fields; +}; + struct mailbox_update { /* All non-zero fields are changed. */ uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; @@ -393,11 +401,19 @@ do forced CLOSE. */ bool mailbox_is_inconsistent(struct mailbox *box); -/* Gets the mailbox status information. */ -void mailbox_get_status(struct mailbox *box, enum mailbox_status_items items, - struct mailbox_status *status_r); -/* Get mailbox GUID, creating it if necessary. */ -int mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]); +/* Gets the mailbox status information, opening the mailbox if necessary. */ +int mailbox_get_status(struct mailbox *box, enum mailbox_status_items items, + struct mailbox_status *status_r); +/* Gets the mailbox status, requires that mailbox is already opened. */ +void mailbox_get_open_status(struct mailbox *box, + enum mailbox_status_items items, + struct mailbox_status *status_r); +/* Gets mailbox metadata */ +int mailbox_get_metadata(struct mailbox *box, enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r); +/* Returns a mask of flags that are private to user in this mailbox + (as opposed to flags shared between users). */ +enum mail_flags mailbox_get_private_flags_mask(struct mailbox *box); /* Synchronize the mailbox. */ struct mailbox_sync_context * @@ -461,22 +477,6 @@ bool mailbox_get_expunges(struct mailbox *box, uint64_t prev_modseq, const ARRAY_TYPE(seq_range) *uids_filter, ARRAY_TYPE(mailbox_expunge_rec) *expunges); -/* If box is a virtual mailbox, look up UID for the given backend message. - Returns TRUE if found, FALSE if not. */ -bool mailbox_get_virtual_uid(struct mailbox *box, const char *backend_mailbox, - uint32_t backend_uidvalidity, - uint32_t backend_uid, uint32_t *uid_r); -/* If box is a virtual mailbox, return all backend mailboxes. If - only_with_msgs=TRUE, return only those mailboxes that have at least one - message existing in the virtual mailbox. */ -void mailbox_get_virtual_backend_boxes(struct mailbox *box, - ARRAY_TYPE(mailboxes) *mailboxes, - bool only_with_msgs); -/* If mailbox is a virtual mailbox, return all mailbox list patterns that - are used to figure out which mailboxes belong to the virtual mailbox. */ -void mailbox_get_virtual_box_patterns(struct mailbox *box, - ARRAY_TYPE(mailbox_virtual_patterns) *includes, - ARRAY_TYPE(mailbox_virtual_patterns) *excludes); /* Initialize new search request. charset specifies the character set used in the search argument strings. If sort_program is non-NULL, the messages are @@ -532,9 +532,8 @@ struct mail_keywords * mailbox_keywords_create_from_indexes(struct mailbox *box, const ARRAY_TYPE(keyword_indexes) *idx); -void mailbox_keywords_ref(struct mailbox *box, struct mail_keywords *keywords); -void mailbox_keywords_unref(struct mailbox *box, - struct mail_keywords **keywords); +void mailbox_keywords_ref(struct mail_keywords *keywords); +void mailbox_keywords_unref(struct mail_keywords **keywords); /* Returns TRUE if keyword is valid, FALSE and error if not. */ bool mailbox_keyword_is_valid(struct mailbox *box, const char *keyword, const char **error_r);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/mailbox-get.c Sat Jan 01 15:59:02 2011 +0200 @@ -0,0 +1,138 @@ +/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "mail-index-modseq.h" +#include "mail-storage-private.h" + +void mailbox_get_seq_range(struct mailbox *box, uint32_t uid1, uint32_t uid2, + uint32_t *seq1_r, uint32_t *seq2_r) +{ + mail_index_lookup_seq_range(box->view, uid1, uid2, seq1_r, seq2_r); +} + +void mailbox_get_uid_range(struct mailbox *box, + const ARRAY_TYPE(seq_range) *seqs, + ARRAY_TYPE(seq_range) *uids) +{ + const struct seq_range *range; + unsigned int i, count; + uint32_t seq, uid; + + range = array_get(seqs, &count); + for (i = 0; i < count; i++) { + if (range[i].seq2 == (uint32_t)-1) { + i_assert(count == i-1); + mail_index_lookup_uid(box->view, range[i].seq1, &uid); + seq_range_array_add_range(uids, uid, (uint32_t)-1); + break; + } + for (seq = range[i].seq1; seq <= range[i].seq2; seq++) { + mail_index_lookup_uid(box->view, seq, &uid); + seq_range_array_add(uids, 0, uid); + } + } +} + +static void +add_expunges(ARRAY_TYPE(mailbox_expunge_rec) *expunges, + const struct mail_transaction_expunge *src, size_t src_size, + const ARRAY_TYPE(seq_range) *uids_filter) +{ + const struct mail_transaction_expunge *end; + struct mailbox_expunge_rec *expunge; + uint32_t uid; + + end = src + src_size / sizeof(*src); + for (; src != end; src++) { + for (uid = src->uid1; uid <= src->uid2; uid++) { + if (seq_range_exists(uids_filter, uid)) { + expunge = array_append_space(expunges); + expunge->uid = uid; + } + } + } +} + +static void +add_guid_expunges(ARRAY_TYPE(mailbox_expunge_rec) *expunges, + const struct mail_transaction_expunge_guid *src, + size_t src_size, const ARRAY_TYPE(seq_range) *uids_filter) +{ + const struct mail_transaction_expunge_guid *end; + struct mailbox_expunge_rec *expunge; + + end = src + src_size / sizeof(*src); + for (; src != end; src++) { + if (seq_range_exists(uids_filter, src->uid)) { + expunge = array_append_space(expunges); + expunge->uid = src->uid; + memcpy(expunge->guid_128, src->guid_128, + sizeof(expunge->guid_128)); + } + } +} + +bool mailbox_get_expunges(struct mailbox *box, uint64_t prev_modseq, + const ARRAY_TYPE(seq_range) *uids_filter, + ARRAY_TYPE(mailbox_expunge_rec) *expunges) +{ + struct mail_transaction_log_view *log_view; + const struct mail_transaction_header *thdr; + const void *tdata; + uint32_t log_seq, tail_seq = 0; + uoff_t log_offset; + bool reset; + int ret; + + if (!mail_index_modseq_get_next_log_offset(box->view, prev_modseq, + &log_seq, &log_offset)) { + log_seq = 1; + log_offset = 0; + } + if (log_seq > box->view->log_file_head_seq || + (log_seq == box->view->log_file_head_seq && + log_offset >= box->view->log_file_head_offset)) { + /* we haven't seen this high expunges at all */ + return TRUE; + } + + log_view = mail_transaction_log_view_open(box->index->log); + ret = mail_transaction_log_view_set(log_view, log_seq, log_offset, + box->view->log_file_head_seq, + box->view->log_file_head_offset, + &reset); + if (ret == 0) { + mail_transaction_log_get_tail(box->index->log, &tail_seq); + i_assert(tail_seq > log_seq); + ret = mail_transaction_log_view_set(log_view, tail_seq, 0, + box->view->log_file_head_seq, + box->view->log_file_head_offset, + &reset); + i_assert(ret != 0); + } + if (ret <= 0) { + mail_transaction_log_view_close(&log_view); + return FALSE; + } + + while ((ret = mail_transaction_log_view_next(log_view, + &thdr, &tdata)) > 0) { + if ((thdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) { + /* skip expunge requests */ + continue; + } + switch (thdr->type & MAIL_TRANSACTION_TYPE_MASK) { + case MAIL_TRANSACTION_EXPUNGE: + add_expunges(expunges, tdata, thdr->size, uids_filter); + break; + case MAIL_TRANSACTION_EXPUNGE_GUID: + add_guid_expunges(expunges, tdata, thdr->size, + uids_filter); + break; + } + } + + mail_transaction_log_view_close(&log_view); + return ret < 0 || tail_seq != 0 ? FALSE : TRUE; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/mailbox-header.c Sat Jan 01 15:59:02 2011 +0200 @@ -0,0 +1,89 @@ +/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mail-cache.h" +#include "mail-storage-private.h" + +#include <stdlib.h> + +static struct mailbox_header_lookup_ctx * +mailbox_header_lookup_init_real(struct mailbox *box, + const char *const headers[]) +{ + struct mail_cache_field *fields, header_field = { + NULL, 0, MAIL_CACHE_FIELD_HEADER, 0, + MAIL_CACHE_DECISION_TEMP + }; + struct mailbox_header_lookup_ctx *ctx; + const char *const *name; + const char **sorted_headers, **dest_name; + pool_t pool; + unsigned int i, count; + + i_assert(*headers != NULL); + + for (count = 0, name = headers; *name != NULL; name++) + count++; + + /* @UNSAFE: headers need to be sorted for filter stream. */ + sorted_headers = t_new(const char *, count); + memcpy(sorted_headers, headers, count * sizeof(*sorted_headers)); + qsort(sorted_headers, count, sizeof(*sorted_headers), i_strcasecmp_p); + headers = sorted_headers; + + /* @UNSAFE */ + fields = t_new(struct mail_cache_field, count); + for (i = 0; i < count; i++) { + header_field.name = t_strconcat("hdr.", headers[i], NULL); + fields[i] = header_field; + } + mail_cache_register_fields(box->cache, fields, count); + + pool = pool_alloconly_create("mailbox_header_lookup_ctx", 1024); + ctx = p_new(pool, struct mailbox_header_lookup_ctx, 1); + ctx->box = box; + ctx->refcount = 1; + ctx->pool = pool; + ctx->count = count; + + ctx->idx = p_new(pool, unsigned int, count); + + /* @UNSAFE */ + dest_name = p_new(pool, const char *, count + 1); + for (i = 0; i < count; i++) { + ctx->idx[i] = fields[i].idx; + dest_name[i] = p_strdup(pool, headers[i]); + } + ctx->name = dest_name; + return ctx; +} + +struct mailbox_header_lookup_ctx * +mailbox_header_lookup_init(struct mailbox *box, const char *const headers[]) +{ + struct mailbox_header_lookup_ctx *ctx; + + T_BEGIN { + ctx = mailbox_header_lookup_init_real(box, headers); + } T_END; + return ctx; +} + +void mailbox_header_lookup_ref(struct mailbox_header_lookup_ctx *ctx) +{ + i_assert(ctx->refcount > 0); + ctx->refcount++; +} + +void mailbox_header_lookup_unref(struct mailbox_header_lookup_ctx **_ctx) +{ + struct mailbox_header_lookup_ctx *ctx = *_ctx; + + *_ctx = NULL; + + i_assert(ctx->refcount > 0); + if (--ctx->refcount > 0) + return; + + pool_unref(&ctx->pool); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/mailbox-keywords.c Sat Jan 01 15:59:02 2011 +0200 @@ -0,0 +1,130 @@ +/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "imap-arg.h" +#include "mail-storage-private.h" + +static struct mail_keywords * +mailbox_keywords_create_skip(struct mailbox *box, + const char *const keywords[]) +{ + struct mail_keywords *kw; + + T_BEGIN { + ARRAY_DEFINE(valid_keywords, const char *); + const char *error; + + t_array_init(&valid_keywords, 32); + for (; *keywords != NULL; keywords++) { + if (mailbox_keyword_is_valid(box, *keywords, &error)) + array_append(&valid_keywords, keywords, 1); + } + (void)array_append_space(&valid_keywords); /* NULL-terminate */ + kw = mail_index_keywords_create(box->index, keywords); + } T_END; + return kw; +} + +static bool +mailbox_keywords_are_valid(struct mailbox *box, const char *const keywords[], + const char **error_r) +{ + unsigned int i; + + for (i = 0; keywords[i] != NULL; i++) { + if (!mailbox_keyword_is_valid(box, keywords[i], error_r)) + return FALSE; + } + return TRUE; +} + +int mailbox_keywords_create(struct mailbox *box, const char *const keywords[], + struct mail_keywords **keywords_r) +{ + const char *error, *empty_keyword_list = NULL; + + i_assert(box->opened); + + if (keywords == NULL) + keywords = &empty_keyword_list; + if (!mailbox_keywords_are_valid(box, keywords, &error)) { + mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, error); + return -1; + } + + *keywords_r = mail_index_keywords_create(box->index, keywords); + return 0; +} + +struct mail_keywords * +mailbox_keywords_create_valid(struct mailbox *box, + const char *const keywords[]) +{ + const char *empty_keyword_list = NULL; + const char *error; + + i_assert(box->opened); + + if (keywords == NULL) + keywords = &empty_keyword_list; + if (mailbox_keywords_are_valid(box, keywords, &error)) + return mail_index_keywords_create(box->index, keywords); + else { + /* found invalid keywords, do this the slow way */ + return mailbox_keywords_create_skip(box, keywords); + } +} + +struct mail_keywords * +mailbox_keywords_create_from_indexes(struct mailbox *box, + const ARRAY_TYPE(keyword_indexes) *idx) +{ + i_assert(box->opened); + + return mail_index_keywords_create_from_indexes(box->index, idx); +} + +void mailbox_keywords_ref(struct mail_keywords *keywords) +{ + mail_index_keywords_ref(keywords); +} + +void mailbox_keywords_unref(struct mail_keywords **keywords) +{ + mail_index_keywords_unref(keywords); +} + +bool mailbox_keyword_is_valid(struct mailbox *box, const char *keyword, + const char **error_r) +{ + unsigned int i, idx; + + i_assert(box->opened); + + /* if it already exists, skip validity checks */ + if (mail_index_keyword_lookup(box->index, keyword, &idx)) + return TRUE; + + if (*keyword == '\0') { + *error_r = "Empty keywords not allowed"; + return FALSE; + } + + /* these are IMAP-specific restrictions, but for now IMAP is all we + care about */ + for (i = 0; keyword[i] != '\0'; i++) { + if (IS_ATOM_SPECIAL((unsigned char)keyword[i])) { + *error_r = "Invalid characters in keyword"; + return FALSE; + } + if ((unsigned char)keyword[i] >= 0x80) { + *error_r = "8bit characters in keyword"; + return FALSE; + } + } + if (i > box->storage->set->mail_max_keyword_length) { + *error_r = "Keyword length too long"; + return FALSE; + } + return TRUE; +}
--- a/src/lib-storage/mailbox-list.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/mailbox-list.c Sat Jan 01 15:59:02 2011 +0200 @@ -490,15 +490,26 @@ { mode_t dir_mode; - if (list->file_create_mode != (mode_t)-1 && name == NULL) { + i_assert(name != NULL); + + mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r, + gid_origin_r); +} + +void mailbox_list_get_root_permissions(struct mailbox_list *list, + mode_t *mode_r, gid_t *gid_r, + const char **gid_origin_r) +{ + mode_t dir_mode; + + if (list->file_create_mode != (mode_t)-1) { *mode_r = list->file_create_mode; *gid_r = list->file_create_gid; *gid_origin_r = list->file_create_gid_origin; - return; + } else { + mailbox_list_get_permissions_full(list, NULL, mode_r, &dir_mode, + gid_r, gid_origin_r); } - - mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r, - gid_origin_r); } void mailbox_list_get_dir_permissions(struct mailbox_list *list, @@ -508,15 +519,26 @@ { mode_t file_mode; - if (list->dir_create_mode != (mode_t)-1 && name == NULL) { + i_assert(name != NULL); + + mailbox_list_get_permissions_full(list, name, &file_mode, + mode_r, gid_r, gid_origin_r); +} + +void mailbox_list_get_root_dir_permissions(struct mailbox_list *list, + mode_t *mode_r, gid_t *gid_r, + const char **gid_origin_r) +{ + mode_t file_mode; + + if (list->dir_create_mode != (mode_t)-1) { *mode_r = list->dir_create_mode; *gid_r = list->file_create_gid; *gid_origin_r = list->file_create_gid_origin; - return; + } else { + mailbox_list_get_permissions_full(list, NULL, &file_mode, + mode_r, gid_r, gid_origin_r); } - - mailbox_list_get_permissions_full(list, name, &file_mode, - mode_r, gid_r, gid_origin_r); } static int @@ -591,7 +613,7 @@ mode_t mode; gid_t gid; - mailbox_list_get_dir_permissions(list, NULL, &mode, &gid, &origin); + mailbox_list_get_root_dir_permissions(list, &mode, &gid, &origin); /* get the directory path up to last %variable. for example unexpanded path may be "/var/mail/%d/%2n/%n/Maildir", and we want @@ -758,8 +780,9 @@ enum mailbox_name_status *status) { if (!mailbox_list_is_valid_existing_name(list, name)) { - *status = MAILBOX_NAME_INVALID; - return 0; + mailbox_list_set_error(list, MAIL_ERROR_PARAMS, + "Invalid mailbox name"); + return -1; } return list->v.get_mailbox_name_status(list, name, status); } @@ -1111,7 +1134,7 @@ path = t_strconcat(path, "/"MAILBOX_LOG_FILE_NAME, NULL); list->changelog = mailbox_log_alloc(path); - mailbox_list_get_permissions(list, NULL, &mode, &gid, &gid_origin); + mailbox_list_get_root_permissions(list, &mode, &gid, &gid_origin); mailbox_log_set_permissions(list->changelog, mode, gid, gid_origin); return TRUE; }
--- a/src/lib-storage/mailbox-list.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/mailbox-list.h Sat Jan 01 15:59:02 2011 +0200 @@ -49,13 +49,11 @@ }; enum mailbox_name_status { + MAILBOX_NAME_NONEXISTENT, /* name points to a selectable mailbox */ MAILBOX_NAME_EXISTS_MAILBOX, /* name points to non-selectable mailbox */ - MAILBOX_NAME_EXISTS_DIR, - MAILBOX_NAME_VALID, - MAILBOX_NAME_INVALID, - MAILBOX_NAME_NOINFERIORS + MAILBOX_NAME_EXISTS_DIR }; enum mailbox_list_iter_flags { @@ -175,18 +173,24 @@ struct mail_storage **storage); /* Returns the mode and GID that should be used when creating new files to - the specified mailbox, or to mailbox list root if name is NULL. (gid_t)-1 is + the specified mailbox or to mailbox list root. (gid_t)-1 is returned if it's not necessary to change the default gid. */ void mailbox_list_get_permissions(struct mailbox_list *list, const char *name, mode_t *mode_r, gid_t *gid_r, const char **gid_origin_r); +void mailbox_list_get_root_permissions(struct mailbox_list *list, + mode_t *mode_r, gid_t *gid_r, + const char **gid_origin_r); /* Like mailbox_list_get_permissions(), but add execute-bits for mode if either read or write bit is set (e.g. 0640 -> 0750). */ void mailbox_list_get_dir_permissions(struct mailbox_list *list, const char *name, mode_t *mode_r, gid_t *gid_r, const char **gid_origin_r); +void mailbox_list_get_root_dir_permissions(struct mailbox_list *list, + mode_t *mode_r, gid_t *gid_r, + const char **gid_origin_r); /* Create path's parent directory with proper permissions. Since most directories are created lazily, this function can be used to easily create them whenever file creation fails with ENOENT. */
--- a/src/lib-storage/mailbox-uidvalidity.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/mailbox-uidvalidity.c Sat Jan 01 15:59:02 2011 +0200 @@ -41,7 +41,7 @@ gid_t gid; const char *gid_origin; - mailbox_list_get_permissions(list, NULL, &mode, &gid, &gid_origin); + mailbox_list_get_root_permissions(list, &mode, &gid, &gid_origin); old_mask = umask(0666 & ~mode); fd = open(path, O_RDWR | O_CREAT, 0666);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/test-mailbox-get.c Sat Jan 01 15:59:02 2011 +0200 @@ -0,0 +1,154 @@ +/* Copyright (c) 2009-2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "test-common.h" +#include "mail-index-modseq.h" +#include "mail-storage-private.h" + +static uint32_t expunge_uids[] = { 25, 15, 7, 3, 11, 1, 53, 33 }; +static uint8_t mail_guids[N_ELEMENTS(expunge_uids)][MAIL_GUID_128_SIZE]; +static unsigned int expunge_idx; +static unsigned int nonexternal_idx; + +void mail_index_lookup_uid(struct mail_index_view *view ATTR_UNUSED, + uint32_t seq, uint32_t *uid_r) +{ + *uid_r = seq; +} + +bool mail_index_lookup_seq_range(struct mail_index_view *view ATTR_UNUSED, + uint32_t first_uid, uint32_t last_uid, + uint32_t *first_seq_r, uint32_t *last_seq_r) +{ + *first_seq_r = first_uid; + *last_seq_r = last_uid; + return TRUE; +} + +bool mail_index_modseq_get_next_log_offset(struct mail_index_view *view ATTR_UNUSED, + uint64_t modseq, uint32_t *log_seq_r, + uoff_t *log_offset_r) +{ + *log_seq_r = modseq >> 32; + *log_offset_r = modseq & 0xfffffff; + return TRUE; +} + +struct mail_transaction_log_view * +mail_transaction_log_view_open(struct mail_transaction_log *log ATTR_UNUSED) { return NULL; } +int mail_transaction_log_view_set(struct mail_transaction_log_view *view ATTR_UNUSED, + uint32_t min_file_seq ATTR_UNUSED, uoff_t min_file_offset ATTR_UNUSED, + uint32_t max_file_seq ATTR_UNUSED, uoff_t max_file_offset ATTR_UNUSED, + bool *reset_r ATTR_UNUSED) { + if (min_file_seq < 99) + return 0; + return 1; +} + +void mail_transaction_log_view_close(struct mail_transaction_log_view **view ATTR_UNUSED) { } + +void mail_transaction_log_get_tail(struct mail_transaction_log *log ATTR_UNUSED, + uint32_t *file_seq_r) +{ + *file_seq_r = 100; +} + +int mail_transaction_log_view_next(struct mail_transaction_log_view *view ATTR_UNUSED, + const struct mail_transaction_header **hdr_r, + const void **data_r) +{ + static struct mail_transaction_header hdr; + static struct mail_transaction_expunge_guid exp; + static struct mail_transaction_expunge old_exp; + + if (expunge_idx == N_ELEMENTS(expunge_uids)) + return 0; + + if (mail_guids[expunge_idx][0] == 0) { + old_exp.uid1 = old_exp.uid2 = expunge_uids[expunge_idx]; + hdr.type = MAIL_TRANSACTION_EXPUNGE; + hdr.size = sizeof(old_exp); + *data_r = &old_exp; + } else { + exp.uid = expunge_uids[expunge_idx]; + memcpy(exp.guid_128, mail_guids[expunge_idx], sizeof(exp.guid_128)); + hdr.type = MAIL_TRANSACTION_EXPUNGE_GUID; + hdr.size = sizeof(exp); + *data_r = &exp; + } + if (expunge_idx != nonexternal_idx) + hdr.type |= MAIL_TRANSACTION_EXTERNAL; + + *hdr_r = &hdr; + expunge_idx++; + return 1; +} + +static void test_index_storage_get_expunges(void) +{ + struct mailbox *box; + ARRAY_TYPE(seq_range) uids_filter; + ARRAY_TYPE(mailbox_expunge_rec) expunges; + const struct mailbox_expunge_rec *exp; + unsigned int i, count; + uint64_t modseq; + + box = t_new(struct mailbox, 1); + box->index = t_new(struct mail_index, 1); + box->view = t_new(struct mail_index_view, 1); + + box->view->log_file_head_seq = 101; + box->view->log_file_head_offset = 1024; + + test_begin("index storage get expunges"); + + nonexternal_idx = 1; + memset(mail_guids + 2, 0, MAIL_GUID_128_SIZE); + memset(mail_guids + 4, 0, MAIL_GUID_128_SIZE); + + t_array_init(&uids_filter, 32); + seq_range_array_add_range(&uids_filter, 1, 20); + seq_range_array_add_range(&uids_filter, 53, 53); + + t_array_init(&expunges, 32); + modseq = 98ULL << 32; + for (i = 0; i < 2; i++) { + test_assert(mailbox_get_expunges(box, modseq, &uids_filter, + &expunges) == i); + + exp = array_get(&expunges, &count); + test_assert(count == 5); + test_assert(exp[0].uid == 7); + test_assert(memcmp(exp[0].guid_128, mail_guids[2], MAIL_GUID_128_SIZE) == 0); + test_assert(exp[1].uid == 3); + test_assert(memcmp(exp[1].guid_128, mail_guids[3], MAIL_GUID_128_SIZE) == 0); + test_assert(exp[2].uid == 11); + test_assert(memcmp(exp[2].guid_128, mail_guids[4], MAIL_GUID_128_SIZE) == 0); + test_assert(exp[3].uid == 1); + test_assert(memcmp(exp[3].guid_128, mail_guids[5], MAIL_GUID_128_SIZE) == 0); + test_assert(exp[4].uid == 53); + test_assert(memcmp(exp[4].guid_128, mail_guids[6], MAIL_GUID_128_SIZE) == 0); + + array_clear(&uids_filter); + expunge_idx = 0; + modseq = 100ULL << 32; + } + + test_end(); +} + +int main(void) +{ + static void (*test_functions[])(void) = { + test_index_storage_get_expunges, + NULL + }; + unsigned int i, j; + + for (i = 0; i < N_ELEMENTS(mail_guids); i++) { + for (j = 0; j < MAIL_GUID_128_SIZE; j++) + mail_guids[i][j] = j + i + 1; + } + return test_run(test_functions); +}
--- a/src/lib-storage/test-mailbox.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib-storage/test-mailbox.c Sat Jan 01 15:59:02 2011 +0200 @@ -68,13 +68,14 @@ return -1; } -static void test_mailbox_get_status(struct mailbox *box ATTR_UNUSED, - enum mailbox_status_items items ATTR_UNUSED, - struct mailbox_status *status_r) +static int test_mailbox_get_status(struct mailbox *box ATTR_UNUSED, + enum mailbox_status_items items ATTR_UNUSED, + struct mailbox_status *status_r) { memset(status_r, 0, sizeof(*status_r)); status_r->uidvalidity = TEST_UID_VALIDITY; status_r->uidnext = 1; + return 0; } static struct mailbox_sync_context * @@ -138,98 +139,6 @@ return 0; } -static void -test_mailbox_transaction_set_max_modseq(struct mailbox_transaction_context *t ATTR_UNUSED, - uint64_t max_modseq ATTR_UNUSED, - ARRAY_TYPE(seq_range) *seqs ATTR_UNUSED) -{ -} - -static int -test_mailbox_keywords_create(struct mailbox *box ATTR_UNUSED, - const char *const keywords[] ATTR_UNUSED, - struct mail_keywords **keywords_r, - bool skip_invalid ATTR_UNUSED) -{ - *keywords_r = i_new(struct mail_keywords, 1); - (*keywords_r)->refcount = 1; - return 0; -} - -static struct mail_keywords * -test_mailbox_keywords_create_from_indexes(struct mailbox *box ATTR_UNUSED, - const ARRAY_TYPE(keyword_indexes) *idx ATTR_UNUSED) -{ - struct mail_keywords *keywords; - - keywords = i_new(struct mail_keywords, 1); - keywords->refcount++; - return keywords; -} - -static void test_mailbox_keywords_ref(struct mail_keywords *keywords) -{ - keywords->refcount++; -} - -static void test_mailbox_keywords_unref(struct mail_keywords *keywords) -{ - if (--keywords->refcount == 0) - i_free(keywords); -} - -static bool -test_mailbox_keyword_is_valid(struct mailbox *box ATTR_UNUSED, - const char *keyword ATTR_UNUSED, - const char **error_r ATTR_UNUSED) -{ - return TRUE; -} - -static void -test_mailbox_get_seq_range(struct mailbox *box ATTR_UNUSED, - uint32_t uid1, uint32_t uid2, - uint32_t *seq1_r, uint32_t *seq2_r) -{ - *seq1_r = uid1; - *seq2_r = uid2; -} - -static void -test_mailbox_get_uid_range(struct mailbox *box ATTR_UNUSED, - const ARRAY_TYPE(seq_range) *seqs, - ARRAY_TYPE(seq_range) *uids) -{ - array_append_array(uids, seqs); -} - -static bool -test_mailbox_get_expunged_uids(struct mailbox *box ATTR_UNUSED, - uint64_t prev_modseq ATTR_UNUSED, - const ARRAY_TYPE(seq_range) *uids_filter ATTR_UNUSED, - ARRAY_TYPE(mailbox_expunge_rec) *expunges ATTR_UNUSED) -{ - return FALSE; -} - -static struct mailbox_header_lookup_ctx * -test_mailbox_header_lookup_init(struct mailbox *box, - const char *const headers[]) -{ - struct mailbox_header_lookup_ctx *ctx; - - ctx = i_new(struct mailbox_header_lookup_ctx, 1); - ctx->box = box; - ctx->headers = headers; /* now exactly right, but .. */ - return ctx; -} - -static void -test_mailbox_header_lookup_deinit(struct mailbox_header_lookup_ctx *ctx) -{ - i_free(ctx); -} - static struct mail_search_context * test_mailbox_search_init(struct mailbox_transaction_context *t, struct mail_search_args *args, @@ -339,21 +248,8 @@ test_mailbox_transaction_begin, test_mailbox_transaction_commit, test_mailbox_transaction_rollback, - test_mailbox_transaction_set_max_modseq, - test_mailbox_keywords_create, - test_mailbox_keywords_create_from_indexes, - test_mailbox_keywords_ref, - test_mailbox_keywords_unref, - test_mailbox_keyword_is_valid, - test_mailbox_get_seq_range, - test_mailbox_get_uid_range, - test_mailbox_get_expunged_uids, - NULL, - NULL, NULL, test_mailbox_mail_alloc, - test_mailbox_header_lookup_init, - test_mailbox_header_lookup_deinit, test_mailbox_search_init, test_mailbox_search_deinit, test_mailbox_search_next_nonblock, @@ -364,7 +260,6 @@ test_mailbox_save_finish, test_mailbox_save_cancel, test_mailbox_copy, - NULL, test_mailbox_is_inconsistent } };
--- a/src/lib/lib.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib/lib.c Sat Jan 01 15:59:02 2011 +0200 @@ -13,7 +13,7 @@ { size_t n = 1; - i_assert(num <= ((size_t)1 << (BITS_IN_SIZE_T-1))); + i_assert(num <= ((size_t)1 << (CHAR_BIT*sizeof(size_t) - 1))); while (n < num) n <<= 1; return n;
--- a/src/lib/macros.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/lib/macros.h Sat Jan 01 15:59:02 2011 +0200 @@ -18,9 +18,6 @@ #define N_ELEMENTS(arr) \ (sizeof(arr) / sizeof((arr)[0])) -#define BITS_IN_UINT (CHAR_BIT * sizeof(unsigned int)) -#define BITS_IN_SIZE_T (CHAR_BIT * sizeof(size_t)) - #define MEM_ALIGN(size) \ (((size) + MEM_ALIGN_SIZE-1) & ~((unsigned int) MEM_ALIGN_SIZE-1)) @@ -34,13 +31,6 @@ #define I_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define I_MAX(a, b) (((a) > (b)) ? (a) : (b)) -#undef CLAMP -#define CLAMP(x, low, high) \ - (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) - -#undef NVL -#define NVL(str, nullstr) ((str) != NULL ? (str) : (nullstr)) - /* make it easier to cast from/to pointers. assumes that sizeof(size_t) == sizeof(void *) and they're both the largest datatypes that are allowed to be used. so, long long isn't safe with these. */
--- a/src/plugins/acl/acl-backend-vfile-acllist.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/acl/acl-backend-vfile-acllist.c Sat Jan 01 15:59:02 2011 +0200 @@ -228,7 +228,7 @@ /* Build it into a temporary file and rename() over. There's no need to use locking, because even if multiple processes are rebuilding the file at the same time the result should be the same. */ - mailbox_list_get_permissions(list, NULL, &mode, &gid, &origin); + mailbox_list_get_root_permissions(list, &mode, &gid, &origin); fd = safe_mkstemp_group(path, mode, gid, origin); if (fd == -1 && errno == ENOENT) { if (mailbox_list_create_parent_dir(backend->backend.list, NULL,
--- a/src/plugins/acl/acl-mailbox-list.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/acl/acl-mailbox-list.c Sat Jan 01 15:59:02 2011 +0200 @@ -407,11 +407,12 @@ return ret; } -static int acl_mailbox_have_any_rights(struct acl_mailbox_list *alist, - const char *name) +static int acl_mailbox_have_visibility_rights(struct acl_mailbox_list *alist, + const char *name) { struct acl_object *aclobj; const char *const *rights; + unsigned int i; int ret; aclobj = acl_object_init_from_name(alist->rights.backend, name); @@ -419,8 +420,21 @@ &rights); acl_object_deinit(&aclobj); - return ret < 0 ? -1 : - (*rights == NULL ? 0 : 1); + if (ret < 0) + return -1; + + /* for now this is used only by IMAP SUBSCRIBE. we'll intentionally + violate RFC 4314 here, because it says SUBSCRIBE should succeed only + when mailbox has 'l' right. But there's no point in not allowing + a subscribe for a mailbox that can be selected anyway. Just the + opposite: subscribing to such mailboxes is a very useful feature. */ + for (i = 0; rights[i] != NULL; i++) { + if (strcmp(rights[i], MAIL_ACL_LOOKUP) == 0 || + strcmp(rights[i], MAIL_ACL_READ) == 0 || + strcmp(rights[i], MAIL_ACL_INSERT) == 0) + return 1; + } + return 0; } static int acl_get_mailbox_name_status(struct mailbox_list *list, @@ -431,7 +445,7 @@ int ret; T_BEGIN { - ret = acl_mailbox_have_any_rights(alist, name); + ret = acl_mailbox_have_visibility_rights(alist, name); } T_END; if (ret < 0) return -1; @@ -439,34 +453,9 @@ if (alist->module_ctx.super.get_mailbox_name_status(list, name, status) < 0) return -1; - if (ret > 0) - return 0; - - /* we shouldn't reveal this mailbox's existance */ - switch (*status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - *status = MAILBOX_NAME_VALID; - break; - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - break; - case MAILBOX_NAME_NOINFERIORS: - /* have to check if we are allowed to see the parent */ - T_BEGIN { - ret = acl_mailbox_list_have_right(list, name, - TRUE, ACL_STORAGE_RIGHT_LOOKUP, NULL); - } T_END; - - if (ret < 0) { - mailbox_list_set_internal_error(list); - return -1; - } - if (ret == 0) { - /* no permission to see the parent */ - *status = MAILBOX_NAME_VALID; - } - break; + if (ret == 0) { + /* we shouldn't reveal this mailbox's existance */ + *status = MAILBOX_NAME_NONEXISTENT; } return 0; }
--- a/src/plugins/acl/acl-mailbox.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/acl/acl-mailbox.c Sat Jan 01 15:59:02 2011 +0200 @@ -64,6 +64,7 @@ { struct acl_mailbox *abox = ACL_CONTEXT(box); enum acl_storage_rights save_right; + enum mail_flags private_flags_mask; if (abox->module_ctx.super.is_readonly(box)) return TRUE; @@ -78,10 +79,12 @@ /* Next up is the "shared flag rights" */ if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE) > 0) return FALSE; - if ((box->private_flags_mask & MAIL_DELETED) == 0 && + + private_flags_mask = mailbox_get_private_flags_mask(box); + if ((private_flags_mask & MAIL_DELETED) == 0 && acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_DELETED) > 0) return FALSE; - if ((box->private_flags_mask & MAIL_SEEN) == 0 && + if ((private_flags_mask & MAIL_SEEN) == 0 && acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE_SEEN) > 0) return FALSE; @@ -425,35 +428,6 @@ return abox->module_ctx.super.transaction_commit(ctx, changes_r); } -static int -acl_keywords_create(struct mailbox *box, const char *const keywords[], - struct mail_keywords **keywords_r, bool skip_invalid) -{ - struct acl_mailbox *abox = ACL_CONTEXT(box); - int ret; - - ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_WRITE); - if (ret < 0) { - if (!skip_invalid) - return -1; - /* we can't return failure. assume we don't have permissions. */ - ret = 0; - } - - if (ret == 0) { - /* no permission to update any flags. just return empty - keywords list. */ - const char *null = NULL; - - return abox->module_ctx.super.keywords_create(box, &null, - keywords_r, - skip_invalid); - } - - return abox->module_ctx.super.keywords_create(box, keywords, - keywords_r, skip_invalid); -} - static int acl_mailbox_open_check_acl(struct mailbox *box) { struct acl_mailbox *abox = ACL_CONTEXT(box); @@ -526,7 +500,6 @@ v->delete = acl_mailbox_delete; v->rename = acl_mailbox_rename; v->save_begin = acl_save_begin; - v->keywords_create = acl_keywords_create; v->copy = acl_copy; v->transaction_commit = acl_transaction_commit; }
--- a/src/plugins/fts-solr/fts-backend-solr.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/fts-solr/fts-backend-solr.c Sat Jan 01 15:59:02 2011 +0200 @@ -7,6 +7,7 @@ #include "unichar.h" #include "mail-storage-private.h" #include "mail-namespace.h" +#include "fts-mailbox.h" #include "solr-connection.h" #include "fts-solr-plugin.h" @@ -297,7 +298,7 @@ box_name = fts_box_get_root(box, &ns); - mailbox_get_status(box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status); str_printfa(str, "uidv:%u+box:", status.uidvalidity); solr_quote_http(str, box_name); solr_add_ns_query_http(str, backend, ns); @@ -339,7 +340,7 @@ box_name = fts_box_get_root(box, &ns); - mailbox_get_status(box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status); str_printfa(str, "uidv:%u+box:", status.uidvalidity); solr_quote_http(str, box_name); solr_add_ns_query_http(str, backend, ns); @@ -452,7 +453,7 @@ t_array_init(&includes_arr, 16); t_array_init(&excludes_arr, 16); - mailbox_get_virtual_box_patterns(box, &includes_arr, &excludes_arr); + fts_mailbox_get_virtual_box_patterns(box, &includes_arr, &excludes_arr); includes = array_get(&includes_arr, &inc_count); excludes = array_get(&excludes_arr, &exc_count); i_assert(inc_count > 0); @@ -538,7 +539,7 @@ ctx->ctx.backend = backend; ctx->cmd = str_new(default_pool, SOLR_CMDBUF_SIZE); - mailbox_get_status(backend->box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(backend->box, STATUS_UIDVALIDITY, &status); ctx->uid_validity = status.uidvalidity; *ctx_r = &ctx->ctx; @@ -736,7 +737,7 @@ { struct mailbox_status status; - mailbox_get_status(mail->box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(mail->box, STATUS_UIDVALIDITY, &status); T_BEGIN { string_t *cmd; @@ -783,8 +784,8 @@ for (; ns != NULL; ns = ns->alias_chain_next) { vname = convert_inbox ? ns->prefix : mail_namespace_get_vname(ns, ctx->vname, mailbox); - if (mailbox_get_virtual_uid(ctx->box, vname, uidvalidity, - *uid, uid)) + if (fts_mailbox_get_virtual_uid(ctx->box, vname, uidvalidity, + *uid, uid)) return TRUE; } return FALSE; @@ -806,7 +807,7 @@ bool virtual; virtual = strcmp(box->storage->name, "virtual") == 0; - mailbox_get_status(box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status); str = t_str_new(256); if (!virtual) {
--- a/src/plugins/fts-squat/fts-backend-squat.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/fts-squat/fts-backend-squat.c Sat Jan 01 15:59:02 2011 +0200 @@ -52,6 +52,7 @@ static struct fts_backend *fts_backend_squat_init(struct mailbox *box) { + const struct mailbox_permissions *perm = mailbox_get_permissions(box); struct squat_fts_backend *backend; struct mail_storage *storage; struct mailbox_status status; @@ -68,7 +69,7 @@ return NULL; } - mailbox_get_status(box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status); if (storage->set->mmap_disable) flags |= SQUAT_INDEX_FLAG_MMAP_DISABLE; if (storage->set->mail_nfs_index) @@ -82,8 +83,8 @@ squat_trie_init(t_strconcat(path, "/"SQUAT_FILE_PREFIX, NULL), status.uidvalidity, storage->set->parsed_lock_method, - flags, box->file_create_mode, - box->file_create_gid); + flags, perm->file_create_mode, + perm->file_create_gid); env = mail_user_plugin_getenv(box->storage->user, "fts_squat"); if (env != NULL)
--- a/src/plugins/fts/Makefile.am Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/fts/Makefile.am Sat Jan 01 15:59:02 2011 +0200 @@ -3,7 +3,8 @@ -I$(top_srcdir)/src/lib-charset \ -I$(top_srcdir)/src/lib-mail \ -I$(top_srcdir)/src/lib-index \ - -I$(top_srcdir)/src/lib-storage + -I$(top_srcdir)/src/lib-storage \ + -I$(top_srcdir)/src/lib-storage/index lib20_fts_plugin_la_LDFLAGS = -module -avoid-version @@ -12,6 +13,7 @@ lib20_fts_plugin_la_SOURCES = \ fts-api.c \ + fts-mailbox.c \ fts-plugin.c \ fts-search.c \ fts-storage.c @@ -19,5 +21,6 @@ noinst_HEADERS = \ fts-api.h \ fts-api-private.h \ + fts-mailbox.h \ fts-plugin.h \ fts-storage.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/fts/fts-mailbox.c Sat Jan 01 15:59:02 2011 +0200 @@ -0,0 +1,56 @@ +/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mail-storage.h" +#include "fts-mailbox.h" +#include "../virtual/virtual-storage.h" + +bool fts_mailbox_get_virtual_uid(struct mailbox *box, + const char *backend_mailbox, + uint32_t backend_uidvalidity, + uint32_t backend_uid, uint32_t *uid_r) +{ + struct virtual_mailbox *vbox; + + if (strcmp(box->storage->name, VIRTUAL_STORAGE_NAME) != 0) + return FALSE; + + vbox = (struct virtual_mailbox *)box; + return vbox->vfuncs.get_virtual_uid(box, backend_mailbox, + backend_uidvalidity, + backend_uid, uid_r); +} + +void fts_mailbox_get_virtual_backend_boxes(struct mailbox *box, + ARRAY_TYPE(mailboxes) *mailboxes, + bool only_with_msgs) +{ + struct virtual_mailbox *vbox; + + if (strcmp(box->storage->name, VIRTUAL_STORAGE_NAME) != 0) + array_append(mailboxes, &box, 1); + else { + vbox = (struct virtual_mailbox *)box; + vbox->vfuncs.get_virtual_backend_boxes(box, mailboxes, + only_with_msgs); + } +} + +void fts_mailbox_get_virtual_box_patterns(struct mailbox *box, + ARRAY_TYPE(mailbox_virtual_patterns) *includes, + ARRAY_TYPE(mailbox_virtual_patterns) *excludes) +{ + struct virtual_mailbox *vbox; + + if (strcmp(box->storage->name, VIRTUAL_STORAGE_NAME) != 0) { + struct mailbox_virtual_pattern pat; + + memset(&pat, 0, sizeof(pat)); + pat.ns = mailbox_list_get_namespace(box->list); + pat.pattern = box->name; + array_append(includes, &pat, 1); + } else { + vbox = (struct virtual_mailbox *)box; + vbox->vfuncs.get_virtual_box_patterns(box, includes, excludes); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/fts/fts-mailbox.h Sat Jan 01 15:59:02 2011 +0200 @@ -0,0 +1,22 @@ +#ifndef FTS_MAILBOX_H +#define FTS_MAILBOX_H + +/* If box is a virtual mailbox, look up UID for the given backend message. + Returns TRUE if found, FALSE if not. */ +bool fts_mailbox_get_virtual_uid(struct mailbox *box, + const char *backend_mailbox, + uint32_t backend_uidvalidity, + uint32_t backend_uid, uint32_t *uid_r); +/* If box is a virtual mailbox, return all backend mailboxes. If + only_with_msgs=TRUE, return only those mailboxes that have at least one + message existing in the virtual mailbox. */ +void fts_mailbox_get_virtual_backend_boxes(struct mailbox *box, + ARRAY_TYPE(mailboxes) *mailboxes, + bool only_with_msgs); +/* If mailbox is a virtual mailbox, return all mailbox list patterns that + are used to figure out which mailboxes belong to the virtual mailbox. */ +void fts_mailbox_get_virtual_box_patterns(struct mailbox *box, + ARRAY_TYPE(mailbox_virtual_patterns) *includes, + ARRAY_TYPE(mailbox_virtual_patterns) *excludes); + +#endif
--- a/src/plugins/fts/fts-storage.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/fts/fts-storage.c Sat Jan 01 15:59:02 2011 +0200 @@ -13,6 +13,7 @@ #include "mail-search-build.h" #include "mail-storage-private.h" #include "fts-api-private.h" +#include "fts-mailbox.h" #include "fts-storage.h" #include "fts-plugin.h" @@ -395,8 +396,8 @@ ret = strcmp(vname, last_uids[uidi].mailbox); if (ret == 0) { /* match. check also that uidvalidity matches. */ - mailbox_get_status(boxes[boxi].box, STATUS_UIDVALIDITY, - &status); + mailbox_get_open_status(boxes[boxi].box, + STATUS_UIDVALIDITY, &status); if (status.uidvalidity != last_uids[uidi].uidvalidity) { uidi++; continue; @@ -453,7 +454,7 @@ int ret; t_array_init(&mailboxes, 64); - mailbox_get_virtual_backend_boxes(fctx->t->box, &mailboxes, TRUE); + fts_mailbox_get_virtual_backend_boxes(fctx->t->box, &mailboxes, TRUE); boxes = array_get_modifiable(&mailboxes, &box_count); vctx->pool = pool_alloconly_create("fts virtual build", 1024); @@ -500,8 +501,8 @@ struct mailbox_status status; int ret; - mailbox_get_status(fctx->t->box, STATUS_MESSAGES | STATUS_UIDNEXT, - &status); + mailbox_get_open_status(fctx->t->box, STATUS_MESSAGES | STATUS_UIDNEXT, + &status); if (status.messages == fctx->fbox->last_messages_count && status.uidnext == fctx->fbox->last_uidnext) { /* no new messages since last check */ @@ -539,8 +540,8 @@ ret = -1; if (ret == 0) { - mailbox_get_status(box, STATUS_MESSAGES | STATUS_UIDNEXT, - &status); + mailbox_get_open_status(box, STATUS_MESSAGES | STATUS_UIDNEXT, + &status); fbox->last_messages_count = status.messages; fbox->last_uidnext = status.uidnext; } @@ -777,7 +778,8 @@ struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box); struct mailbox_status status; - mailbox_get_status(ctx->transaction->box, STATUS_MESSAGES, &status); + mailbox_get_open_status(ctx->transaction->box, + STATUS_MESSAGES, &status); fctx->seqs_set = FALSE; ctx->seq = fctx->first_nonindexed_seq - 1;
--- a/src/plugins/imap-acl/imap-acl-plugin.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/imap-acl/imap-acl-plugin.c Sat Jan 01 15:59:02 2011 +0200 @@ -58,7 +58,6 @@ struct mail_namespace *ns; struct mailbox *box; const char *storage_name; - enum mailbox_name_status status; int ret; if (ACL_USER_CONTEXT(cmd->client->user) == NULL) { @@ -66,19 +65,10 @@ return NULL; } - ns = client_find_namespace(cmd, name, &storage_name, &status); + ns = client_find_namespace(cmd, name, &storage_name); if (ns == NULL) return NULL; - switch (status) { - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_VALID: - client_fail_mailbox_name_status(cmd, name, NULL, status); - return NULL; - default: - break; - } - /* Force opening the mailbox so that we can give a nicer error message if mailbox isn't selectable but is listable. */ box = mailbox_alloc(ns->list, storage_name, ACL_MAILBOX_FLAGS | @@ -330,7 +320,7 @@ return TRUE; } - ns = client_find_namespace(cmd, mailbox, &storage_name, NULL); + ns = client_find_namespace(cmd, mailbox, &storage_name); if (ns == NULL) return TRUE;
--- a/src/plugins/imap-quota/imap-quota-plugin.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/imap-quota/imap-quota-plugin.c Sat Jan 01 15:59:02 2011 +0200 @@ -81,7 +81,7 @@ if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; - ns = client_find_namespace(cmd, mailbox, &storage_name, NULL); + ns = client_find_namespace(cmd, mailbox, &storage_name); if (ns == NULL) return TRUE;
--- a/src/plugins/lazy-expunge/lazy-expunge-plugin.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/lazy-expunge/lazy-expunge-plugin.c Sat Jan 01 15:59:02 2011 +0200 @@ -242,7 +242,7 @@ int ret; /* make sure the destination root directory exists */ - mailbox_list_get_dir_permissions(dest_list, NULL, &mode, &gid, &origin); + mailbox_list_get_root_dir_permissions(dest_list, &mode, &gid, &origin); dir = mailbox_list_get_path(dest_list, NULL, MAILBOX_LIST_PATH_TYPE_DIR); if (mkdir_parents_chgrp(dir, mode, gid, origin) < 0 && errno != EEXIST) {
--- a/src/plugins/quota/quota-maildir.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/quota/quota-maildir.c Sat Jan 01 15:59:02 2011 +0200 @@ -236,16 +236,15 @@ namespaces = array_get(&root->root.quota->namespaces, &count); i_assert(count > 0); for (i = 0; i < count; i++) { - if ((namespaces[i]->flags & NAMESPACE_FLAG_INBOX_USER) != 0) { - mailbox_list_get_permissions(namespaces[i]->list, - NULL, &mode, &gid, - &gid_origin); - mailbox_list_get_dir_permissions(namespaces[i]->list, - NULL, - &dir_mode, &dir_gid, - &dir_gid_origin); - break; - } + if ((namespaces[i]->flags & NAMESPACE_FLAG_INBOX_USER) == 0) + continue; + + mailbox_list_get_root_permissions(namespaces[i]->list, + &mode, &gid, &gid_origin); + mailbox_list_get_root_dir_permissions(namespaces[i]->list, + &dir_mode, &dir_gid, + &dir_gid_origin); + break; } dotlock_settings.use_excl_lock = set->dotlock_use_excl;
--- a/src/plugins/virtual/virtual-config.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/virtual/virtual-config.c Sat Jan 01 15:59:02 2011 +0200 @@ -327,23 +327,24 @@ struct mail_storage *storage = mbox->box.storage; struct virtual_parse_context ctx; struct stat st; - const char *path, *line, *error; + const char *box_path, *path, *line, *error; unsigned int linenum = 0; int fd, ret = 0; i_array_init(&mbox->backend_boxes, 8); mbox->search_args_crc32 = (uint32_t)-1; - path = t_strconcat(mbox->box.path, "/"VIRTUAL_CONFIG_FNAME, NULL); + box_path = mailbox_get_path(&mbox->box); + path = t_strconcat(box_path, "/"VIRTUAL_CONFIG_FNAME, NULL); fd = open(path, O_RDONLY); if (fd == -1) { if (errno == EACCES) { mail_storage_set_critical(storage, "%s", - mail_error_eacces_msg("stat", mbox->box.path)); + mail_error_eacces_msg("open", path)); } else if (errno != ENOENT) { mail_storage_set_critical(storage, "open(%s) failed: %m", path); - } else if (stat(mbox->box.path, &st) == 0) { + } else if (stat(box_path, &st) == 0) { mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE, "Virtual mailbox missing configuration file"); } else if (errno == ENOENT) { @@ -351,7 +352,7 @@ T_MAIL_ERR_MAILBOX_NOT_FOUND(mbox->box.name)); } else { mail_storage_set_critical(storage, - "stat(%s) failed: %m", mbox->box.path); + "stat(%s) failed: %m", box_path); } return -1; }
--- a/src/plugins/virtual/virtual-mail.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/virtual/virtual-mail.c Sat Jan 01 15:59:02 2011 +0200 @@ -42,7 +42,6 @@ vmail->imail.data_pool = pool_alloconly_create("virtual index_mail", 512); vmail->imail.ibox = INDEX_STORAGE_CONTEXT(t->box); - vmail->imail.trans = (struct index_transaction_context *)t; vmail->wanted_fields = wanted_fields; if (wanted_headers != NULL) { @@ -98,7 +97,7 @@ backend_headers = vmail->wanted_headers == NULL ? NULL : mailbox_header_lookup_init(bbox->box, - vmail->wanted_headers->headers); + vmail->wanted_headers->name); vmail->backend_mail = mail_alloc(backend_trans, vmail->wanted_fields, backend_headers); if (backend_headers != NULL) @@ -302,7 +301,7 @@ return -1; backend_headers = mailbox_header_lookup_init(vmail->backend_mail->box, - headers->headers); + headers->name); ret = mail_get_header_stream(vmail->backend_mail, backend_headers, stream_r); mailbox_header_lookup_unref(&backend_headers);
--- a/src/plugins/virtual/virtual-save.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/virtual/virtual-save.c Sat Jan 01 15:59:02 2011 +0200 @@ -25,7 +25,7 @@ return _t->save_ctx; ctx = i_new(struct virtual_save_context, 1); - ctx->ctx.transaction = &t->ictx.mailbox_ctx; + ctx->ctx.transaction = &t->t; if (mbox->save_bbox != NULL) { backend_trans = @@ -50,7 +50,7 @@ return NULL; t_array_init(&kw_strings, src_keywords->count + 1); - mailbox_get_status(src_box, STATUS_KEYWORDS, &status); + mailbox_get_open_status(src_box, STATUS_KEYWORDS, &status); for (i = 0; i < src_keywords->count; i++) { kwp = array_idx(status.keywords, src_keywords->idx[i]); @@ -125,7 +125,7 @@ struct virtual_save_context *ctx = (struct virtual_save_context *)_ctx; if (ctx->backend_keywords != NULL) - mailbox_keywords_unref(ctx->backend_box, &ctx->backend_keywords); + mailbox_keywords_unref(&ctx->backend_keywords); if (ctx->backend_save_ctx != NULL) mailbox_save_cancel(&ctx->backend_save_ctx); i_free(ctx);
--- a/src/plugins/virtual/virtual-storage.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/virtual/virtual-storage.c Sat Jan 01 15:59:02 2011 +0200 @@ -29,6 +29,7 @@ extern struct mail_storage virtual_storage; extern struct mailbox virtual_mailbox; +extern struct virtual_mailbox_vfuncs virtual_mailbox_vfuncs; struct virtual_storage_module virtual_storage_module = MODULE_CONTEXT_INIT(&mail_storage_module_register); @@ -234,6 +235,7 @@ mbox->box.storage = _storage; mbox->box.list = list; mbox->box.mail_vfuncs = &virtual_mail_vfuncs; + mbox->vfuncs = virtual_mailbox_vfuncs; index_storage_mailbox_alloc(&mbox->box, name, flags, VIRTUAL_INDEX_PREFIX); @@ -333,12 +335,16 @@ } static int -virtual_mailbox_get_guid(struct mailbox *box, - uint8_t guid[MAIL_GUID_128_SIZE] ATTR_UNUSED) +virtual_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) { - mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE, - "Virtual mailboxes have no GUIDs"); - return -1; + if ((items & MAILBOX_METADATA_GUID) != 0) { + mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE, + "Virtual mailboxes have no GUIDs"); + return -1; + } + return index_mailbox_get_metadata(box, items, metadata_r); } static void @@ -435,7 +441,7 @@ if (bbox == NULL) return FALSE; - mailbox_get_status(bbox->box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(bbox->box, STATUS_UIDVALIDITY, &status); if (status.uidvalidity != backend_uidvalidity) return FALSE; @@ -515,7 +521,7 @@ index_storage_mailbox_delete, index_storage_mailbox_rename, index_storage_get_status, - virtual_mailbox_get_guid, + virtual_mailbox_get_metadata, NULL, NULL, virtual_storage_sync_init, @@ -526,21 +532,8 @@ virtual_transaction_begin, virtual_transaction_commit, virtual_transaction_rollback, - index_transaction_set_max_modseq, - index_keywords_create, - index_keywords_create_from_indexes, - index_keywords_ref, - index_keywords_unref, - index_keyword_is_valid, - index_storage_get_seq_range, - index_storage_get_uid_range, - index_storage_get_expunges, - virtual_get_virtual_uid, - virtual_get_virtual_backend_boxes, - virtual_get_virtual_box_patterns, + NULL, virtual_mail_alloc, - index_header_lookup_init, - index_header_lookup_deinit, virtual_search_init, virtual_search_deinit, virtual_search_next_nonblock, @@ -551,7 +544,12 @@ virtual_save_finish, virtual_save_cancel, mail_storage_copy, - NULL, virtual_is_inconsistent } }; + +struct virtual_mailbox_vfuncs virtual_mailbox_vfuncs = { + virtual_get_virtual_uid, + virtual_get_virtual_backend_boxes, + virtual_get_virtual_box_patterns +};
--- a/src/plugins/virtual/virtual-storage.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/virtual/virtual-storage.h Sat Jan 01 15:59:02 2011 +0200 @@ -99,6 +99,19 @@ }; ARRAY_DEFINE_TYPE(virtual_backend_box, struct virtual_backend_box *); +struct virtual_mailbox_vfuncs { + bool (*get_virtual_uid)(struct mailbox *box, + const char *backend_mailbox, + uint32_t backend_uidvalidity, + uint32_t backend_uid, uint32_t *uid_r); + void (*get_virtual_backend_boxes)(struct mailbox *box, + ARRAY_TYPE(mailboxes) *mailboxes, + bool only_with_msgs); + void (*get_virtual_box_patterns)(struct mailbox *box, + ARRAY_TYPE(mailbox_virtual_patterns) *includes, + ARRAY_TYPE(mailbox_virtual_patterns) *excludes); +}; + struct virtual_mailbox { struct mailbox box; struct virtual_storage *storage; @@ -122,6 +135,8 @@ ARRAY_TYPE(mailbox_virtual_patterns) list_include_patterns; ARRAY_TYPE(mailbox_virtual_patterns) list_exclude_patterns; + struct virtual_mailbox_vfuncs vfuncs; + unsigned int uids_mapped:1; unsigned int sync_initialized:1; unsigned int inconsistent:1;
--- a/src/plugins/virtual/virtual-sync.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/virtual/virtual-sync.c Sat Jan 01 15:59:02 2011 +0200 @@ -148,6 +148,7 @@ static int virtual_sync_ext_header_read(struct virtual_sync_context *ctx) { + const char *box_path = mailbox_get_path(&ctx->mbox->box); const struct virtual_mail_index_header *ext_hdr; const struct mail_index_header *hdr; const struct virtual_mail_index_mailbox_record *mailboxes; @@ -184,7 +185,7 @@ if (ext_name_offset >= ext_size || ext_hdr->mailbox_count > INT_MAX/sizeof(*mailboxes)) { i_error("virtual index %s: Broken mailbox_count header", - ctx->mbox->box.path); + box_path); ctx->index_broken = TRUE; ext_mailbox_count = 0; ret = 0; @@ -199,18 +200,18 @@ if (mailboxes[i].id > ext_hdr->highest_mailbox_id || mailboxes[i].id <= prev_mailbox_id) { i_error("virtual index %s: Broken mailbox id", - ctx->mbox->box.path); + box_path); break; } if (mailboxes[i].name_len == 0 || mailboxes[i].name_len > ext_size) { i_error("virtual index %s: Broken mailbox name_len", - ctx->mbox->box.path); + box_path); break; } if (ext_name_offset + mailboxes[i].name_len > ext_size) { i_error("virtual index %s: Broken mailbox list", - ctx->mbox->box.path); + box_path); break; } T_BEGIN { @@ -405,7 +406,7 @@ MODIFY_ADD : MODIFY_REMOVE; mail_update_keywords(bbox->sync_mail, modify_type, keywords); - mailbox_keywords_unref(bbox->box, &keywords); + mailbox_keywords_unref(&keywords); break; case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET: kw_names[0] = NULL; @@ -413,7 +414,7 @@ kw_names); mail_update_keywords(bbox->sync_mail, MODIFY_REPLACE, keywords); - mailbox_keywords_unref(bbox->box, &keywords); + mailbox_keywords_unref(&keywords); break; case MAIL_INDEX_SYNC_TYPE_APPEND: i_unreached(); @@ -985,8 +986,8 @@ unsigned int mailbox_offset; uint64_t wanted_ondisk_highest_modseq; - mailbox_get_status(bbox->box, STATUS_UIDVALIDITY | - STATUS_HIGHESTMODSEQ, &status); + mailbox_get_open_status(bbox->box, STATUS_UIDVALIDITY | + STATUS_HIGHESTMODSEQ, &status); wanted_ondisk_highest_modseq = array_count(&bbox->sync_pending_removes) > 0 ? 0 : status.highest_modseq; @@ -1052,7 +1053,7 @@ if (mailbox_sync(bbox->box, sync_flags) < 0) return -1; - mailbox_get_status(bbox->box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(bbox->box, STATUS_UIDVALIDITY, &status); virtual_backend_box_sync_mail_set(bbox); if (status.uidvalidity != bbox->sync_uid_validity) { /* UID validity changed since last sync (or this is @@ -1444,7 +1445,7 @@ if (mail_index_unlink(ctx->index) < 0) { i_error("virtual index %s: Failed to unlink() " "broken indexes: %m", - ctx->mbox->box.path); + mailbox_get_path(&ctx->mbox->box)); } } mail_index_sync_rollback(&ctx->index_sync_ctx);
--- a/src/plugins/virtual/virtual-transaction.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/virtual/virtual-transaction.c Sat Jan 01 15:59:02 2011 +0200 @@ -35,8 +35,8 @@ vt = i_new(struct virtual_transaction_context, 1); i_array_init(&vt->backend_transactions, array_count(&mbox->backend_boxes)); - index_transaction_init(&vt->ictx, box, flags); - return &vt->ictx.mailbox_ctx; + index_transaction_init(&vt->t, box, flags); + return &vt->t; } int virtual_transaction_commit(struct mailbox_transaction_context *t,
--- a/src/plugins/virtual/virtual-transaction.h Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/virtual/virtual-transaction.h Sat Jan 01 15:59:02 2011 +0200 @@ -4,7 +4,7 @@ #include "index-storage.h" struct virtual_transaction_context { - struct index_transaction_context ictx; + struct mailbox_transaction_context t; ARRAY_DEFINE(backend_transactions, struct mailbox_transaction_context *);
--- a/src/plugins/zlib/zlib-plugin.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/plugins/zlib/zlib-plugin.c Sat Jan 01 15:59:02 2011 +0200 @@ -310,14 +310,16 @@ if (mail_storage_is_mailbox_file(box->storage)) { /* looks like a compressed single file mailbox. we should be able to handle this. */ - fd = open(box->path, O_RDONLY); + const char *box_path = mailbox_get_path(box); + + fd = open(box_path, O_RDONLY); if (fd == -1) { mail_storage_set_critical(box->storage, - "open(%s) failed: %m", box->path); + "open(%s) failed: %m", box_path); return -1; } input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE); - i_stream_set_name(input, box->path); + i_stream_set_name(input, box_path); box->input = handler->create_istream(input, TRUE); i_stream_unref(&input); box->flags |= MAILBOX_FLAG_READONLY;
--- a/src/pop3/pop3-client.c Sat Jan 01 14:34:14 2011 +0200 +++ b/src/pop3/pop3-client.c Sat Jan 01 15:59:02 2011 +0200 @@ -116,7 +116,7 @@ *failed_uid_r = 0; - mailbox_get_status(client->mailbox, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(client->mailbox, STATUS_UIDVALIDITY, &status); client->uid_validity = status.uidvalidity; client->messages_count = status.messages;