/* last maildir sync: */
time_t last_new_mtime, last_uidlist_mtime;
- time_t maildir_cur_dirty;
+ time_t maildir_cur_dirty, next_dirty_flush;
int maildir_lock_fd;
pool_t new_filename_pool;
struct hash_table *new_filenames;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
#endif
/* defaults - same as above but prefixed with mail_index_. */
/* ":2,DFRST" - leave the 2 extra for other clients' additions */
#define MAILDIR_LOCATION_EXTRA_SPACE 10
+/* How often to try to flush dirty flags. */
+#define MAILDIR_DIRTY_FLUSH_TIMEOUT (60*5)
+
struct mail_index *
maildir_index_alloc(const char *maildir, const char *index_dir,
const char *control_dir);
int maildir_index_update_flags(struct mail_index *index,
struct mail_index_record *rec, unsigned int seq,
enum mail_flags flags, int external_change);
+int maildir_try_flush_dirty_flags(struct mail_index *index, int force);
struct istream *maildir_open_mail(struct mail_index *index,
struct mail_index_record *rec,
#include <stdio.h>
+int maildir_try_flush_dirty_flags(struct mail_index *index, int force)
+{
+ struct mail_index_record *rec;
+ const char *old_fname, *old_path, *new_fname, *new_path;
+ int flag, dirty = FALSE;
+
+ if (index->next_dirty_flush == 0 ||
+ (ioloop_time < index->next_dirty_flush && !force))
+ return TRUE;
+
+ if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
+ return FALSE;
+
+ rec = index->lookup(index, 1);
+ while (rec != NULL) {
+ if ((rec->index_flags & INDEX_MAIL_FLAG_DIRTY) != 0) {
+ old_fname = maildir_get_location(index, rec);
+ if (old_fname == NULL)
+ return FALSE;
+
+ flag = (rec->index_flags &
+ INDEX_MAIL_FLAG_MAILDIR_NEW) != 0;
+ old_path = t_strconcat(index->mailbox_path,
+ flag ? "/new/" : "/cur/",
+ old_fname, NULL);
+
+ new_fname = maildir_filename_set_flags(old_fname,
+ rec->msg_flags);
+ new_path = t_strconcat(index->mailbox_path,
+ "/cur/", new_fname, NULL);
+
+ if (strcmp(old_path, new_path) == 0 ||
+ rename(old_path, new_path) == 0)
+ rec->index_flags &= ~INDEX_MAIL_FLAG_DIRTY;
+ else {
+ dirty = TRUE;
+ if (errno != ENOENT && errno != EACCES &&
+ !ENOSPACE(errno)) {
+ index_set_error(index,
+ "rename(%s, %s) failed: %m",
+ old_path, new_path);
+ return FALSE;
+ }
+ }
+ }
+
+ rec = index->next(index, rec);
+ }
+
+ if (!dirty) {
+ index->header->flags &= ~MAIL_INDEX_FLAG_DIRTY_MESSAGES;
+ index->next_dirty_flush = 0;
+ } else {
+ index->next_dirty_flush =
+ ioloop_time + MAILDIR_DIRTY_FLUSH_TIMEOUT;
+ }
+
+ return TRUE;
+}
+
static int handle_error(struct mail_index *index,
const char *path, const char *new_path)
{
"/cur/", new_fname, NULL);
}
+ ret = 0; break;
+
if (strcmp(old_fname, new_fname) == 0)
ret = 1;
else {
/* we couldn't actually rename() the file now.
leave it's flags dirty so they get changed later. */
rec->index_flags |= INDEX_MAIL_FLAG_DIRTY;
+ index->header->flags |= MAIL_INDEX_FLAG_DIRTY_MESSAGES;
+ index->next_dirty_flush =
+ ioloop_time + MAILDIR_DIRTY_FLUSH_TIMEOUT;
+ *new_fname_r = NULL;
}
return TRUE;
}
{
struct mail_index_update *update;
const char *new_fname;
- int ret;
+ int failed = FALSE;
t_push();
if (!maildir_rename_mail(index, rec, flags, &new_fname)) {
return FALSE;
}
- /* update the filename in index */
- update = index->update_begin(index, rec);
- index->update_field(update, DATA_FIELD_LOCATION, new_fname, 0);
-
- if (!index->update_end(update))
- ret = FALSE;
- else if (!mail_index_update_flags(index, rec, seq, flags,
- external_change))
- ret = FALSE;
- else
- ret = TRUE;
+ if (new_fname != NULL) {
+ /* update the filename in index */
+ update = index->update_begin(index, rec);
+ index->update_field(update, DATA_FIELD_LOCATION, new_fname, 0);
+ if (!index->update_end(update))
+ failed = TRUE;
+ }
+
+ if (!failed && !mail_index_update_flags(index, rec, seq, flags,
+ external_change))
+ failed = TRUE;
t_pop();
- return ret;
+ return !failed;
}
}
}
+static int maildir_storage_close(struct mailbox *box)
+{
+ struct index_mailbox *ibox = (struct index_mailbox *) box;
+ int failed = FALSE;
+
+ index_storage_init_lock_notify(ibox);
+ if (!maildir_try_flush_dirty_flags(ibox->index, TRUE)) {
+ mail_storage_set_index_error(ibox);
+ failed = TRUE;
+ }
+ ibox->index->set_lock_notify_callback(ibox->index, NULL, NULL);
+
+ return index_storage_close(box) && !failed;
+}
+
static void maildir_storage_auto_sync(struct mailbox *box,
enum mailbox_sync_type sync_type,
unsigned int min_newmail_notify_interval)
NULL, /* name */
NULL, /* storage */
- index_storage_close,
+ maildir_storage_close,
index_storage_get_status,
index_storage_sync,
maildir_storage_auto_sync,