]> granicus.if.org Git - neomutt/commitdiff
Split hcache code into per-backend files
authorPietro Cerutti <gahr@gahr.ch>
Wed, 26 Oct 2016 12:29:29 +0000 (12:29 +0000)
committerRichard Russon <rich@flatcap.org>
Fri, 11 Nov 2016 23:16:43 +0000 (23:16 +0000)
Also,
- make configure arguments consistent in the form of --with-<backend>[=DIR]
- rename WITH_DB4 macro to WITH_BDB (db5 is supported as well)

Issue: #216

19 files changed:
configure.ac
doc/makedoc-defs.h
globals.h
hcache-bdb.c [new file with mode: 0644]
hcache-gdbm.c [new file with mode: 0644]
hcache-kc.c [new file with mode: 0644]
hcache-lmdb.c [new file with mode: 0644]
hcache-qdbm.c [new file with mode: 0644]
hcache-tc.c [new file with mode: 0644]
hcache.c
hcache.h
imap/imap.c
imap/message.c
imap/util.c
init.h
mh.c
newsrc.c
nntp.c
pop.c

index 8e72c16f00abc4c41da75a26d5273fd15edf3766..9a22684ed991b875573657e6b7cbeeef9d2bf931 100644 (file)
@@ -905,18 +905,34 @@ AC_ARG_ENABLE(exact-address, AS_HELP_STRING([--enable-exact-address],[Enable reg
         fi])
 
 dnl -- start cache --
-db_found=no
 db_requested=auto
 hcache_db_used=no
 AC_ARG_ENABLE(hcache, AS_HELP_STRING([--enable-hcache],[Enable header caching]))
-AC_ARG_WITH(tokyocabinet, AS_HELP_STRING([--without-tokyocabinet],[Don't use tokyocabinet even if it is available]))
-AC_ARG_WITH(kyotocabinet, AS_HELP_STRING([--without-kyotocabinet],[Don't use kyotocabinet even if it is available]))
-AC_ARG_WITH(qdbm, AS_HELP_STRING([--without-qdbm],[Don't use qdbm even if it is available]))
-AC_ARG_WITH(gdbm, AS_HELP_STRING([--without-gdbm],[Don't use gdbm even if it is available]))
-AC_ARG_WITH(bdb, AS_HELP_STRING([--with-bdb@<:@=DIR@:>@],[Use BerkeleyDB4 if gdbm is not available]))
-AC_ARG_WITH(lmdb, AS_HELP_STRING([--with-lmdb@<:@=DIR@:>@],[Use LMDB if gdbm is not available]))
-
-db_found=no
+AC_ARG_WITH(gdbm,
+    AS_HELP_STRING(
+        [--with-gdbm@<:@=DIR@:>@],
+        [Use gdbm for the header cache (default)]))
+AC_ARG_WITH(tokyocabinet,
+    AS_HELP_STRING(
+        [--with-tokyocabinet@<:@=DIR@:>@],
+        [Use tokyocabinet for the header cache]))
+AC_ARG_WITH(kyotocabinet,
+    AS_HELP_STRING(
+        [--with-kyotocabinet@<:@=DIR@:>@],
+        [Use kyotocabinet for the header cache]))
+AC_ARG_WITH(qdbm,
+    AS_HELP_STRING(
+        [--with-qdbm@<:@=DIR@:>@],
+        [Use qdbm for the header cache]))
+AC_ARG_WITH(bdb,
+    AS_HELP_STRING(
+        [--with-bdb@<:@=DIR@:>@],
+        [Use BerkeleyDB for the header cache]))
+AC_ARG_WITH(lmdb,
+    AS_HELP_STRING(
+        [--with-lmdb@<:@=DIR@:>@],
+        [Use LMDB for the header cache]))
+
 if test x$enable_hcache = xyes
 then
     AC_DEFINE(USE_HCACHE, 1, [Enable header caching])
@@ -934,7 +950,7 @@ then
     fi
     if test -n "$with_kyotocabinet" && test "$with_kyotocabinet" != "no"
     then
-      if test "$db_requested" != "auto"
+      if test $db_requested != auto
       then
         AC_MSG_ERROR([more than one header cache engine requested.])
       else
@@ -943,7 +959,7 @@ then
     fi
     if test -n "$with_qdbm" && test "$with_qdbm" != "no"
     then
-      if test "$db_requested" != "auto"
+      if test $db_requested != auto
       then
         AC_MSG_ERROR([more than one header cache engine requested.])
       else
@@ -952,7 +968,7 @@ then
     fi
     if test -n "$with_gdbm" && test "$with_gdbm" != "no"
     then
-      if test "$db_requested" != "auto"
+      if test $db_requested != auto
       then
         AC_MSG_ERROR([more than one header cache engine requested.])
       else
@@ -961,7 +977,7 @@ then
     fi
     if test -n "$with_bdb" && test "$with_bdb" != "no"
     then
-      if test "$db_requested" != "auto"
+      if test $db_requested != auto
       then
         AC_MSG_ERROR([more than one header cache engine requested.])
       else
@@ -970,7 +986,7 @@ then
     fi
     if test -n "$with_lmdb" && test "$with_lmdb" != "no"
     then
-      if test "$db_requested" != "auto"
+      if test $db_requested != auto
       then
         AC_MSG_ERROR([more than one header cache engine requested.])
       else
@@ -979,8 +995,8 @@ then
     fi
     
     dnl -- Tokyo Cabinet --
-    if test "$with_tokyocabinet" != "no" \
-           && test "$db_requested" = auto -o "$db_requested" = TokyoCabinet
+    if test "$with_tokyocabinet" != "no" && test $hcache_db_used = no \
+           && test $db_requested = auto -o $db_requested = TokyoCabinet
     then
       if test -n "$with_tokyocabinet" && test "$with_tokyocabinet" != "yes"
       then
@@ -992,18 +1008,19 @@ then
       AC_CHECK_LIB(tokyocabinet, tcbdbopen,
         [MUTTLIBS="$MUTTLIBS -ltokyocabinet"
          AC_DEFINE(HAVE_TC, 1, [Tokyo Cabinet Support])
-         db_found=TokyoCabinet],
+         MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS hcache-tc.o"
+         hcache_db_used=TokyoCabinet],
         [CPPFLAGS="$OLDCPPFLAGS"
          LDFLAGS="$OLDLDFLAGS"]))
-      if test "$db_requested" != auto && test "$db_found" != "$db_requested"
+      if test $db_requested != auto && test $hcache_db_used != $db_requested
       then
         AC_MSG_ERROR([Tokyo Cabinet could not be used. Check config.log for details.])
       fi
     fi
 
     dnl -- Kyoto Cabinet --
-    if test "$with_kyotocabinet" != "no" \
-        && test "$db_requested" = auto -o "$db_requested" = KyotoCabinet
+    if test "$with_kyotocabinet" != "no" && test $hcache_db_used = no \
+        && test $db_requested = auto -o $db_requested = KyotoCabinet
     then
       if test -n "$with_kyotocabinet" && test "$with_kyotocabinet" != "yes"
       then
@@ -1015,51 +1032,54 @@ then
       AC_CHECK_LIB(kyotocabinet, kcdbopen,
         [MUTTLIBS="$MUTTLIBS -lkyotocabinet"
          AC_DEFINE(HAVE_KC, 1, [Kyoto Cabinet Support])
-         db_found=KyotoCabinet],
+         MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS hcache-kc.o"
+         hcache_db_used=KyotoCabinet],
         [CPPFLAGS="$OLDCPPFLAGS"
          LDFLAGS="$OLDLDFLAGS"]))
-      if test "$db_requested" != auto && test "$db_found" != "$db_requested"
+      if test $db_requested != auto && test $hcache_db_used != $db_requested
       then
         AC_MSG_ERROR([Kyoto Cabinet could not be used. Check config.log for details.])
       fi
     fi
 
     dnl -- QDBM --
-    if test "$with_qdbm" != "no" && test $db_found = no \
-           && test "$db_requested" = auto -o "$db_requested" = QDBM
+    if test "$with_qdbm" != "no" && test $hcache_db_used = no \
+           && test $db_requested = auto -o $db_requested = QDBM
     then
       if test -n "$with_qdbm" && test "$with_qdbm" != "yes"
       then
         if test -d $with_qdbm/include/qdbm; then
           CPPFLAGS="$CPPFLAGS -I$with_qdbm/include/qdbm"
-       else
+        else
           CPPFLAGS="$CPPFLAGS -I$with_qdbm/include"
-       fi
+        fi
         LDFLAGS="$LDFLAGS -L$with_qdbm/lib"
-      else
-         if test -d /usr/include/qdbm; then
-           CPPFLAGS="$CPPFLAGS -I/usr/include/qdbm"
-        fi
+      else                                                                                                                                                      
+        if test -d /usr/include/qdbm; then                                                                                                                     
+            CPPFLAGS="$CPPFLAGS -I/usr/include/qdbm"                                                                                                             
+        fi     
       fi
 
       saved_LIBS="$LIBS"
       AC_CHECK_HEADERS(villa.h)
       AC_CHECK_LIB(qdbm, vlopen,
         [MUTTLIBS="$MUTTLIBS -lqdbm"
+         MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS hcache-qdbm.o"
          AC_DEFINE(HAVE_QDBM, 1, [QDBM Support])
-         db_found=QDBM],
+         hcache_db_used=QDBM
+        ],
         [CPPFLAGS="$OLDCPPFLAGS"
          LDFLAGS="$OLDLDFLAGS"])
       LIBS="$saved_LIBS"
-      if test "$db_requested" != auto && test "$db_found" != "$db_requested"
+      if test $db_requested != auto && test $hcache_db_used != $db_requested
       then
         AC_MSG_ERROR([QDBM could not be used. Check config.log for details.])
       fi
     fi
 
     dnl -- GDBM --
-    if test x$with_gdbm != xno && test $db_found = no \
-           && test "$db_requested" = auto -o "$db_requested" = GDBM
+    if test "$with_gdbm" != "no" && test $hcache_db_used = no \
+           && test $db_requested = auto -o $db_requested = GDBM
     then
         if test "$with_gdbm" != "yes"
         then
@@ -1075,11 +1095,12 @@ then
         LIBS="$saved_LIBS"
         if test "$ac_cv_gdbmopen" = yes
         then
-          AC_DEFINE(HAVE_GDBM, 1, [GDBM Support])
           MUTTLIBS="$MUTTLIBS -lgdbm"
-          db_found=GDBM
+          MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS hcache-gdbm.o"
+          AC_DEFINE(HAVE_GDBM, 1, [GDBM Support])
+          hcache_db_used=GDBM
         fi
-        if test "$db_requested" != auto && test "$db_found" != "$db_requested"
+        if test $db_requested != auto && test $hcache_db_used != $db_requested
         then
           AC_MSG_ERROR([GDBM could not be used. Check config.log for details.])
         fi
@@ -1087,8 +1108,8 @@ then
 
     dnl -- BDB --
     ac_bdb_prefix="$with_bdb"
-    if test x$with_bdb != xno && test $db_found = no \
-           && test "$db_requested" = auto -o "$db_requested" = BDB
+    if test "$with_bdb" != "no" && test $hcache_db_used = no \
+           && test $db_requested = auto -o $db_requested = BDB
     then
         if test x$ac_bdb_prefix = xyes || test x$ac_bdb_prefix = x
         then
@@ -1136,19 +1157,24 @@ then
         then
             AC_MSG_RESULT(yes)
             CPPFLAGS="$OLDCPPFLAGS -I$BDB_INCLUDE_DIR"
+            AC_DEFINE(HAVE_BDB, 1, [Berkeley DB Support])
             LIBS="$OLDLIBS -L$BDB_LIB_DIR -l$BDB_LIB"
-            AC_DEFINE(HAVE_DB4, 1, [Berkeley DB4 Support])
-            db_found=BDB
+            MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS hcache-bdb.o"
+            hcache_db_used=BDB
         else
             AC_MSG_RESULT(no)
         fi
+        if test $db_requested != auto && test $hcache_db_used != $db_requested
+        then
+          AC_MSG_ERROR([BDB could not be used. Check config.log for details.])
+        fi
     fi
 
     dnl -- LMDB --
-    if test x$with_lmdb != xno && test $db_found = no \
-           && test "$db_requested" = auto -o "$db_requested" = LMDB
+    if test "$with_lmdb" != "no" && test $hcache_db_used = no \
+           && test $db_requested = auto -o $db_requested = LMDB
     then
-        if test "$with_lmdb" != "yes"
+        if test "$with_lmdb" != "yes" && test "$with_lmdb" != "NONE"
         then
           CPPFLAGS="$CPPFLAGS -I$with_lmdb/include"
           LDFLAGS="$LDFLAGS -L$with_lmdb/lib"
@@ -1164,30 +1190,30 @@ then
         then
           AC_DEFINE(HAVE_LMDB, 1, [LMDB Support])
           MUTTLIBS="$MUTTLIBS -llmdb"
-          db_found=LMDB
+          MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS hcache-lmdb.o"
+          hcache_db_used=LMDB
         fi
-        if test "$db_requested" != auto && test "$db_found" != "$db_requested"
+        if test $db_requested != auto && test $hcache_db_used != $db_requested
         then
           AC_MSG_ERROR([LMDB could not be used. Check config.log for details.])
         fi
     fi
 
-    if test $db_found = no
+    if test $hcache_db_used = no
     then
-        AC_MSG_ERROR([You need Tokyo Cabinet, Kyoto Cabinet, QDBM, GDBM, Berkeley DB4 or LMDB for hcache])
+        AC_MSG_ERROR([You need Tokyo Cabinet, Kyoto Cabinet, QDBM, GDBM, Berkeley DB or LMDB for hcache])
     fi
 fi
-hcache_db_used=$db_found
 dnl -- end cache --
 
-AM_CONDITIONAL(BUILD_HCACHE, test x$db_found != xno)
+AM_CONDITIONAL(BUILD_HCACHE, test x$hcache_db_used != xno)
 
 if test "$need_md5" = "yes"
 then
   MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS md5.o"
 fi
 
-if test x$db_found != xno ; then
+if test x$hcache_db_used != xno ; then
   MUTT_MD5="mutt_md5$EXEEXT"
 fi
 AC_SUBST(MUTT_MD5)
index ac6cd33e09e273c8aed661d3514cbb9d1abc4fe7..6bfbb7d647d58b29a9b76b1b20cd62d67f72c231 100644 (file)
@@ -37,8 +37,8 @@
 # ifndef USE_HCACHE
 #  define USE_HCACHE
 # endif
-# ifndef HAVE_DB4
-#  define HAVE_DB4
+# ifndef HAVE_BDB
+#  define HAVE_BDB
 # endif
 # ifndef HAVE_GDBM
 #  define HAVE_GDBM
index d49337d43beb5f885fa0003daa7f15c15ee2c068..dcaa7433e1c207d65dbe8537223e540870589ec3 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -75,9 +75,9 @@ WHERE char *MessageCachedir;
 #endif
 #if USE_HCACHE
 WHERE char *HeaderCache;
-#if HAVE_GDBM || HAVE_DB4
+#if HAVE_GDBM || HAVE_BDB
 WHERE char *HeaderCachePageSize;
-#endif /* HAVE_GDBM || HAVE_DB4 */
+#endif /* HAVE_GDBM || HAVE_BDB */
 #endif /* USE_HCACHE */
 WHERE char *MhFlagged;
 WHERE char *MhReplied;
diff --git a/hcache-bdb.c b/hcache-bdb.c
new file mode 100644 (file)
index 0000000..575a5f8
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * 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>
+ * Copyright (C) 2016 Pietro Cerutti <gahr@gahr.ch>
+ *
+ *     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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_BDB
+
+#include "hcache.h"
+#include "globals.h"
+#include "mx.h"
+#include <db.h>
+#include <fcntl.h>
+#include <errno.h>
+
+typedef struct
+{
+  DB_ENV *env;
+  DB *db;
+  int fd;
+  char lockfile[_POSIX_PATH_MAX];
+} hcache_db_ctx_t;
+
+static void
+dbt_init(DBT *dbt, void *data, size_t len)
+{
+  dbt->data = data;
+  dbt->size = dbt->ulen = len;
+  dbt->dlen = dbt->doff = 0;
+  dbt->flags = DB_DBT_USERMEM;
+}
+
+static void
+dbt_empty_init(DBT *dbt)
+{
+  dbt->data = NULL;
+  dbt->size = dbt->ulen = dbt->dlen = dbt->doff = 0;
+  dbt->flags = 0;
+}
+
+static void *
+hcache_bdb_open(const char *path)
+{
+  struct stat sb;
+  int ret;
+  u_int32_t createflags = DB_CREATE;
+  int pagesize;
+
+  hcache_db_ctx_t *ctx = safe_malloc(sizeof(hcache_db_ctx_t));
+
+  if (mutt_atoi (HeaderCachePageSize, &pagesize) < 0 || pagesize <= 0)
+    pagesize = 16384;
+
+  snprintf (ctx->lockfile, _POSIX_PATH_MAX, "%s-lock-hack", path);
+
+  ctx->fd = open (ctx->lockfile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+  if (ctx->fd < 0)
+  {
+    FREE(&ctx);
+    return NULL;
+  }
+
+  if (mx_lock_file (ctx->lockfile, ctx->fd, 1, 0, 5))
+    goto fail_close;
+
+  ret = db_env_create (&ctx->env, 0);
+  if (ret)
+    goto fail_unlock;
+
+  ret = (*ctx->env->open)(ctx->env, NULL, DB_INIT_MPOOL | DB_CREATE | DB_PRIVATE, 0600);
+  if (ret)
+    goto fail_env;
+
+  ctx->db = NULL;
+  ret = db_create (&ctx->db, ctx->env, 0);
+  if (ret)
+    goto fail_env;
+
+  if (stat(path, &sb) != 0 && errno == ENOENT)
+  {
+    createflags |= DB_EXCL;
+    ctx->db->set_pagesize(ctx->db, pagesize);
+  }
+
+  ret = (*ctx->db->open)(ctx->db, NULL, path, NULL, DB_BTREE, createflags,
+                       0600);
+  if (ret)
+    goto fail_db;
+
+  return ctx;
+
+fail_db:
+  ctx->db->close (ctx->db, 0);
+fail_env:
+  ctx->env->close (ctx->env, 0);
+fail_unlock:
+  mx_unlock_file (ctx->lockfile, ctx->fd, 0);
+fail_close:
+  close (ctx->fd);
+  unlink (ctx->lockfile);
+  FREE(&ctx);
+
+  return NULL;
+}
+
+static void *
+hcache_bdb_fetch(void *vctx, const char *key, size_t keylen)
+{
+  DBT dkey;
+  DBT data;
+
+  if (!vctx)
+    return NULL;
+
+  hcache_db_ctx_t *ctx = vctx;
+
+  dbt_init(&dkey, (void *) key, keylen);
+  dbt_empty_init(&data);
+  data.flags = DB_DBT_MALLOC;
+
+  ctx->db->get(ctx->db, NULL, &dkey, &data, 0);
+
+  return data.data;
+}
+
+static int
+hcache_bdb_store(void *vctx, const char *key, size_t keylen, void *data, size_t dlen)
+{
+  DBT dkey;
+  DBT databuf;
+
+  if (!vctx)
+    return -1;
+
+  hcache_db_ctx_t *ctx = vctx;
+
+  dbt_init(&dkey, (void *) key, keylen);
+  dbt_empty_init(&databuf);
+  databuf.flags = DB_DBT_USERMEM;
+  databuf.data = data;
+  databuf.size = dlen;
+  databuf.ulen = dlen;
+
+  return ctx->db->put(ctx->db, NULL, &dkey, &databuf, 0);
+}
+
+static int
+hcache_bdb_delete(void *vctx, const char *key, size_t keylen)
+{
+  DBT dkey;
+
+  if (!vctx)
+    return -1;
+
+  hcache_db_ctx_t *ctx = vctx;
+
+  dbt_init(&dkey, (void *) key, keylen);
+  return ctx->db->del(ctx->db, NULL, &dkey, 0);
+}
+
+static void
+hcache_bdb_close(void **vctx)
+{
+  if (!vctx || !*vctx)
+    return;
+
+  hcache_db_ctx_t *ctx = *vctx;
+
+  ctx->db->close (ctx->db, 0);
+  ctx->env->close (ctx->env, 0);
+  mx_unlock_file (ctx->lockfile, ctx->fd, 0);
+  close (ctx->fd);
+  unlink (ctx->lockfile);
+  FREE(vctx); /* __FREE_CHECKED__ */
+}
+
+static const char *
+hcache_bdb_backend(void)
+{
+  return DB_VERSION_STRING;
+}
+
+HCACHE_BACKEND_OPS(bdb)
+
+#endif /* HAVE_BDB */
diff --git a/hcache-gdbm.c b/hcache-gdbm.c
new file mode 100644 (file)
index 0000000..ae8a3a3
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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>
+ * Copyright (C) 2016 Pietro Cerutti <gahr@gahr.ch>
+ *
+ *     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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_GDBM
+
+#include "hcache.h"
+#include "globals.h"
+#include <gdbm.h>
+
+static void *
+hcache_gdbm_open(const char *path)
+{
+  int pagesize;
+
+  if (mutt_atoi (HeaderCachePageSize, &pagesize) < 0 || pagesize <= 0)
+    pagesize = 16384;
+
+  GDBM_FILE db = gdbm_open((char *) path, pagesize, GDBM_WRCREAT, 00600, NULL);
+  if (db)
+    return db;
+
+  /* if rw failed try ro */
+  return gdbm_open((char *) path, pagesize, GDBM_READER, 00600, NULL);
+}
+
+static void *
+hcache_gdbm_fetch(void *ctx, const char *key, size_t keylen)
+{
+  datum dkey;
+  datum data;
+
+  if (!ctx)
+    return NULL;
+
+  GDBM_FILE db = ctx;
+
+  dkey.dptr = (char *)key;
+  dkey.dsize = keylen;
+  data = gdbm_fetch(db, dkey);
+  return data.dptr;
+}
+
+static int
+hcache_gdbm_store(void *ctx, const char *key, size_t keylen, void *data, size_t dlen)
+{
+  datum dkey;
+  datum databuf;
+
+  if (!ctx)
+    return -1;
+
+  GDBM_FILE db = ctx;
+
+  dkey.dptr = (char *)key;
+  dkey.dsize = keylen;
+
+  databuf.dsize = dlen;
+  databuf.dptr = data;
+
+  return gdbm_store(db, dkey, databuf, GDBM_REPLACE);
+}
+
+static int
+hcache_gdbm_delete(void *ctx, const char *key, size_t keylen)
+{
+  datum dkey;
+
+  if (!ctx)
+    return -1;
+
+  GDBM_FILE db = ctx;
+
+  dkey.dptr = (char *)key;
+  dkey.dsize = keylen;
+
+  return gdbm_delete(db, dkey);
+}
+
+static void
+hcache_gdbm_close(void **ctx)
+{
+  if (!ctx)
+    return;
+
+  GDBM_FILE db = *ctx;
+  gdbm_close(db);
+}
+
+static const char *
+hcache_gdbm_backend(void)
+{
+  return gdbm_version;
+}
+
+HCACHE_BACKEND_OPS(gdbm)
+
+#endif /* HAVE_GDBM */
diff --git a/hcache-kc.c b/hcache-kc.c
new file mode 100644 (file)
index 0000000..bf5de39
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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>
+ * Copyright (C) 2016 Pietro Cerutti <gahr@gahr.ch>
+ *
+ *     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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_KC
+
+#include "hcache.h"
+#include <kclangc.h>
+
+static void *
+hcache_kc_open(const char *path)
+{
+  char kcdbpath[_POSIX_PATH_MAX];
+  int printfresult;
+
+  printfresult = snprintf(kcdbpath, sizeof(kcdbpath),
+                          "%s#type=kct#opts=%s#rcomp=lex",
+                          path, option(OPTHCACHECOMPRESS) ? "lc" : "l");
+  if ((printfresult < 0) || (printfresult >= sizeof(kcdbpath)))
+  {
+    return NULL;
+  }
+
+  KCDB *db = kcdbnew();
+  if (!db)
+      return NULL;
+
+  if (kcdbopen(db, kcdbpath, KCOWRITER | KCOCREATE))
+    return db;
+  else
+  {
+#ifdef DEBUG
+    int ecode = kcdbecode (db);
+    dprint (2, (debugfile, "kcdbopen failed for %s: %s (ecode %d)\n", kcdbpath, kcdbemsg (db), ecode));
+#endif
+    kcdbdel(db);
+    return NULL;
+  }
+}
+
+static void *
+hcache_kc_fetch(void *ctx, const char *key, size_t keylen)
+{
+  size_t sp;
+
+  if (!ctx)
+      return NULL;
+
+  KCDB *db = ctx;
+  return kcdbget(db, key, keylen, &sp);
+}
+
+static int
+hcache_kc_store(void *ctx, const char* key, size_t keylen, void *data, size_t dlen)
+{
+  if (!ctx)
+    return -1;
+
+  KCDB *db = ctx;
+  return kcdbset(db, key, keylen, data, dlen);
+}
+
+static int
+hcache_kc_delete(void *ctx, const char *key, size_t keylen)
+{
+  if (!ctx)
+    return -1;
+
+  KCDB *db = ctx;
+  return kcdbremove(db, key, keylen);
+}
+
+static void
+hcache_kc_close(void **ctx)
+{
+  if (!ctx || !*ctx)
+    return;
+
+  KCDB *db = *ctx;
+  if (!kcdbclose(db))
+  {
+#ifdef DEBUG
+    int ecode = kcdbecode (db);
+    dprint (2, (debugfile, "kcdbclose failed: %s (ecode %d)\n", kcdbemsg (db), ecode));
+#endif
+  }
+  kcdbdel(db);
+}
+
+static const char *
+hcache_kc_backend(void)
+{
+  /* SHORT_STRING(128) should be more than enough for KCVERSION */
+  static char version_cache[SHORT_STRING] = "";
+  if (!version_cache[0])
+    snprintf(version_cache, sizeof(version_cache), "kyotocabinet %s", KCVERSION);
+
+  return version_cache;
+}
+
+HCACHE_BACKEND_OPS(kc)
+
+#endif /* HAVE_KC */
diff --git a/hcache-lmdb.c b/hcache-lmdb.c
new file mode 100644 (file)
index 0000000..c2d727b
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * 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>
+ * Copyright (C) 2016 Pietro Cerutti <gahr@gahr.ch>
+ *
+ *     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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_LMDB
+
+#include "hcache.h"
+
+#define LMDB_DB_SIZE (1024 * 1024 * 1024)
+#include <lmdb.h>
+
+enum mdb_txn_mode
+{
+  txn_uninitialized = 0,
+  txn_read          = 1 << 0,
+  txn_write         = 1 << 1
+};
+
+typedef struct
+{
+  MDB_env *env;
+  MDB_txn *txn;
+  MDB_dbi db;
+  enum mdb_txn_mode txn_mode;
+} hcache_lmdb_ctx_t;
+
+static int
+mdb_get_r_txn(hcache_lmdb_ctx_t *ctx)
+{
+  int rc;
+
+  if (ctx->txn && (ctx->txn_mode & (txn_read | txn_write)) > 0)
+    return MDB_SUCCESS;
+
+  if (ctx->txn)
+    rc = mdb_txn_renew(ctx->txn);
+  else
+    rc = mdb_txn_begin(ctx->env, NULL, MDB_RDONLY, &ctx->txn);
+
+  if (rc == MDB_SUCCESS)
+    ctx->txn_mode = txn_read;
+
+  return rc;
+}
+
+static int
+mdb_get_w_txn(hcache_lmdb_ctx_t *ctx)
+{
+  int rc;
+
+  if (ctx->txn && (ctx->txn_mode == txn_write))
+    return MDB_SUCCESS;
+
+  if (ctx->txn)
+  {
+    if (ctx->txn_mode == txn_read)
+      mdb_txn_reset(ctx->txn);
+    ctx->txn = NULL;
+  }
+
+  rc = mdb_txn_begin(ctx->env, NULL, 0, &ctx->txn);
+  if (rc == MDB_SUCCESS)
+    ctx->txn_mode = txn_write;
+
+  return rc;
+}
+
+static void *
+hcache_lmdb_open(const char *path)
+{
+  int rc;
+
+  hcache_lmdb_ctx_t *ctx = safe_malloc(sizeof(hcache_lmdb_ctx_t));
+  ctx->txn = NULL;
+  ctx->db  = 0;
+
+  rc = mdb_env_create(&ctx->env);
+  if (rc != MDB_SUCCESS)
+  {
+    fprintf(stderr, "hcache_open_lmdb: mdb_env_create: %s", mdb_strerror(rc));
+    return NULL;
+  }
+
+  mdb_env_set_mapsize(ctx->env, LMDB_DB_SIZE);
+
+  rc = mdb_env_open(ctx->env, path, MDB_NOSUBDIR, 0644);
+  if (rc != MDB_SUCCESS)
+  {
+    fprintf(stderr, "hcache_open_lmdb: mdb_env_open: %s", mdb_strerror(rc));
+    goto fail_env;
+  }
+
+  rc = mdb_get_r_txn(ctx);
+  if (rc != MDB_SUCCESS)
+  {
+      fprintf(stderr, "hcache_open_lmdb: mdb_txn_begin: %s", mdb_strerror(rc));
+      goto fail_env;
+  }
+
+  rc = mdb_dbi_open(ctx->txn, NULL, MDB_CREATE, &ctx->db);
+  if (rc != MDB_SUCCESS)
+  {
+    fprintf(stderr, "hcache_open_lmdb: mdb_dbi_open: %s", mdb_strerror(rc));
+    goto fail_dbi;
+  }
+
+  mdb_txn_reset(ctx->txn);
+  ctx->txn_mode = txn_uninitialized;
+  return ctx;
+
+fail_dbi:
+  mdb_txn_abort(ctx->txn);
+  ctx->txn_mode = txn_uninitialized;
+  ctx->txn = NULL;
+
+fail_env:
+  mdb_env_close(ctx->env);
+  FREE(&ctx);
+  return NULL;
+}
+
+static void *
+hcache_lmdb_fetch(void *vctx, const char *key, size_t keylen)
+{
+  MDB_val dkey;
+  MDB_val data;
+  int rc;
+
+  if (!vctx)
+      return NULL;
+
+  hcache_lmdb_ctx_t *ctx = vctx;
+
+  dkey.mv_data = (void *)key;
+  dkey.mv_size = keylen;
+  data.mv_data = NULL;
+  data.mv_size = 0;
+  rc = mdb_get_r_txn(ctx);
+  if (rc != MDB_SUCCESS)
+  {
+    ctx->txn = NULL;
+    fprintf(stderr, "txn_renew: %s\n", mdb_strerror(rc));
+    return NULL;
+  }
+  rc = mdb_get(ctx->txn, ctx->db, &dkey, &data);
+  if (rc == MDB_NOTFOUND)
+  {
+    return NULL;
+  }
+  if (rc != MDB_SUCCESS)
+  {
+    fprintf(stderr, "mdb_get: %s\n", mdb_strerror(rc));
+    return NULL;
+  }
+  /* Caller frees the data we return, so I MUST make a copy of it */
+
+  char *d = safe_malloc(data.mv_size);
+  memcpy(d, data.mv_data, data.mv_size);
+
+  return d;
+}
+
+static int
+hcache_lmdb_store(void *vctx, const char *key, size_t keylen, void *data, size_t dlen)
+{
+  MDB_val dkey;
+  MDB_val databuf;
+  int rc;
+
+  if (!vctx)
+    return -1;
+
+  hcache_lmdb_ctx_t *ctx = vctx;
+
+  dkey.mv_data = (void *)key;
+  dkey.mv_size = keylen;
+  databuf.mv_data = data;
+  databuf.mv_size = dlen;
+  rc = mdb_get_w_txn(ctx);
+  if (rc != MDB_SUCCESS)
+  {
+    fprintf(stderr, "txn_begin: %s\n", mdb_strerror(rc));
+    return rc;
+  }
+  rc = mdb_put(ctx->txn, ctx->db, &dkey, &databuf, 0);
+  if (rc != MDB_SUCCESS)
+  {
+    fprintf(stderr, "mdb_put: %s\n", mdb_strerror(rc));
+    mdb_txn_abort(ctx->txn);
+    ctx->txn_mode = txn_uninitialized;
+    ctx->txn = NULL;
+    return rc;
+  }
+  return rc;
+}
+
+static int
+hcache_lmdb_delete(void *vctx, const char *key, size_t keylen)
+{
+  MDB_val dkey;
+  int rc;
+
+  if (!vctx)
+    return -1;
+
+  hcache_lmdb_ctx_t *ctx = vctx;
+
+  dkey.mv_data = (void *)key;
+  dkey.mv_size = keylen;
+  rc = mdb_get_w_txn(ctx);
+  if (rc != MDB_SUCCESS)
+  {
+    fprintf(stderr, "txn_begin: %s\n", mdb_strerror(rc));
+    return rc;
+  }
+  rc = mdb_del(ctx->txn, ctx->db, &dkey, NULL);
+  if (rc != MDB_SUCCESS)
+  {
+    if (rc != MDB_NOTFOUND)
+    {
+      fprintf(stderr, "mdb_del: %s\n", mdb_strerror(rc));
+      mdb_txn_abort(ctx->txn);
+      ctx->txn_mode = txn_uninitialized;
+      ctx->txn = NULL;
+    }
+    return rc;
+  }
+
+  return rc;
+}
+
+static void
+hcache_lmdb_close(void **vctx)
+{
+  if (!vctx || !*vctx)
+    return;
+
+  hcache_lmdb_ctx_t *ctx = *vctx;
+
+  if (ctx->txn && ctx->txn_mode == txn_write)
+  {
+    mdb_txn_commit(ctx->txn);
+    ctx->txn_mode = txn_uninitialized;
+    ctx->txn = NULL;
+  }
+
+  mdb_env_close(ctx->env);
+  FREE(vctx); /* __FREE_CHECKED__ */
+}
+
+static const char *
+hcache_lmdb_backend(void)
+{
+  return "lmdb " MDB_VERSION_STRING;
+}
+
+HCACHE_BACKEND_OPS(lmdb)
+
+#endif /* HAVE_LMDB */
diff --git a/hcache-qdbm.c b/hcache-qdbm.c
new file mode 100644 (file)
index 0000000..dd302ef
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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>
+ * Copyright (C) 2016 Pietro Cerutti <gahr@gahr.ch>
+ *
+ *     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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_QDBM
+
+#include "hcache.h"
+#include <depot.h>
+#include <cabin.h>
+#include <villa.h>
+
+static void *
+hcache_qdbm_open(const char *path)
+{
+  int flags = VL_OWRITER | VL_OCREAT;
+
+  if (option(OPTHCACHECOMPRESS))
+    flags |= VL_OZCOMP;
+
+  return vlopen (path, flags, VL_CMPLEX);
+}
+
+static void *
+hcache_qdbm_fetch(void *ctx, const char *key, size_t keylen)
+{
+  if (!ctx)
+    return NULL;
+
+  VILLA *db = ctx;
+  return vlget(db, key, keylen, NULL);
+}
+
+static int
+hcache_qdbm_store(void *ctx, const char *key, size_t keylen, void *data, size_t dlen)
+{
+  if (!ctx)
+    return -1;
+
+  VILLA *db = ctx;
+  return vlput(db, key, keylen, data, dlen, VL_DOVER);
+}
+
+static int
+hcache_qdbm_delete(void *ctx, const char *key, size_t keylen)
+{
+  if (!ctx)
+    return -1;
+
+  VILLA *db = ctx;
+  return vlout(db, key, keylen);
+}
+
+static void
+hcache_qdbm_close(void **ctx)
+{
+  if (!ctx || !*ctx)
+    return;
+
+  VILLA *db = *ctx;
+  vlclose(db);
+}
+
+static const char *
+hcache_qdbm_backend(void)
+{
+  return "qdbm " _QDBM_VERSION;
+}
+
+HCACHE_BACKEND_OPS(qdbm)
+
+#endif /* HAVE_LMDB */
diff --git a/hcache-tc.c b/hcache-tc.c
new file mode 100644 (file)
index 0000000..10e43a8
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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>
+ * Copyright (C) 2016 Pietro Cerutti <gahr@gahr.ch>
+ *
+ *     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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_TC
+
+#include "hcache.h"
+#include <tcbdb.h>
+
+static void *
+hcache_tc_open(const char *path)
+{
+  TCBDB *db = tcbdbnew();
+  if (!db)
+      return NULL;
+  if (option(OPTHCACHECOMPRESS))
+    tcbdbtune(db, 0, 0, 0, -1, -1, BDBTDEFLATE);
+  if (tcbdbopen(db, path, BDBOWRITER | BDBOCREAT))
+    return db;
+  else
+  {
+#ifdef DEBUG
+    int ecode = tcbdbecode (db);
+    dprint (2, (debugfile, "tcbdbopen failed for %s: %s (ecode %d)\n", path, tcbdberrmsg (ecode), ecode));
+#endif
+    tcbdbdel(db);
+    return NULL;
+  }
+}
+
+static void *
+hcache_tc_fetch(void *ctx, const char *key, size_t keylen)
+{
+  int sp;
+
+  if (!ctx)
+    return NULL;
+
+  TCBDB *db = ctx;
+  return tcbdbget(db, key, keylen, &sp);
+}
+
+static int
+hcache_tc_store(void *ctx, const char *key, size_t keylen, void *data, size_t dlen)
+{
+  if (!ctx)
+    return -1;
+
+  TCBDB *db = ctx;
+  return tcbdbput(db, key, keylen, data, dlen);
+}
+
+static int
+hcache_tc_delete(void *ctx, const char *key, size_t keylen)
+{
+  if (!ctx)
+    return -1;
+
+  TCBDB *db = ctx;
+  return tcbdbout(db, key, keylen);
+}
+
+static void
+hcache_tc_close(void **ctx)
+{
+  if (!ctx || !*ctx)
+    return;
+
+  TCBDB *db = *ctx;
+  if (!tcbdbclose(db))
+  {
+#ifdef DEBUG
+    int ecode = tcbdbecode (db);
+    dprint (2, (debugfile, "tcbdbclose failed: %s (ecode %d)\n", tcbdberrmsg (ecode), ecode));
+#endif
+  }
+  tcbdbdel(db);
+}
+
+static const char *
+hcache_tc_backend(void)
+{
+  return "tokyocabinet " _TC_VERSION;
+}
+
+HCACHE_BACKEND_OPS(tc)
+
+#endif /* HAVE_TC */
index 870e05417cdb9df61036312300e6a89dcfb1eff9..9946c2367b7ce8dba98e3e719cb38ecdc6260b35 100644 (file)
--- a/hcache.c
+++ b/hcache.c
@@ -2,6 +2,7 @@
  * 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>
+ * Copyright (C) 2016 Pietro Cerutti <gahr@gahr.ch>
  *
  *     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
 #include "config.h"
 #endif                         /* HAVE_CONFIG_H */
 
-#if HAVE_QDBM
-#include <depot.h>
-#include <cabin.h>
-#include <villa.h>
-#elif HAVE_TC
-#include <tcbdb.h>
-#elif HAVE_KC
-#include <kclangc.h>
-#elif HAVE_GDBM
-#include <gdbm.h>
-#elif HAVE_DB4
-#include <db.h>
-#elif HAVE_LMDB
-#define LMDB_DB_SIZE    (1024 * 1024 * 1024)
-#include <lmdb.h>
+#if !(HAVE_TC || HAVE_KC || HAVE_GDBM || HAVE_BDB || HAVE_LMDB || HAVE_QDBM)
+#error "No hcache backend defined"
 #endif
 
 #include <errno.h>
-#include <fcntl.h>
 #if HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#include "mutt.h"
 #include "hcache.h"
 #include "hcversion.h"
-#include "mx.h"
-#include "lib.h"
 #include "md5.h"
-#include "rfc822.h"
 
-unsigned int hcachever = 0x0;
+static unsigned int hcachever = 0x0;
 
-#if HAVE_QDBM
-struct header_cache
-{
-  VILLA *db;
-  char *folder;
-  unsigned int crc;
-};
-#elif HAVE_TC
-struct header_cache
-{
-  TCBDB *db;
-  char *folder;
-  unsigned int crc;
-};
-#elif HAVE_KC
-struct header_cache
-{
-  KCDB *db;
-  char *folder;
-  unsigned int crc;
-};
-#elif HAVE_GDBM
-struct header_cache
-{
-  GDBM_FILE db;
-  char *folder;
-  unsigned int crc;
-};
-#elif HAVE_DB4
-struct header_cache
-{
-  DB_ENV *env;
-  DB *db;
-  char *folder;
-  unsigned int crc;
-  int fd;
-  char lockfile[_POSIX_PATH_MAX];
-};
-
-static void mutt_hcache_dbt_init(DBT * dbt, void *data, size_t len);
-static void mutt_hcache_dbt_empty_init(DBT * dbt);
-#elif HAVE_LMDB
-enum mdb_txn_mode
-{
-  txn_uninitialized = 0,
-  txn_read = 1 << 0,
-  txn_write = 1 << 1
-};
+/**
+ * header_cache_t - header cache structure.
+ *
+ * This struct holds both the backend-agnostic and the backend-specific parts
+ * of the header cache. Backend code MUST initialize the fetch, store,
+ * delete and close function pointers in hcache_open, and MAY store
+ * backend-specific context in the ctx pointer.
+ */
 struct header_cache
 {
-  MDB_env *env;
-  MDB_txn *txn;
-  MDB_dbi db;
   char *folder;
   unsigned int crc;
-  enum mdb_txn_mode txn_mode;
+  void *ctx;
 };
 
-static int mdb_get_r_txn(header_cache_t *h)
-{
-  int rc;
-
-  if (h->txn && (h->txn_mode & (txn_read | txn_write)) > 0)
-    return MDB_SUCCESS;
-
-  if (h->txn)
-    rc = mdb_txn_renew(h->txn);
-  else
-    rc = mdb_txn_begin(h->env, NULL, MDB_RDONLY, &h->txn);
-
-  if (rc == MDB_SUCCESS)
-    h->txn_mode = txn_read;
-
-  return rc;
-}
-
-static int mdb_get_w_txn(header_cache_t *h)
-{
-  int rc;
-
-  if (h->txn && (h->txn_mode == txn_write))
-    return MDB_SUCCESS;
-
-  if (h->txn)
-  {
-    if (h->txn_mode == txn_read)
-      mdb_txn_reset(h->txn);
-    h->txn = NULL;
-  }
-
-  rc = mdb_txn_begin(h->env, NULL, 0, &h->txn);
-  if (rc == MDB_SUCCESS)
-    h->txn_mode = txn_write;
-
-  return rc;
-}
-#endif
-
 typedef union
 {
   struct timeval timeval;
   unsigned int uidvalidity;
 } validate;
 
+#define HCACHE_BACKEND(name) extern hcache_ops_t hcache_##name##_ops;
+HCACHE_BACKEND_LIST
+#undef HCACHE_BACKEND
+
+static hcache_ops_t *
+hcache_get_ops(void)
+{
+  // TODO - switch to run-time config
+  return
+#if defined(HAVE_BDB)
+    &hcache_bdb_ops
+#elif defined(HAVE_GDBM)
+    &hcache_gdbm_ops
+#elif defined(HAVE_KC)
+    &hcache_kc_ops
+#elif defined(HAVE_LMDB)
+    &hcache_lmdb_ops
+#elif defined(HAVE_QDBM)
+    &hcache_qdbm_ops
+#elif defined(HAVE_TC)
+    &hcache_tc_ops
+#else
+    NULL
+#endif
+    ;
+}
+
 static void *
 lazy_malloc(size_t siz)
 {
-  if (0 < siz && siz < 4096)
+  if (siz < 4096)
     siz = 4096;
 
   return safe_malloc(siz);
@@ -172,7 +99,7 @@ lazy_realloc(void *ptr, size_t siz)
 {
   void **p = (void **) ptr;
 
-  if (p != NULL && 0 < siz && siz < 4096)
+  if (p != NULL && siz < 4096)
     return;
 
   safe_realloc(ptr, siz);
@@ -683,7 +610,7 @@ mutt_hcache_per_folder(const char *path, const char *folder,
  */
 static void *
 mutt_hcache_dump(header_cache_t *h, HEADER * header, int *off,
-                unsigned int uidvalidity, mutt_hcache_store_flags_t flags)
+                 unsigned int uidvalidity)
 {
   unsigned char *d = NULL;
   HEADER nh;
@@ -692,7 +619,7 @@ mutt_hcache_dump(header_cache_t *h, HEADER * header, int *off,
   *off = 0;
   d = lazy_malloc(sizeof (validate));
 
-  if (flags & MUTT_GENERATE_UIDVALIDITY)
+  if (uidvalidity == 0)
   {
     struct timeval now;
     gettimeofday(&now, NULL);
@@ -741,7 +668,7 @@ mutt_hcache_dump(header_cache_t *h, HEADER * header, int *off,
 }
 
 HEADER *
-mutt_hcache_restore(const unsigned char *d, HEADER ** oh)
+mutt_hcache_restore(const unsigned char *d)
 {
   int off = 0;
   HEADER *h = mutt_new_header();
@@ -764,252 +691,9 @@ mutt_hcache_restore(const unsigned char *d, HEADER ** oh)
 
   restore_char(&h->maildir_flags, d, &off, convert);
 
-  /* 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;
 }
 
-void *
-mutt_hcache_fetch(header_cache_t *h, const char *filename,
-                 size_t(*keylen) (const char *fn))
-{
-  void* data;
-
-  data = mutt_hcache_fetch_raw (h, filename, keylen);
-
-  if (!data || !crc_matches(data, h->crc))
-  {
-    FREE(&data);
-    return NULL;
-  }
-  
-  return data;
-}
-
-void *
-mutt_hcache_fetch_raw (header_cache_t *h, const char *filename,
-                       size_t(*keylen) (const char *fn))
-{
-#ifndef HAVE_DB4
-  char path[_POSIX_PATH_MAX];
-  int ksize;
-#endif
-#ifdef HAVE_QDBM
-  char *data = NULL;
-#elif HAVE_TC
-  void *data;
-  int sp;
-#elif HAVE_KC
-  void *data;
-  size_t sp;
-#elif HAVE_GDBM
-  datum key;
-  datum data;
-#elif HAVE_DB4
-  DBT key;
-  DBT data;
-#elif HAVE_LMDB
-  MDB_val key;
-  MDB_val data;
-  size_t folderlen;
-  int rc;
-#endif
-  
-  if (!h)
-    return NULL;
-  
-#ifdef HAVE_DB4
-  if (filename[0] == '/')
-    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);
-  
-  return data.data;
-#elif HAVE_LMDB
-  strncpy(path, h->folder, sizeof (path));
-  safe_strcat(path, sizeof (path), filename);
-
-  folderlen = strlen(h->folder);
-  ksize = folderlen + keylen(path + folderlen);  
-  key.mv_data = (char *)path;
-  key.mv_size = ksize;
-  data.mv_data = NULL;
-  data.mv_size = 0;
-  rc = mdb_get_r_txn(h);
-  if (rc != MDB_SUCCESS)
-  {
-    h->txn = NULL;
-    fprintf(stderr, "txn_renew: %s\n", mdb_strerror(rc));
-    return NULL;
-  }
-  rc = mdb_get(h->txn, h->db, &key, &data);
-  if (rc == MDB_NOTFOUND)
-  {
-    return NULL;
-  }
-  if (rc != MDB_SUCCESS)
-  {
-    fprintf(stderr, "mdb_get: %s\n", mdb_strerror(rc));
-    return NULL;
-  }
-  /* Caller frees the data we return, so I MUST make a copy of it */
-
-  char *d = safe_malloc(data.mv_size);
-  memcpy(d, data.mv_data, data.mv_size);
-
-  return d;
-
-#else
-  strncpy(path, h->folder, sizeof (path));
-  safe_strcat(path, sizeof (path), filename);
-
-  ksize = strlen (h->folder) + keylen (path + strlen (h->folder));  
-#endif
-#ifdef HAVE_QDBM
-  data = vlget(h->db, path, ksize, NULL);
-  
-  return data;
-#elif HAVE_TC
-  data = tcbdbget(h->db, path, ksize, &sp);
-
-  return data;
-#elif HAVE_KC
-  data = kcdbget(h->db, path, ksize, &sp);
-
-  return data;
-#elif HAVE_GDBM
-  key.dptr = path;
-  key.dsize = ksize;
-  
-  data = gdbm_fetch(h->db, key);
-  
-  return data.dptr;
-#endif
-}
-
-/*
- * flags
- *
- * MUTT_GENERATE_UIDVALIDITY
- * ignore uidvalidity param and store gettimeofday() as the value
- */
-int
-mutt_hcache_store(header_cache_t *h, const char *filename, HEADER * header,
-                 unsigned int uidvalidity,
-                 size_t(*keylen) (const char *fn),
-                 mutt_hcache_store_flags_t flags)
-{
-  char* data;
-  int dlen;
-  int ret;
-  
-  if (!h)
-    return -1;
-  
-  data = mutt_hcache_dump(h, header, &dlen, uidvalidity, flags);
-  ret = mutt_hcache_store_raw (h, filename, data, dlen, keylen);
-  
-  FREE(&data);
-  
-  return ret;
-}
-
-int
-mutt_hcache_store_raw (header_cache_t* h, const char* filename, void* data,
-                       size_t dlen, size_t(*keylen) (const char* fn))
-{
-#ifndef HAVE_DB4
-  char path[_POSIX_PATH_MAX];
-  int ksize;
-#endif
-#if HAVE_GDBM
-  datum key;
-  datum databuf;
-#elif HAVE_DB4
-  DBT key;
-  DBT databuf;
-#elif HAVE_LMDB
-  MDB_val key;
-  MDB_val databuf;
-  size_t folderlen;
-  int rc;
-#endif
-  
-  if (!h)
-    return -1;
-
-#if HAVE_DB4
-  if (filename[0] == '/')
-    filename++;
-  
-  mutt_hcache_dbt_init(&key, (void *) filename, keylen(filename));
-  
-  mutt_hcache_dbt_empty_init(&databuf);
-  databuf.flags = DB_DBT_USERMEM;
-  databuf.data = data;
-  databuf.size = dlen;
-  databuf.ulen = dlen;
-  
-  return h->db->put(h->db, NULL, &key, &databuf, 0);
-#elif HAVE_LMDB
-  folderlen = strlen(h->folder);
-  strncpy(path, h->folder, sizeof (path));
-  safe_strcat(path, sizeof (path), filename);
-  ksize = folderlen + keylen(path + folderlen);
-
-  key.mv_data = (char *)path;
-  key.mv_size = ksize;
-  databuf.mv_data = data;
-  databuf.mv_size = dlen;
-  rc = mdb_get_w_txn(h);
-  if (rc != MDB_SUCCESS)
-  {
-    fprintf(stderr, "txn_begin: %s\n", mdb_strerror(rc));
-    return rc;
-  }
-  rc = mdb_put(h->txn, h->db, &key, &databuf, 0);
-  if (rc != MDB_SUCCESS)
-  {
-    fprintf(stderr, "mdb_put: %s\n", mdb_strerror(rc));
-    mdb_txn_abort(h->txn);
-    h->txn_mode = txn_uninitialized;
-    h->txn = NULL;
-    return rc;
-  }
-  return rc;
-#else
-  strncpy(path, h->folder, sizeof (path));
-  safe_strcat(path, sizeof (path), filename);
-
-  ksize = strlen(h->folder) + keylen(path + strlen(h->folder));
-#endif
-#if HAVE_QDBM
-  return vlput(h->db, path, ksize, data, dlen, VL_DOVER);
-#elif HAVE_TC
-  return tcbdbput(h->db, path, ksize, data, dlen);
-#elif HAVE_KC
-  return kcdbset(h->db, path, ksize, data, dlen);
-#elif HAVE_GDBM
-  key.dptr = path;
-  key.dsize = ksize;
-  
-  databuf.dsize = dlen;
-  databuf.dptr = data;
-  
-  return gdbm_store(h->db, key, databuf, GDBM_REPLACE);
-#endif
-}
-
 static char* get_foldername(const char *folder)
 {
   char *p = NULL;
@@ -1031,464 +715,15 @@ static char* get_foldername(const char *folder)
   return p;
 }
 
-#if HAVE_QDBM
-static int
-hcache_open_qdbm (struct header_cache* h, const char* path)
-{
-  int    flags = VL_OWRITER | VL_OCREAT;
-
-  if (option(OPTHCACHECOMPRESS))
-    flags |= VL_OZCOMP;
-
-  h->db = vlopen (path, flags, VL_CMPLEX);
-  if (h->db)
-    return 0;
-  else
-    return -1;
-}
-
-void
-mutt_hcache_close(header_cache_t *h)
-{
-  if (!h)
-    return;
-
-  vlclose(h->db);
-  FREE(&h->folder);
-  FREE(&h);
-}
-
-int
-mutt_hcache_delete(header_cache_t *h, const char *filename,
-                  size_t(*keylen) (const char *fn))
-{
-  char path[_POSIX_PATH_MAX];
-  int ksize;
-
-  if (!h)
-    return -1;
-
-  strncpy(path, h->folder, sizeof (path));
-  safe_strcat(path, sizeof (path), filename);
-
-  ksize = strlen(h->folder) + keylen(path + strlen(h->folder));
-
-  return vlout(h->db, path, ksize);
-}
-
-#elif HAVE_TC
-static int
-hcache_open_tc (struct header_cache* h, const char* path)
-{
-  h->db = tcbdbnew();
-  if (!h->db)
-      return -1;
-  if (option(OPTHCACHECOMPRESS))
-    tcbdbtune(h->db, 0, 0, 0, -1, -1, BDBTDEFLATE);
-  if (tcbdbopen(h->db, path, BDBOWRITER | BDBOCREAT))
-    return 0;
-  else
-  {
-#ifdef DEBUG
-    int ecode = tcbdbecode (h->db);
-    dprint (2, (debugfile, "tcbdbopen failed for %s: %s (ecode %d)\n", path, tcbdberrmsg (ecode), ecode));
-#endif
-    tcbdbdel(h->db);
-    return -1;
-  }
-}
-
-void
-mutt_hcache_close(header_cache_t *h)
-{
-  if (!h)
-    return;
-
-  if (!tcbdbclose(h->db))
-  {
-#ifdef DEBUG
-    int ecode = tcbdbecode (h->db);
-    dprint (2, (debugfile, "tcbdbclose failed for %s: %s (ecode %d)\n", h->folder, tcbdberrmsg (ecode), ecode));
-#endif
-  }
-  tcbdbdel(h->db);
-  FREE(&h->folder);
-  FREE(&h);
-}
-
-int
-mutt_hcache_delete(header_cache_t *h, const char *filename,
-                  size_t(*keylen) (const char *fn))
-{
-  char path[_POSIX_PATH_MAX];
-  int ksize;
-
-  if (!h)
-    return -1;
-
-  strncpy(path, h->folder, sizeof (path));
-  safe_strcat(path, sizeof (path), filename);
-
-  ksize = strlen(h->folder) + keylen(path + strlen(h->folder));
-
-  return tcbdbout(h->db, path, ksize);
-}
-
-#elif HAVE_KC
-static int
-hcache_open_kc (struct header_cache *h, const char *path)
-{
-  char kcdbpath[_POSIX_PATH_MAX];
-  int printfresult;
-
-  printfresult = snprintf(kcdbpath, sizeof(kcdbpath),
-                          "%s#type=kct#opts=%s#rcomp=lex",
-                          path, option(OPTHCACHECOMPRESS) ? "lc" : "l");
-  if ((printfresult < 0) || (printfresult >= sizeof(kcdbpath)))
-  {
-    return -1;
-  }
-
-  h->db = kcdbnew();
-  if (!h->db)
-      return -1;
-
-  if (kcdbopen(h->db, kcdbpath, KCOWRITER | KCOCREATE))
-    return 0;
-  else
-  {
-#ifdef DEBUG
-    int ecode = kcdbecode (h->db);
-    dprint (2, (debugfile, "kcdbopen failed for %s: %s (ecode %d)\n", kcdbpath, kcdbemsg (h->db), ecode));
-#endif
-    kcdbdel(h->db);
-    return -1;
-  }
-}
-
-void
-mutt_hcache_close(header_cache_t *h)
-{
-  if (!h)
-    return;
-
-  if (!kcdbclose(h->db))
-  {
-#ifdef DEBUG
-    int ecode = kcdbecode (h->db);
-    dprint (2, (debugfile, "kcdbclose failed for %s: %s (ecode %d)\n", h->folder, kcdbemsg (h->db), ecode));
-#endif
-  }
-  kcdbdel(h->db);
-  FREE(&h->folder);
-  FREE(&h);
-}
-
-int
-mutt_hcache_delete(header_cache_t *h, const char *filename,
-                  size_t(*keylen) (const char *fn))
-{
-  char path[_POSIX_PATH_MAX];
-  int ksize;
-
-  if (!h)
-    return -1;
-
-  strncpy(path, h->folder, sizeof (path));
-  safe_strcat(path, sizeof (path), filename);
-
-  ksize = strlen(h->folder) + keylen(path + strlen(h->folder));
-
-  return kcdbremove(h->db, path, ksize);
-}
-
-#elif HAVE_GDBM
-static int
-hcache_open_gdbm (struct header_cache* h, const char* path)
-{
-  int pagesize;
-
-  if (mutt_atoi (HeaderCachePageSize, &pagesize) < 0 || pagesize <= 0)
-    pagesize = 16384;
-
-  h->db = gdbm_open((char *) path, pagesize, GDBM_WRCREAT, 00600, NULL);
-  if (h->db)
-    return 0;
-
-  /* if rw failed try ro */
-  h->db = gdbm_open((char *) path, pagesize, GDBM_READER, 00600, NULL);
-  if (h->db)
-    return 0;
-
-  return -1;
-}
-
-void
-mutt_hcache_close(header_cache_t *h)
-{
-  if (!h)
-    return;
-
-  gdbm_close(h->db);
-  FREE(&h->folder);
-  FREE(&h);
-}
-
-int
-mutt_hcache_delete(header_cache_t *h, const char *filename,
-                  size_t(*keylen) (const char *fn))
-{
-  datum key;
-  char path[_POSIX_PATH_MAX];
-
-  if (!h)
-    return -1;
-
-  strncpy(path, h->folder, sizeof (path));
-  safe_strcat(path, sizeof (path), filename);
-
-  key.dptr = path;
-  key.dsize = strlen(h->folder) + keylen(path + strlen(h->folder));
-
-  return gdbm_delete(h->db, key);
-}
-#elif HAVE_DB4
-
-static void
-mutt_hcache_dbt_init(DBT * dbt, void *data, size_t len)
-{
-  dbt->data = data;
-  dbt->size = dbt->ulen = len;
-  dbt->dlen = dbt->doff = 0;
-  dbt->flags = DB_DBT_USERMEM;
-}
-
-static void
-mutt_hcache_dbt_empty_init(DBT * dbt)
-{
-  dbt->data = NULL;
-  dbt->size = dbt->ulen = dbt->dlen = dbt->doff = 0;
-  dbt->flags = 0;
-}
-
-static int
-hcache_open_db4 (struct header_cache* h, const char* path)
-{
-  struct stat sb;
-  int ret;
-  u_int32_t createflags = DB_CREATE;
-  int pagesize;
-
-  if (mutt_atoi (HeaderCachePageSize, &pagesize) < 0 || pagesize <= 0)
-    pagesize = 16384;
-
-  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)
-    return -1;
-
-  if (mx_lock_file (h->lockfile, h->fd, 1, 0, 5))
-    goto fail_close;
-
-  ret = db_env_create (&h->env, 0);
-  if (ret)
-    goto fail_unlock;
-
-  ret = (*h->env->open)(h->env, NULL, DB_INIT_MPOOL | DB_CREATE | DB_PRIVATE,
-       0600);
-  if (ret)
-    goto fail_env;
-
-  ret = db_create (&h->db, h->env, 0);
-  if (ret)
-    goto fail_env;
-
-  if (stat(path, &sb) != 0 && errno == ENOENT)
-  {
-    createflags |= DB_EXCL;
-    h->db->set_pagesize(h->db, pagesize);
-  }
-
-  ret = (*h->db->open)(h->db, NULL, path, h->folder, DB_BTREE, createflags,
-                       0600);
-  if (ret)
-    goto fail_db;
-
-  return 0;
-
-  fail_db:
-  h->db->close (h->db, 0);
-  fail_env:
-  h->env->close (h->env, 0);
-  fail_unlock:
-  mx_unlock_file (h->lockfile, h->fd, 0);
-  fail_close:
-  close (h->fd);
-  unlink (h->lockfile);
-
-  return -1;
-}
-
-void
-mutt_hcache_close(header_cache_t *h)
-{
-  if (!h)
-    return;
-
-  h->db->close (h->db, 0);
-  h->env->close (h->env, 0);
-  mx_unlock_file (h->lockfile, h->fd, 0);
-  close (h->fd);
-  unlink (h->lockfile);
-  FREE (&h->folder);
-  FREE (&h);
-}
-
-int
-mutt_hcache_delete(header_cache_t *h, const char *filename,
-                  size_t(*keylen) (const char *fn))
-{
-  DBT key;
-
-  if (!h)
-    return -1;
-
-  if (filename[0] == '/')
-    filename++;
-
-  mutt_hcache_dbt_init(&key, (void *) filename, keylen(filename));
-  return h->db->del(h->db, NULL, &key, 0);
-}
-#elif HAVE_LMDB
-
-static int
-hcache_open_lmdb (struct header_cache* h, const char* path)
-{
-  int rc;
-
-  h->txn = NULL;
-
-  rc = mdb_env_create(&h->env);
-  if (rc != MDB_SUCCESS)
-  {
-    fprintf(stderr, "hcache_open_lmdb: mdb_env_create: %s", mdb_strerror(rc));
-    return -1;
-  }
-
-  mdb_env_set_mapsize(h->env, LMDB_DB_SIZE);
-
-  rc = mdb_env_open(h->env, path, MDB_NOSUBDIR, 0644);
-  if (rc != MDB_SUCCESS)
-  {
-    fprintf(stderr, "hcache_open_lmdb: mdb_env_open: %s", mdb_strerror(rc));
-    goto fail_env;
-  }
-
-  rc = mdb_get_r_txn(h);
-  if (rc != MDB_SUCCESS)
-  {
-      fprintf(stderr, "hcache_open_lmdb: mdb_txn_begin: %s", mdb_strerror(rc));
-      goto fail_env;
-  }
-
-  rc = mdb_dbi_open(h->txn, NULL, MDB_CREATE, &h->db);
-  if (rc != MDB_SUCCESS)
-  {
-    fprintf(stderr, "hcache_open_lmdb: mdb_dbi_open: %s", mdb_strerror(rc));
-    goto fail_dbi;
-  }
-
-  mdb_txn_reset(h->txn);
-  h->txn_mode = txn_uninitialized;
-  return 0;
-
-fail_dbi:
-  mdb_txn_abort(h->txn);
-  h->txn_mode = txn_uninitialized;
-  h->txn = NULL;
-
-fail_env:
-  mdb_env_close(h->env);
-  return -1;
-}
-
-void
-mutt_hcache_close(header_cache_t *h)
-{
-  if (!h)
-    return;
-
-  if (h->txn && h->txn_mode == txn_write)
-  {
-    mdb_txn_commit(h->txn);
-    h->txn_mode = txn_uninitialized;
-    h->txn = NULL;
-  }
-
-  mdb_env_close(h->env);
-  FREE (&h->folder);
-  FREE (&h);
-}
-
-int
-mutt_hcache_delete(header_cache_t *h, const char *filename,
-                   size_t(*keylen) (const char *fn))
-{
-  MDB_val key;
-  int rc;
-
-  if (!h)
-    return -1;
-
-  if (filename[0] == '/')
-    filename++;
-
-  key.mv_data = (char *)filename;
-  key.mv_size = strlen(filename);
-  rc = mdb_get_w_txn(h);
-  if (rc != MDB_SUCCESS)
-  {
-    fprintf(stderr, "txn_begin: %s\n", mdb_strerror(rc));
-    return rc;
-  }
-  rc = mdb_del(h->txn, h->db, &key, NULL);
-  if (rc != MDB_SUCCESS)
-  {
-    if (rc != MDB_NOTFOUND)
-    {
-      fprintf(stderr, "mdb_del: %s\n", mdb_strerror(rc));
-      mdb_txn_abort(h->txn);
-      h->txn_mode = txn_uninitialized;
-      h->txn = NULL;
-    }
-    return rc;
-  }
-
-  return rc;
-}
-#endif
-
 header_cache_t *
 mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
 {
-  struct header_cache *h = safe_calloc(1, sizeof (struct header_cache));
-  int (*hcache_open) (struct header_cache* h, const char* path);
+  hcache_ops_t *ops = hcache_get_ops();
+  header_cache_t *h = safe_calloc(1, sizeof (header_cache_t));
   struct stat sb;
 
-#if HAVE_QDBM
-  hcache_open = hcache_open_qdbm;
-#elif HAVE_TC
-  hcache_open = hcache_open_tc;
-#elif HAVE_KC
-  hcache_open = hcache_open_kc;
-#elif HAVE_GDBM
-  hcache_open = hcache_open_gdbm;
-#elif HAVE_DB4
-  hcache_open = hcache_open_db4;
-#elif HAVE_LMDB
-  hcache_open = hcache_open_lmdb;
-#endif
+  if (!ops)
+    return NULL;
 
   /* Calculate the current hcache version from dynamic configuration */
   if (hcachever == 0x0) {
@@ -1525,11 +760,6 @@ mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
     hcachever = digest.intval;
   }
 
-#if HAVE_LMDB
-  h->db = 0;
-#else
-  h->db = NULL;
-#endif
   h->folder = get_foldername(folder);
   h->crc = hcachever;
 
@@ -1542,14 +772,16 @@ mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
 
   path = mutt_hcache_per_folder(path, h->folder, namer);
 
-  if (!hcache_open (h, path))
+  h->ctx = ops->open(path);
+  if (h->ctx)
     return h;
   else
   {
     /* remove a possibly incompatible version */
     if (!stat (path, &sb) && !unlink (path))
     {
-      if (!hcache_open (h, path))
+      h->ctx = ops->open(path);
+      if (h->ctx)
         return h;
     }
     FREE(&h->folder);
@@ -1559,39 +791,100 @@ mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
   }
 }
 
-#if HAVE_DB4
-const char *mutt_hcache_backend (void)
+void mutt_hcache_close(header_cache_t *h)
 {
-  return DB_VERSION_STRING;
+  hcache_ops_t *ops = hcache_get_ops();
+  if (!h || !ops)
+    return;
+
+  ops->close(&h->ctx);
+  FREE (&h->folder);
+  FREE (&h);
 }
-#elif HAVE_LMDB
-const char *mutt_hcache_backend (void)
+
+void *
+mutt_hcache_fetch(header_cache_t *h, const char *key, size_t keylen)
 {
-  return "lmdb " MDB_VERSION_STRING;
+  void* data;
+
+  data = mutt_hcache_fetch_raw (h, key, keylen);
+
+  if (!data || !crc_matches(data, h->crc))
+  {
+    FREE(&data);
+    return NULL;
+  }
+
+  return data;
 }
-#elif HAVE_GDBM
-const char *mutt_hcache_backend (void)
+
+void *
+mutt_hcache_fetch_raw(header_cache_t *h, const char *key, size_t keylen)
 {
-  return gdbm_version;
+  char path[_POSIX_PATH_MAX];
+  hcache_ops_t *ops = hcache_get_ops();
+
+  if (!h || !ops)
+    return NULL;
+
+  keylen = snprintf(path, sizeof(path), "%s%s", h->folder, key);
+
+  return ops->fetch(h->ctx, path, keylen);
 }
-#elif HAVE_QDBM
-const char *mutt_hcache_backend (void)
+
+int
+mutt_hcache_store(header_cache_t *h, const char *key, size_t keylen,
+                  HEADER * header, unsigned int uidvalidity)
 {
-  return "qdbm " _QDBM_VERSION;
+  char* data;
+  int dlen;
+  int ret;
+
+  if (!h)
+    return -1;
+
+  data = mutt_hcache_dump(h, header, &dlen, uidvalidity);
+  ret = mutt_hcache_store_raw (h, key, keylen, data, dlen);
+
+  FREE(&data);
+
+  return ret;
 }
-#elif HAVE_TC
-const char *mutt_hcache_backend (void)
+
+int
+mutt_hcache_store_raw(header_cache_t *h, const char* key, size_t keylen,
+                      void* data, size_t dlen)
 {
-  return "tokyocabinet " _TC_VERSION;
+  char path[_POSIX_PATH_MAX];
+  hcache_ops_t *ops = hcache_get_ops();
+
+  if (!h || !ops)
+    return -1;
+
+  keylen = snprintf(path, sizeof(path), "%s%s", h->folder, key);
+
+  return ops->store(h->ctx, path, keylen, data, dlen);
 }
-#elif HAVE_KC
-const char *mutt_hcache_backend (void)
+
+int
+mutt_hcache_delete(header_cache_t *h, const char *key, size_t keylen)
 {
-  /* SHORT_STRING(128) should be more than enough for KCVERSION */
-  static char version_cache[SHORT_STRING] = "";
-  if (!version_cache[0])
-    snprintf(version_cache, sizeof(version_cache), "kyotocabinet %s", KCVERSION);
+  char path[_POSIX_PATH_MAX];
+  hcache_ops_t *ops = hcache_get_ops();
 
-  return version_cache;
+  if (!h)
+    return -1;
+
+  keylen = snprintf(path, sizeof(path), "%s%s", h->folder, key);
+
+  return ops->delete(h->ctx, path, keylen);
+}
+
+const char *
+mutt_hcache_backend()
+{
+  hcache_ops_t *ops = hcache_get_ops();
+  if (!ops)
+      return NULL;
+  return ops->backend();
 }
-#endif
index ca0b425e296c439bcf80bd1a6c55f27152003fc7..23786d90f777dc192b77985732657e65561bbcae 100644 (file)
--- a/hcache.h
+++ b/hcache.h
@@ -2,6 +2,7 @@
  * 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>
+ * Copyright (C) 2016 Pietro Cerutti <gahr@gahr.ch>
  *
  *     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
 #ifndef _HCACHE_H_
 #define _HCACHE_H_ 1
 
+#include "mutt.h"
+
 struct header_cache;
 typedef struct header_cache header_cache_t;
 
+/**
+ * hcache_open_t - backend-specific routing to open the header cache database.
+ *
+ * @param path The path to the database file.
+ * @return Pointer to backend-specific context on success, NULL otherwise.
+ *
+ * The hcache_open function has the purpose of opening a backend-specific
+ * connection to the database file specified by the path parameter. Backends
+ * MUST return non-NULL specific context informations on success. This will be
+ * stored in the ctx member of the header_cache_t structure and passed on to
+ * all other backend-specific functions (see below).
+ */
+typedef void * (*hcache_open_t)(const char *path);
+
+/**
+ * hcache_fetch_t -  backend-specific routine to fetch a message's headers.
+ *
+ * @param ctx The backend-specific context retrieved via hcache_open.
+ * @param key A message identification string.
+ * @param keylen The length of the string pointed to by key.
+ * @return Pointer to the message's headers on success, NULL otherwise.
+ */
+typedef void * (*hcache_fetch_t)(void *ctx, const char *key, size_t keylen);
+
+/**
+ * hcache_store_t - backend-specific routine to store a message's headers.
+ *
+ * @param ctx The backend-specific context retrieved via hcache_open.
+ * @param key A message identification string.
+ * @param keylen The length of the string pointed to by key.
+ * @param data The message headers data.
+ * @param datalen The length of the string pointed to by data.
+ * @return 0 on success, a backend-specific error code otherwise.
+ */
+typedef int (*hcache_store_t)(void *ctx, const char *key, size_t keylen,
+                                  void *data, size_t datalen);
+
+/**
+ * hcache_delete_t - backend-specific routine to delete a message's headers.
+ *
+ * @param ctx The backend-specific context retrieved via hcache_open.
+ * @param key A message identification string.
+ * @param keylen The length of the string pointed to by key.
+ * @return 0 on success, a backend-specific error code otherwise.
+ */
+typedef int (*hcache_delete_t)(void *ctx, const char *key, size_t keylen);
+
+/**
+ * hcache_close_t - backend-specific routine to close a context.
+ *
+ * @param ctx The backend-specific context retrieved via hcache_open.
+ *
+ * Backend code is responsible for freeing any resources associated with the
+ * @ctx parameter. For this reason, backend code is passed a pointer-to-pointer
+ * to the context, so that FREE can be invoked on it.
+ */
+typedef void (*hcache_close_t)(void **ctx);
+
+/**
+ * hcache_backend_t - backend-specific identification string.
+ *
+ * @return String describing the currently used hcache backend.
+ */
+typedef const char *(*hcache_backend_t)(void);
+
+typedef struct
+{
+    hcache_open_t    open;
+    hcache_fetch_t   fetch;
+    hcache_store_t   store;
+    hcache_delete_t  delete;
+    hcache_close_t   close;
+    hcache_backend_t backend;
+} hcache_ops_t;
+
 typedef int (*hcache_namer_t)(const char* path, char* dest, size_t dlen);
 
-header_cache_t *mutt_hcache_open(const char *path, const char *folder,
-  hcache_namer_t namer);
-void mutt_hcache_close(header_cache_t *h);
-HEADER *mutt_hcache_restore(const unsigned char *d, HEADER **oh);
-void *mutt_hcache_fetch(header_cache_t *h, const char *filename, size_t (*keylen)(const char *fn));
-void *mutt_hcache_fetch_raw (header_cache_t *h, const char *filename,
-                             size_t (*keylen)(const char *fn));
-
-typedef enum {
-  MUTT_GENERATE_UIDVALIDITY = 1 /* use gettimeofday() as value */
-} mutt_hcache_store_flags_t;
-
-/* uidvalidity is an IMAP-specific unsigned 32 bit number */
-int mutt_hcache_store(header_cache_t *h, const char *filename, HEADER *header,
-                      unsigned int uidvalidity, size_t (*keylen)(const char *fn), mutt_hcache_store_flags_t flags_t);
-int mutt_hcache_store_raw (header_cache_t *h, const char* filename, void* data,
-                           size_t dlen, size_t(*keylen) (const char* fn));
-int mutt_hcache_delete(header_cache_t *h, const char *filename, size_t (*keylen)(const char *fn));
-
-const char *mutt_hcache_backend (void);
+/**
+ * mutt_hcache_open - open the connection to the header cache.
+ *
+ * @param path Location of the header cache (often as specified by the user).
+ * @param folder Name of the folder containing the messages.
+ * @param namer Optional (might be NULL) client-specific function to form the
+ * final name of the hcache database file.
+ * @return Pointer to a header_cache_t struct on success, NULL otherwise.
+ */
+header_cache_t *
+mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer);
+
+/**
+ * mutt_hcache_close - close the connection to the header cache.
+ *
+ * @param h Pointer to the header_cache_t structure got by mutt_hcache_open.
+ */
+void
+mutt_hcache_close(header_cache_t *h);
+
+/**
+ * mutt_hcache_fetch - fetch and validate a  message's header from the cache.
+ *
+ * @param h Pointer to the header_cache_t structure got by mutt_hcache_open.
+ * @param key Message identification string.
+ * @param keylen Length of the string pointed to by key.
+ * @return Pointer to the data if found and valid, NULL otherwise.
+ * @note This function performs a check on the validity of the data found by
+ * comparing it with the crc value of the header_cache_t structure.
+ */
+void *
+mutt_hcache_fetch(header_cache_t *h, const char *key, size_t keylen);
+
+/**
+ * mutt_hcache_fetch_raw - fetch a message's header from the cache.
+ *
+ * @param h Pointer to the header_cache_t structure got by mutt_hcache_open.
+ * @param key Message identification string.
+ * @param keylen Length of the string pointed to by key.
+ * @return Pointer to the data if found, NULL otherwise.
+ * @note This function does not perform any check on the validity of the data
+ * found.
+ */
+void *
+mutt_hcache_fetch_raw(header_cache_t *h, const char *key, size_t keylen);
+
+/**
+ * mutt_hcache_restore - restore a HEADER from data retrieved from the cache.
+ *
+ * @param d Data retrieved using mutt_hcache_fetch or mutt_hcache_fetch_raw.
+ * @return Pointer to the restored header (cannot be NULL).
+ * @note The returned HEADER must be free'd by caller code with
+ * mutt_free_header.
+ */
+HEADER *
+mutt_hcache_restore(const unsigned char *d);
+
+/**
+ * mutt_hcache_store - store a HEADER along with a validity datum.
+ *
+ * @param h Pointer to the header_cache_t structure got by mutt_hcache_open.
+ * @param key Message identification string.
+ * @param keylen Length of the string pointed to by key.
+ * @param header Message header to store.
+ * @param uidvalidity IMAP-specific UIDVALIDITY value, or 0 to use the current
+ * time.
+ * @return 0 on success, -1 otherwise.
+ */
+int
+mutt_hcache_store(header_cache_t *h, const char *key, size_t keylen,
+                  HEADER *header, unsigned int uidvalidity);
+
+/**
+ * mutt_hcache_store_raw - store a key / data pair.
+ *
+ * @param h Pointer to the header_cache_t structure got by mutt_hcache_open.
+ * @param key Message identification string.
+ * @param keylen Length of the string pointed to by key.
+ * @param data Payload to associate with key.
+ * @param dlen Length of the buffer pointed to by the @data parameter.
+ * @return 0 on success, -1 otherwise.
+ */
+int
+mutt_hcache_store_raw(header_cache_t *h, const char* key, size_t keylen, 
+                      void* data, size_t dlen);
+
+/**
+ * mutt_hcache_delete - delete a key / data pair.
+ *
+ * @param h Pointer to the header_cache_t structure got by mutt_hcache_open.
+ * @param key Message identification string.
+ * @param keylen Length of the string pointed to by key.
+ * @return 0 on success, -1 otherwise.
+ */
+int
+mutt_hcache_delete(header_cache_t *h, const char *key, size_t keylen);
+
+/**
+ * mutt_hcache_backend - get a backend-specific identification string.
+ *
+ * @return String describing the currently used hcache backend.
+ */
+const char *
+mutt_hcache_backend(void);
+
+#define HCACHE_BACKEND_LIST \
+  HCACHE_BACKEND(bdb) \
+  HCACHE_BACKEND(gdbm) \
+  HCACHE_BACKEND(kc) \
+  HCACHE_BACKEND(lmdb) \
+  HCACHE_BACKEND(qdbm) \
+  HCACHE_BACKEND(tc)
+
+#define HCACHE_BACKEND_OPS(name)       \
+  hcache_ops_t hcache_##name##_ops = { \
+    .open    = hcache_##name##_open,   \
+    .fetch   = hcache_##name##_fetch,  \
+    .store   = hcache_##name##_store,  \
+    .delete  = hcache_##name##_delete, \
+    .close   = hcache_##name##_close,  \
+    .backend = hcache_##name##_backend \
+  };
 
 #endif /* _HCACHE_H_ */
index e65d5312e584a6a95e731f357d3c376189203eb0..7e1c21694c5329ebf647d0699eff97662d9f566a 100644 (file)
@@ -1680,8 +1680,8 @@ IMAP_STATUS* imap_mboxcache_get (IMAP_DATA* idata, const char* mbox, int create)
   hc = imap_hcache_open (idata, mbox);
   if (hc)
   {
-    uidvalidity = mutt_hcache_fetch_raw (hc, "/UIDVALIDITY", imap_hcache_keylen);
-    uidnext = mutt_hcache_fetch_raw (hc, "/UIDNEXT", imap_hcache_keylen);
+    uidvalidity = mutt_hcache_fetch_raw (hc, "/UIDVALIDITY", 12);
+    uidnext = mutt_hcache_fetch_raw (hc, "/UIDNEXT", 8);
     mutt_hcache_close (hc);
     if (uidvalidity)
     {
index 3e8b555d565ac6c0a1e91be7e79443c858c68545..857914c889e996e247600bea2577d9b5c266aa6a 100644 (file)
@@ -124,8 +124,8 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend)
 
   if (idata->hcache && !msgbegin)
   {
-    uid_validity = mutt_hcache_fetch_raw (idata->hcache, "/UIDVALIDITY", imap_hcache_keylen);
-    puidnext = mutt_hcache_fetch_raw (idata->hcache, "/UIDNEXT", imap_hcache_keylen);
+    uid_validity = mutt_hcache_fetch_raw (idata->hcache, "/UIDVALIDITY", 12);
+    puidnext = mutt_hcache_fetch_raw (idata->hcache, "/UIDNEXT", 8);
     if (puidnext)
     {
       uidnext = *puidnext;
@@ -359,16 +359,16 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend)
     status->uidnext = maxuid + 1;
 
 #if USE_HCACHE
-  mutt_hcache_store_raw (idata->hcache, "/UIDVALIDITY", &idata->uid_validity,
-                         sizeof (idata->uid_validity), imap_hcache_keylen);
+  mutt_hcache_store_raw (idata->hcache, "/UIDVALIDITY", 12,
+          &idata->uid_validity, sizeof (idata->uid_validity));
   if (maxuid && idata->uidnext < maxuid + 1)
   {
     dprint (2, (debugfile, "Overriding UIDNEXT: %u -> %u\n", idata->uidnext, maxuid + 1));
     idata->uidnext = maxuid + 1;
   }
   if (idata->uidnext > 1)
-    mutt_hcache_store_raw (idata->hcache, "/UIDNEXT", &idata->uidnext,
-                          sizeof (idata->uidnext), imap_hcache_keylen);
+    mutt_hcache_store_raw (idata->hcache, "/UIDNEXT", 8,
+            &idata->uidnext, sizeof (idata->uidnext));
 
   imap_hcache_close (idata);
 #endif /* USE_HCACHE */
index cb911a1125faa84b2d8563ea8cd5659bac8a8308..6b44e2fd023f91ff5dac0647eccbc3cda749d23f 100644 (file)
@@ -223,12 +223,12 @@ HEADER* imap_hcache_get (IMAP_DATA* idata, unsigned int uid)
     return NULL;
 
   sprintf (key, "/%u", uid);
-  uv = (unsigned int*)mutt_hcache_fetch (idata->hcache, key,
-                                         imap_hcache_keylen);
+  uv = mutt_hcache_fetch (idata->hcache, key,
+                                         imap_hcache_keylen(key));
   if (uv)
   {
     if (*uv == idata->uid_validity)
-      h = mutt_hcache_restore ((unsigned char*)uv, NULL);
+      h = mutt_hcache_restore ((const unsigned char*)uv);
     else
       dprint (3, (debugfile, "hcache uidvalidity mismatch: %u", *uv));
     FREE (&uv);
@@ -245,8 +245,8 @@ int imap_hcache_put (IMAP_DATA* idata, HEADER* h)
     return -1;
 
   sprintf (key, "/%u", HEADER_DATA (h)->uid);
-  return mutt_hcache_store (idata->hcache, key, h, idata->uid_validity,
-                            imap_hcache_keylen, 0);
+  return mutt_hcache_store (idata->hcache, key, imap_hcache_keylen(key), h,
+                            idata->uid_validity);
 }
 
 int imap_hcache_del (IMAP_DATA* idata, unsigned int uid)
@@ -257,7 +257,7 @@ int imap_hcache_del (IMAP_DATA* idata, unsigned int uid)
     return -1;
 
   sprintf (key, "/%u", uid);
-  return mutt_hcache_delete (idata->hcache, key, imap_hcache_keylen);
+  return mutt_hcache_delete (idata->hcache, key, imap_hcache_keylen(key));
 }
 #endif
 
diff --git a/init.h b/init.h
index 9de4de95fa1bcc4ca01a7d84b7568bd0b5aa294f..3a6d50ca2a271beded2f56c9cb79426ecad65a29 100644 (file)
--- a/init.h
+++ b/init.h
@@ -1064,7 +1064,7 @@ struct option_t MuttVars[] = {
   ** cached folders.
   */
 #endif /* HAVE_QDBM */
-#if defined(HAVE_GDBM) || defined(HAVE_DB4)
+#if defined(HAVE_GDBM) || defined(HAVE_BDB)
   { "header_cache_pagesize", DT_STR, R_NONE, UL &HeaderCachePageSize, UL "16384" },
   /*
   ** .pp
@@ -1073,7 +1073,7 @@ struct option_t MuttVars[] = {
   ** values can waste space, memory, or CPU time. The default should be more
   ** or less optimal for most use cases.
   */
-#endif /* HAVE_GDBM || HAVE_DB4 */
+#endif /* HAVE_GDBM || HAVE_BDB */
 #endif /* USE_HCACHE */
   { "help",            DT_BOOL, R_BOTH|R_REFLOW, OPTHELP, 1 },
   /*
diff --git a/mh.c b/mh.c
index c90679ec6ae4d7bc14a87ce66ac58dbbc2872efc..45af0b33ced71200f03985ff1893ca64540bcb78 100644 (file)
--- a/mh.c
+++ b/mh.c
@@ -1128,6 +1128,8 @@ static void maildir_delayed_parsing (CONTEXT * ctx, struct maildir **md,
 #if USE_HCACHE
   header_cache_t *hc = NULL;
   void *data;
+  const char *key;
+  size_t keylen;
   struct timeval *when = NULL;
   struct stat lastchanged;
   int ret;
@@ -1183,16 +1185,27 @@ static void maildir_delayed_parsing (CONTEXT * ctx, struct maildir **md,
     }
 
     if (ctx->magic == MUTT_MH)
-      data = mutt_hcache_fetch (hc, p->h->path, strlen);
+    {
+      key = p->h->path;
+      keylen = strlen(key);
+    }
     else
-      data = mutt_hcache_fetch (hc, p->h->path + 3, &maildir_hcache_keylen);
+    {
+      key = p->h->path + 3;
+      keylen = maildir_hcache_keylen(key);
+    }
+    data = mutt_hcache_fetch (hc, key, keylen);
     when = (struct timeval *) data;
 
     if (data != NULL && !ret && lastchanged.st_mtime <= when->tv_sec)
     {
-      p->h = mutt_hcache_restore ((unsigned char *)data, &p->h);
+      HEADER* h = mutt_hcache_restore((unsigned char *)data);
+      h->old = p->h->old;
+      h->path = safe_strdup(p->h->path);
+      mutt_free_header(&p->h);
+      p->h = h;
       if (ctx->magic == MUTT_MAILDIR)
-       maildir_parse_flags (p->h, fn);
+          maildir_parse_flags (p->h, fn);
     }
     else
     {
@@ -1203,9 +1216,16 @@ static void maildir_delayed_parsing (CONTEXT * ctx, struct maildir **md,
       p->header_parsed = 1;
 #if USE_HCACHE
       if (ctx->magic == MUTT_MH)
-       mutt_hcache_store (hc, p->h->path, p->h, 0, strlen, MUTT_GENERATE_UIDVALIDITY);
+      {
+        key = p->h->path;
+        keylen = strlen(key);
+      }
       else
-       mutt_hcache_store (hc, p->h->path + 3, p->h, 0, &maildir_hcache_keylen, MUTT_GENERATE_UIDVALIDITY);
+      {
+        key = p->h->path + 3;
+        keylen = maildir_hcache_keylen(key);
+      }
+      mutt_hcache_store (hc, key, keylen, p->h, 0);
 #endif
     } else
       mutt_free_header (&p->h);
@@ -1895,6 +1915,10 @@ int mh_sync_mailbox_message (CONTEXT * ctx, int msgno, header_cache_t *hc)
 int mh_sync_mailbox_message (CONTEXT * ctx, int msgno)
 #endif
 {
+#if USE_HCACHE
+    const char *key;
+    size_t keylen;
+#endif
     char path[_POSIX_PATH_MAX], tmp[_POSIX_PATH_MAX];
     HEADER *h = ctx->hdrs[msgno];
 
@@ -1905,12 +1929,20 @@ int mh_sync_mailbox_message (CONTEXT * ctx, int msgno)
          || (option (OPTMHPURGE) && ctx->magic == MUTT_MH))
       {
 #if USE_HCACHE
-       if (hc) {
-           if (ctx->magic == MUTT_MAILDIR)
-              mutt_hcache_delete (hc, h->path + 3, &maildir_hcache_keylen);
-          else if (ctx->magic == MUTT_MH)
-             mutt_hcache_delete (hc, h->path, strlen);
-       }
+        if (hc)
+        {
+          if (ctx->magic == MUTT_MH)
+          {
+            key = h->path;
+            keylen = strlen(key);
+          }
+          else
+          {
+            key = h->path + 3;
+            keylen = maildir_hcache_keylen(key);
+          }
+          mutt_hcache_delete (hc, key, keylen);
+        }
 #endif /* USE_HCACHE */
        unlink (path);
       }
@@ -1947,10 +1979,17 @@ int mh_sync_mailbox_message (CONTEXT * ctx, int msgno)
 #if USE_HCACHE
     if (hc && h->changed)
     {
-      if (ctx->magic == MUTT_MAILDIR)
-       mutt_hcache_store (hc, h->path + 3, h, 0, &maildir_hcache_keylen, MUTT_GENERATE_UIDVALIDITY);
-      else if (ctx->magic == MUTT_MH)
-       mutt_hcache_store (hc, h->path, h, 0, strlen, MUTT_GENERATE_UIDVALIDITY);
+      if (ctx->magic == MUTT_MH)
+      {
+        key = h->path;
+        keylen = strlen(key);
+      }
+      else
+      {
+        key = h->path + 3;
+        keylen = maildir_hcache_keylen(key);
+      }
+      mutt_hcache_store (hc, key, keylen, h, 0);
     }
 #endif
 
index ad8255f03e608966a41aab4509f025b422c15e93..d30d5545a7d2f30a9a9305534463d1d08fdf83b1 100644 (file)
--- a/newsrc.c
+++ b/newsrc.c
@@ -644,7 +644,7 @@ void nntp_hcache_update (NNTP_DATA *nntp_data, header_cache_t *hc)
     return;
 
   /* fetch previous values of first and last */
-  hdata = mutt_hcache_fetch_raw (hc, "index", strlen);
+  hdata = mutt_hcache_fetch_raw (hc, "index", 5);
   if (hdata)
   {
     dprint (2, (debugfile,
@@ -664,7 +664,7 @@ void nntp_hcache_update (NNTP_DATA *nntp_data, header_cache_t *hc)
        snprintf (buf, sizeof (buf), "%d", current);
        dprint (2, (debugfile,
                    "nntp_hcache_update: mutt_hcache_delete %s\n", buf));
-       mutt_hcache_delete (hc, buf, strlen);
+       mutt_hcache_delete (hc, buf, strlen(buf));
       }
     }
     FREE (&hdata);
@@ -678,7 +678,7 @@ void nntp_hcache_update (NNTP_DATA *nntp_data, header_cache_t *hc)
                                          nntp_data->lastMessage);
     dprint (2, (debugfile,
                "nntp_hcache_update: mutt_hcache_store index: %s\n", buf));
-    mutt_hcache_store_raw (hc, "index", buf, strlen (buf) + 1, strlen);
+    mutt_hcache_store_raw (hc, "index", 5, buf, strlen (buf));
   }
 }
 #endif
@@ -709,12 +709,11 @@ void nntp_bcache_update (NNTP_DATA *nntp_data)
 /* Remove hcache and bcache of newsgroup */
 void nntp_delete_group_cache (NNTP_DATA *nntp_data)
 {
-  char file[_POSIX_PATH_MAX];
-
   if (!nntp_data || !nntp_data->nserv || !nntp_data->nserv->cacheable)
     return;
 
 #ifdef USE_HCACHE
+  char file[_POSIX_PATH_MAX];
   nntp_hcache_namer (nntp_data->group, file, sizeof (file));
   cache_expand (file, sizeof (file), &nntp_data->nserv->conn->account, file);
   unlink (file);
@@ -1030,7 +1029,7 @@ NNTP_SERVER *nntp_select_server (char *server, int leave_lock)
          continue;
 
        /* fetch previous values of first and last */
-       hdata = mutt_hcache_fetch_raw (hc, "index", strlen);
+       hdata = mutt_hcache_fetch_raw (hc, "index", 5);
        if (hdata)
        {
          anum_t first, last;
diff --git a/nntp.c b/nntp.c
index b928aaa4b48614db16045d41b127f9656915567e..494149ec4ee985e650d29ec0e4da8093bed68a74 100644 (file)
--- a/nntp.c
+++ b/nntp.c
@@ -1117,14 +1117,14 @@ static int parse_overview_line (char *line, void *data)
 
     /* try to replace with header from cache */
     snprintf (buf, sizeof (buf), "%d", anum);
-    hdata = mutt_hcache_fetch (fc->hc, buf, strlen);
+    hdata = mutt_hcache_fetch (fc->hc, buf, strlen(buf));
     if (hdata)
     {
       dprint (2, (debugfile,
                  "parse_overview_line: mutt_hcache_fetch %s\n", buf));
       mutt_free_header (&hdr);
       ctx->hdrs[ctx->msgcount] =
-      hdr = mutt_hcache_restore (hdata, NULL);
+      hdr = mutt_hcache_restore (hdata);
       FREE (&hdata);
       hdr->data = 0;
       hdr->read = 0;
@@ -1148,7 +1148,7 @@ static int parse_overview_line (char *line, void *data)
     {
       dprint (2, (debugfile,
                  "parse_overview_line: mutt_hcache_store %s\n", buf));
-      mutt_hcache_store (fc->hc, buf, hdr, 0, strlen, MUTT_GENERATE_UIDVALIDITY);
+      mutt_hcache_store (fc->hc, buf, strlen(buf), hdr, 0);
     }
   }
 #endif
@@ -1249,7 +1249,7 @@ static int nntp_fetch_headers (CONTEXT *ctx, void *hc,
        {
          dprint (2, (debugfile,
                      "nntp_fetch_headers: mutt_hcache_delete %s\n", buf));
-         mutt_hcache_delete (fc.hc, buf, strlen);
+         mutt_hcache_delete (fc.hc, buf, strlen(buf));
        }
 #endif
       }
@@ -1282,13 +1282,13 @@ static int nntp_fetch_headers (CONTEXT *ctx, void *hc,
 
 #ifdef USE_HCACHE
     /* try to fetch header from cache */
-    hdata = mutt_hcache_fetch (fc.hc, buf, strlen);
+    hdata = mutt_hcache_fetch (fc.hc, buf, strlen(buf));
     if (hdata)
     {
       dprint (2, (debugfile,
                  "nntp_fetch_headers: mutt_hcache_fetch %s\n", buf));
       ctx->hdrs[ctx->msgcount] =
-      hdr = mutt_hcache_restore (hdata, NULL);
+      hdr = mutt_hcache_restore (hdata);
       FREE (&hdata);
       hdr->data = 0;
 
@@ -1798,7 +1798,7 @@ int nntp_sync_mailbox (CONTEXT *ctx)
       if (hdr->deleted && !hdr->read)
        nntp_data->unread--;
       dprint (2, (debugfile, "nntp_sync_mailbox: mutt_hcache_store %s\n", buf));
-      mutt_hcache_store (hc, buf, hdr, 0, strlen, MUTT_GENERATE_UIDVALIDITY);
+      mutt_hcache_store (hc, buf, strlen(buf), hdr, 0);
     }
 #endif
   }
@@ -2042,14 +2042,14 @@ int nntp_check_mailbox (CONTEXT *ctx, int *index_hint)
          messages[anum - first] = 1;
 
        snprintf (buf, sizeof (buf), "%d", anum);
-       hdata = mutt_hcache_fetch (hc, buf, strlen);
+       hdata = mutt_hcache_fetch (hc, buf, strlen(buf));
        if (hdata)
        {
          int deleted;
 
          dprint (2, (debugfile,
                      "nntp_check_mailbox: mutt_hcache_fetch %s\n", buf));
-         hdr = mutt_hcache_restore (hdata, NULL);
+         hdr = mutt_hcache_restore (hdata);
          FREE (&hdata);
          hdr->data = 0;
          deleted = hdr->deleted;
@@ -2089,7 +2089,7 @@ int nntp_check_mailbox (CONTEXT *ctx, int *index_hint)
        continue;
 
       snprintf (buf, sizeof (buf), "%d", anum);
-      hdata = mutt_hcache_fetch (hc, buf, strlen);
+      hdata = mutt_hcache_fetch (hc, buf, strlen(buf));
       if (hdata)
       {
        dprint (2, (debugfile,
@@ -2098,7 +2098,7 @@ int nntp_check_mailbox (CONTEXT *ctx, int *index_hint)
          mx_alloc_memory (ctx);
 
        ctx->hdrs[ctx->msgcount] =
-       hdr = mutt_hcache_restore (hdata, NULL);
+       hdr = mutt_hcache_restore (hdata);
        FREE (&hdata);
        hdr->data = 0;
        if (hdr->deleted)
diff --git a/pop.c b/pop.c
index 294d71d8d5f1c3d6ee0fecc2f4277d457ec16bea..f8d4d79a22fb571b6b0878b2e0bea53bb1daa70e 100644 (file)
--- a/pop.c
+++ b/pop.c
@@ -303,7 +303,7 @@ static int pop_fetch_headers (CONTEXT *ctx)
       if (!ctx->quiet)
        mutt_progress_update (&progress, i + 1 - old_count, -1);
 #if USE_HCACHE
-      if ((data = mutt_hcache_fetch (hc, ctx->hdrs[i]->data, strlen)))
+      if ((data = mutt_hcache_fetch (hc, ctx->hdrs[i]->data, strlen(ctx->hdrs[i]->data))))
       {
        char *uidl = safe_strdup (ctx->hdrs[i]->data);
        int refno = ctx->hdrs[i]->refno;
@@ -317,7 +317,7 @@ static int pop_fetch_headers (CONTEXT *ctx)
         *   (the old h->data should point inside a malloc'd block from
         *   hcache so there shouldn't be a memleak here)
         */
-       HEADER *h = mutt_hcache_restore ((unsigned char *) data, NULL);
+       HEADER *h = mutt_hcache_restore ((unsigned char *) data);
        mutt_free_header (&ctx->hdrs[i]);
        ctx->hdrs[i] = h;
        ctx->hdrs[i]->refno = refno;
@@ -333,7 +333,8 @@ static int pop_fetch_headers (CONTEXT *ctx)
 #if USE_HCACHE
       else
       {
-       mutt_hcache_store (hc, ctx->hdrs[i]->data, ctx->hdrs[i], 0, strlen, MUTT_GENERATE_UIDVALIDITY);
+       mutt_hcache_store (hc, ctx->hdrs[i]->data, strlen(ctx->hdrs[i]->data), 
+                       ctx->hdrs[i], 0);
       }
 
       FREE(&data);
@@ -700,7 +701,7 @@ int pop_sync_mailbox (CONTEXT *ctx, int *index_hint)
        {
          mutt_bcache_del (pop_data->bcache, ctx->hdrs[i]->data);
 #if USE_HCACHE
-         mutt_hcache_delete (hc, ctx->hdrs[i]->data, strlen);
+         mutt_hcache_delete (hc, ctx->hdrs[i]->data, strlen(ctx->hdrs[i]->data));
 #endif
        }
       }
@@ -708,7 +709,8 @@ int pop_sync_mailbox (CONTEXT *ctx, int *index_hint)
 #if USE_HCACHE
       if (ctx->hdrs[i]->changed)
       {
-       mutt_hcache_store (hc, ctx->hdrs[i]->data, ctx->hdrs[i], 0, strlen, MUTT_GENERATE_UIDVALIDITY);
+       mutt_hcache_store (hc, ctx->hdrs[i]->data, strlen(ctx->hdrs[i]->data),
+                       ctx->hdrs[i], 0);
       }
 #endif