Mercurial > dovecot > original-hg > dovecot-1.2
diff src/lib-index/maildir/maildir-index.c @ 0:3b1985cbc908 HEAD
Initial revision
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 09 Aug 2002 12:15:38 +0300 |
parents | |
children | 1b34ec11fff8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-index/maildir/maildir-index.c Fri Aug 09 12:15:38 2002 +0300 @@ -0,0 +1,182 @@ +/* Copyright (C) 2002 Timo Sirainen */ + +#include "lib.h" +#include "maildir-index.h" +#include "mail-index-util.h" + +#include <stdio.h> + +static MailIndex maildir_index; + +const char *maildir_filename_set_flags(const char *fname, MailFlags flags) +{ + const char *info, *oldflags; + char *flags_buf, *p; + int i, nextflag; + + /* remove the old :info from file name, and get the old flags */ + info = strrchr(fname, ':'); + if (info != NULL && strrchr(fname, '/') > info) + info = NULL; + + oldflags = ""; + if (info != NULL) { + fname = t_strndup(fname, (unsigned int) (info-fname)); + if (info[1] == '2' && info[2] == ',') + oldflags = info+3; + } + + /* insert the new flags between old flags. flags must be sorted by + their ASCII code. unknown flags are kept. */ + flags_buf = t_malloc(MAIL_FLAGS_COUNT+strlen(oldflags)+1); + p = flags_buf; + + for (;;) { + /* skip all known flags */ + while (*oldflags == 'D' || *oldflags == 'F' || + *oldflags == 'R' || *oldflags == 'S' || + *oldflags == 'T' || + (*oldflags >= 'a' && *oldflags <= 'z')) + oldflags++; + + nextflag = *oldflags == '\0' ? 256 : + (unsigned char) *oldflags; + + if ((flags & MAIL_DRAFT) && nextflag > 'D') { + *p++ = 'D'; + flags &= ~MAIL_DRAFT; + } + if ((flags & MAIL_FLAGGED) && nextflag > 'F') { + *p++ = 'F'; + 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_get_sequence, + maildir_open_mail, + mail_index_expunge, + maildir_index_update_flags, + mail_index_append, + mail_index_update_begin, + mail_index_update_end, + mail_index_update_field, + mail_index_get_last_error, + mail_index_is_inconsistency_error +};