maildir-index.c revision dec504e26667fb97d47f6145e5f65c0bc1c615ea
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen#include "lib.h"
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen#include "maildir-index.h"
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen#include "mail-index-util.h"
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen#include <stdio.h>
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic MailIndex maildir_index;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo SirainenMailFlags maildir_filename_get_flags(const char *fname, MailFlags default_flags)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen{
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen const char *info;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen MailFlags flags;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen info = strchr(fname, ':');
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (info == NULL || info[1] != '2' || info[2] != ',')
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen return default_flags;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags = 0;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen for (info += 3; *info != '\0'; info++) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen switch (*info) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen case 'R': /* replied */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags |= MAIL_ANSWERED;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen break;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen case 'S': /* seen */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags |= MAIL_SEEN;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen break;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen case 'T': /* trashed */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags |= MAIL_DELETED;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen break;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen case 'D': /* draft */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags |= MAIL_DRAFT;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen break;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen case 'F': /* flagged */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags |= MAIL_FLAGGED;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen break;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen default:
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (*info >= 'a' && *info <= 'z') {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* custom flag */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags |= 1 << (MAIL_CUSTOM_FLAG_1_BIT +
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen *info-'a');
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen break;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* unknown flag - ignore */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen break;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen return flags;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen}
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenconst char *maildir_filename_set_flags(const char *fname, MailFlags flags)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen{
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen const char *info, *oldflags;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen char *flags_buf, *p;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen int i, nextflag;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* remove the old :info from file name, and get the old flags */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen info = strrchr(fname, ':');
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (info != NULL && strrchr(fname, '/') > info)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen info = NULL;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen oldflags = "";
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (info != NULL) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen fname = t_strdup_until(fname, info);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (info[1] == '2' && info[2] == ',')
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen oldflags = info+3;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* insert the new flags between old flags. flags must be sorted by
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen their ASCII code. unknown flags are kept. */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags_buf = t_malloc(MAIL_FLAGS_COUNT+strlen(oldflags)+1);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen p = flags_buf;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen for (;;) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* skip all known flags */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen while (*oldflags == 'D' || *oldflags == 'F' ||
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen *oldflags == 'R' || *oldflags == 'S' ||
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen *oldflags == 'T' ||
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen (*oldflags >= 'a' && *oldflags <= 'z'))
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen oldflags++;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen nextflag = *oldflags == '\0' ? 256 :
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen (unsigned char) *oldflags;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if ((flags & MAIL_DRAFT) && nextflag > 'D') {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen *p++ = 'D';
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags &= ~MAIL_DRAFT;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if ((flags & MAIL_FLAGGED) && nextflag > 'F') {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen *p++ = 'F';
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags &= ~MAIL_FLAGGED;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if ((flags & MAIL_ANSWERED) && nextflag > 'R') {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen *p++ = 'R';
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags &= ~MAIL_ANSWERED;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if ((flags & MAIL_SEEN) && nextflag > 'S') {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen *p++ = 'S';
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags &= ~MAIL_SEEN;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if ((flags & MAIL_DELETED) && nextflag > 'T') {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen *p++ = 'T';
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags &= ~MAIL_DELETED;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if ((flags & MAIL_CUSTOM_FLAGS_MASK) && nextflag > 'a') {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (flags & (1 << (i + MAIL_CUSTOM_FLAG_1_BIT)))
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen *p++ = 'a' + i;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen flags &= ~MAIL_CUSTOM_FLAGS_MASK;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (*oldflags == '\0')
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen break;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen *p++ = *oldflags++;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen *p = '\0';
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen return t_strconcat(fname, ":2,", flags_buf, NULL);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen}
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo SirainenMailIndex *maildir_index_alloc(const char *dir)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen{
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen MailIndex *index;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen int len;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen i_assert(dir != NULL);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen index = i_new(MailIndex, 1);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen memcpy(index, &maildir_index, sizeof(MailIndex));
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen index->fd = -1;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen index->dir = i_strdup(dir);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen len = strlen(index->dir);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (index->dir[len-1] == '/')
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen index->dir[len-1] = '\0';
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen return (MailIndex *) index;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen}
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic void maildir_index_free(MailIndex *index)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen{
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_close(index);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen i_free(index->dir);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen i_free(index);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen}
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic int maildir_index_update_flags(MailIndex *index, MailIndexRecord *rec,
0e94016c18197cb42d00be0085e6da4223a1c84eTimo Sirainen unsigned int seq, MailFlags flags,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen int external_change)
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen{
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen MailIndexUpdate *update;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen const char *old_fname, *new_fname;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen const char *old_path, *new_path;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
0e94016c18197cb42d00be0085e6da4223a1c84eTimo Sirainen if (!mail_index_update_flags(index, rec, seq, flags, external_change))
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen return FALSE;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* we need to update the flags in the file name */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen old_fname = index->lookup_field(index, rec, FIELD_TYPE_LOCATION);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (old_fname == NULL) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen INDEX_MARK_CORRUPTED(index);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen index_set_error(index, "Corrupted index file %s: "
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen "Missing location field for record %u",
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen index->filepath, rec->uid);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen return FALSE;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen new_fname = maildir_filename_set_flags(old_fname, flags);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (strcmp(old_fname, new_fname) != 0) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen old_path = t_strconcat(index->dir, "/cur/", old_fname, NULL);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen new_path = t_strconcat(index->dir, "/cur/", new_fname, NULL);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* minor problem: new_path is overwritten if it exists.. */
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (rename(old_path, new_path) == -1) {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen index_set_error(index, "maildir flags update: "
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen "rename(%s, %s) failed: %m",
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen old_path, new_path);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen return FALSE;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
0e94016c18197cb42d00be0085e6da4223a1c84eTimo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen /* update the filename in index */
0e94016c18197cb42d00be0085e6da4223a1c84eTimo Sirainen update = index->update_begin(index, rec);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen index->update_field(update, FIELD_TYPE_LOCATION, new_fname, 0);
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen if (!index->update_end(update))
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen return FALSE;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen }
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen return TRUE;
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen}
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainenstatic MailIndex maildir_index = {
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_open,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_open_or_create,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen maildir_index_free,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_set_lock,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_try_lock,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen maildir_index_rebuild,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_fsck,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen maildir_index_sync,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_get_header,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_lookup,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_next,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_lookup_uid_range,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_lookup_field,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_lookup_field_raw,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_get_sequence,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen maildir_open_mail,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_expunge,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen maildir_index_update_flags,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_append,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_update_begin,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_update_end,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_update_field,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_update_field_raw,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_get_last_error,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen mail_index_is_inconsistency_error,
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen MAIL_INDEX_PRIVATE_FILL
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen};
b90c23a9862b91594959b918b035d73f7bc0b265Timo Sirainen