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])
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
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
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
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
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
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
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
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
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
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
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"
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)
# 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
#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;
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
* 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);
{
void **p = (void **) ptr;
- if (p != NULL && 0 < siz && siz < 4096)
+ if (p != NULL && siz < 4096)
return;
safe_realloc(ptr, siz);
*/
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;
*off = 0;
d = lazy_malloc(sizeof (validate));
- if (flags & MUTT_GENERATE_UIDVALIDITY)
+ if (uidvalidity == 0)
{
struct timeval now;
gettimeofday(&now, NULL);
}
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();
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;
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) {
hcachever = digest.intval;
}
-#if HAVE_LMDB
- h->db = 0;
-#else
- h->db = NULL;
-#endif
h->folder = get_foldername(folder);
h->crc = hcachever;
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);
}
}
-#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
* 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_ */
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)
{
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;
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 */
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);
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)
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
** 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
** 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 },
/*
#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;
}
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
{
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);
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];
|| (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);
}
#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
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,
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);
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
/* 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);
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;
/* 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;
{
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
{
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
}
#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;
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
}
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;
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,
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)
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;
* (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;
#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);
{
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
}
}
#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