index-mailbox-list.c revision 7761758f43d6150be4b07f4c54457ce662f78c4c
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (C) 2006-2007 Timo Sirainen */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen/* min 2 seconds */
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenstruct index_mailbox_list_module index_mailbox_list_module =
d22301419109ed4a38351715e6760011421dadecTimo Sirainen MODULE_CONTEXT_INIT(&mailbox_list_module_register);
d22301419109ed4a38351715e6760011421dadecTimo Sirainenstatic void (*index_next_hook_mailbox_list_created)(struct mailbox_list *list);
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainenindex_mailbox_view_sync(struct index_mailbox_list_iterate_context *ctx)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (mail_index_view_sync_begin(ctx->mail_view, 0,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mailbox_list_set_internal_error(ctx->ctx.list);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen while ((ret = mail_index_view_sync_next(sync_ctx, &sync_rec)) > 0) ;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenindex_mailbox_list_is_synced(struct index_mailbox_list_iterate_context *ctx)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen const char *path = ctx->ctx.list->set.root_dir;
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen /* FIXME: single sync_stamp works only with maildir++ */
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen if mtime is older than 2 secs, we set the first bit on
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if mtime is 0-2 secs old, we set the first bit off.
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen this way we'll always do a resync later when syncing a recently
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen changed directory. if the directory changes while we're syncing it
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen we'll resync it again later.
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen this would work with 1 second difference if we didn't store the
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen dirtyness flag in the stamp's first bit.
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (st.st_mtime < ioloop_time - MAILBOX_LIST_SYNC_SECS)
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainenstatic void mask_parse(struct mailbox_list *list, const char *mask,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenindex_mailbox_list_iter_init(struct mailbox_list *list, const char *mask,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct index_mailbox_list_iterate_context *ctx;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ctx = i_new(struct index_mailbox_list_iterate_context, 1);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ctx->glob = imap_match_init(default_pool, mask, TRUE,
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen ctx->mail_view = mail_index_view_open(ilist->mail_index);
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen ctx->view = mailbox_list_index_view_init(ilist->list_index,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if ((flags & MAILBOX_LIST_ITER_RAW_LIST) != 0) {
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen /* Ignore indexes completely */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen } else if (index_mailbox_list_is_synced(ctx) > 0) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* synced, list from index */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen mask_parse(list, mask, &prefix, &recurse_level);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen pool_alloconly_create("mailbox name pool", 128);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen ctx->iter_ctx = mailbox_list_index_iterate_init(ctx->view,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen ctx->prefix = *prefix == '\0' ? i_strdup("") :
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_strdup_printf("%s%c", prefix, list->hierarchy_sep);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen /* FIXME: this works nicely with maildir++, but not others */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen sync_flags = MAILBOX_LIST_SYNC_FLAG_RECURSIVE;
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen pool_alloconly_create("mailbox name pool", 128);
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen if (mailbox_list_index_sync_init(ilist->list_index, "",
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen ctx->trans = mailbox_list_index_sync_get_transaction(
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainenindex_mailbox_list_index_flags_translate(enum mailbox_list_index_flags flags)
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen if ((flags & MAILBOX_LIST_INDEX_FLAG_CHILDREN) != 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if ((flags & MAILBOX_LIST_INDEX_FLAG_NOCHILDREN) != 0)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if ((flags & MAILBOX_LIST_INDEX_FLAG_NONEXISTENT) != 0)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if ((flags & MAILBOX_LIST_INDEX_FLAG_NOSELECT) != 0)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenindex_mailbox_list_info_flags_translate(enum mailbox_info_flags info_flags)
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen/* skip nonexistent mailboxes when finding with "*" */
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen (((info)->flags & MAILBOX_NONEXISTENT) == 0 || \
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainenstatic int iter_next_nonsync(struct index_mailbox_list_iterate_context *ctx,
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(ctx->ctx.list);
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen /* find the next matching mailbox */
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen ret = mailbox_list_index_iterate_next(ctx->iter_ctx, &iinfo);
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen ctx->info.name = *ctx->prefix == '\0' ? iinfo.name :
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen } while (imap_match(ctx->glob, ctx->info.name) != IMAP_MATCH_YES);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* get the mailbox's flags */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_index_lookup_uid_range(ctx->mail_view, iinfo.uid, iinfo.uid,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen mailbox_list_index_set_corrupted(ilist->list_index,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen "Desynced: Record expunged from mail index");
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen if (mail_index_lookup(ctx->mail_view, seq, &rec) < 0)
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen ctx->info.flags = index_mailbox_list_index_flags_translate(rec->flags);
7bd301fdbfefe7cef3576d19ece29c75ebe53bafTimo Sirainen /* do some sanity checks to the flags */
7bd301fdbfefe7cef3576d19ece29c75ebe53bafTimo Sirainen if ((ctx->info.flags & MAILBOX_CHILDREN) != 0 &&
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen (ctx->info.flags & MAILBOX_NOCHILDREN) != 0) {
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen mailbox_list_index_set_corrupted(ilist->list_index,
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen "Mail index has both children and nochildren flags");
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if ((ctx->info.flags & MAILBOX_NOCHILDREN) != 0 &&
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen mailbox_list_index_set_corrupted(ilist->list_index,
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen "Desynced: Children flags wrong in mail index");
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainenmailbox_info_move_to_parent(struct index_mailbox_list_iterate_context *ctx,
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen if (imap_match(ctx->glob, name) == IMAP_MATCH_YES) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen ctx->info.name = p_strdup(ctx->info_pool, name);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen ctx->info.flags = MAILBOX_CHILDREN | MAILBOX_NONEXISTENT;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainenindex_mailbox_list_iter_next(struct mailbox_list_iterate_context *_ctx)
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen struct index_mailbox_list_iterate_context *ctx =
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen (struct index_mailbox_list_iterate_context *)_ctx;
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(_ctx->list);
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen info = ilist->module_ctx.super.iter_next(ctx->backend_ctx);
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen /* if the sync fails, just ignore it. we don't require synced
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen indexes to be able to return valid output. */
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen if (mailbox_list_index_sync_more(ctx->sync_ctx, info->name,
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen flags = index_mailbox_list_info_flags_translate(
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen mail_index_update_flags(ctx->trans, seq, MODIFY_REPLACE,
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen info = mailbox_info_move_to_parent(ctx, info);
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen /* no "*" wildcards, keep track of what mailboxes we
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen have returned so we don't return same parents
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen multiple times. */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen } while (match != IMAP_MATCH_YES || !info_flags_match(ctx, info));
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenindex_mailbox_list_iter_deinit(struct mailbox_list_iterate_context *_ctx)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen struct index_mailbox_list_iterate_context *ctx =
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen (struct index_mailbox_list_iterate_context *)_ctx;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(_ctx->list);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen mailbox_list_index_iterate_deinit(&ctx->iter_ctx);
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen /* FIXME: single sync_stamp works only with maildir++ */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen offsetof(struct mail_index_header, sync_stamp),
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen &ctx->sync_stamp, sizeof(ctx->sync_stamp), TRUE);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen ret = ilist->module_ctx.super.iter_deinit(ctx->backend_ctx);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen mailbox_list_index_sync_rollback(&ctx->sync_ctx);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen /* index updates aren't that important. if the commit
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen fails, we've still returned full output. */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen (void)mailbox_list_index_sync_commit(&ctx->sync_ctx);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ret = ilist->module_ctx.super.iter_deinit(ctx->backend_ctx);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainenstatic void index_mailbox_list_deinit(struct mailbox_list *list)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen mailbox_list_index_view_deinit(&ilist->list_sync_view);
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainenstatic int index_mailbox_list_open_indexes(struct mailbox_list *list,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen const char *dir)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* FIXME: a bit ugly way to get the flags, but this will do for now.. */
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen storage_flags = *list->set.mail_storage_flags;
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen if ((storage_flags & MAIL_STORAGE_FLAG_MMAP_DISABLE) != 0)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (mail_index_open(ilist->mail_index, index_flags,
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen if (mail_index_move_to_memory(ilist->mail_index) < 0) {
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen /* try opening once more. it should be created
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen directly into memory now. */
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen ret = mail_index_open(ilist->mail_index, index_flags,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* everything failed. there's a bug in the
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainen code, but just work around it by disabling
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen the index completely */
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen path = t_strconcat(dir, "/"MAILBOX_LIST_INDEX_NAME, NULL);
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen ilist->list_index = mailbox_list_index_alloc(path, list->hierarchy_sep,
NULL);
const char *dir;
void index_mailbox_list_init(void)