maildir-keywords.c revision a75d470c9223a75801418fcdda258885c36317e0
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen/* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen/* note that everything here depends on uidlist file being locked the whole
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen time. that's why we don't have any locking of our own, or that we do things
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen that would be racy otherwise. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "lib.h"
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen#include "array.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "ioloop.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "hash.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "str.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "istream.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "eacces-error.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "file-dotlock.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "write-full.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "nfs-workarounds.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "maildir-storage.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "maildir-uidlist.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include "maildir-keywords.h"
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen#include <stdlib.h>
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include <sys/stat.h>
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#include <utime.h>
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen/* how many seconds to wait before overriding dovecot-keywords.lock */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen#define KEYWORDS_LOCK_STALE_TIMEOUT (60*2)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstruct maildir_keywords {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct maildir_mailbox *mbox;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_storage *storage;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen char *path;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen pool_t pool;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ARRAY_TYPE(keywords) list;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen HASH_TABLE(char *, void *) hash; /* name -> idx+1 */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct dotlock_settings dotlock_settings;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen time_t synced_mtime;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int synced:1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int changed:1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen};
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstruct maildir_keywords_sync_ctx {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct maildir_keywords *mk;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_index *index;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const ARRAY_TYPE(keywords) *keywords;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ARRAY(char) idx_to_chr;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int chridx_to_idx[MAILDIR_MAX_KEYWORDS];
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen bool readonly;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen};
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstruct maildir_keywords *maildir_keywords_init(struct maildir_mailbox *mbox)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen struct maildir_keywords *mk;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk = maildir_keywords_init_readonly(&mbox->box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->mbox = mbox;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return mk;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstruct maildir_keywords *
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenmaildir_keywords_init_readonly(struct mailbox *box)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct maildir_keywords *mk;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char *dir;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen dir = mailbox_list_get_path(box->list, box->name,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen MAILBOX_LIST_PATH_TYPE_CONTROL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk = i_new(struct maildir_keywords, 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->storage = box->storage;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->path = i_strconcat(dir, "/" MAILDIR_KEYWORDS_NAME, NULL);
bd63b5b860658b01b1f46f26d406e1e4a9dc019aTimo Sirainen mk->pool = pool_alloconly_create("maildir keywords", 512);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_array_init(&mk->list, MAILDIR_MAX_KEYWORDS);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen hash_table_create(&mk->hash, mk->pool, 0, strcase_hash, strcasecmp);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->dotlock_settings.use_excl_lock =
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box->storage->set->dotlock_use_excl;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->dotlock_settings.nfs_flush =
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen box->storage->set->mail_nfs_storage;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->dotlock_settings.timeout =
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_get_lock_timeout(box->storage,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen KEYWORDS_LOCK_STALE_TIMEOUT + 2);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->dotlock_settings.stale_timeout = KEYWORDS_LOCK_STALE_TIMEOUT;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->dotlock_settings.temp_prefix =
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mailbox_list_get_temp_prefix(box->list);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return mk;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenvoid maildir_keywords_deinit(struct maildir_keywords **_mk)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct maildir_keywords *mk = *_mk;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *_mk = NULL;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen hash_table_destroy(&mk->hash);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen array_free(&mk->list);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen pool_unref(&mk->pool);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_free(mk->path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_free(mk);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic void maildir_keywords_clear(struct maildir_keywords *mk)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen array_clear(&mk->list);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen hash_table_clear(mk->hash, FALSE);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen p_clear(mk->pool);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int maildir_keywords_sync(struct maildir_keywords *mk)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct istream *input;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct stat st;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen char *line, *p, *new_name;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen const char **strp;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen unsigned int idx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen int fd;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* Remember that we rely on uidlist file locking in here. That's why
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen we rely on stat()'s timestamp and don't bother handling ESTALE
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen errors. */
049da065aa64c1a5ed46eed6cde7382b011612a9Timo Sirainen
049da065aa64c1a5ed46eed6cde7382b011612a9Timo Sirainen if (mk->storage->set->mail_nfs_storage) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* file is updated only by replacing it, no need to flush
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen attribute cache */
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen nfs_flush_file_handle_cache(mk->path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (nfs_safe_stat(mk->path, &st) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (errno == ENOENT) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen maildir_keywords_clear(mk);
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen mk->synced = TRUE;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(mk->storage,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "stat(%s) failed: %m", mk->path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (st.st_mtime == mk->synced_mtime) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* hasn't changed */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->synced = TRUE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->synced_mtime = st.st_mtime;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen fd = open(mk->path, O_RDONLY);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (fd == -1) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (errno == ENOENT) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen maildir_keywords_clear(mk);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->synced = TRUE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(mk->storage,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "open(%s) failed: %m", mk->path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen maildir_keywords_clear(mk);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen input = i_stream_create_fd(fd, 1024, FALSE);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen while ((line = i_stream_read_next_line(input)) != NULL) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen p = strchr(line, ' ');
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (p == NULL) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* note that when converting .customflags file this
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen case happens in the first line. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen continue;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *p++ = '\0';
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (str_to_uint(line, &idx) < 0 ||
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen idx >= MAILDIR_MAX_KEYWORDS || *p == '\0') {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* shouldn't happen */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen continue;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* save it */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen new_name = p_strdup(mk->pool, p);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen hash_table_insert(mk->hash, new_name, POINTER_CAST(idx + 1));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen strp = array_idx_modifiable(&mk->list, idx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *strp = new_name;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_stream_destroy(&input);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (close(fd) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(mk->storage,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "close(%s) failed: %m", mk->path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->synced = TRUE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenmaildir_keywords_lookup(struct maildir_keywords *mk, const char *name,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int *chridx_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen void *value;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen value = hash_table_lookup(mk->hash, name);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (value == 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (mk->synced)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (maildir_keywords_sync(mk) < 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(mk->synced);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen value = hash_table_lookup(mk->hash, name);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (value == 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *chridx_r = POINTER_CAST_TO(value, unsigned int)-1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic void
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenmaildir_keywords_create(struct maildir_keywords *mk, const char *name,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int chridx)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char **strp;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen char *new_name;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(chridx < MAILDIR_MAX_KEYWORDS);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen new_name = p_strdup(mk->pool, name);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen hash_table_insert(mk->hash, new_name, POINTER_CAST(chridx + 1));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen strp = array_idx_modifiable(&mk->list, chridx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *strp = new_name;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->changed = TRUE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenmaildir_keywords_lookup_or_create(struct maildir_keywords *mk, const char *name,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int *chridx_r)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char *const *keywords;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int i, count;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen int ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if ((ret = maildir_keywords_lookup(mk, name, chridx_r)) != 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* see if we are full */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen keywords = array_get(&mk->list, &count);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0; i < count; i++) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (keywords[i] == NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen break;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (i == count && count >= MAILDIR_MAX_KEYWORDS)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (!maildir_uidlist_is_locked(mk->mbox->uidlist))
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen maildir_keywords_create(mk, name, i);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *chridx_r = i;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic const char *
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenmaildir_keywords_idx(struct maildir_keywords *mk, unsigned int idx)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char *const *keywords;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int count;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen keywords = array_get(&mk->list, &count);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (idx >= count) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (mk->synced)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return NULL;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (maildir_keywords_sync(mk) < 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return NULL;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(mk->synced);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen keywords = array_get(&mk->list, &count);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return idx >= count ? NULL : keywords[idx];
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int maildir_keywords_write_fd(struct maildir_keywords *mk,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char *path, int fd)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct maildir_mailbox *mbox = mk->mbox;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mailbox *box = &mbox->box;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const struct mailbox_permissions *perm = mailbox_get_permissions(box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char *const *keywords;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int i, count;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen string_t *str;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct stat st;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen str = t_str_new(256);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen keywords = array_get(&mk->list, &count);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0; i < count; i++) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (keywords[i] != NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen str_printfa(str, "%u %s\n", i, keywords[i]);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (write_full(fd, str_data(str), str_len(str)) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(mk->storage,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "write_full(%s) failed: %m", path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (fstat(fd, &st) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(mk->storage,
c8c4bbf6b1415e9d0845bc8f1cd6d19b76ab0392Timo Sirainen "fstat(%s) failed: %m", path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (st.st_gid != perm->file_create_gid &&
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen perm->file_create_gid != (gid_t)-1) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (errno == EPERM) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(mk->storage, "%s",
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen eperm_error_get_chgrp("fchown", path,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen perm->file_create_gid,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen perm->file_create_gid_origin));
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } else {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(mk->storage,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "fchown(%s) failed: %m", path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* mtime must grow every time */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (st.st_mtime <= mk->synced_mtime) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct utimbuf ut;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->synced_mtime = ioloop_time <= mk->synced_mtime ?
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->synced_mtime + 1 : ioloop_time;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ut.actime = ioloop_time;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ut.modtime = mk->synced_mtime;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (utime(path, &ut) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(mk->storage,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "utime(%s) failed: %m", path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (fsync(fd) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(mk->storage,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "fsync(%s) failed: %m", path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstatic int maildir_keywords_commit(struct maildir_keywords *mk)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const struct mailbox_permissions *perm;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct dotlock *dotlock;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char *lock_path;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mode_t old_mask;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen int i, fd;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->synced = FALSE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (!mk->changed || mk->mbox == NULL)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen lock_path = t_strconcat(mk->path, ".lock", NULL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen (void)unlink(lock_path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen perm = mailbox_get_permissions(&mk->mbox->box);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen for (i = 0;; i++) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* we could just create the temp file directly, but doing it
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen this ways avoids potential problems with overwriting
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen contents in malicious symlinks */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen old_mask = umask(0777 & ~perm->file_create_mode);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen fd = file_dotlock_open(&mk->dotlock_settings, mk->path,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen DOTLOCK_CREATE_FLAG_NONBLOCK, &dotlock);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen umask(old_mask);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (fd != -1)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen break;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(mk->storage,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "file_dotlock_open(%s) failed: %m", mk->path);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen return -1;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen }
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen /* the control dir doesn't exist. create it unless the whole
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen mailbox was just deleted. */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (!maildir_set_deleted(&mk->mbox->box))
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (maildir_keywords_write_fd(mk, lock_path, fd) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen file_dotlock_delete(&dotlock);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (file_dotlock_replace(&dotlock, 0) < 0) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_storage_set_critical(mk->storage,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen "file_dotlock_replace(%s) failed: %m", mk->path);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return -1;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mk->changed = FALSE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return 0;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstruct maildir_keywords_sync_ctx *
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenmaildir_keywords_sync_init(struct maildir_keywords *mk,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_index *index)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct maildir_keywords_sync_ctx *ctx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ctx = i_new(struct maildir_keywords_sync_ctx, 1);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ctx->mk = mk;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ctx->index = index;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ctx->keywords = mail_index_get_keywords(index);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_array_init(&ctx->idx_to_chr, MAILDIR_MAX_KEYWORDS);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return ctx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenstruct maildir_keywords_sync_ctx *
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainenmaildir_keywords_sync_init_readonly(struct maildir_keywords *mk,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct mail_index *index)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct maildir_keywords_sync_ctx *ctx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ctx = maildir_keywords_sync_init(mk, index);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ctx->readonly = TRUE;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return ctx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenvoid maildir_keywords_sync_deinit(struct maildir_keywords_sync_ctx **_ctx)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen struct maildir_keywords_sync_ctx *ctx = *_ctx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen *_ctx = NULL;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen T_BEGIN {
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen (void)maildir_keywords_commit(ctx->mk);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen } T_END;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen array_free(&ctx->idx_to_chr);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen i_free(ctx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen}
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainenunsigned int maildir_keywords_char_idx(struct maildir_keywords_sync_ctx *ctx,
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen char keyword)
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen{
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen const char *name;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int chridx, idx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen i_assert(keyword >= MAILDIR_KEYWORD_FIRST &&
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen keyword <= MAILDIR_KEYWORD_LAST);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen chridx = keyword - MAILDIR_KEYWORD_FIRST;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen if (ctx->chridx_to_idx[chridx] != 0)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return ctx->chridx_to_idx[chridx];
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* lookup / create */
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen name = maildir_keywords_idx(ctx->mk, chridx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (name == NULL) {
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen /* name is lost. just generate one ourself. */
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen name = t_strdup_printf("unknown-%u", chridx);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen while (maildir_keywords_lookup(ctx->mk, name, &idx) > 0) {
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen /* don't create a duplicate name.
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen keep changing the name until it doesn't exist */
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen name = t_strconcat(name, "?", NULL);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen maildir_keywords_create(ctx->mk, name, chridx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen }
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen mail_index_keyword_lookup_or_create(ctx->index, name, &idx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen ctx->chridx_to_idx[chridx] = idx;
0e7d5ff38f28d8c85e197a031bbb66b322ff89e6Timo Sirainen return idx;
0e7d5ff38f28d8c85e197a031bbb66b322ff89e6Timo Sirainen}
0e7d5ff38f28d8c85e197a031bbb66b322ff89e6Timo Sirainen
0e7d5ff38f28d8c85e197a031bbb66b322ff89e6Timo Sirainenchar maildir_keywords_idx_char(struct maildir_keywords_sync_ctx *ctx,
0e7d5ff38f28d8c85e197a031bbb66b322ff89e6Timo Sirainen unsigned int idx)
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen{
0e7d5ff38f28d8c85e197a031bbb66b322ff89e6Timo Sirainen const char *const *name_p;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen char *chr_p;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen unsigned int chridx;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen int ret;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen chr_p = array_idx_modifiable(&ctx->idx_to_chr, idx);
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen if (*chr_p != '\0')
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen return *chr_p;
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen
c8593b070319d0ff83f8d6c4b5ed5abf2d578a06Timo Sirainen name_p = array_idx(ctx->keywords, idx);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen ret = !ctx->readonly ?
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen maildir_keywords_lookup_or_create(ctx->mk, *name_p, &chridx) :
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen maildir_keywords_lookup(ctx->mk, *name_p, &chridx);
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen if (ret <= 0)
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen return '\0';
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen *chr_p = chridx + MAILDIR_KEYWORD_FIRST;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen return *chr_p;
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen}
b10c3f9ed997748fdbb03b9daadc8c31eed02120Timo Sirainen