diff -Ndurp -X ignore mutt-cvs/Makefile.am mutt-hcache/Makefile.am --- mutt-cvs/Makefile.am Thu Jan 24 13:53:19 2002 +++ mutt-hcache/Makefile.am Thu Jan 24 23:11:57 2002 @@ -60,7 +60,7 @@ CPPFLAGS=@CPPFLAGS@ -I$(includedir) EXTRA_mutt_SOURCES = account.c md5c.c mutt_sasl.c mutt_socket.c mutt_ssl.c \ mutt_tunnel.c pop.c pop_auth.c pop_lib.c crypt.c smime.c pgp.c pgpinvoke.c pgpkey.c \ pgplib.c sha1.c pgpmicalg.c gnupgparse.c resize.c dotlock.c remailer.c \ - browser.h mbyte.h remailer.h url.h mutt_ssl_nss.c pgppacket.c + browser.h mbyte.h remailer.h url.h mutt_ssl_nss.c pgppacket.c cache.c EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP OPS.CRYPT OPS.SMIME TODO \ configure acconfig.h account.h \ diff -Ndurp -X ignore mutt-cvs/PATCHES mutt-hcache/PATCHES --- mutt-cvs/PATCHES Thu Jan 24 04:10:47 2002 +++ mutt-hcache/PATCHES Thu Jan 24 23:31:47 2002 @@ -0,0 +1 @@ +1.5.0-me.hcache.8 diff -Ndurp -X ignore mutt-cvs/cache.c mutt-hcache/cache.c --- mutt-cvs/cache.c Wed Dec 31 16:00:00 1969 +++ mutt-hcache/cache.c Thu Jan 24 23:11:57 2002 @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2002 Michael R. Elkins + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#if USE_CACHE + +#if HAVE_LIBDB +#define DB_DBM_HSEARCH 1 +#include +#else +#include +#endif + +#include +#include "mutt.h" +#include "mime.h" +#include "mx.h" + +/* Wrapper around the DBM struct. This is necessary to acheive proper + * exclusive locking using the mx_lock_file() + */ +typedef struct +{ + DBM *db; + char *path; + int fd; +} +hcache_t; + +/****************************************************************************** + * NDBM Wrapper Functions + * + * The following section contains code which is a thin layer over their + * counterparts in NDBM. NDBM lacks field access inside of each database + * record, and to avoid using a full blown database I define a structure + * for each record that allows arbitrary number of fields. + * + * Each record consists of length byte(s) indicating how much data is in the + * field, followed by the field bytes. If the length of the field is less + * than 128 bytes, only a single length byte is required. Otherwise, the + * length is broken into 7-bit pieces and the high order bit of each piece + * except for the last is set. NOTE: currently there is only support for up + * to 14-bits of length, which should be more than sufficient for our + * purposes with header caching in Mutt. + *****************************************************************************/ + +/* Stores a record under the index defined by `key' consisting of the + * elements in `field' which is `nfields' long. `flag' is as with + * dbm_store and is passed directly. + */ +static int +field_store (DBM * db, datum key, datum * field, size_t nfields, int flag) +{ + datum d; + unsigned char *dptr; + size_t i; + int r; + + d.dsize = 0; + for (i = 0; i < nfields; i++) + d.dsize += ((field[i].dsize > 127) ? 2 : 1) + field[i].dsize; + + d.dptr = safe_malloc (d.dsize); + for (i = 0, dptr = (unsigned char *) d.dptr; i < nfields; i++) + { + if (field[i].dsize > 127) + *dptr++ = 0x80 | (field[i].dsize >> 7); + *dptr++ = field[i].dsize & 0x7f; + memcpy (dptr, field[i].dptr, field[i].dsize); + dptr += field[i].dsize; + } + + r = dbm_store (db, key, d, flag); + + FREE (&d.dptr); + + return r; +} + +/* Retreives the record associated with the index `key'. The returned + * record is an array consisting of `nfields' elements. `nfields' is + * set to the number of elements, or 0 upon failure--which could be due to + * a malformed cache entry, or missing entry. + */ +static datum * +field_fetch (DBM * db, datum key, size_t * nfields) +{ + datum d = dbm_fetch (db, key); + datum *field = 0; + size_t ofst = 0; + size_t n; + + *nfields = 0; + + while (ofst < d.dsize) + { + field = realloc (field, sizeof (datum) * (1 + *nfields)); + n = (unsigned char) d.dptr[ofst++]; + if (n > 127) + { + n &= ~0x80; + n <<= 7; + n |= (unsigned char) d.dptr[ofst++]; + } + field[*nfields].dsize = n; + if (field[*nfields].dsize) + { + field[*nfields].dptr = safe_malloc (field[*nfields].dsize); + memcpy (field[*nfields].dptr, d.dptr + ofst, + field[*nfields].dsize); + ofst += field[*nfields].dsize; + } + else + field[*nfields].dptr = NULL; + ++*nfields; + } + + /* `d' contains static storage? */ + + return field; +} + +/* Helper function to free() all the elements of a record. It expects `d' + * to be an array of `nfields' elements. + */ +static void +field_free (datum * d, size_t nfields) +{ + size_t i; + + for (i = 0; i < nfields; i++) + FREE (&d[i].dptr); + FREE (&d); +} + +/****************************************************************************** + * Header Caching Code + *****************************************************************************/ + +/* These are the fields of each record, in order. Note that you can add + * fields before hc_max, but if you change the order of any of these + * constants, existing cache databases will be invalide. Furthurmore, there + * is no support for detection of older database so don't mess with this + * unless it is absolutely critical. + * + * Note: anything checked in mbox_strict_cmp_headers() should be cached here + * or else the check will fail for valid matches. + */ +enum +{ + hc_from, + hc_to, + hc_cc, + hc_subj, + hc_msgid, + hc_date, + hc_replyto, + hc_refs, + hc_inreplyto, + hc_contenttype, + hc_encoding, /*content-transfer-encoding */ + hc_contentlength, + hc_contentoffset, + hc_lines, + hc_returnpath, /* return-path: value */ + hc_sender, /* sender: value */ + hc_received, /* received time */ + hc_max /* MUST BE LAST--Indicates the number of fields per record */ +}; + +void * +mutt_hcache_open (const char *path) +{ + char dbfile[_POSIX_PATH_MAX]; + hcache_t *h = safe_calloc (1, sizeof (hcache_t)); + + /* Lock the db file in a NFS-safe manner. Since we can't guarantee + * what the real name of the db file will be, create a temp file + * in place of it. Too bad we can't juse use a lock file by itself + * as a mutex without the requirement for a source file. + */ + snprintf (dbfile, sizeof (dbfile), "%s-lock-hack", path); + h->fd = open (dbfile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + if (h->fd < 0) + { + FREE (&h); + return NULL; + } + if (mx_lock_file (dbfile, h->fd, 1, 1, 5)) + { + close (h->fd); + FREE (&h); + return NULL; + } + + h->db = dbm_open (path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if (h->db == NULL) + { + mx_unlock_file (path, h->fd, 1); + /* XXX perhaps we should use mx_unlink_empty() instead? */ + unlink (path); + close (h->fd); + FREE (&h); + return NULL; + } + + h->path = safe_strdup (dbfile); + + return h; +} + +void +mutt_hcache_close (void *ref) +{ + hcache_t *h = (hcache_t *) ref; + + if (h) + { + dbm_close (h->db); + /* XXX I think there is no problem with unlinking here. There + * could be other writers waiting that still have the file open, + * and if another writer comes along and creates a new file they + * will still try to create a lockfile with the same name. This + * is why we don't bother with O_EXCL in the open() call. + */ + mx_unlock_file (h->path, h->fd, 1); + unlink (h->path); + close (h->fd); + FREE (&h->path); + FREE (&h); + } +} + +static ADDRESS * +field_to_address (datum * d) +{ + ADDRESS *addr = 0; + + if (d->dptr) + addr = rfc822_parse_adrlist (NULL, d->dptr); + return addr; +} + +static char * +field_to_string (datum * d) +{ + char *s = d->dptr; + + d->dptr = 0; + return s; +} + +static LIST * +field_to_list (datum * d) +{ + LIST *head = NULL; + LIST **cur = &head; + char *p = d->dptr; + char *q; + + while (p) + { + q = strchr (p, ' '); + if (q) + *q++ = 0; + *cur = safe_calloc (1, sizeof (LIST)); + (*cur)->data = safe_strdup (p); + cur = &(*cur)->next; + p = q; + } + + return head; +} + +#define field_to_int(d) ((d).dptr ? atol((d).dptr) : 0) + +HEADER * +mutt_hcache_fetch (void *ref, const char *key, size_t klen) +{ + datum *rec; + size_t nrec; + datum d; + HEADER *h; + hcache_t *cache = (hcache_t *) ref; + + d.dptr = (char *) key; + d.dsize = klen; + + rec = field_fetch (cache->db, d, &nrec); + if (nrec < hc_max) + { + if (rec) + field_free (rec, nrec); + return NULL; /* missing/invalid cache entry */ + } + + h = mutt_new_header (); + h->env = mutt_new_envelope (); + h->content = mutt_new_body (); + + /* address fields */ + h->env->from = field_to_address (&rec[hc_from]); + h->env->to = field_to_address (&rec[hc_to]); + h->env->cc = field_to_address (&rec[hc_cc]); + h->env->reply_to = field_to_address (&rec[hc_replyto]); + h->env->return_path = field_to_address (&rec[hc_returnpath]); + h->env->sender = field_to_address (&rec[hc_sender]); + + /* string fields */ + h->env->subject = field_to_string (&rec[hc_subj]); + if (h->env->subject) + { + regmatch_t pmatch[1]; + + if (regexec (ReplyRegexp.rx, h->env->subject, 1, pmatch, 0) == 0) + h->env->real_subj = h->env->subject + pmatch[0].rm_eo; + else + h->env->real_subj = h->env->subject; + } + h->env->message_id = field_to_string (&rec[hc_msgid]); + h->env->date = field_to_string (&rec[hc_date]); + + /* list fields */ + h->env->references = field_to_list (&rec[hc_refs]); + h->env->in_reply_to = field_to_list (&rec[hc_inreplyto]); + + /* integer fields */ + h->content->length = field_to_int (rec[hc_contentlength]); + h->content->offset = field_to_int (rec[hc_contentoffset]); + h->lines = field_to_int (rec[hc_lines]); + h->received = field_to_int (rec[hc_received]); + + h->content->encoding = mutt_check_encoding (rec[hc_encoding].dptr); + + /* special case - content-type */ + if (rec[hc_contenttype].dptr) + mutt_parse_content_type (rec[hc_contenttype].dptr, h->content); + + if (h->env->date) + h->date_sent = mutt_parse_date (h->env->date, h); + + field_free (rec, nrec); + + return h; +} + +/* stores an integer in ascii representation to avoid interoperability + * problems among different architectures. + */ +static void +int_to_field (datum * d, size_t n) +{ + char tmp[16]; + + snprintf (tmp, sizeof (tmp), "%u", n); + d->dptr = safe_strdup (tmp); + d->dsize = strlen (tmp) + 1; +} + +static void +string_to_field (datum * d, const char *s) +{ + if (s) + { + d->dptr = safe_strdup (s); + d->dsize = strlen (s) + 1; + } +} + +static void +address_to_field (datum * d, ADDRESS * a) +{ + char tmp[2048]; + + if (a) + { + tmp[0] = 0; + rfc822_write_address (tmp, sizeof (tmp), a); + d->dptr = safe_strdup (tmp); + d->dsize = strlen (tmp) + 1; + } +} + +static void +list_to_field (datum * d, LIST * l) +{ + if (l) + { + while (l) + { + size_t i = strlen (l->data) + 1; + d->dptr = realloc (d->dptr, d->dsize + i + 1); + sprintf (d->dptr + d->dsize, "%s%s", d->dsize > 0 ? " " : "", + l->data); + d->dsize += i; + l = l->next; + } + d->dsize++; + } +} + +int +mutt_hcache_store (void *ref, const char *key, size_t klen, HEADER * h) +{ + datum d; + int r; + size_t i; + datum rec[hc_max]; + char buf[1024]; /* icky */ + hcache_t *cache = (hcache_t *) ref; + + memset (rec, 0, sizeof (rec)); + + /* address fields */ + address_to_field (&rec[hc_from], h->env->from); + address_to_field (&rec[hc_to], h->env->to); + address_to_field (&rec[hc_cc], h->env->cc); + address_to_field (&rec[hc_replyto], h->env->reply_to); + address_to_field (&rec[hc_returnpath], h->env->return_path); + address_to_field (&rec[hc_sender], h->env->sender); + + /* string fields */ + string_to_field (&rec[hc_subj], h->env->subject); + string_to_field (&rec[hc_msgid], h->env->message_id); + string_to_field (&rec[hc_date], h->env->date); + string_to_field (&rec[hc_encoding], ENCODING (h->content->encoding)); + + /* list fields */ + list_to_field (&rec[hc_refs], h->env->references); + list_to_field (&rec[hc_inreplyto], h->env->in_reply_to); + + /* integer fields */ + int_to_field (&rec[hc_contentlength], h->content->length); + int_to_field (&rec[hc_contentoffset], h->content->offset); + int_to_field (&rec[hc_lines], h->lines); + int_to_field (&rec[hc_received], h->received); + + /* special case for content-type */ + { + PARAMETER *p; + + /* XXX TYPEOTHER is not handled here */ + snprintf (buf, sizeof (buf), "%s/%s", TYPE (h->content), + h->content->subtype); + for (p = h->content->parameter; p; p = p->next) + { + snprintf (buf + strlen (buf), sizeof (buf) - strlen (buf), + "; %s=\"%s\"", p->attribute, p->value); + } + + rec[hc_contenttype].dptr = safe_strdup (buf); + rec[hc_contenttype].dsize = strlen (buf) + 1; + } + + d.dptr = (char *) key; + d.dsize = klen; + r = field_store (cache->db, d, rec, hc_max, DBM_REPLACE); + + for (i = 0; i < hc_max; i++) + if (rec[i].dptr) + FREE (&rec[i].dptr); + + return r; +} + +int +mutt_hcache_delete (void *ref, const char *key, size_t klen) +{ + datum d; + hcache_t *cache = (hcache_t *) ref; + + d.dptr = (char *) key; + d.dsize = klen; + + return dbm_delete (cache->db, d); +} +#endif /* USE_CACHE */ + +/* vim: set sw=2: */ diff -Ndurp -X ignore mutt-cvs/configure.in mutt-hcache/configure.in --- mutt-cvs/configure.in Thu Jan 24 13:53:19 2002 +++ mutt-hcache/configure.in Thu Jan 24 23:11:57 2002 @@ -345,6 +345,39 @@ if test $mutt_cv_regex = yes; then LIBOBJS="$LIBOBJS regex.o" fi +dnl -- start cache -- +AC_ARG_ENABLE(cache, +[ --enable-cache Enable header caching for Maildir folders], +[if test x$enableval = xyes; then + AC_DEFINE(USE_CACHE, 1, [Enable header caching for Maildir style mailboxes]) + MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS cache.o" + AC_CACHE_CHECK(for dbm_open, ac_cv_dbmopen, + [ac_cv_dbmopen=no + AC_TRY_LINK([#include ],[dbm_open(0,0,0);],[ac_cv_dbmopen=yes])]) + + if test $ac_cv_dbmopen = no; then + AC_CACHE_CHECK(for dbm_open in -ldb, ac_cv_libdb, + [old_LIBS="$LIBS" + LIBS="$LIBS -ldb" + dnl -- this will detect either libdb2 or libdb3 -- + ac_cv_libdb=no + AC_TRY_LINK([#define DB_DBM_HSEARCH 1 +#include ], + [dbm_open(0,0,0);], + [ac_cv_libdb=yes]) + LIBS="$old_LIBS"]) + if test $ac_cv_libdb = yes; then + AC_DEFINE(HAVE_LIBDB, 1, [Use libdb to provide NDBM interface]) + MUTTLIBS="$MUTTLIBS -ldb" + ac_cv_dbmopen=yes + fi + fi + + if test $ac_cv_dbmopen = no; then + AC_MSG_ERROR(You must install libdb or some other NDBM library with --enable-cache) + fi +fi]) +dnl -- end cache -- AC_ARG_WITH(homespool, [ --with-homespool[=FILE] File in user's directory where new mail is spooled], with_homespool=${withval}) if test x$with_homespool != x; then Binary files mutt-cvs/gmon.out and mutt-hcache/gmon.out differ diff -Ndurp -X ignore mutt-cvs/main.c mutt-hcache/main.c --- mutt-cvs/main.c Thu Jan 24 13:53:19 2002 +++ mutt-hcache/main.c Thu Jan 24 23:11:57 2002 @@ -42,13 +42,13 @@ To contact the developers, please mail t To report a bug, please use the flea(1) utility.\n"); static const char *Notice = N_("\ -Copyright (C) 1996-2001 Michael R. Elkins and others.\n\ +Copyright (C) 1996-2002 Michael R. Elkins and others.\n\ Mutt comes with ABSOLUTELY NO WARRANTY; for details type `mutt -vv'.\n\ Mutt is free software, and you are welcome to redistribute it\n\ under certain conditions; type `mutt -vv' for details.\n"); static const char *Copyright = N_("\ -Copyright (C) 1996-2001 Michael R. Elkins \n\ +Copyright (C) 1996-2002 Michael R. Elkins \n\ Copyright (C) 1996-2001 Brandon Long \n\ Copyright (C) 1997-2001 Thomas Roessler \n\ Copyright (C) 1998-2001 Werner Koch \n\ @@ -383,6 +383,12 @@ static void show_version (void) "+HAVE_GETADDRINFO " #else "-HAVE_GETADDRINFO " +#endif + +#if USE_CACHE + "+USE_CACHE " +#else + "-USE_CACHE " #endif ); Binary files mutt-cvs/makedoc and mutt-hcache/makedoc differ diff -Ndurp -X ignore mutt-cvs/mbox.c mutt-hcache/mbox.c --- mutt-cvs/mbox.c Thu Jan 24 04:10:49 2002 +++ mutt-hcache/mbox.c Thu Jan 24 23:11:57 2002 @@ -535,7 +535,6 @@ int mbox_strict_cmp_headers (const HEADE h1->zhours != h2->zhours || h1->zminutes != h2->zminutes || h1->zoccident != h2->zoccident || - h1->mime != h2->mime || !strict_cmp_envelopes (h1->env, h2->env) || !strict_cmp_bodies (h1->content, h2->content)) return (0); diff -Ndurp -X ignore mutt-cvs/mh.c mutt-hcache/mh.c --- mutt-cvs/mh.c Thu Jan 24 15:33:26 2002 +++ mutt-hcache/mh.c Fri Jan 25 10:27:24 2002 @@ -45,7 +45,6 @@ struct maildir { HEADER *h; char *canon_fname; - unsigned header_parsed:1; struct maildir *next; }; @@ -559,8 +558,7 @@ static void maildir_update_mtime (CONTEX * 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) +static HEADER *maildir_parse_message (int magic, const char *fname, HEADER * _h) { FILE *f; HEADER *h = _h; @@ -583,16 +581,6 @@ static HEADER *maildir_parse_message (in h->index = -1; - if (magic == M_MAILDIR) - { - /* - * maildir stores its flags in the filename, so ignore the - * flags in the header of the message - */ - - h->old = is_old; - maildir_parse_flags (h, fname); - } } return h; } @@ -624,7 +612,7 @@ static int maildir_parse_entry (CONTEXT snprintf (buf, sizeof (buf), "%s/%s", ctx->path, fname); if (ctx->magic == M_MH) - h = maildir_parse_message (ctx->magic, buf, is_old, NULL); + h = maildir_parse_message (ctx->magic, buf, NULL); else { h = mutt_new_header (); @@ -651,7 +639,6 @@ static int maildir_parse_entry (CONTEXT entry = safe_calloc (sizeof (struct maildir), 1); entry->h = h; - entry->header_parsed = (ctx->magic == M_MH); **last = entry; *last = &entry->next; @@ -765,6 +752,18 @@ static int maildir_move_to_context (CONT return r; } +#if USE_CACHE +/* + * Calculates the length of the filename without the flags. This is the + * part of the filename we use as the key for the header cache lookup. + */ + +size_t maildir_cache_keylen (const char *fn) +{ + const char * p = strchr (fn, ':'); + return p ? (size_t) (p - fn) : strlen (fn); +} +#endif /* * This function does the second parsing pass for a maildir-style @@ -775,20 +774,73 @@ void maildir_delayed_parsing (CONTEXT * { struct maildir *p; char fn[_POSIX_PATH_MAX]; +#if USE_CACHE + void *db; + HEADER *h = NULL; + + snprintf (fn, sizeof (fn), "%s/hcache", ctx->path); + db = mutt_hcache_open (fn); +#endif for (p = md; p; p = p->next) - if (p && p->h && !p->header_parsed) + if (p && p->h) { 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; + +#if USE_CACHE + /* See if we get a cache hit for this message */ + if (db) + { + /* + * The key for the lookup is the basename of the file sans flags. + * We don't include the subdirectory so that the cache line is still + * valid when the message is moved from new to cur + */ + + h = mutt_hcache_fetch (db, p->h->path + 4, + maildir_cache_keylen (p->h->path + 4)); + if (h) + { + /* + * Replace the fake HEADER struct with the full value restored + * from the cache. + */ + h->old = p->h->old; + h->path = safe_strdup (p->h->path); + maildir_parse_flags (h, fn); + mutt_free_header (&p->h); + p->h = h; + continue; + } + } +#endif + + if (maildir_parse_message (ctx->magic, fn, p->h)) + { + /* + * maildir stores its flags in the filename, so ignore the + * flags in the header of the message + */ + + maildir_parse_flags (p->h, fn); + +#if USE_CACHE + /* + * This header is not cached. Attempt to do it now if the DB + * is open. + */ + if (db) + mutt_hcache_store (db, p->h->path + 4, maildir_cache_keylen (p->h->path + 4), p->h); +#endif + } else mutt_free_header (&p->h); } +#if USE_CACHE + mutt_hcache_close (db); +#endif } - - /* Read a MH/maildir style mailbox. * * args: @@ -820,8 +872,7 @@ int mh_read_dir (CONTEXT * ctx, const ch mh_update_maildir (md, &mhs); mhs_free_sequences (&mhs); } - - if (ctx->magic == M_MAILDIR) + else if (ctx->magic == M_MAILDIR) maildir_delayed_parsing (ctx, md); maildir_move_to_context (ctx, &md); @@ -1241,15 +1292,23 @@ int mh_sync_mailbox (CONTEXT * ctx, int { char path[_POSIX_PATH_MAX], tmp[_POSIX_PATH_MAX]; int i, j; +#if USE_CACHE + void *db; +#endif if (ctx->magic == M_MH) i = mh_check_mailbox (ctx, index_hint); else i = maildir_check_mailbox (ctx, index_hint); - + if (i != 0) return i; +#if USE_CACHE + snprintf (tmp, sizeof (tmp), "%s/hcache", ctx->path); + db = mutt_hcache_open (tmp); +#endif + for (i = 0; i < ctx->msgcount; i++) { if (ctx->hdrs[i]->deleted @@ -1258,7 +1317,14 @@ int mh_sync_mailbox (CONTEXT * ctx, int snprintf (path, sizeof (path), "%s/%s", ctx->path, ctx->hdrs[i]->path); if (ctx->magic == M_MAILDIR || (option (OPTMHPURGE) && ctx->magic == M_MH)) + { unlink (path); +#if USE_CACHE + if (db) + mutt_hcache_delete (db, ctx->hdrs[i]->path + 4, + maildir_cache_keylen (ctx->hdrs[i]->path + 4)); +#endif + } else if (ctx->magic == M_MH) { /* MH just moves files out of the way when you delete them */ @@ -1280,15 +1346,18 @@ int mh_sync_mailbox (CONTEXT * ctx, int 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_CACHE + mutt_hcache_close (db); +#endif if (ctx->magic == M_MH) mh_update_sequences (ctx); @@ -1310,6 +1379,12 @@ int mh_sync_mailbox (CONTEXT * ctx, int } return 0; + +err: +#if USE_CACHE + mutt_hcache_close (db); +#endif + return -1; } static char *maildir_canon_filename (char *dest, const char *src, size_t l) @@ -1415,6 +1490,9 @@ int maildir_check_mailbox (CONTEXT * ctx int i; HASH *fnames; /* hash table for quickly looking up the base filename for a maildir message */ +#if USE_CACHE + void *db; +#endif /* XXX seems like this check belongs in mx_check_mailbox() * rather than here. @@ -1466,6 +1544,11 @@ int maildir_check_mailbox (CONTEXT * ctx hash_insert (fnames, p->canon_fname, p, 0); } +#if USE_CACHE + snprintf (buf, sizeof (buf), "%s/hcache", ctx->path); + db = mutt_hcache_open (buf); +#endif + /* check for modifications and adjust flags */ for (i = 0; i < ctx->msgcount; i++) { @@ -1504,6 +1587,19 @@ int maildir_check_mailbox (CONTEXT * ctx * subdirectory it used to reside in. */ occult = 1; +#if USE_CACHE + /* + * Since this message doesn't appear to be around any longer, + * go ahead and purge its info from the cache. This won't + * catch any messages that are removed from the mailbox while + * Mutt is running, however. A separate utility will have to + * be written, perhaps run as a cron job periodically to + * compress the cache by removing stale entries. + */ + if (db) + mutt_hcache_delete (db, ctx->hdrs[i]->path + 4, + maildir_cache_keylen (ctx->hdrs[i]->path + 4)); +#endif } else { @@ -1515,13 +1611,17 @@ int maildir_check_mailbox (CONTEXT * ctx } } +#if USE_CACHE + mutt_hcache_close (db); +#endif + /* destroy the file name hash */ hash_destroy (&fnames, NULL); /* If we didn't just get new mail, update the tables. */ if (occult) maildir_update_tables (ctx, index_hint); - + /* do any delayed parsing we need to do. */ maildir_delayed_parsing (ctx, md); @@ -1725,3 +1825,5 @@ FILE *maildir_open_find_message (const c return NULL; } + +/* vim: set sw=2: */ Binary files mutt-cvs/mutt and mutt-hcache/mutt differ diff -Ndurp -X ignore mutt-cvs/mutt.h mutt-hcache/mutt.h --- mutt-cvs/mutt.h Thu Jan 24 13:53:19 2002 +++ mutt-hcache/mutt.h Thu Jan 24 23:11:57 2002 @@ -1,5 +1,5 @@ /* - * Copyright (C) 1996-2000 Michael R. Elkins + * Copyright (C) 1996-2002 Michael R. Elkins * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -623,7 +623,7 @@ typedef struct header see: crypt.h pgplib.h, smime.h */ #endif - unsigned int mime : 1; /* has a Mime-Version header? */ + unsigned int xxx : 1; /* unused */ unsigned int flagged : 1; /* marked important? */ unsigned int tagged : 1; unsigned int deleted : 1; diff -Ndurp -X ignore mutt-cvs/parse.c mutt-hcache/parse.c --- mutt-cvs/parse.c Thu Jan 24 13:53:19 2002 +++ mutt-hcache/parse.c Thu Jan 24 23:37:32 2002 @@ -1070,9 +1070,7 @@ int mutt_parse_rfc822_line (ENVELOPE *e, case 'm': if (!ascii_strcasecmp (line + 1, "ime-version")) { - if (hdr) - hdr->mime = 1; - matched = 1; + matched = 1; } else if (!ascii_strcasecmp (line + 1, "essage-id")) { Binary files mutt-cvs/pgpewrap and mutt-hcache/pgpewrap differ Binary files mutt-cvs/pgpring and mutt-hcache/pgpring differ diff -Ndurp -X ignore mutt-cvs/protos.h mutt-hcache/protos.h --- mutt-cvs/protos.h Thu Jan 24 13:53:19 2002 +++ mutt-hcache/protos.h Thu Jan 24 23:11:57 2002 @@ -1,5 +1,5 @@ /* - * Copyright (C) 1996-2000 Michael R. Elkins + * Copyright (C) 1996-2002 Michael R. Elkins * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -103,6 +103,7 @@ LIST *mutt_make_references(ENVELOPE *e); ENVELOPE *mutt_read_rfc822_header (FILE *, HEADER *, short, short); HEADER *mutt_dup_header (HEADER *); +HEADER *mutt_hcache_fetch (void *, const char *, size_t); ATTACHPTR **mutt_gen_attach_list (BODY *, int, ATTACHPTR **, short *, short *, int, int); @@ -188,6 +189,8 @@ void mutt_free_envelope (ENVELOPE **); void mutt_free_header (HEADER **); void mutt_free_parameter (PARAMETER **); void mutt_generate_header (char *, size_t, HEADER *, int); +void mutt_hcache_close (void *); +void *mutt_hcache_open (const char *); void mutt_help (int); void mutt_draw_tree (CONTEXT *); void mutt_check_lookup_list (BODY *, char *, int); @@ -279,6 +282,8 @@ int mutt_get_hook_type (const char *); int mutt_get_password (char *, char *, size_t); int mutt_get_postponed (CONTEXT *, HEADER *, HEADER **, char *, size_t); int mutt_get_tmp_attachment (BODY *); +int mutt_hcache_delete (void *, const char *, size_t); +int mutt_hcache_store (void *, const char *, size_t, HEADER *); int mutt_index_menu (void); int mutt_invoke_sendmail (ADDRESS *, ADDRESS *, ADDRESS *, ADDRESS *, const char *, int); int mutt_is_autoview (BODY *, const char *);