* mailboxes.
*/
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include "mutt.h"
#include "mailbox.h"
#include "mx.h"
#include "sort.h"
#include <sys/stat.h>
+#include <sys/types.h>
#include <dirent.h>
#include <limits.h>
#include <unistd.h>
HEADER *h;
char *canon_fname;
unsigned header_parsed:1;
+ ino_t inode;
struct maildir *next;
};
{
snprintf (path, _POSIX_PATH_MAX, "%s/.mutt-%s-%d-%d",
dest->path, NONULL (Hostname), (int) getpid (), Counter++);
- if ((fd = open (path, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1)
+ umask(Umask);
+ if ((fd = open (path, O_WRONLY | O_EXCL | O_CREAT, 0666)) == -1)
{
if (errno != EEXIST)
{
static int maildir_parse_entry (CONTEXT * ctx, struct maildir ***last,
const char *subdir, const char *fname,
- int *count, int is_old)
+ int *count, int is_old, ino_t inode)
{
struct maildir *entry;
HEADER *h = NULL;
entry = safe_calloc (sizeof (struct maildir), 1);
entry->h = h;
entry->header_parsed = (ctx->magic == M_MH);
+ entry->inode = inode;
**last = entry;
*last = &entry->next;
dprint (2,
(debugfile, "%s:%d: parsing %s\n", __FILE__, __LINE__,
de->d_name));
- maildir_parse_entry (ctx, last, subdir, de->d_name, count, is_old);
+ maildir_parse_entry (ctx, last, subdir, de->d_name, count, is_old,
+ de->d_ino);
}
closedir (dirp);
return r;
}
+/*
+ * Merge two maildir lists according to the inode numbers.
+ */
+static struct maildir* maildir_merge_inode (struct maildir *left,
+ struct maildir *right)
+{
+ struct maildir* head;
+ struct maildir* tail;
+
+ if (left && right)
+ {
+ if (left->inode < right->inode)
+ {
+ head = left;
+ left = left->next;
+ }
+ else
+ {
+ head = right;
+ right = right->next;
+ }
+ }
+ else
+ {
+ if (left)
+ return left;
+ else
+ return right;
+ }
+
+ tail = head;
+
+ while (left && right)
+ {
+ if (left->inode < right->inode)
+ {
+ tail->next = left;
+ left = left->next;
+ }
+ else
+ {
+ tail->next = right;
+ right = right->next;
+ }
+ tail = tail->next;
+ }
+
+ if (left)
+ {
+ tail->next = left;
+ }
+ else
+ {
+ tail->next = right;
+ }
+
+ return head;
+}
+
+/*
+ * Sort maildir list according to inode.
+ */
+static struct maildir* maildir_sort_inode(struct maildir* list)
+{
+ struct maildir* left = list;
+ struct maildir* right = list;
+
+ if (!list || !list->next)
+ {
+ return list;
+ }
+
+ list = list->next;
+ while (list && list->next)
+ {
+ right = right->next;
+ list = list->next->next;
+ }
+
+ list = right;
+ right = right->next;
+ list->next = 0;
+
+ left = maildir_sort_inode(left);
+ right = maildir_sort_inode(right);
+ return maildir_merge_inode(left, right);
+}
+
+#if USE_HCACHE
+static size_t maildir_hcache_keylen (const char *fn)
+{
+ const char * p = strchr (fn, ':');
+ return p ? (size_t) (p - fn) : mutt_strlen(fn);
+}
+#endif
/*
* This function does the second parsing pass for a maildir-style
* folder.
*/
-
void maildir_delayed_parsing (CONTEXT * ctx, struct maildir *md)
{
struct maildir *p;
char fn[_POSIX_PATH_MAX];
+ int count;
- for (p = md; p; p = p->next)
- if (p && p->h && !p->header_parsed)
- {
- snprintf (fn, sizeof (fn), "%s/%s", ctx->path, p->h->path);
- if (maildir_parse_message (ctx->magic, fn, p->h->old, p->h))
- p->header_parsed = 1;
- else
- mutt_free_header (&p->h);
- }
-}
+#if USE_HCACHE
+ void *hc = NULL;
+ void *data;
+ unsigned int size;
+ struct timeval *when = NULL;
+ struct stat lastchanged;
+ int ret;
+
+ hc = mutt_hcache_open (HeaderCache, ctx->path);
+#endif
+
+ for (p = md, count = 0; p; p = p->next, count++)
+ {
+ if (! (p && p->h && !p->header_parsed))
+ continue;
+#if USE_HCACHE
+ data = mutt_hcache_fetch (hc, p->h->path + 3, &maildir_hcache_keylen);
+ when = (struct timeval *) data;
+#endif
+
+ if (!ctx->quiet && ReadInc && ((count % ReadInc) == 0 || count == 1))
+ mutt_message (_("Reading %s... %d"), ctx->path, count);
+ snprintf (fn, sizeof (fn), "%s/%s", ctx->path, p->h->path);
+#if USE_HCACHE
+ if (option(OPTHCACHEVERIFY)) {
+ ret = stat(fn, &lastchanged);
+ } else {
+ lastchanged.st_mtime = 0;
+ ret = 0;
+ }
+
+ if (data != NULL && !ret && lastchanged.st_mtime <= when->tv_sec)
+ {
+ p->h = mutt_hcache_restore ((unsigned char *)data, &p->h);
+ maildir_parse_flags (p->h, fn);
+ } else
+#endif
+ if (maildir_parse_message (ctx->magic, fn, p->h->old, p->h))
+ {
+ p->header_parsed = 1;
+ maildir_parse_flags (p->h, fn);
+#if USE_HCACHE
+ mutt_hcache_store (hc, p->h->path + 3, p->h, 0, &maildir_hcache_keylen);
+#endif
+ } else
+ mutt_free_header (&p->h);
+#if USE_HCACHE
+ FREE(&data);
+#endif
+ }
+#if USE_HCACHE
+ mutt_hcache_close (hc);
+#endif
+}
/* Read a MH/maildir style mailbox.
*
mhs_free_sequences (&mhs);
}
+ md = maildir_sort_inode(md);
+
if (ctx->magic == M_MAILDIR)
maildir_delayed_parsing (ctx, md);
FOREVER
{
- snprintf (path, _POSIX_PATH_MAX, "%s/tmp/%s.%ld.%d_%d.%s%s",
- dest->path, subdir, time (NULL), getpid (), Counter++,
- NONULL (Hostname), suffix);
+ snprintf (path, _POSIX_PATH_MAX, "%s/tmp/%s.%ld.%u_%d.%s%s",
+ dest->path, subdir, time (NULL), (unsigned int)getpid (),
+ Counter++, NONULL (Hostname), suffix);
dprint (2, (debugfile, "maildir_open_new_message (): Trying %s.\n",
path));
- if ((fd = open (path, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1)
+ umask(Umask);
+ if ((fd = open (path, O_WRONLY | O_EXCL | O_CREAT, 0666)) == -1)
{
if (errno != EEXIST)
{
/* construct a new file name. */
FOREVER
{
- snprintf (path, _POSIX_PATH_MAX, "%s/%ld.%d_%d.%s%s", subdir,
- time (NULL), getpid (), Counter++, NONULL (Hostname), suffix);
+ snprintf (path, _POSIX_PATH_MAX, "%s/%ld.%u_%d.%s%s", subdir,
+ time (NULL), (unsigned int)getpid (), Counter++,
+ NONULL (Hostname), suffix);
snprintf (full, _POSIX_PATH_MAX, "%s/%s", ctx->path, path);
dprint (2, (debugfile, "maildir_commit_message (): renaming %s to %s.\n",
{
char path[_POSIX_PATH_MAX], tmp[_POSIX_PATH_MAX];
int i, j;
+#if USE_HCACHE
+ void *hc = NULL;
+#endif /* USE_HCACHE */
if (ctx->magic == M_MH)
i = mh_check_mailbox (ctx, index_hint);
if (i != 0)
return i;
+#if USE_HCACHE
+ if (ctx->magic == M_MAILDIR)
+ hc = mutt_hcache_open(HeaderCache, ctx->path);
+#endif /* USE_HCACHE */
+
for (i = 0; i < ctx->msgcount; i++)
{
if (ctx->hdrs[i]->deleted
snprintf (path, sizeof (path), "%s/%s", ctx->path, ctx->hdrs[i]->path);
if (ctx->magic == M_MAILDIR
|| (option (OPTMHPURGE) && ctx->magic == M_MH))
+ {
+#if USE_HCACHE
+ if (ctx->magic == M_MAILDIR)
+ mutt_hcache_delete (hc, ctx->hdrs[i]->path + 3, &maildir_hcache_keylen);
+#endif /* USE_HCACHE */
unlink (path);
+ }
else if (ctx->magic == M_MH)
{
/* MH just moves files out of the way when you delete them */
if (ctx->magic == M_MAILDIR)
{
if (maildir_sync_message (ctx, i) == -1)
- return -1;
+ goto err;
}
else
{
if (mh_sync_message (ctx, i) == -1)
- return -1;
+ goto err;
}
}
}
+#if USE_HCACHE
+ if (ctx->magic == M_MAILDIR)
+ mutt_hcache_close (hc);
+#endif /* USE_HCACHE */
+
if (ctx->magic == M_MH)
mh_update_sequences (ctx);
}
return 0;
+
+err:
+#if USE_HCACHE
+ if (ctx->magic == M_MAILDIR)
+ mutt_hcache_close (hc);
+#endif /* USE_HCACHE */
+ return -1;
}
static char *maildir_canon_filename (char *dest, const char *src, size_t l)