summaryrefslogtreecommitdiff
path: root/mail/mutt-devel/files/extra-patch-maildir-header-cache
diff options
context:
space:
mode:
authorKirill Ponomarev <krion@FreeBSD.org>2004-08-18 18:02:36 +0000
committerKirill Ponomarev <krion@FreeBSD.org>2004-08-18 18:02:36 +0000
commit0ab5af4b92d71d93251666a7716be6959a9b4d1b (patch)
treeb1a37d81e54a5d0fdcc6cfaedd22eb35f5aa406e /mail/mutt-devel/files/extra-patch-maildir-header-cache
parentUpdate to 2.0.1. (diff)
Update the maildir header cache patch, which now also
implements the IMAP header cache. This is far more stable than the old IMAP header cache patch. PR: ports/70623 Submitted by: maintainer
Notes
Notes: svn path=/head/; revision=116612
Diffstat (limited to 'mail/mutt-devel/files/extra-patch-maildir-header-cache')
-rw-r--r--mail/mutt-devel/files/extra-patch-maildir-header-cache703
1 files changed, 557 insertions, 146 deletions
diff --git a/mail/mutt-devel/files/extra-patch-maildir-header-cache b/mail/mutt-devel/files/extra-patch-maildir-header-cache
index 170d52e44c10..807b3f21b466 100644
--- a/mail/mutt-devel/files/extra-patch-maildir-header-cache
+++ b/mail/mutt-devel/files/extra-patch-maildir-header-cache
@@ -1,20 +1,21 @@
---- Makefile.am.orig Fri Mar 5 15:34:57 2004
-+++ Makefile.am Fri Mar 5 15:35:55 2004
+diff -Nru a/Makefile.am b/Makefile.am
+--- a/Makefile.am 2004-08-18 10:08:12 +02:00
++++ b/Makefile.am 2004-08-18 10:08:12 +02:00
@@ -20,2 +20,3 @@
mutt_SOURCES = $(BUILT_SOURCES) \
+ hcache.c \
addrbook.c alias.c attach.c base64.c browser.c buffy.c color.c \
diff -Nru a/configure.in b/configure.in
---- configure.in.orig Sat Jun 12 09:49:17 2004
-+++ configure.in Sat Jun 12 09:50:18 2004
-@@ -773,6 +773,80 @@
+--- a/configure.in 2004-08-18 10:08:12 +02:00
++++ b/configure.in 2004-08-18 10:08:12 +02:00
+@@ -768,6 +768,80 @@
fi])
+dnl -- start cache --
-+AC_ARG_ENABLE(hcache, [ --enable-hcache Enable header caching for Maildir folders],
++AC_ARG_ENABLE(hcache, [ --enable-hcache Enable header caching],
+[if test x$enableval = xyes; then
-+ AC_DEFINE(USE_HCACHE, 1, [Enable header caching for Maildir style mailboxes])
++ AC_DEFINE(USE_HCACHE, 1, [Enable header caching])
+
+ OLDCPPFLAGS="$CPPFLAGS"
+ OLDLIBS="$LIBS"
@@ -44,17 +45,17 @@ diff -Nru a/configure.in b/configure.in
+ for v in `echo $BDB_VERSIONS`; do
+ CPPFLAGS="$OLDCPPFLAGS -I$BDB_INCLUDE_DIR"
+ LIBS="$OLDLIBS -L$BDB_LIB_DIR -l$v"
-+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
-+ #include <stdlib.h>
++ AC_TRY_LINK([
++ #include <stdlib.h>
+ #include <db.h>
-+ ]],[[
++ ],[
+ DB *db = NULL;
+ db->open(db,NULL,NULL,NULL,0,0,0);
-+ ]])],[
++ ],[
+ ac_cv_dbcreate=yes
+ BDB_LIB="$v"
+ break
-+ ])
++ ])
+ done
+ test x$BDB_LIB != x && break
+ done
@@ -89,25 +90,26 @@ diff -Nru a/configure.in b/configure.in
AC_SUBST(MUTT_LIB_OBJECTS)
AC_SUBST(LIBIMAP)
diff -Nru a/globals.h b/globals.h
---- globals.h 2004-06-10 14:03:44 +02:00
-+++ globals.h 2004-06-10 14:03:44 +02:00
+--- a/globals.h 2004-08-18 10:08:12 +02:00
++++ b/globals.h 2004-08-18 10:08:12 +02:00
@@ -63,6 +63,10 @@
WHERE char *Locale;
WHERE char *MailcapPath;
WHERE char *Maildir;
+#if USE_HCACHE
-+WHERE char *MaildirCache;
-+WHERE short MaildirCachePageSize;
++WHERE char *HeaderCache;
++WHERE short HeaderCachePageSize;
+#endif
WHERE char *MhFlagged;
WHERE char *MhReplied;
WHERE char *MhUnseen;
diff -Nru a/hcache.c b/hcache.c
---- hcache.c.orig Sat Jun 12 09:52:31 2004
-+++ hcache.c Sat Jun 12 09:52:56 2004
-@@ -0,0 +1,676 @@
+--- /dev/null Wed Dec 31 16:00:00 196900
++++ b/hcache.c 2004-08-18 10:08:12 +02:00
+@@ -0,0 +1,794 @@
+/*
+ * Copyright (C) 2004 Thomas Glanzmann <sithglan@stud.uni-erlangen.de>
++ * Copyright (C) 2004 Tobias Werth <sitowert@stud.uni-erlangen.de>
+ * Copyright (C) 2004 Brian Fundakowski Feldman <green@FreeBSD.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
@@ -138,10 +140,39 @@ diff -Nru a/hcache.c b/hcache.c
+#include <errno.h>
+#include <fcntl.h>
+#include "mutt.h"
++#ifdef USE_IMAP
++#include "message.h"
++#endif
+#include "mime.h"
+#include "mx.h"
+#include "lib.h"
+
++#if HAVE_GDBM
++static struct
++header_cache
++{
++ GDBM_FILE db;
++ char *folder;
++ unsigned int crc;
++} HEADER_CACHE;
++#elif HAVE_DB4
++static struct
++header_cache
++{
++ DB_ENV *env;
++ DB *db;
++ unsigned int crc;
++ int fd;
++ char lockfile[_POSIX_PATH_MAX];
++} HEADER_CACHE;
++#endif
++
++typedef union
++{
++ struct timeval timeval;
++ unsigned long long uid_validity;
++} validate;
++
+static unsigned char *
+dump_int(unsigned int i, unsigned char *d, int *off)
+{
@@ -170,7 +201,24 @@ diff -Nru a/hcache.c b/hcache.c
+ return d;
+ }
+
-+ size = strlen(c) + 1;
++ size = mutt_strlen(c) + 1;
++ d = dump_int(size, d, off);
++ safe_realloc(&d, *off + size);
++ memcpy(d + *off, c, size);
++ *off += size;
++
++ return d;
++}
++
++static unsigned char *
++dump_char_size(char *c, unsigned char *d, int *off, ssize_t size)
++{
++ if (c == NULL) {
++ size = 0;
++ d = dump_int(size, d, off);
++ return d;
++ }
++
+ d = dump_int(size, d, off);
+ safe_realloc(&d, *off + size);
+ memcpy(d + *off, c, size);
@@ -195,14 +243,6 @@ diff -Nru a/hcache.c b/hcache.c
+ *off += size;
+}
+
-+static void
-+skip_char(const unsigned char *d, int *off)
-+{
-+ unsigned int size;
-+ restore_int(&size, d, off);
-+ *off += size;
-+}
-+
+static unsigned char *
+dump_address(ADDRESS *a, unsigned char *d, int *off)
+{
@@ -247,7 +287,6 @@ diff -Nru a/hcache.c b/hcache.c
+ }
+
+ *a = NULL;
-+ return;
+}
+
+static unsigned char *
@@ -284,7 +323,43 @@ diff -Nru a/hcache.c b/hcache.c
+ }
+
+ *l = NULL;
-+ return;
++}
++
++static unsigned char *
++dump_buffer(BUFFER *b, unsigned char *d, int *off)
++{
++ if (! b) {
++ d = dump_int(0, d, off);
++ return d;
++ } else {
++ d = dump_int(1, d, off);
++ }
++
++ d = dump_char_size(b->data, d, off, b->dsize + 1);
++ d = dump_int(b->dptr - b->data, d, off);
++ d = dump_int(b->dsize, d, off);
++ d = dump_int(b->destroy, d, off);
++
++ return d;
++}
++
++static void
++restore_buffer(BUFFER **b, const unsigned char *d, int *off)
++{
++ unsigned int used;
++ unsigned int offset;
++ restore_int(&used, d, off);
++ if (! used) {
++ return;
++ }
++
++ *b = safe_malloc(sizeof(BUFFER));
++
++ restore_char(& (*b)->data, d, off);
++ restore_int(& offset, d, off);
++ (*b)->dptr = (*b)->data + offset;
++ restore_int(& (*b)->dsize, d, off);
++ restore_int((unsigned int *) & (*b)->destroy, d, off);
+}
+
+static unsigned char *
@@ -323,7 +398,6 @@ diff -Nru a/hcache.c b/hcache.c
+ }
+
+ *p = NULL;
-+ return;
+}
+
+static unsigned char *
@@ -408,7 +482,7 @@ diff -Nru a/hcache.c b/hcache.c
+ restore_address(& e->mail_followup_to, d, off);
+
+ restore_char(& e->subject, d, off);
-+ restore_int(& real_subj_off, d, off);
++ restore_int((unsigned int *) (& real_subj_off), d, off);
+ if (0 <= real_subj_off) {
+ e->real_subj = e->subject + real_subj_off;
+ } else {
@@ -424,42 +498,72 @@ diff -Nru a/hcache.c b/hcache.c
+ restore_list(& e->userhdrs, d, off);
+}
+
++static
++unsigned int crc32(unsigned int crc, unsigned char const *p, size_t len)
++{
++ int i;
++ while (len--) {
++ crc ^= *p++;
++ for (i = 0; i < 8; i++)
++ crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
++ }
++ return crc;
++}
+
-+/* This function transforms a header into a char so that it is useable by
-+ * gdbm_store */
++static int
++generate_crc32()
++{
++ int crc = 0;
++
++ crc = crc32(crc, (unsigned char const *) "HCACHE V1", mutt_strlen("HCACHE V1"));
+
+#if HAVE_LANGINFO_CODESET
-+int
-+mutt_hcache_charset_matches(const char *d)
++ crc = crc32(crc, (unsigned char const *) Charset, mutt_strlen(Charset));
++ crc = crc32(crc, (unsigned char const *) "HAVE_LANGINFO_CODESET", mutt_strlen("HAVE_LANGINFO_CODESET"));
++#endif
++
++#if EXACT_ADDRESS
++ crc = crc32(crc, (unsigned char const *) "EXACT_ADDRESS", mutt_strlen("EXACT_ADDRESS"));
++#endif
++ return crc;
++}
++
++static int
++crc32_matches(const char *d, unsigned int crc)
+{
-+ int matches;
-+ int off = sizeof(struct timeval);
-+ char *charset = NULL;
++ int off = sizeof(validate);
++ unsigned int mycrc = 0;
++
++ if (! d) {
++ return 0;
++ }
+
-+ restore_char(&charset, (unsigned char *) d, &off);
-+ matches = (0 == mutt_strcmp(charset, Charset));
-+ FREE(&charset);
++ restore_int(&mycrc, (unsigned char *) d, &off);
+
-+ return (matches);
++ return (crc == mycrc);
+}
-+#endif /* HAVE_LANGINFO_CODESET */
+
++/* This function transforms a header into a char so that it is useable by
++ * db_store */
+static void *
-+mutt_hcache_dump(HEADER *h, int *off)
++mutt_hcache_dump(void *_db, HEADER *h, int *off, unsigned long long uid_validity)
+{
++ struct header_cache *db = _db;
+ unsigned char *d = NULL;
-+ struct timeval now;
+ *off = 0;
+
-+ d = safe_malloc(sizeof(struct timeval));
-+ gettimeofday(&now, NULL);
-+ memcpy(d, &now, sizeof(struct timeval));
-+ *off += sizeof(struct timeval);
++ d = safe_malloc(sizeof(validate));
+
-+#if HAVE_LANGINFO_CODESET
-+ d = dump_char(Charset, d, off);
-+#endif /* HAVE_LANGINFO_CODESET */
++ if (uid_validity) {
++ memcpy(d, &uid_validity, sizeof(long long));
++ } else {
++ struct timeval now;
++ gettimeofday(&now, NULL);
++ memcpy(d, &now, sizeof(struct timeval));
++ }
++ *off += sizeof(validate);
+
++ d = dump_int(db->crc, d, off);
+
+ safe_realloc(&d, *off + sizeof(HEADER));
+ memcpy(d + *off, h, sizeof(HEADER));
@@ -478,12 +582,11 @@ diff -Nru a/hcache.c b/hcache.c
+ int off = 0;
+ HEADER *h = mutt_new_header();
+
-+ /* skip timeval */
-+ off += sizeof(struct timeval);
++ /* skip validate */
++ off += sizeof(validate);
+
-+#if HAVE_LANGINFO_CODESET
-+ skip_char(d, &off);
-+#endif /* HAVE_LANGINFO_CODESET */
++ /* skip crc */
++ off += sizeof(unsigned int);
+
+ memcpy(h, d + off, sizeof(HEADER));
+ off += sizeof(HEADER);
@@ -496,45 +599,39 @@ diff -Nru a/hcache.c b/hcache.c
+
+ restore_char(&h->maildir_flags, d, &off);
+
-+ h->old = (*oh)->old;
-+ h->path = safe_strdup((*oh)->path);
-+ mutt_free_header (oh);
++ /* this is needed for maildir style mailboxes */
++ if (oh) {
++ h->old = (*oh)->old;
++ h->path = safe_strdup((*oh)->path);
++ mutt_free_header (oh);
++ }
+
+ return h;
+}
+
-+static size_t mutt_hcache_keylen (const char *fn)
-+{
-+ const char * p = strchr (fn, ':');
-+ return p ? (size_t) (p - fn) : strlen (fn);
-+}
-+
+#if HAVE_GDBM
-+static struct
-+header_cache
-+{
-+ GDBM_FILE db;
-+ char *folder;
-+} HEADER_CACHE;
+
+void *
+mutt_hcache_open(const char *path, const char *folder)
+{
-+ struct header_cache *h = malloc(sizeof(HEADER_CACHE));
++ struct header_cache *h = safe_calloc(1, sizeof(HEADER_CACHE));
+ h->db = NULL;
+ h->folder = safe_strdup (folder);
++ h->crc = generate_crc32();
+
+ if (! path || path[0] == '\0') {
++ FREE(& h->folder);
++ FREE(& h);
+ return NULL;
+ }
+
-+ h->db = gdbm_open((char *) path, (int) MaildirCachePageSize, GDBM_WRCREAT, 00600, NULL);
++ h->db = gdbm_open((char *) path, (int) HeaderCachePageSize, GDBM_WRCREAT, 00600, NULL);
+ if (h->db) {
+ return h;
+ }
+
+ /* if rw failed try ro */
-+ h->db = gdbm_open((char *) path, (int) MaildirCachePageSize, GDBM_READER, 00600, NULL);
++ h->db = gdbm_open((char *) path, (int) HeaderCachePageSize, GDBM_READER, 00600, NULL);
+ if(h->db) {
+ return h;
+ } else {
@@ -560,7 +657,7 @@ diff -Nru a/hcache.c b/hcache.c
+}
+
+void *
-+mutt_hcache_fetch(void *db, const char *filename)
++mutt_hcache_fetch(void *db, const char *filename, size_t (*keylen)(const char *fn))
+{
+ struct header_cache *h = db;
+ datum key;
@@ -572,18 +669,23 @@ diff -Nru a/hcache.c b/hcache.c
+ }
+
+ strncpy(path, h->folder, sizeof(path));
-+ strncat(path, filename, sizeof(path) - strlen(path));
++ strncat(path, filename, sizeof(path) - mutt_strlen(path));
+
+ key.dptr = path;
-+ key.dsize = mutt_hcache_keylen(path);
++ key.dsize = keylen(path);
+
+ data = gdbm_fetch(h->db, key);
+
++ if (! crc32_matches(data.dptr, h->crc)) {
++ free(data.dptr);
++ return NULL;
++ }
++
+ return data.dptr;
+}
+
+int
-+mutt_hcache_store(void *db, const char *filename, HEADER *header)
++mutt_hcache_store(void *db, const char *filename, HEADER *header, unsigned long long uid_validity, size_t (*keylen)(const char *fn))
+{
+ struct header_cache *h = db;
+ datum key;
@@ -596,12 +698,12 @@ diff -Nru a/hcache.c b/hcache.c
+ }
+
+ strncpy(path, h->folder, sizeof(path));
-+ strncat(path, filename, sizeof(path) - strlen(path));
++ strncat(path, filename, sizeof(path) - mutt_strlen(path));
+
+ key.dptr = path;
-+ key.dsize = mutt_hcache_keylen(path);
++ key.dsize = keylen(path);
+
-+ data.dptr = mutt_hcache_dump(header, &data.dsize);
++ data.dptr = mutt_hcache_dump(db, header, &data.dsize, uid_validity);
+
+ ret = gdbm_store(h->db, key, data, GDBM_REPLACE);
+
@@ -611,7 +713,7 @@ diff -Nru a/hcache.c b/hcache.c
+}
+
+int
-+mutt_hcache_delete(void *db, const char *filename)
++mutt_hcache_delete(void *db, const char *filename, size_t (*keylen)(const char *fn))
+{
+ datum key;
+ struct header_cache *h = db;
@@ -622,22 +724,15 @@ diff -Nru a/hcache.c b/hcache.c
+ }
+
+ strncpy(path, h->folder, sizeof(path));
-+ strncat(path, filename, sizeof(path) - strlen(path));
++ strncat(path, filename, sizeof(path) - mutt_strlen(path));
+
+ key.dptr = path;
-+ key.dsize = mutt_hcache_keylen(path);
++ key.dsize = keylen(path);
+
+ return gdbm_delete(h->db, key);
+}
+#elif HAVE_DB4
+
-+static struct
-+header_cache
-+{
-+ DB_ENV *env;
-+ DB *db;
-+} HEADER_CACHE;
-+
+static void
+mutt_hcache_dbt_init(DBT *dbt, void *data, size_t len)
+{
@@ -661,15 +756,32 @@ diff -Nru a/hcache.c b/hcache.c
+ struct stat sb;
+ u_int32_t createflags = DB_CREATE;
+ int ret;
-+ struct header_cache *h = malloc(sizeof(HEADER_CACHE));
++ struct header_cache *h = calloc(1, sizeof(HEADER_CACHE));
++
++ h->crc = generate_crc32();
+
+ if (! path || path[0] == '\0') {
+ FREE(& h);
+ return NULL;
+ }
+
++ snprintf (h->lockfile, _POSIX_PATH_MAX, "%s-lock-hack", path);
++
++ h->fd = open(h->lockfile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
++ if (h->fd < 0) {
++ FREE (&h);
++ return NULL;
++ }
++
++ if (mx_lock_file(h->lockfile, h->fd, 1, 0, 5)) {
++ close(h->fd);
++ FREE (&h);
++ return NULL;
++ }
++
+ ret = db_env_create(&h->env, 0);
+ if (ret) {
++ mx_unlock_file(h->lockfile, h->fd, 0);
+ FREE(& h);
+ return NULL;
+ }
@@ -679,6 +791,7 @@ diff -Nru a/hcache.c b/hcache.c
+ ret = db_create(&h->db, h->env, 0);
+ if (ret) {
+ h->env->close(h->env, 0);
++ mx_unlock_file(h->lockfile, h->fd, 0);
+ FREE(& h);
+ return NULL;
+ }
@@ -686,13 +799,14 @@ diff -Nru a/hcache.c b/hcache.c
+
+ if (stat(path, &sb) != 0 && errno == ENOENT) {
+ createflags |= DB_EXCL;
-+ h->db->set_pagesize(h->db, (int) MaildirCachePageSize);
++ h->db->set_pagesize(h->db, (int) HeaderCachePageSize);
+ }
+
+ ret = h->db->open(h->db, NULL, path, folder, DB_BTREE, createflags, 0600);
+ if (ret) {
+ h->db->close(h->db, 0);
+ h->env->close(h->env, 0);
++ mx_unlock_file(h->lockfile, h->fd, 0);
+ FREE(& h);
+ return NULL;
+ }
@@ -712,12 +826,12 @@ diff -Nru a/hcache.c b/hcache.c
+
+ h->db->close(h->db, 0);
+ h->env->close(h->env, 0);
-+
++ mx_unlock_file(h->lockfile, h->fd, 0);
+ FREE(& h);
+}
+
+void *
-+mutt_hcache_fetch(void *db, const char *filename)
++mutt_hcache_fetch(void *db, const char *filename, size_t (*keylen)(const char *fn))
+{
+ DBT key;
+ DBT data;
@@ -729,17 +843,22 @@ diff -Nru a/hcache.c b/hcache.c
+
+ filename++; /* skip '/' */
+
-+ mutt_hcache_dbt_init(&key, (void *) filename, mutt_hcache_keylen(filename));
++ mutt_hcache_dbt_init(&key, (void *) filename, keylen(filename));
+ mutt_hcache_dbt_empty_init(&data);
+ data.flags = DB_DBT_MALLOC;
+
+ h->db->get(h->db, NULL, &key, &data, 0);
+
++ if (! crc32_matches(data.data, h->crc)) {
++ free(data.data);
++ return NULL;
++ }
++
+ return data.data;
+}
+
+int
-+mutt_hcache_store(void *db, const char *filename, HEADER *header)
++mutt_hcache_store(void *db, const char *filename, HEADER *header, unsigned long long uid_validity, size_t (*keylen)(const char *fn))
+{
+ DBT key;
+ DBT data;
@@ -752,11 +871,11 @@ diff -Nru a/hcache.c b/hcache.c
+
+ filename++; /* skip '/' */
+
-+ mutt_hcache_dbt_init(&key, (void *) filename, mutt_hcache_keylen(filename));
++ mutt_hcache_dbt_init(&key, (void *) filename, keylen(filename));
+
+ mutt_hcache_dbt_empty_init(&data);
+ data.flags = DB_DBT_USERMEM;
-+ data.data = mutt_hcache_dump(header, (signed int *) &data.size);
++ data.data = mutt_hcache_dump(db, header, (signed int *) &data.size, uid_validity);
+ data.ulen = data.size;
+
+ ret = h->db->put(h->db, NULL, &key, &data, 0);
@@ -767,7 +886,7 @@ diff -Nru a/hcache.c b/hcache.c
+}
+
+int
-+mutt_hcache_delete(void *db, const char *filename)
++mutt_hcache_delete(void *db, const char *filename, size_t (*keylen)(const char *fn))
+{
+ DBT key;
+ struct header_cache *h = db;
@@ -778,31 +897,323 @@ diff -Nru a/hcache.c b/hcache.c
+
+ filename++; /* skip '/' */
+
-+ mutt_hcache_dbt_init(&key, (void *) filename, mutt_hcache_keylen(filename));
++ mutt_hcache_dbt_init(&key, (void *) filename, keylen(filename));
+ return h->db->del(h->db, NULL, &key, 0);
+}
+#endif
+diff -Nru a/imap/imap.c b/imap/imap.c
+--- a/imap/imap.c 2004-08-18 10:08:12 +02:00
++++ b/imap/imap.c 2004-08-18 10:08:12 +02:00
+@@ -602,6 +602,17 @@
+ if ((pc = imap_get_flags (&(idata->flags), pc)) == NULL)
+ goto fail;
+ }
++#ifdef USE_HCACHE
++ /* save UIDVALIDITY for the header cache */
++ else if (ascii_strncasecmp("OK [UIDVALIDITY", pc, 14) == 0)
++ {
++ dprint(2, (debugfile, "Getting mailbox UIDVALIDITY\n"));
++ pc += 3;
++ pc = imap_next_word(pc);
++
++ sscanf(pc, "%u", &(idata->uid_validity));
++ }
++#endif
+ else
+ {
+ pc = imap_next_word (pc);
+diff -Nru a/imap/imap_private.h b/imap/imap_private.h
+--- a/imap/imap_private.h 2004-08-18 10:08:12 +02:00
++++ b/imap/imap_private.h 2004-08-18 10:08:12 +02:00
+@@ -179,6 +179,9 @@
+ unsigned int newMailCount;
+ IMAP_CACHE cache[IMAP_CACHE_LEN];
+ int noclose : 1;
++#ifdef USE_HCACHE
++ unsigned long long uid_validity;
++#endif
+
+ /* all folder flags - system flags AND keywords */
+ LIST *flags;
+diff -Nru a/imap/message.c b/imap/message.c
+--- a/imap/message.c 2004-08-18 10:08:12 +02:00
++++ b/imap/message.c 2004-08-18 10:08:12 +02:00
+@@ -39,6 +39,12 @@
+ static int msg_parse_fetch (IMAP_HEADER* h, char* s);
+ static char* msg_parse_flags (IMAP_HEADER* h, char* s);
+
++#if USE_HCACHE
++static int msg_fetch_header_fetch (CONTEXT* ctx, IMAP_HEADER* h, char* buf,
++ FILE* fp);
++static size_t imap_hcache_keylen (const char *fn);
++#endif /* USE_HCACHE */
++
+ /* imap_read_headers:
+ * Changed to read many headers instead of just one. It will return the
+ * msgno of the last message read. It will return a value other than
+@@ -57,8 +63,18 @@
+ int fetchlast = 0;
+ const char *want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE IN-REPLY-TO REPLY-TO LINES X-LABEL";
+
++#if USE_HCACHE
++ void *hc = NULL;
++ unsigned long long *uid_validity = NULL;
++ char uid_buf[64];
++#endif /* USE_HCACHE */
++
+ ctx = idata->ctx;
+
++#if USE_HCACHE
++ hc = mutt_hcache_open (HeaderCache, ctx->path);
++#endif /* USE_HCACHE */
++
+ if (mutt_bit_isset (idata->capabilities,IMAP4REV1))
+ {
+ snprintf (hdrreq, sizeof (hdrreq), "BODY.PEEK[HEADER.FIELDS (%s)]",
+@@ -73,6 +89,9 @@
+ { /* Unable to fetch headers for lower versions */
+ mutt_error _("Unable to fetch headers from this IMAP server version.");
+ mutt_sleep (2); /* pause a moment to let the user see the error */
++#if USE_HCACHE
++ mutt_hcache_close (hc);
++#endif /* USE_HCACHE */
+ return -1;
+ }
+
+@@ -83,6 +102,9 @@
+ {
+ mutt_error (_("Could not create temporary file %s"), tempfile);
+ mutt_sleep (2);
++#if USE_HCACHE
++ mutt_hcache_close (hc);
++#endif /* USE_HCACHE */
+ return -1;
+ }
+ unlink (tempfile);
+@@ -95,14 +117,88 @@
+ idata->reopen &= ~IMAP_NEWMAIL_PENDING;
+ idata->newMailCount = 0;
+
++#if USE_HCACHE
++ snprintf (buf, sizeof (buf),
++ "FETCH %d:%d (UID FLAGS)", msgbegin + 1, msgend + 1);
++ fetchlast = msgend + 1;
++
++ imap_cmd_start (idata, buf);
++
++ for (msgno = msgbegin; msgno <= msgend ; msgno++)
++ {
++ if (ReadInc && (!msgno || ((msgno+1) % ReadInc == 0)))
++ mutt_message (_("Evaluating cache... [%d/%d]"), msgno + 1,
++ msgend + 1);
++
++ rewind (fp);
++ memset (&h, 0, sizeof (h));
++ h.data = safe_calloc (1, sizeof (IMAP_HEADER_DATA));
++ do
++ {
++ mfhrc = 0;
++
++ rc = imap_cmd_step (idata);
++ if (rc != IMAP_CMD_CONTINUE)
++ break;
++
++ if ((mfhrc = msg_fetch_header_fetch (idata->ctx, &h, idata->cmd.buf, fp)) == -1)
++ continue;
++ else if (mfhrc < 0)
++ break;
++
++ /* make sure we don't get remnants from older larger message headers */
++ fputs ("\n\n", fp);
++
++ sprintf(uid_buf, "/%u", h.data->uid); /* XXX --tg 21:41 04-07-11 */
++ uid_validity = (unsigned long long *) mutt_hcache_fetch (hc, uid_buf, &imap_hcache_keylen);
++
++ if (uid_validity != NULL
++ && *uid_validity == idata->uid_validity) {
++ ctx->hdrs[msgno] = mutt_hcache_restore((unsigned char *) uid_validity, 0);
++ ctx->hdrs[msgno]->index = h.sid - 1;
++ if (h.sid != ctx->msgcount + 1)
++ dprint (1, (debugfile, "imap_read_headers: msgcount and sequence ID are inconsistent!"));
++ /* messages which have not been expunged are ACTIVE (borrowed from mh
++ * folders) */
++ ctx->hdrs[msgno]->active = 1;
++ ctx->hdrs[msgno]->read = h.read;
++ ctx->hdrs[msgno]->old = h.old;
++ ctx->hdrs[msgno]->deleted = h.deleted;
++ ctx->hdrs[msgno]->flagged = h.flagged;
++ ctx->hdrs[msgno]->replied = h.replied;
++ ctx->hdrs[msgno]->changed = h.changed;
++ /* ctx->hdrs[msgno]->received is restored from mutt_hcache_restore */
++ ctx->hdrs[msgno]->data = (void *) (h.data);
++
++ ctx->msgcount++;
++ }
++ rewind (fp);
++
++ FREE(&uid_validity);
++
++ }
++ while ((rc != IMAP_CMD_OK) && ((mfhrc == -1) ||
++ ((msgno + 1) >= fetchlast)));
++ }
++
++ fetchlast = msgbegin;
++#endif /* USE_HCACHE */
++
+ for (msgno = msgbegin; msgno <= msgend ; msgno++)
+ {
+ if (ReadInc && (!msgno || ((msgno+1) % ReadInc == 0)))
+ mutt_message (_("Fetching message headers... [%d/%d]"), msgno + 1,
+ msgend + 1);
+
++ if (ctx->hdrs[msgno])
++ continue;
++
+ if (msgno + 1 > fetchlast)
+ {
++ fetchlast = msgno + 1;
++ while((fetchlast <= msgend) && (! ctx->hdrs[fetchlast]))
++ fetchlast++;
++
+ /*
+ * Make one request for everything. This makes fetching headers an
+ * order of magnitude faster if you have a large mailbox.
+@@ -112,11 +208,9 @@
+ */
+ snprintf (buf, sizeof (buf),
+ "FETCH %d:%d (UID FLAGS INTERNALDATE RFC822.SIZE %s)", msgno + 1,
+- msgend + 1, hdrreq);
++ fetchlast, hdrreq);
+
+ imap_cmd_start (idata, buf);
+-
+- fetchlast = msgend + 1;
+ }
+
+ /* freshen fp, h */
+@@ -170,6 +264,11 @@
+ /* content built as a side-effect of mutt_read_rfc822_header */
+ ctx->hdrs[msgno]->content->length = h.content_length;
+
++#if USE_HCACHE
++ sprintf(uid_buf, "/%u", h.data->uid);
++ mutt_hcache_store(hc, uid_buf, ctx->hdrs[msgno], idata->uid_validity, &imap_hcache_keylen);
++#endif /* USE_HCACHE */
++
+ ctx->msgcount++;
+ }
+ while ((rc != IMAP_CMD_OK) && ((mfhrc == -1) ||
+@@ -179,7 +278,9 @@
+ {
+ imap_free_header_data ((void**) &h.data);
+ fclose (fp);
+-
++#if USE_HCACHE
++ mutt_hcache_close (hc);
++#endif /* USE_HCACHE */
+ return -1;
+ }
+
+@@ -194,6 +295,10 @@
+ }
+ }
+
++#if USE_HCACHE
++ mutt_hcache_close (hc);
++#endif /* USE_HCACHE */
++
+ fclose(fp);
+
+ if (ctx->msgcount > oldmsgcount)
+@@ -724,6 +829,7 @@
+ return s;
+ }
+
++
+ /* msg_fetch_header: import IMAP FETCH response into an IMAP_HEADER.
+ * Expects string beginning with * n FETCH.
+ * Returns:
+@@ -782,6 +888,56 @@
+
+ return rc;
+ }
++
++#if USE_HCACHE
++static size_t imap_hcache_keylen (const char *fn)
++{
++ return mutt_strlen(fn);
++}
++
++/* msg_fetch_header: import IMAP FETCH response into an IMAP_HEADER.
++ * Expects string beginning with * n FETCH.
++ * Returns:
++ * 0 on success
++ * -1 if the string is not a fetch response
++ * -2 if the string is a corrupt fetch response */
++static int msg_fetch_header_fetch (CONTEXT* ctx, IMAP_HEADER* h, char* buf, FILE* fp)
++{
++ IMAP_DATA* idata;
++ long bytes;
++ int rc = -1; /* default now is that string isn't FETCH response*/
++
++ idata = (IMAP_DATA*) ctx->data;
++
++ if (buf[0] != '*')
++ return rc;
++
++ /* skip to message number */
++ buf = imap_next_word (buf);
++ h->sid = atoi (buf);
++
++ /* find FETCH tag */
++ buf = imap_next_word (buf);
++ if (ascii_strncasecmp ("FETCH", buf, 5))
++ return rc;
++
++ rc = -2; /* we've got a FETCH response, for better or worse */
++ if (!(buf = strchr (buf, '(')))
++ return rc;
++ buf++;
++
++ if (msg_parse_fetch (h, buf) < 0) {
++ return -2;
++ }
++
++ if (!(buf = strchr (buf, ')')))
++ return rc;
++ buf++;
++
++ return 0;
++}
++#endif /* USE_HCACHE */
++
+
+ /* msg_has_flag: do a caseless comparison of the flag against a flag list,
+ * return 1 if found or flag list has '\*', 0 otherwise */
diff -Nru a/init.h b/init.h
---- init.h 2004-06-10 14:03:44 +02:00
-+++ init.h 2004-06-10 14:03:44 +02:00
-@@ -981,6 +981,28 @@
+--- a/init.h 2004-08-18 10:08:12 +02:00
++++ b/init.h 2004-08-18 10:08:12 +02:00
+@@ -981,6 +981,30 @@
** \fBDON'T CHANGE THIS SETTING UNLESS YOU ARE REALLY SURE WHAT YOU ARE
** DOING!\fP
*/
+#if USE_HCACHE
-+ { "maildir_cache", DT_PATH, R_NONE, UL &MaildirCache, 0 },
++
++ { "header_cache", DT_PATH, R_NONE, UL &HeaderCache, 0 },
+ /*
+ ** .pp
-+ ** Path to the maildir cache file. If unset no cache will be used.
++ ** Path to the header cache file. If unset no cache will be used. Otherwise
++ ** the cache will be enabled for Maildir and IMAP mailboxes.
+ */
-+ { "maildir_cache_verify", DT_BOOL, R_NONE, OPTHCACHEVERIFY, 1 },
++ { "maildir_header_cache_verify", DT_BOOL, R_NONE, OPTHCACHEVERIFY, 1 },
+ /*
+ ** .pp
-+ ** Check for programs other than mutt having modified maildir
-+ ** files when the header cache is in use. This incurs one stat(2)
-+ ** per message every time the folder is opened.
++ ** Check for Maildir unaware programs other than mutt having modified maildir
++ ** files when the header cache is in use. This incurs one stat(2) per
++ ** message every time the folder is opened.
+ */
-+ { "maildir_cache_page_size", DT_NUM, R_NONE, UL &MaildirCachePageSize, 16384 },
++ { "header_cache_pagesize", DT_NUM, R_NONE, UL &HeaderCachePageSize, 16384 },
+ /*
+ ** .pp
+ ** Change the maildir header cache database page size. Too large
@@ -815,8 +1226,8 @@ diff -Nru a/init.h b/init.h
/*
** .pp
diff -Nru a/main.c b/main.c
---- main.c 2004-06-10 14:03:44 +02:00
-+++ main.c 2004-06-10 14:03:44 +02:00
+--- a/main.c 2004-08-18 10:08:12 +02:00
++++ b/main.c 2004-08-18 10:08:12 +02:00
@@ -411,6 +411,12 @@
"-HAVE_GETADDRINFO "
#endif
@@ -831,13 +1242,20 @@ diff -Nru a/main.c b/main.c
#ifdef ISPELL
diff -Nru a/mh.c b/mh.c
---- mh.c 2004-06-10 14:03:44 +02:00
-+++ mh.c 2004-06-10 14:03:44 +02:00
-@@ -779,11 +779,65 @@
+--- a/mh.c 2004-08-18 10:08:12 +02:00
++++ b/mh.c 2004-08-18 10:08:12 +02:00
+@@ -779,11 +779,68 @@
return r;
}
+#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);
++}
++
/*
* This function does the second parsing pass for a maildir-style
@@ -854,14 +1272,14 @@ diff -Nru a/mh.c b/mh.c
+ struct stat lastchanged;
+ int ret;
+
-+ hc = mutt_hcache_open (MaildirCache, ctx->path);
++ hc = mutt_hcache_open (HeaderCache, ctx->path);
+
+ for (p = md; p; p = p->next) {
+ if (! (p && p->h && !p->header_parsed)) {
+ continue;
+ }
+
-+ data = mutt_hcache_fetch (hc, p->h->path + 3);
++ data = mutt_hcache_fetch (hc, p->h->path + 3, &maildir_hcache_keylen);
+ when = (struct timeval *) data;
+
+ snprintf(fn, sizeof (fn), "%s/%s", ctx->path, p->h->path);
@@ -875,18 +1293,14 @@ diff -Nru a/mh.c b/mh.c
+
+ if (data != NULL
+ && ret == 0
-+ && lastchanged.st_mtime <= when->tv_sec
-+#if HAVE_LANGINFO_CODESET
-+ && mutt_hcache_charset_matches (data)
-+#endif /* HAVE_LANGINFO_CODESET */
-+ ) {
++ && lastchanged.st_mtime <= when->tv_sec) {
+ p->h = mutt_hcache_restore ((unsigned char *)data, &p->h);
+ maildir_parse_flags (p->h, fn);
+
+ } else if (maildir_parse_message (ctx->magic, fn, p->h->old, p->h)) {
+ maildir_parse_flags(p->h, fn);
+ p->header_parsed = 1;
-+ mutt_hcache_store (hc, p->h->path + 3, p->h);
++ mutt_hcache_store (hc, p->h->path + 3, p->h, 0, &maildir_hcache_keylen);
+ } else {
+ mutt_free_header (&p->h);
+ }
@@ -899,7 +1313,7 @@ diff -Nru a/mh.c b/mh.c
void maildir_delayed_parsing (CONTEXT * ctx, struct maildir *md)
{
-@@ -801,7 +855,7 @@
+@@ -801,7 +858,7 @@
}
}
@@ -908,7 +1322,7 @@ diff -Nru a/mh.c b/mh.c
/* Read a MH/maildir style mailbox.
*
-@@ -1293,6 +1347,9 @@
+@@ -1293,6 +1350,9 @@
{
char path[_POSIX_PATH_MAX], tmp[_POSIX_PATH_MAX];
int i, j;
@@ -918,33 +1332,33 @@ diff -Nru a/mh.c b/mh.c
if (ctx->magic == M_MH)
i = mh_check_mailbox (ctx, index_hint);
-@@ -1302,6 +1359,11 @@
+@@ -1302,6 +1362,11 @@
if (i != 0)
return i;
+#if USE_HCACHE
+ if (ctx->magic == M_MAILDIR)
-+ hc = mutt_hcache_open(MaildirCache, ctx->path);
++ hc = mutt_hcache_open(HeaderCache, ctx->path);
+#endif /* USE_HCACHE */
+
for (i = 0; i < ctx->msgcount; i++)
{
if (ctx->hdrs[i]->deleted
-@@ -1310,7 +1372,13 @@
+@@ -1310,7 +1375,13 @@
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);
++ 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 */
-@@ -1332,16 +1400,21 @@
+@@ -1332,16 +1403,21 @@
if (ctx->magic == M_MAILDIR)
{
if (maildir_sync_message (ctx, i) == -1)
@@ -968,7 +1382,7 @@ diff -Nru a/mh.c b/mh.c
if (ctx->magic == M_MH)
mh_update_sequences (ctx);
-@@ -1362,6 +1435,13 @@
+@@ -1362,6 +1438,13 @@
}
return 0;
@@ -983,8 +1397,8 @@ diff -Nru a/mh.c b/mh.c
static char *maildir_canon_filename (char *dest, const char *src, size_t l)
diff -Nru a/mutt.h b/mutt.h
---- mutt.h 2004-06-10 14:03:44 +02:00
-+++ mutt.h 2004-06-10 14:03:44 +02:00
+--- a/mutt.h 2004-08-18 10:08:12 +02:00
++++ b/mutt.h 2004-08-18 10:08:12 +02:00
@@ -345,6 +345,9 @@
OPTFORCENAME,
OPTFORWDECODE,
@@ -996,9 +1410,9 @@ diff -Nru a/mutt.h b/mutt.h
OPTHEADER,
OPTHELP,
diff -Nru a/protos.h b/protos.h
---- protos.h 2004-06-10 14:03:44 +02:00
-+++ protos.h 2004-06-10 14:03:44 +02:00
-@@ -99,6 +99,19 @@
+--- a/protos.h 2004-08-18 10:08:12 +02:00
++++ b/protos.h 2004-08-18 10:08:12 +02:00
+@@ -99,6 +99,16 @@
ENVELOPE *mutt_read_rfc822_header (FILE *, HEADER *, short, short);
HEADER *mutt_dup_header (HEADER *);
@@ -1006,12 +1420,9 @@ diff -Nru a/protos.h b/protos.h
+void *mutt_hcache_open(const char *path, const char *folder);
+void mutt_hcache_close(void *db);
+HEADER *mutt_hcache_restore(const unsigned char *d, HEADER **oh);
-+void *mutt_hcache_fetch(void *db, const char *filename);
-+int mutt_hcache_store(void *db, const char *filename, HEADER *h);
-+int mutt_hcache_delete(void *db, const char *filename);
-+#if HAVE_LANGINFO_CODESET
-+int mutt_hcache_charset_matches(const char *d);
-+#endif /* HAVE_LANGINFO_CODESET */
++void *mutt_hcache_fetch(void *db, const char *filename, size_t (*keylen)(const char *fn));
++int mutt_hcache_store(void *db, const char *filename, HEADER *h, unsigned long long uid_validity, size_t (*keylen)(const char *fn));
++int mutt_hcache_delete(void *db, const char *filename, size_t (*keylen)(const char *fn));
+#endif /* USE_HCACHE */
+
+
@@ -1021,4 +1432,4 @@ diff -Nru a/protos.h b/protos.h
--- PATCHES.orig Tue Nov 6 19:59:33 2001
+++ PATCHES Tue Nov 6 19:59:42 2001
@@ -1,0 +1 @@
-+maildir-header-cache.19
++patch-1.5.6.tg.hcache.0