Commit 013a498d authored by Thomas Roessler's avatar Thomas Roessler

Make reading maildirs more efficient.

parent 0bd84f19
...@@ -45,6 +45,7 @@ struct maildir ...@@ -45,6 +45,7 @@ struct maildir
{ {
HEADER *h; HEADER *h;
char *canon_fname; char *canon_fname;
unsigned header_parsed : 1;
struct maildir *next; struct maildir *next;
}; };
...@@ -544,15 +545,20 @@ static void maildir_update_mtime(CONTEXT *ctx) ...@@ -544,15 +545,20 @@ static void maildir_update_mtime(CONTEXT *ctx)
ctx->mtime = st.st_mtime; ctx->mtime = st.st_mtime;
} }
static HEADER *maildir_parse_message(int magic, const char *fname, int is_old) /*
* Actually parse a maildir message. This may also be used to fill
* out a fake header structure generated by lazy maildir parsing.
*/
static HEADER *maildir_parse_message (int magic, const char *fname, int is_old, HEADER *_h)
{ {
FILE *f; FILE *f;
HEADER *h = NULL; HEADER *h = _h;
struct stat st; struct stat st;
if ((f = fopen (fname, "r")) != NULL) if ((f = fopen (fname, "r")) != NULL)
{ {
h = mutt_new_header(); if (!h)
h = mutt_new_header();
h->env = mutt_read_rfc822_header (f, h, 0, 0); h->env = mutt_read_rfc822_header (f, h, 0, 0);
fstat (fileno (f), &st); fstat (fileno (f), &st);
...@@ -568,25 +574,37 @@ static HEADER *maildir_parse_message(int magic, const char *fname, int is_old) ...@@ -568,25 +574,37 @@ static HEADER *maildir_parse_message(int magic, const char *fname, int is_old)
if (magic == M_MAILDIR) if (magic == M_MAILDIR)
{ {
/* maildir stores its flags in the filename, so ignore the flags in /*
* the header of the message * maildir stores its flags in the filename, so ignore the
* flags in the header of the message
*/ */
h->old = is_old; h->old = is_old;
maildir_parse_flags(h, fname); maildir_parse_flags (h, fname);
} }
} }
return h; return h;
} }
/* note that this routine will _not_ modify the context given by ctx. */ /*
* Note that this routine will _not_ modify the context given by
* ctx.
*
* It's used in the first parsing pass on maildir and MH folders.
* In the MH case, this means full parsing of the folder. In the
* maildir case, it means that we only look at flags, and create a
* fake HEADER structure, which may later be filled in by
* maildir_parse_message(), when called from
* maildir_delayed_parsing().
*
*/
static int maildir_parse_entry(CONTEXT *ctx, struct maildir ***last, static int maildir_parse_entry (CONTEXT *ctx, struct maildir ***last,
const char *subdir, const char *fname, const char *subdir, const char *fname,
int *count, int is_old) int *count, int is_old)
{ {
struct maildir *entry; struct maildir *entry;
HEADER *h; HEADER *h = NULL;
char buf[_POSIX_PATH_MAX]; char buf[_POSIX_PATH_MAX];
if(subdir) if(subdir)
...@@ -594,9 +612,18 @@ static int maildir_parse_entry(CONTEXT *ctx, struct maildir ***last, ...@@ -594,9 +612,18 @@ static int maildir_parse_entry(CONTEXT *ctx, struct maildir ***last,
else else
snprintf(buf, sizeof(buf), "%s/%s", ctx->path, fname); snprintf(buf, sizeof(buf), "%s/%s", ctx->path, fname);
if((h = maildir_parse_message(ctx->magic, buf, is_old)) != NULL) if (ctx->magic == M_MH)
h = maildir_parse_message (ctx->magic, buf, is_old, NULL);
else
{
h = mutt_new_header ();
h->old = is_old;
maildir_parse_flags (h, buf);
}
if (h != NULL)
{ {
if(count) if (count)
{ {
(*count)++; (*count)++;
if (!ctx->quiet && ReadInc && ((*count % ReadInc) == 0 || *count == 1)) if (!ctx->quiet && ReadInc && ((*count % ReadInc) == 0 || *count == 1))
...@@ -613,6 +640,7 @@ static int maildir_parse_entry(CONTEXT *ctx, struct maildir ***last, ...@@ -613,6 +640,7 @@ static int maildir_parse_entry(CONTEXT *ctx, struct maildir ***last,
entry = safe_calloc(sizeof(struct maildir), 1); entry = safe_calloc(sizeof(struct maildir), 1);
entry->h = h; entry->h = h;
entry->header_parsed = (ctx->magic == M_MH);
**last = entry; **last = entry;
*last = &entry->next; *last = &entry->next;
...@@ -622,6 +650,8 @@ static int maildir_parse_entry(CONTEXT *ctx, struct maildir ***last, ...@@ -622,6 +650,8 @@ static int maildir_parse_entry(CONTEXT *ctx, struct maildir ***last,
return -1; return -1;
} }
/* Ignore the garbage files. A valid MH message consists of only /* Ignore the garbage files. A valid MH message consists of only
* digits. Deleted message get moved to a filename with a comma before * digits. Deleted message get moved to a filename with a comma before
* it. * it.
...@@ -637,8 +667,8 @@ int mh_valid_message (const char *s) ...@@ -637,8 +667,8 @@ int mh_valid_message (const char *s)
return 1; return 1;
} }
static int maildir_parse_dir(CONTEXT *ctx, struct maildir ***last, static int maildir_parse_dir (CONTEXT *ctx, struct maildir ***last,
const char *subdir, int *count) const char *subdir, int *count)
{ {
DIR *dirp; DIR *dirp;
struct dirent *de; struct dirent *de;
...@@ -711,10 +741,34 @@ static void maildir_add_to_context(CONTEXT *ctx, struct maildir *md) ...@@ -711,10 +741,34 @@ static void maildir_add_to_context(CONTEXT *ctx, struct maildir *md)
static void maildir_move_to_context(CONTEXT *ctx, struct maildir **md) static void maildir_move_to_context(CONTEXT *ctx, struct maildir **md)
{ {
maildir_add_to_context(ctx, *md); maildir_add_to_context (ctx, *md);
maildir_free_maildir(md); maildir_free_maildir (md);
} }
/*
* 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];
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);
}
}
/* Read a MH/maildir style mailbox. /* Read a MH/maildir style mailbox.
* *
* args: * args:
...@@ -737,7 +791,7 @@ int mh_read_dir (CONTEXT *ctx, const char *subdir) ...@@ -737,7 +791,7 @@ int mh_read_dir (CONTEXT *ctx, const char *subdir)
maildir_update_mtime(ctx); maildir_update_mtime(ctx);
if(maildir_parse_dir(ctx, &last, subdir, &count) == -1) if (maildir_parse_dir(ctx, &last, subdir, &count) == -1)
return -1; return -1;
if (ctx->magic == M_MH) if (ctx->magic == M_MH)
...@@ -747,6 +801,9 @@ int mh_read_dir (CONTEXT *ctx, const char *subdir) ...@@ -747,6 +801,9 @@ int mh_read_dir (CONTEXT *ctx, const char *subdir)
mhs_free_sequences (&mhs); mhs_free_sequences (&mhs);
} }
if (ctx->magic == M_MAILDIR)
maildir_delayed_parsing (ctx, md);
maildir_move_to_context(ctx, &md); maildir_move_to_context(ctx, &md);
return 0; return 0;
} }
...@@ -1379,8 +1436,8 @@ int mh_check_mailbox(CONTEXT *ctx, int *index_hint) ...@@ -1379,8 +1436,8 @@ int mh_check_mailbox(CONTEXT *ctx, int *index_hint)
dprint(2, (debugfile, "%s:%d: mh_check_mailbox(): Looking for %s.\n", __FILE__, __LINE__, b1)); dprint(2, (debugfile, "%s:%d: mh_check_mailbox(): Looking for %s.\n", __FILE__, __LINE__, b1));
if((p = hash_find(fnames, b1)) && p->h && if ((p = hash_find(fnames, b1)) && p->h &&
mbox_strict_cmp_headers(ctx->hdrs[i], p->h)) (ctx->magic == M_MAILDIR || mbox_strict_cmp_headers(ctx->hdrs[i], p->h)))
{ {
/* found the right message */ /* found the right message */
...@@ -1448,6 +1505,7 @@ int mh_check_mailbox(CONTEXT *ctx, int *index_hint) ...@@ -1448,6 +1505,7 @@ int mh_check_mailbox(CONTEXT *ctx, int *index_hint)
occult = 1; occult = 1;
} }
} }
/* destroy the file name hash */ /* destroy the file name hash */
...@@ -1481,6 +1539,10 @@ int mh_check_mailbox(CONTEXT *ctx, int *index_hint) ...@@ -1481,6 +1539,10 @@ int mh_check_mailbox(CONTEXT *ctx, int *index_hint)
mx_update_tables(ctx, 0); mx_update_tables(ctx, 0);
} }
/* If this is a maildir folder, do any delayed parsing we need to do. */
if (ctx->magic == M_MAILDIR)
maildir_delayed_parsing (ctx, md);
/* Incorporate new messages */ /* Incorporate new messages */
maildir_move_to_context(ctx, &md); maildir_move_to_context(ctx, &md);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment