Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-storage/index/maildir/maildir-util.c @ 1947:777da553d1d3 HEAD
Recent-flag should work now
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 01 May 2004 21:30:52 +0300 |
parents | 79790750c349 |
children | 4dec6a3d79fd |
line wrap: on
line source
/* Copyright (C) 2004 Timo Sirainen */ #include "lib.h" #include "hostpid.h" #include "ioloop.h" #include "str.h" #include "maildir-storage.h" #include "maildir-uidlist.h" #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> static int maildir_file_do_try(struct index_mailbox *ibox, uint32_t uid, maildir_file_do_func *func, void *context) { const char *fname, *path; enum maildir_uidlist_rec_flag flags; int ret; fname = maildir_uidlist_lookup(ibox->uidlist, uid, &flags); if (fname == NULL) return -2; /* expunged */ if ((flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) { /* probably in new/ dir */ path = t_strconcat(ibox->path, "/new/", fname, NULL); ret = func(ibox, path, context); if (ret != 0) return ret; } path = t_strconcat(ibox->path, "/cur/", fname, NULL); return func(ibox, path, context); } int maildir_file_do(struct index_mailbox *ibox, uint32_t uid, maildir_file_do_func *func, void *context) { int i, ret; ret = maildir_file_do_try(ibox, uid, func, context); for (i = 0; i < 10 && ret == 0; i++) { /* file is either renamed or deleted. sync the maildir and see which one. if file appears to be renamed constantly, don't try to open it more than 10 times. */ if (maildir_storage_sync_readonly(ibox) < 0) return -1; ret = maildir_file_do_try(ibox, uid, func, context); } return ret == -2 ? 0 : ret; } int maildir_filename_get_flags(const char *fname, enum mail_flags *flags_r, custom_flags_mask_t custom_flags_r) { const char *info; unsigned int num; *flags_r = 0; memset(custom_flags_r, 0, INDEX_CUSTOM_FLAGS_BYTE_COUNT); info = strchr(fname, ':'); if (info == NULL || info[1] != '2' || info[2] != ',') return 0; for (info += 3; *info != '\0' && *info != ','; info++) { switch (*info) { case 'R': /* replied */ *flags_r |= MAIL_ANSWERED; break; case 'S': /* seen */ *flags_r |= MAIL_SEEN; break; case 'T': /* trashed */ *flags_r |= MAIL_DELETED; break; case 'D': /* draft */ *flags_r |= MAIL_DRAFT; break; case 'F': /* flagged */ *flags_r |= MAIL_FLAGGED; break; default: if (*info >= 'a' && *info <= 'z') { /* custom flag */ num = (*info - 'a'); custom_flags_r[num / CHAR_BIT] |= num % CHAR_BIT; break; } /* unknown flag - ignore */ break; } } return 1; } const char *maildir_filename_set_flags(const char *fname, enum mail_flags flags, custom_flags_mask_t custom_flags) { string_t *flags_str; const char *info, *oldflags; int i, nextflag; if (custom_flags != NULL) { /* see if any custom flags are given */ for (i = 0; i < INDEX_CUSTOM_FLAGS_BYTE_COUNT; i++) { if (custom_flags[i] != 0) break; } if (i == INDEX_CUSTOM_FLAGS_BYTE_COUNT) custom_flags = NULL; } /* 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_strdup_until(fname, info); 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_str = t_str_new(256); str_append(flags_str, fname); str_append(flags_str, ":2,"); for (;;) { /* skip all known flags */ while (*oldflags == 'D' || *oldflags == 'F' || *oldflags == 'R' || *oldflags == 'S' || *oldflags == 'T' || (*oldflags >= 'a' && *oldflags <= 'z')) oldflags++; nextflag = *oldflags == '\0' || *oldflags == ',' ? 256 : (unsigned char) *oldflags; if ((flags & MAIL_DRAFT) && nextflag > 'D') { str_append_c(flags_str, 'D'); flags &= ~MAIL_DRAFT; } if ((flags & MAIL_FLAGGED) && nextflag > 'F') { str_append_c(flags_str, 'F'); flags &= ~MAIL_FLAGGED; } if ((flags & MAIL_ANSWERED) && nextflag > 'R') { str_append_c(flags_str, 'R'); flags &= ~MAIL_ANSWERED; } if ((flags & MAIL_SEEN) && nextflag > 'S') { str_append_c(flags_str, 'S'); flags &= ~MAIL_SEEN; } if ((flags & MAIL_DELETED) && nextflag > 'T') { str_append_c(flags_str, 'T'); flags &= ~MAIL_DELETED; } if (custom_flags != NULL && nextflag > 'a') { for (i = 0; i < INDEX_CUSTOM_FLAGS_COUNT; i++) { if ((custom_flags[i / CHAR_BIT] & (1 << (i % CHAR_BIT))) != 0) str_append_c(flags_str, 'a' + i); } custom_flags = NULL; } if (*oldflags == '\0' || *oldflags == ',') break; str_append_c(flags_str, *oldflags); oldflags++; } if (*oldflags == ',') { /* another flagset, we don't know about these, just keep them */ while (*oldflags != '\0') str_append_c(flags_str, *oldflags++); } return str_c(flags_str); } const char *maildir_generate_tmp_filename(const struct timeval *tv) { static unsigned int create_count = 0; static time_t first_stamp = 0; if (first_stamp == 0 || first_stamp == ioloop_time) { /* it's possible that within last second another process had the same UID as us. Use usecs to make sure we don't create duplicate base name. */ first_stamp = ioloop_time; return t_strdup_printf("%s.P%sQ%uM%s.%s", dec2str(tv->tv_sec), my_pid, create_count++, dec2str(tv->tv_usec), my_hostname); } else { /* Don't bother with usecs. Saves a bit space :) */ return t_strdup_printf("%s.P%sQ%u.%s", dec2str(tv->tv_sec), my_pid, create_count++, my_hostname); } } int maildir_create_tmp(struct index_mailbox *ibox, const char *dir, mode_t mode, const char **fname_r) { const char *path, *tmp_fname; struct stat st; struct timeval *tv, tv_now; pool_t pool; int fd; tv = &ioloop_timeval; pool = pool_alloconly_create("maildir_tmp", 4096); for (;;) { p_clear(pool); tmp_fname = maildir_generate_tmp_filename(tv); path = p_strconcat(pool, dir, "/", tmp_fname, NULL); if (stat(path, &st) < 0 && errno == ENOENT) { /* doesn't exist */ mode_t old_mask = umask(0); fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode); umask(old_mask); if (fd != -1 || errno != EEXIST) break; } /* wait and try again - very unlikely */ sleep(2); tv = &tv_now; if (gettimeofday(&tv_now, NULL) < 0) i_fatal("gettimeofday(): %m"); } *fname_r = t_strdup(path); if (fd == -1) { mail_storage_set_critical(ibox->box.storage, "open(%s) failed: %m", path); } pool_unref(pool); return fd; } /* a char* hash function from ASU -- from glib */ unsigned int maildir_hash(const void *p) { const unsigned char *s = p; unsigned int g, h = 0; while (*s != ':' && *s != '\0') { h = (h << 4) + *s; if ((g = h & 0xf0000000UL)) { h = h ^ (g >> 24); h = h ^ g; } s++; } return h; } int maildir_cmp(const void *p1, const void *p2) { const char *s1 = p1, *s2 = p2; while (*s1 == *s2 && *s1 != ':' && *s1 != '\0') { s1++; s2++; } if ((*s1 == '\0' || *s1 == ':') && (*s2 == '\0' || *s2 == ':')) return 0; return *s1 - *s2; }