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