commit-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Mailutils branch, master, updated. release-2.2-409-g442711b


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-409-g442711b
Date: Tue, 25 Oct 2011 18:28:01 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Mailutils".

http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=442711bcda49eeca667d15c509d200995379c832

The branch, master has been updated
       via  442711bcda49eeca667d15c509d200995379c832 (commit)
       via  0cb608de0ac37bfe71e06f4d592c232c78ac4db1 (commit)
      from  f70ebb8c1d67d70222768b34ce7568b78fe191de (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 442711bcda49eeca667d15c509d200995379c832
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Oct 25 21:27:45 2011 +0300

    Use MU_CTYPE_ENDLN to trim \r\n.

commit 0cb608de0ac37bfe71e06f4d592c232c78ac4db1
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Oct 25 15:19:46 2011 +0300

    Reimplement DBM support.
    
    * lib/mu_dbm.c: Remove.
    * lib/mu_dbm.h: Remove.
    * lib/Makefile.am: Remove mu_dbm.[ch].
    * include/mailutils/sys/dbm.h: New file.
    * include/mailutils/sys/Makefile.am: Add dbm.h
    * include/mailutils/dbm.h: New file.
    * include/mailutils/Makefile.am (pkginclude_HEADERS): Add dbm.h.
    * include/mailutils/types.hin (mu_dbm_file_t): New data type.
    
    * libmu_dbm/Makefile.am: New file.
    * libmu_dbm/berkeley.c: New file.
    * libmu_dbm/close.c: New file.
    * libmu_dbm/create.c: New file.
    * libmu_dbm/datumfree.c: New file.
    * libmu_dbm/dbm.c: New file.
    * libmu_dbm/delete.c: New file.
    * libmu_dbm/destroy.c: New file.
    * libmu_dbm/errstr.c: New file.
    * libmu_dbm/fetch.c: New file.
    * libmu_dbm/firstkey.c: New file.
    * libmu_dbm/gdbm.c: New file.
    * libmu_dbm/mudbm.h: New file.
    * libmu_dbm/ndbm.c: New file.
    * libmu_dbm/nextkey.c: New file.
    * libmu_dbm/open.c: New file.
    * libmu_dbm/safety.c: New file.
    * libmu_dbm/store.c: New file.
    
    * Makefile.am [MU_COND_DBM]: Define LIBMU_DBM_DIR
    (SUBDIRS): Add $(LIBMU_DBM_DIR)
    * configure.ac: Revamp DBM support: several database types can
    be specified at once.
    (AC_CONFIG_FILES): Build libmu_dbm/Makefile
    
    * libmu_sieve/extensions/vacation.c: Remove inclusion of mu_dbm.h.
    * maidag/Makefile.am (maidag_LDADD): Add DBM libraries.
    * maidag/maidag.c: ENABLE_DBM instead of USE_DBM
    * maidag/maidag.h: Include <mailutils/dbm.h> instead of mu_dbm.h.
    * maidag/mailquota.c (dbm_retrieve_quota): Rewrite using libmu_dbm
    library calls.
    * mu/Makefile.am [MU_COND_DBM]: Define DBM_C.
    (MODULES): Add $(DBM_C).
    (AM_CPPFLAGS): Define DBMLIBS.
    * mu/ldflags.c (NEEDAUTH): Change definition.
    (lib_descr) <weight>: New member. All uses changed.
    (add_entry): Null arguments ignored.
    (mutool_ldflags): Rewrite traversal of lib_descr.
    * mu/dbm.c: New file.
    
    * pop3d/Makefile.am (pop3d_LDADD, popauth_LDADD): Add DBM libraries.
    * pop3d/apop.c: Rewrite using libmu_dbm library calls.
    * pop3d/bulletin.c: Likewise.
    * pop3d/logindelay.c: Likewise.
    * pop3d/pop3d.c: Change USE_DBM to ENABLE_DBM.
    * pop3d/pop3d.h: Include mailutils/dbm.h instead of mu_dbm.h
    * pop3d/popauth.c: Rewrite using libmu_dbm library calls.
    
    * include/mailutils/cctype.h (MU_CTYPE_ENDLN): New character class.
    (mu_isendln): New macro.
    * libmailutils/string/muctype.c (mu_c_tab): Mark \r and \n as
    MU_CTYPE_ENDLN.

-----------------------------------------------------------------------

Summary of changes:
 Makefile.am                                        |    5 +
 configure.ac                                       |  322 +++++----
 imap4d/io.c                                        |    2 +-
 imap4d/preauth.c                                   |    2 +-
 include/mailutils/Makefile.am                      |    1 +
 include/mailutils/cctype.h                         |    2 +
 include/mailutils/dbm.h                            |   77 ++
 include/mailutils/sys/Makefile.am                  |    1 +
 include/mailutils/{radius.h => sys/dbm.h}          |   26 +-
 include/mailutils/types.hin                        |    4 +-
 lib/Makefile.am                                    |    2 -
 lib/mu_dbm.c                                       |  575 ---------------
 lib/mu_dbm.h                                       |   89 ---
 libmailutils/string/muctype.c                      |    4 +-
 {libproto/imap => libmu_dbm}/Makefile.am           |   50 +-
 libmu_dbm/berkeley.c                               |  340 +++++++++
 lib/argp_base.c => libmu_dbm/close.c               |   19 +-
 libproto/imap/capatst.c => libmu_dbm/create.c      |   22 +-
 libmailutils/cidr/match.c => libmu_dbm/datumfree.c |   24 +-
 libmu_dbm/dbm.c                                    |  265 +++++++
 libmailutils/cidr/match.c => libmu_dbm/delete.c    |   25 +-
 libmailutils/cidr/match.c => libmu_dbm/destroy.c   |   27 +-
 .../sockaddr/unlink.c => libmu_dbm/errstr.c        |   34 +-
 libproto/imap/capatst.c => libmu_dbm/fetch.c       |   21 +-
 libmailutils/cidr/match.c => libmu_dbm/firstkey.c  |   24 +-
 libmu_dbm/gdbm.c                                   |  290 ++++++++
 libmailutils/cidr/match.c => libmu_dbm/getfd.c     |   24 +-
 libproto/nntp/url.c => libmu_dbm/mudbm.h           |   54 +-
 libmu_dbm/ndbm.c                                   |  244 +++++++
 libmailutils/cidr/match.c => libmu_dbm/nextkey.c   |   24 +-
 libmailutils/cidr/match.c => libmu_dbm/open.c      |   26 +-
 libproto/imap/create.c => libmu_dbm/safety.c       |   69 +-
 libproto/imap/capatst.c => libmu_dbm/store.c       |   20 +-
 libmu_sieve/extensions/spamd.c                     |    2 +-
 libmu_sieve/extensions/vacation.c                  |    1 -
 libproto/mailer/smtp_io.c                          |    4 +-
 libproto/mbox/mbox.c                               |    5 +-
 libproto/pop/mbox.c                                |    2 +-
 maidag/Makefile.am                                 |    2 +
 maidag/lmtp.c                                      |    2 +-
 maidag/maidag.c                                    |    2 +-
 maidag/maidag.h                                    |    5 +-
 maidag/mailquota.c                                 |   78 ++-
 mu/Makefile.am                                     |   12 +-
 mu/dbm.c                                           |  751 ++++++++++++++++++++
 mu/ldflags.c                                       |   82 ++--
 pop3d/Makefile.am                                  |   20 +-
 pop3d/apop.c                                       |   66 ++-
 pop3d/bulletin.c                                   |  142 ++--
 pop3d/logindelay.c                                 |  103 ++-
 pop3d/pop3d.c                                      |    4 +-
 pop3d/pop3d.h                                      |    4 +-
 pop3d/popauth.c                                    |  378 +++++++----
 53 files changed, 2981 insertions(+), 1398 deletions(-)
 create mode 100644 include/mailutils/dbm.h
 copy include/mailutils/{radius.h => sys/dbm.h} (60%)
 delete mode 100644 lib/mu_dbm.c
 delete mode 100644 lib/mu_dbm.h
 copy {libproto/imap => libmu_dbm}/Makefile.am (56%)
 create mode 100644 libmu_dbm/berkeley.c
 copy lib/argp_base.c => libmu_dbm/close.c (72%)
 copy libproto/imap/capatst.c => libmu_dbm/create.c (66%)
 copy libmailutils/cidr/match.c => libmu_dbm/datumfree.c (69%)
 create mode 100644 libmu_dbm/dbm.c
 copy libmailutils/cidr/match.c => libmu_dbm/delete.c (71%)
 copy libmailutils/cidr/match.c => libmu_dbm/destroy.c (70%)
 copy libmailutils/sockaddr/unlink.c => libmu_dbm/errstr.c (67%)
 copy libproto/imap/capatst.c => libmu_dbm/fetch.c (70%)
 copy libmailutils/cidr/match.c => libmu_dbm/firstkey.c (71%)
 create mode 100644 libmu_dbm/gdbm.c
 copy libmailutils/cidr/match.c => libmu_dbm/getfd.c (71%)
 copy libproto/nntp/url.c => libmu_dbm/mudbm.h (52%)
 create mode 100644 libmu_dbm/ndbm.c
 copy libmailutils/cidr/match.c => libmu_dbm/nextkey.c (71%)
 copy libmailutils/cidr/match.c => libmu_dbm/open.c (71%)
 copy libproto/imap/create.c => libmu_dbm/safety.c (52%)
 copy libproto/imap/capatst.c => libmu_dbm/store.c (68%)
 create mode 100644 mu/dbm.c

diff --git a/Makefile.am b/Makefile.am
index 33f8fcf..8d2f5ab 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -83,6 +83,10 @@ if MU_COND_SUPPORT_CXX
   LIBMU_CPP_DIR = libmu_cpp
 endif
 
+if MU_COND_DBM
+  LIBMU_DBM_DIR = libmu_dbm
+endif
+
 SUBDIRS = . \
  mu-aux\
  include\
@@ -99,6 +103,7 @@ SUBDIRS = . \
  $(LIBMU_CPP_DIR)\
  $(GINT_DIR)\
  $(LIBMU_SCM_DIR)\
+ $(LIBMU_DBM_DIR)\
  libmu_sieve\
  $(PYTHON_DIR)\
  doc\
diff --git a/configure.ac b/configure.ac
index 8adfb8d..eaaea12 100644
--- a/configure.ac
+++ b/configure.ac
@@ -88,7 +88,7 @@ AM_PROG_LIBTOOL
 ## Predefine several variables used to display configuration status
 status_pam=no
 status_ltdl=no
-status_dbm=no
+status_dbm=
 status_gsasl=no
 status_mysql=no
 status_pgsql=no
@@ -354,22 +354,31 @@ AH_BOTTOM(
 # define MU_PATH_MAILDIR PATH_MAILDIR "/"
 #endif])
 
-use_dbm=no
+##################################
+# DBM Support
+##################################
+AC_SUBST(DBMLIBS)
+AC_SUBST(DBMLIB_DEPENDENCY)
+AC_SUBST(DBMINCLUDES)
+
+enable_dbm=no
+disable_dbm=no
+
 AC_ARG_WITH([gdbm],
             AC_HELP_STRING([--with-gdbm],
                            [use GNU DBM]),
             [
 case "${withval}" in
-  yes) use_dbm=GDBM ;;
-  no)  use_dbm=no ;;
+  yes) enable_dbm="$enable_dbm GDBM";;
+  no)  disable_dbm="$disable_dbm GDBM";;
   *)   AC_MSG_ERROR(bad value ${withval} for --with-gdbm) ;;
 esac])
 
 ## Support --with-db2 for backward compatibility
 if test "${with_db2+set}" = set; then
   case "${with_db2}" in
-  yes) use_dbm=BDB2 ;;
-  no)  use_dbm=no ;;
+  yes) enable_dbm="$enable_dbm BDB2";;
+  no)  disable_dbm="$disable_dbm BDB2";;
   *)   AC_MSG_ERROR(bad value ${with_db2} for --with-db2) ;;
   esac
 fi
@@ -379,9 +388,9 @@ AC_ARG_WITH([berkeley-db],
                            [use Berkeley DB]),
             [
 case "${withval}" in
-  yes) use_dbm=BDB ;;
-  no)  use_dbm=no ;;
-  *)   use_dbm=BDB="${withval}";;
+  yes) enable_dbm="$enable_dbm BDB";;
+  no)  disable_dbm="$disable_dbm BDB";;
+  *)   enable_dbm="$enable_dbm BDB=${withval}";;
 esac])
 
 AC_ARG_WITH([ndbm],
@@ -389,8 +398,8 @@ AC_ARG_WITH([ndbm],
                            [use NDBM]),
             [
 case "${withval}" in
-  yes) use_dbm=NDBM ;;
-  no)  use_dbm=no ;;
+  yes) enable_dbm="$enable_dbm NDBM";;
+  no)  disable_dbm="$disable_dbm NDBM";;
   *)   AC_MSG_ERROR(bad value ${withval} for --with-ndbm) ;;
 esac])
 
@@ -399,11 +408,174 @@ AC_ARG_WITH([tokyocabinet],
                            [use Tokyo Cabinet]),
             [
 case "${withval}" in
-  yes) use_dbm=TC ;;
-  no)  use_dbm=no ;;
+  yes) enable_dbm="$enable_dbm TC";;
+  no)  disable_dbm="$disable_dbm TC";;
   *)   AC_MSG_ERROR(bad value ${withval} for --with-tokyocabinet) ;;
 esac])
 
+dnl Check for DBM
+
+AH_TEMPLATE([WITH_BDB],
+            [Define to the major version of Berkeley DB library to use])
+
+status_bdb=no
+
+## Set the variable status_bdb to $1 if:
+##
+##  1. Function $3 is defined in the library $2
+##  2. Header file db.h is available
+##
+## Then check if the major version, minor version and patchlevel of the
+## library matches those from the header. If so, define WITH_BDB
+## to the version (i.e. $1 with all dots removed). Otherwise, report
+## an error and stop.
+##
+check_bdb() {
+        ver=`echo $1 | tr -d '.'`
+       major=`expr $ver : '\(.\).*'`
+       status_bdb=no
+       AC_CHECK_LIB($2, $3,
+                     [AC_CHECK_HEADERS(db.h)
+                      if test $ac_cv_header_db_h = yes; then
+                        DBMLIBS="$DBMLIBS -l$2"
+                        MU_DB2_CURSOR
+                        status_bdb="$1"
+                      fi])
+       if test "$status_bdb" = no; then
+               :
+       else
+         save_LIBS=$LIBS
+         LIBS="$LIBS $DBMLIBS"
+         AC_RUN_IFELSE(
+           [AC_LANG_PROGRAM([#include "db.h"],
+            [int v_major, v_minor, v_patch;
+             db_version(&v_major, &v_minor, &v_patch);
+             return !(DB_VERSION_MAJOR == $major
+                       && v_major == DB_VERSION_MAJOR
+                       && v_minor == DB_VERSION_MINOR
+                       && v_patch == DB_VERSION_PATCH);
+            ])],
+           [],
+           [status_bdb=no])
+          LIBS=$save_LIBS
+           if test "$status_bdb" != no; then
+            AC_DEFINE_UNQUOTED(WITH_BDB,$ver)
+           fi
+       fi
+}
+
+## Check for the Berkeley DB library version $1, assuming Slackware-like
+## installation layout (header files in /usr/incude/db$vn and library named
+## libdb-$version.so, where $version is the library version and $vn is
+## $version with all dots removed.
+##
+check_slackware_bdb() {
+       dir=db`echo $1|tr -d '.'`
+       save_CPPFLAGS=$CPPFLAGS
+       CPPFLAGS="$CPPFLAGS -I/usr/include/$dir"
+       check_bdb "$1" db-$1 db_create
+       CPPFLAGS=$save_CPPFLAGS
+       if test "$status_bdb" = "$1"; then
+           DBMINCLUDES="$DBMINCLUDES -I/usr/include/$dir"
+            status_dbm="$status_dbm,Berkeley DB v. $status_bdb"
+       fi
+}
+
+check_dbm_impl() {
+  case "$1" in
+  GDBM)
+       AC_CHECK_LIB(gdbm, gdbm_open,
+                     [AC_CHECK_HEADERS(gdbm.h,
+                                       AC_DEFINE(WITH_GDBM,1,
+                                                 [Enable use of GNU DBM 
library]))
+                     DBMLIBS="$DBMLIBS -lgdbm"
+                     status_dbm="$status_dbm,GDBM"]);;
+
+  BDB2)   check_bdb 2 db db_open
+          test -n "$status_bdb" && status_dbm="$status_dbm,Berkeley DB v. 
$status_bdb";;
+
+  BDB)    for version in 4 3 2
+         do
+               case $version in
+               4|3) func=db_create;;
+               2)   func=db_open;;
+               esac
+               check_bdb $version db $func
+               if test "$status_bdb" != no; then
+                  status_dbm="$status_dbm,Berkeley DB v. $status_bdb"
+                  break;
+               fi
+         done;;
+
+  BDB=*)
+         name=`expr $use_dbm : 'BDB=\(.*\)'`
+         case $name in
+         [[0-9]]*)  check_slackware_bdb $name;;
+         *)         for version in 4 3 2
+                    do
+                       case $version in
+                       4|3) func=db_create;;
+                       2)   func=db_open;;
+                       esac
+                       check_bdb $version $name $func
+                       if test "$status_bdb" != no; then
+                          status_dbm="$status_dbm,Berkeley DB v. $status_bdb"
+                          break;
+                       fi
+                    done
+                    ;;
+         esac
+          ;;
+
+  NDBM)
+          has_ndbm=no        
+         AC_CHECK_HEADERS(ndbm.h,[has_ndbm=yes])
+         if test $has_ndbm = yes; then
+           AC_CHECK_FUNC(dbm_open,:,[has_ndbm=no])
+           if test $has_ndbm = no; then
+             AC_CHECK_LIB(ndbm, dbm_open,
+                           [DBMLIBS="$DBMLIBS -lndbm"])
+           fi                      
+          fi
+         if test $has_ndbm = yes; then
+           AC_DEFINE(WITH_NDBM,1,[Enable use of NDBM])
+            status_dbm="$status_dbm,NDBM"
+         fi
+         ;;
+
+  TC)
+         AC_CHECK_LIB(tokyocabinet, tchdbnew,
+                       [AC_CHECK_HEADERS(tchdb.h,
+                                         AC_DEFINE(WITH_TOKYOCABINET,1,
+                                                 [Enable use of Tokyo 
Cabinet]))
+                      DBMLIB_DEPENDENCY="$DBMLIB_DEPENDENCY -lz -lbz2 -lrt"
+                       DBMLIBS="$DBMLIBS -ltokyocabinet"
+                       status_dbm="$status_dbm,Tokyo Cabinet"]);;
+  esac
+}
+
+if test "$enable_dbm" = no; then
+  enable_dbm="GDBM BDB TC NDBM"
+fi
+
+for impl in $enable_dbm
+do
+  if echo "$disable_dbm" | grep $impl >/dev/null; then
+    : # skip it
+  else
+    check_dbm_impl $impl
+  fi
+done
+
+if test -z "$status_dbm"; then
+  status_dbm=no
+else
+  status_dbm=`echo "$status_dbm" | sed 's/^,//'`
+  AC_DEFINE([ENABLE_DBM], 1, [Define if DBM interface is compiled])
+fi
+AM_CONDITIONAL([MU_COND_DBM], [test "$status_dbm" != no])
+
+####################
 AC_MSG_CHECKING(for log facility)
 log_facility="LOG_MAIL"
 AC_ARG_WITH([log-facility],
@@ -938,129 +1110,6 @@ AH_BOTTOM([
 # define rl_completion_matches completion_matches
 #endif])
 
-dnl Check for DBM
-
-AH_TEMPLATE([WITH_BDB],
-            [Define to the major version of Berkeley DB library to use])
-
-## Set the variable status_dbm to $1 if:
-##
-##  1. Function $3 is defined in the library $2
-##  2. Header file db.h is available
-##
-## Then check if the major version, minor version and patchlevel of the
-## library matches those from the header. If so, define WITH_BDB
-## to the version (i.e. $1 with all dots removed). Otherwise, report
-## an error and stop.
-##
-check_bdb() {
-        ver=`echo $1 | tr -d '.'`
-       major=`expr $ver : '\(.\).*'`
-       AC_CHECK_LIB($2, $3,
-                     [AC_CHECK_HEADERS(db.h)
-                      if test $ac_cv_header_db_h = yes; then
-                        LIBS="$LIBS -l$2"
-                        MU_DB2_CURSOR
-                        status_dbm=$1
-                      fi])
-       if test "$status_dbm" = no; then
-               :
-       else
-         AC_RUN_IFELSE(
-           [AC_LANG_PROGRAM([#include "db.h"],
-            [int v_major, v_minor, v_patch;
-             db_version(&v_major, &v_minor, &v_patch);
-             return !(DB_VERSION_MAJOR == $major
-                       && v_major == DB_VERSION_MAJOR
-                       && v_minor == DB_VERSION_MINOR
-                       && v_patch == DB_VERSION_PATCH);
-            ])],
-           [],
-           [status_dbm=no])
-           if test "$status_dbm" != no; then
-            AC_DEFINE_UNQUOTED(WITH_BDB,$ver)
-           fi
-       fi
-}
-
-## Check for the Berkeley DB library version $1, assuming Slackware-like
-## installation layout (header files in /usr/incude/db$vn and library named
-## libdb-$version.so, where $version is the library version and $vn is
-## $version with all dots removed.
-##
-check_slackware_bdb() {
-       dir=db`echo $1|tr -d '.'`
-       save_CPPFLAGS=$CPPFLAGS
-       CPPFLAGS="$CPPFLAGS -I/usr/include/$dir"
-       check_bdb "$1" db-$1 db_create
-       CPPFLAGS=$save_CPPFLAGS
-       if test "$status_dbm" = "$1"; then
-           MU_COMMON_INCLUDES="$MU_COMMON_INCLUDES -I/usr/include/$dir"
-       fi
-}
-
-case "$use_dbm" in
-GDBM)
-       AC_CHECK_LIB(gdbm, gdbm_open,
-                     [AC_CHECK_HEADERS(gdbm.h,
-                                       AC_DEFINE(WITH_GDBM,1,
-                                                 [Enable use of GNU DBM 
library]))
-                     LIBS="$LIBS -lgdbm"
-                     status_dbm="GDBM"]);;
-
-BDB2)   check_bdb 2 db db_open
-        test -n "$status_dbm" && status_dbm="Berkeley DB v. $status_dbm";;
-
-BDB)    for version in 4 3 2
-       do
-               case $version in
-               4|3) func=db_create;;
-               2)   func=db_open;;
-               esac
-               check_bdb $version db $func
-               if test "$status_dbm" != no; then
-                   status_dbm="Berkeley DB v. $status_dbm"
-                  break;
-               fi
-       done;;
-
-BDB=*)
-       name=`expr $use_dbm : 'BDB=\(.*\)'`
-       case $name in
-       [[0-9]]*)  check_slackware_bdb $name;;
-       *)         for version in 4 3 2
-                  do
-                       case $version in
-                       4|3) func=db_create;;
-                       2)   func=db_open;;
-                       esac
-                       check_bdb $version $name $func
-                       if test "$status_dbm" != no; then
-                          status_dbm="Berkeley DB v. $status_dbm"
-                          break;
-                       fi
-                  done
-                  ;;
-       esac
-        ;;
-
-NDBM)
-       AC_CHECK_LIB(ndbm, dbm_open,
-                     [AC_CHECK_HEADERS(ndbm.h,
-                                       AC_DEFINE(WITH_NDBM,1,
-                                                 [Enable use of NDBM]))
-                     LIBS="$LIBS -lndbm"
-                     status_dbm="NDBM"]);;
-
-TC)
-       AC_CHECK_LIB(tokyocabinet, tchdbnew,
-                     [AC_CHECK_HEADERS(tchdb.h,
-                                       AC_DEFINE(WITH_TOKYOCABINET,1,
-                                                 [Enable use of Tokyo 
Cabinet]))
-                     LIBS="$LIBS -ltokyocabinet -lz -lbz2 -lrt"
-                     status_dbm="Tokyo Cabinet"]);;
-esac
-
 AC_SUBST(POPAUTH)
 if test "$status_dbm" != no; then
   POPAUTH='popauth$(EXEEXT)'
@@ -1397,6 +1446,7 @@ AC_CONFIG_FILES([
  libmu_cpp/Makefile
  libmu_scm/Makefile
  libmu_scm/mailutils/Makefile
+ libmu_dbm/Makefile
  libmu_sieve/Makefile
  libmu_sieve/extensions/Makefile
  libproto/Makefile
diff --git a/imap4d/io.c b/imap4d/io.c
index 4fad3c3..2033638 100644
--- a/imap4d/io.c
+++ b/imap4d/io.c
@@ -319,7 +319,7 @@ io_getline (char **pbuf, size_t *psize, size_t *pnbytes)
           imap4d_bye (ERR_NO_IFILE);
           /*FIXME rc = ECONNABORTED;*/
         }
-      len = mu_rtrim_cset (s, "\r\n");
+      len = mu_rtrim_class (s, MU_CTYPE_ENDLN);
       if (pnbytes)
        *pnbytes = len;
     }
diff --git a/imap4d/preauth.c b/imap4d/preauth.c
index 5e145e3..43cd6b2 100644
--- a/imap4d/preauth.c
+++ b/imap4d/preauth.c
@@ -463,7 +463,7 @@ do_preauth_program (struct sockaddr *pcs, struct sockaddr 
*sa)
     }
   else
     {
-      mu_rtrim_cset (buf, "\r\n");
+      mu_rtrim_class (buf, MU_CTYPE_ENDLN);
       return buf;
     }
   return NULL;
diff --git a/include/mailutils/Makefile.am b/include/mailutils/Makefile.am
index 1e21894..6682884 100644
--- a/include/mailutils/Makefile.am
+++ b/include/mailutils/Makefile.am
@@ -39,6 +39,7 @@ pkginclude_HEADERS = \
  cidr.h\
  cstr.h\
  daemon.h\
+ dbm.h\
  debug.h\
  diag.h\
  envelope.h\
diff --git a/include/mailutils/cctype.h b/include/mailutils/cctype.h
index 8953b34..f56dfc0 100644
--- a/include/mailutils/cctype.h
+++ b/include/mailutils/cctype.h
@@ -35,6 +35,7 @@ extern "C" {
 #define MU_CTYPE_PUNCT   0x100
 #define MU_CTYPE_SPACE   0x200
 #define MU_CTYPE_XLETR   0x400
+#define MU_CTYPE_ENDLN   0x800
 
 #define MU_C_TAB_MAX     128
 
@@ -56,6 +57,7 @@ extern int mu_c_tab[MU_C_TAB_MAX];
 #define mu_isalnum(c) mu_c_is_class (c, MU_CTYPE_ALPHA|MU_CTYPE_DIGIT)
 #define mu_isascii(c) (((unsigned)c) < MU_C_TAB_MAX)
 #define mu_isblank(c) ((c) == ' ' || (c) == '\t')
+#define mu_isendln(c) mu_c_is_class (c, MU_CTYPE_ENDLN)
 
 #define mu_tolower(c)                                  \
   ({ int __c = (c);                                    \
diff --git a/include/mailutils/dbm.h b/include/mailutils/dbm.h
new file mode 100644
index 0000000..0d194f6
--- /dev/null
+++ b/include/mailutils/dbm.h
@@ -0,0 +1,77 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifndef _MAILUTILS_DBM_H
+#define _MAILUTILS_DBM_H
+
+#include <mailutils/types.h>
+
+struct mu_dbm_datum
+{
+  char *mu_dptr;               /* Data pointer */
+  size_t mu_dsize;             /* Data size */
+  void *mu_data;               /* Implementation-dependent data */
+  struct mu_dbm_impl *mu_sys;  /* Pointer to implementation */
+};
+
+struct mu_dbm_impl
+{
+  char *_dbm_name;
+  int (*_dbm_file_safety) (mu_dbm_file_t db, int mode, uid_t owner);
+  int (*_dbm_get_fd) (mu_dbm_file_t db, int *pag, int *dir);
+  int (*_dbm_open) (mu_dbm_file_t db, int flags, int mode);
+  int (*_dbm_close) (mu_dbm_file_t db);
+  int (*_dbm_fetch) (mu_dbm_file_t db, struct mu_dbm_datum const *key,
+                    struct mu_dbm_datum *ret);
+  int (*_dbm_store) (mu_dbm_file_t db, struct mu_dbm_datum const *key,
+                    struct mu_dbm_datum const *contents, int replace);
+  int (*_dbm_delete) (mu_dbm_file_t db,
+                     struct mu_dbm_datum const *key);
+  int (*_dbm_firstkey) (mu_dbm_file_t db, struct mu_dbm_datum *ret);
+  int (*_dbm_nextkey) (mu_dbm_file_t db, struct mu_dbm_datum *ret);
+  void (*_dbm_datum_free) (struct mu_dbm_datum *datum);
+  char const *(*_dbm_strerror) (mu_dbm_file_t db);
+};
+
+extern mu_url_t mu_dbm_hint;
+
+int mu_dbm_register (struct mu_dbm_impl *impl);
+int mu_dbm_create_from_url (mu_url_t url, mu_dbm_file_t *db);
+int mu_dbm_create (char *name, mu_dbm_file_t *db);
+int mu_dbm_close (mu_dbm_file_t db);
+void mu_dbm_datum_free (struct mu_dbm_datum *datum);
+int mu_dbm_delete (mu_dbm_file_t db, struct mu_dbm_datum const *key);
+void mu_dbm_destroy (mu_dbm_file_t *pdb);
+int mu_dbm_fetch (mu_dbm_file_t db, struct mu_dbm_datum const *key,
+                 struct mu_dbm_datum *ret);
+int mu_dbm_store (mu_dbm_file_t db, struct mu_dbm_datum const *key,
+                 struct mu_dbm_datum const *contents, int replace);
+int mu_dbm_firstkey (mu_dbm_file_t db, struct mu_dbm_datum *ret);
+int mu_dbm_nextkey (mu_dbm_file_t db, struct mu_dbm_datum *ret);
+int mu_dbm_open (mu_dbm_file_t db, int flags, int mode);
+int mu_dbm_safety_get_owner (mu_dbm_file_t db, uid_t *uid);
+int mu_dbm_safety_get_flags (mu_dbm_file_t db, int *flags);
+int mu_dbm_safety_set_owner (mu_dbm_file_t db, uid_t uid);
+int mu_dbm_safety_set_flags (mu_dbm_file_t db, int flags);
+int mu_dbm_safety_check (mu_dbm_file_t db);
+char const *mu_dbm_strerror (mu_dbm_file_t db);
+int mu_dbm_get_fd (mu_dbm_file_t db, int *pag, int *dir);
+
+int mu_dbm_impl_iterator (mu_iterator_t *itr);
+
+#endif
diff --git a/include/mailutils/sys/Makefile.am 
b/include/mailutils/sys/Makefile.am
index 56942cf..e46a294 100644
--- a/include/mailutils/sys/Makefile.am
+++ b/include/mailutils/sys/Makefile.am
@@ -21,6 +21,7 @@ sysinclude_HEADERS = \
  attribute.h\
  auth.h\
  body.h\
+ dbm.h\
  debcat.h\
  envelope.h\
  file_stream.h\
diff --git a/include/mailutils/radius.h b/include/mailutils/sys/dbm.h
similarity index 60%
copy from include/mailutils/radius.h
copy to include/mailutils/sys/dbm.h
index c538a14..bf1d8d5 100644
--- a/include/mailutils/radius.h
+++ b/include/mailutils/sys/dbm.h
@@ -1,6 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2004, 2005, 2007, 2008, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 2011 Free Software Foundation, Inc.
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -16,18 +15,23 @@
    Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
-#ifndef _MAILUTILS_RADIUS_H
-#define _MAILUTILS_RADIUS_H
-#include <mailutils/types.h>
+#ifndef _MAILUTILS_SYS_DBM_H
+# define _MAILUTILS_SYS_DBM_H
 
-struct mu_radius_module_data
+union _mu_dbm_errno
 {
-  char *config_dir;
-  char *auth_request;
-  char *getpwnam_request;
-  char *getpwuid_request;
+  int n;
+  void *p;
 };
 
-extern int mu_radius_module_init (enum mu_gocs_op, void *data);
+struct _mu_dbm_file
+{
+  char *db_name;              /* Database name */
+  void *db_descr;             /* Database descriptor */
+  int db_safety_flags;        /* Safety checks */
+  uid_t db_owner;             /* Database owner UID */
+  struct mu_dbm_impl *db_sys; /* Pointer to the database implementation */
+  union _mu_dbm_errno db_errno;
+};
 
 #endif
diff --git a/include/mailutils/types.hin b/include/mailutils/types.hin
index bf81756..c1f4b44 100644
--- a/include/mailutils/types.hin
+++ b/include/mailutils/types.hin
@@ -75,7 +75,8 @@ struct _mu_assoc;
 struct _mu_acl;  
 struct _mu_server;
 struct _mu_tcp_server;
-
+struct _mu_dbm_file;
+  
 struct mu_sockaddr; /* defined in mailutils/sockaddr.h */  
 struct mu_cidr;     /* defined in mailutils/cidr.h */  
   
@@ -121,6 +122,7 @@ typedef struct _mu_opool *mu_opool_t;
 typedef struct _mu_progmailer *mu_progmailer_t;
 typedef struct _mu_secret *mu_secret_t;
 typedef struct _mu_mime_io_buffer *mu_mime_io_buffer_t;
+typedef struct _mu_dbm_file *mu_dbm_file_t;
 
 typedef void (*mu_onexit_t) (void*);
 typedef unsigned int mu_debug_handle_t;
diff --git a/lib/Makefile.am b/lib/Makefile.am
index c53879f..8901769 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -24,7 +24,6 @@ libmuaux_a_SOURCES += \
  daemon.c\
  mailcap.c\
  manlock.c\
- mu_dbm.c\
  signal.c\
  strexit.c\
  tcpwrap.c\
@@ -34,7 +33,6 @@ libmuaux_a_SOURCES += \
 noinst_HEADERS +=\
  mailcap.h\
  muaux.h\
- mu_dbm.h\
  tcpwrap.h
 
 EXTRA_DIST += utmp.c
diff --git a/lib/mu_dbm.c b/lib/mu_dbm.c
deleted file mode 100644
index ec270f0..0000000
--- a/lib/mu_dbm.c
+++ /dev/null
@@ -1,575 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2002, 2006, 2007, 2009, 2010, 2011
-   Free Software Foundation, Inc.
-
-   GNU Mailutils 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 3, or (at your option)
-   any later version.
-
-   GNU Mailutils 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 GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
-#include <errno.h>
-#include <mailutils/errno.h>
-#include <mailutils/stream.h>
-#include <mu_dbm.h>
-#include <xalloc.h>
-
-int
-mu_fcheck_perm (int fd, int mode)
-{
-  struct stat st;
-
-  if (mode == 0)
-    return 0;
-  if (fstat (fd, &st) == -1)
-    {
-      if (errno == ENOENT)
-       return 0;
-      else
-       return 1;
-    }
-  if ((st.st_mode & 0777) != mode)
-    {
-      errno = MU_ERR_UNSAFE_PERMS;
-      return 1;
-    }
-  return 0;
-}
-
-int
-mu_check_perm (const char *name, int mode)
-{
-  struct stat st;
-
-  if (mode == 0)
-    return 0;
-  if (stat (name, &st) == -1)
-    {
-      if (errno == ENOENT)
-       return 0;
-      else
-       return 1;
-    }
-  if ((st.st_mode & 0777) != mode)
-    {
-      errno = MU_ERR_UNSAFE_PERMS;
-      return 1;
-    }
-  return 0;
-}
-
-static char *
-make_db_name (const char *name, const char *suffix)
-{
-  int nlen = strlen (name);
-  int slen = strlen (suffix);
-  char *p;
-  
-  if (nlen > slen && strcmp (name + nlen - slen, suffix) == 0)
-    p = xstrdup (name);
-  else
-    {
-      p = xmalloc (strlen (name) + slen + 1);
-      strcat (strcpy (p, name), suffix);
-    }
-  return p;
-}
-
-#if defined(WITH_GDBM)
-
-#define DB_SUFFIX ".db"
-
-int
-mu_dbm_stat (char *name, struct stat *sb)
-{
-  int rc;
-  char *pfname = make_db_name (name, DB_SUFFIX);
-  rc = stat (pfname, sb);
-  free (pfname);
-  return rc;
-}
-
-int
-mu_dbm_open (char *name, DBM_FILE *db, int flags, int mode)
-{
-  int f;
-  char *pfname = make_db_name (name, DB_SUFFIX);
-
-  if (mu_check_perm (pfname, mode))
-    {
-      free (pfname);
-      return -1;
-    }
-
-  switch (flags)
-    {
-    case MU_STREAM_CREAT:
-      f = GDBM_NEWDB;
-      break;
-      
-    case MU_STREAM_READ:
-      f = GDBM_READER;
-      break;
-      
-    case MU_STREAM_RDWR:
-      f = GDBM_WRCREAT;
-      break;
-      
-    default:
-      free (pfname);
-      errno = EINVAL;
-      return 1;
-    }
-  *db = gdbm_open (pfname, 512, f, mode, NULL);
-  free (pfname);
-  return *db == NULL;
-}
-
-int
-mu_dbm_close (DBM_FILE db)
-{
-  gdbm_close(db);
-  return 0;
-}
-
-int
-mu_dbm_fetch (DBM_FILE db, DBM_DATUM key, DBM_DATUM *ret)
-{
-  *ret = gdbm_fetch (db, key);
-  return ret->dptr == NULL;
-}
-
-int
-mu_dbm_delete (DBM_FILE db, DBM_DATUM key)
-{
-  return gdbm_delete (db, key);
-}
-
-int
-mu_dbm_insert (DBM_FILE db, DBM_DATUM key, DBM_DATUM contents, int replace)
-{
-  return gdbm_store (db, key, contents,
-                    replace ? GDBM_REPLACE : GDBM_INSERT);
-}
-
-DBM_DATUM
-mu_dbm_firstkey (DBM_FILE db)
-{
-  return gdbm_firstkey (db);
-}
-
-DBM_DATUM
-mu_dbm_nextkey (DBM_FILE db, DBM_DATUM key)
-{
-  return gdbm_nextkey (db, key);
-}
-
-void
-mu_dbm_datum_free (DBM_DATUM *datum)
-{
-  void *ptr = MU_DATUM_PTR (*datum);
-  if (ptr)
-    free (ptr);
-  MU_DATUM_PTR (*datum) = 0;
-}
-
-#elif defined(WITH_BDB)
-
-#define DB_SUFFIX ".db"
-
-int
-mu_dbm_stat (char *name, struct stat *sb)
-{
-  int rc;
-  char *pfname = make_db_name (name, DB_SUFFIX);
-  rc = stat (pfname, sb);
-  free (pfname);
-  return rc;
-}
-
-int
-mu_dbm_open (char *name, DBM_FILE *dbm, int flags, int mode)
-{
-  int f, rc;
-  DB *db;
-  char *pfname = make_db_name (name, DB_SUFFIX);
-
-  if (mu_check_perm (pfname, mode))
-    {
-      free (pfname);
-      errno = MU_ERR_UNSAFE_PERMS;
-      return -1;
-    }
-
-  switch (flags)
-    {
-    case MU_STREAM_CREAT:
-      f = DB_CREATE|DB_TRUNCATE;
-      break;
-      
-    case MU_STREAM_READ:
-      f = DB_RDONLY;
-      break;
-      
-    case MU_STREAM_RDWR:
-      f = DB_CREATE;
-      break;
-      
-    default:
-      free (pfname);
-      errno = EINVAL;
-      return -1;
-    }
-
-#if WITH_BDB == 2  
-  rc = db_open (pfname, DB_HASH, f, mode, NULL, NULL, &db);
-#else
-  rc = db_create (&db, NULL, 0);
-  if (rc != 0 || db == NULL)
-    return rc;
-# if DB_VERSION_MAJOR == 3
-  rc = db->open (db, pfname, NULL, DB_HASH, f, mode);
-# else
-  rc = db->open (db, NULL, pfname, NULL, DB_HASH, f, mode);
-# endif
-#endif
-  
-  free (pfname);
-  if (rc)
-    return -1;
-
-  *dbm = malloc (sizeof **dbm);
-  if (!*dbm)
-    {
-      db->close (db, 0);
-      errno = ENOMEM;
-      return -1;
-    }
-  (*dbm)->db = db;
-  (*dbm)->dbc = NULL;
-  return 0;
-}
-
-int
-mu_dbm_close (DBM_FILE db)
-{
-  db->db->close (db->db, 0);
-  free (db);
-  return 0;
-}
-
-int
-mu_dbm_fetch (DBM_FILE db, DBM_DATUM key, DBM_DATUM *ret)
-{
-  return db->db->get (db->db, NULL, &key, ret, 0);
-}
-
-int
-mu_dbm_delete (DBM_FILE db, DBM_DATUM key)
-{
-  return db->db->del (db->db, NULL, &key, 0);
-}
-
-int
-mu_dbm_insert (DBM_FILE db, DBM_DATUM key, DBM_DATUM contents, int replace)
-{
-  /*FIXME: replace unused*/
-  return db->db->put (db->db, NULL, &key, &contents, 0);
-}
-
-DBM_DATUM
-mu_dbm_firstkey (DBM_FILE db)
-{
-  DBT key, data;
-  int ret;
-
-  memset (&key, 0, sizeof key);
-  memset (&data, 0, sizeof data);
-
-  if (!db->dbc)
-    {
-      if (db->db->cursor (db->db, NULL, &db->dbc BDB2_CURSOR_LASTARG) != 0)
-       return key;
-    }
-
-  if ((ret = db->dbc->c_get (db->dbc, &key, &data, DB_FIRST)) != 0)
-    {
-      key.data = NULL;
-      key.size = 0;
-      if (ret == DB_NOTFOUND)
-       errno = MU_ERR_NOENT;
-      else
-       errno = ret;
-    }
-  return key;
-}
-
-DBM_DATUM
-mu_dbm_nextkey (DBM_FILE db, DBM_DATUM pkey /*unused*/)
-{
-  DBT key, data;
-  int ret;
-
-  memset (&key, 0, sizeof key);
-  memset (&data, 0, sizeof data);
-
-  if (!db->dbc)
-    return key;
-
-  if ((ret = db->dbc->c_get (db->dbc, &key, &data, DB_NEXT)) != 0)
-    {
-      key.data = NULL;
-      key.size = 0;
-      if (ret == DB_NOTFOUND)
-       errno = MU_ERR_NOENT;
-      else
-       errno = ret;
-    }
-  return key;
-}
-
-void
-mu_dbm_datum_free (DBM_DATUM *datum)
-{
-  /* empty */
-}
-
-#elif defined(WITH_NDBM)
-
-#define DB_SUFFIX ".pag"
-
-int
-mu_dbm_stat (char *name, struct stat *sb)
-{
-  int rc;
-  char *pfname = make_db_name (name, DB_SUFFIX);
-  rc = stat (pfname, sb);
-  free (pfname);
-  return rc;
-}
-
-int
-mu_dbm_open (char *name, DBM_FILE *db, int flags, int mode)
-{
-  int f;
-  char *pfname;
-
-  switch (flags)
-    {
-    case MU_STREAM_CREAT:
-      f = O_CREAT|O_TRUNC|O_RDWR;
-      break;
-      
-    case MU_STREAM_READ:
-      f = O_RDONLY;
-      break;
-      
-    case MU_STREAM_RDWR:
-      f = O_CREAT|O_RDWR;
-      break;
-      
-    default:
-      errno = EINVAL;
-      return -1;
-    }
-  pfname = strip_suffix (name, DB_SUFFIX);
-  *db = dbm_open (pfname, f, mode);
-  free (pfname);
-  if (!*db)
-    return -1;
-
-  if (mu_fcheck_perm (dbm_dirfno (*db), mode)
-      || mu_fcheck_perm (dbm_pagfno (*db), mode))
-    {
-      dbm_close (*db);
-      return 1;
-    }
-
-  return 0;
-}
-
-int
-mu_dbm_close (DBM_FILE db)
-{
-  dbm_close (db);
-  return 0;
-}
-
-int
-mu_dbm_fetch (DBM_FILE db, DBM_DATUM key, DBM_DATUM *ret)
-{
-  *ret = dbm_fetch (db, key);
-  return ret->dptr == NULL;
-}
-
-int
-mu_dbm_delete (DBM_FILE db, DBM_DATUM key)
-{
-  return dbm_delete (db, key);
-}
-
-int
-mu_dbm_insert (DBM_FILE db, DBM_DATUM key, DBM_DATUM contents, int replace)
-{
-  return dbm_store (db, key, contents, replace ? DBM_REPLACE : DBM_INSERT);
-}
-
-DBM_DATUM
-mu_dbm_firstkey (DBM_FILE db)
-{
-  return dbm_firstkey (db);
-}
-
-DBM_DATUM
-mu_dbm_nextkey (DBM_FILE db, DBM_DATUM key)
-{
-  return dbm_nextkey (db, key);
-}
-
-void
-mu_dbm_datum_free (DBM_DATUM *datum)
-{
-  /* empty */
-}
-
-#elif defined(WITH_TOKYOCABINET)
-
-#define DB_SUFFIX ".tch"
-
-int
-mu_dbm_stat (char *name, struct stat *sb)
-{
-  int rc;
-  char *pfname = make_db_name (name, DB_SUFFIX);
-  rc = stat (pfname, sb);
-  free (pfname);
-  return rc;
-}
-
-int
-mu_dbm_open (char *name, DBM_FILE *db, int flags, int mode)
-{
-  int f, ecode;
-  char *pfname = make_db_name (name, DB_SUFFIX);
-
-  if (mu_check_perm (pfname, mode))
-    {
-      free (pfname);
-      return -1;
-    }
-
-  switch (flags)
-    {
-    case MU_STREAM_CREAT:
-      f = HDBOWRITER | HDBOCREAT;
-      break;
-      
-    case MU_STREAM_READ:
-      f = HDBOREADER;
-      break;
-      
-    case MU_STREAM_RDWR:
-      f = HDBOREADER | HDBOWRITER;
-      break;
-      
-    default:
-      free (pfname);
-      errno = EINVAL;
-      return 1;
-    }
-
-  *db = malloc (sizeof **db);
-  if (!*db)
-    {
-      errno = ENOMEM;
-      return -1;
-    }
-  (*db)->hdb = tchdbnew ();
-
-  if (!tchdbopen ((*db)->hdb, pfname, f))
-    ecode = tchdbecode ((*db)->hdb);
-
-  free (pfname);
-  return 0;
-}
-
-int
-mu_dbm_close (DBM_FILE db)
-{
-  tchdbclose (db->hdb);
-  tchdbdel (db->hdb);
-  return 0;
-}
-
-int
-mu_dbm_fetch (DBM_FILE db, DBM_DATUM key, DBM_DATUM *ret)
-{
-  ret->data = tchdbget (db->hdb, key.data, key.size, &ret->size);
-  return ret->data == NULL;
-}
-
-int
-mu_dbm_delete (DBM_FILE db, DBM_DATUM key)
-{
-  return !tchdbout (db->hdb, key.data, key.size);
-}
-
-int
-mu_dbm_insert (DBM_FILE db, DBM_DATUM key, DBM_DATUM contents, int replace)
-{
-  if (replace)
-    return !tchdbput (db->hdb, key.data, key.size, contents.data, 
contents.size);
-  else
-    return !tchdbputkeep (db->hdb, key.data, key.size,
-                         contents.data, contents.size);
-}
-
-DBM_DATUM
-mu_dbm_firstkey (DBM_FILE db)
-{
-  DBM_DATUM key;
-  memset (&key, 0, sizeof key);
-
-  tchdbiterinit (db->hdb);
-  key.data = tchdbiternext (db->hdb, &key.size);
-  return key;
-}
-
-DBM_DATUM
-mu_dbm_nextkey (DBM_FILE db, DBM_DATUM unused)
-{
-  DBM_DATUM key;
-  memset (&key, 0, sizeof key);
-
-  key.data = tchdbiternext (db->hdb, &key.size);
-  return key;
-}
-
-void
-mu_dbm_datum_free (DBM_DATUM *datum)
-{
-  /* empty */
-}
-
-#endif
-
diff --git a/lib/mu_dbm.h b/lib/mu_dbm.h
deleted file mode 100644
index fee27e4..0000000
--- a/lib/mu_dbm.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2009, 2010, 2011
-   Free Software Foundation, Inc.
-
-   GNU Mailutils 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 3, or (at your option)
-   any later version.
-
-   GNU Mailutils 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 GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
-
-#if defined(WITH_GDBM)
-
-#include <gdbm.h>
-#define USE_DBM
-typedef GDBM_FILE DBM_FILE;
-typedef datum DBM_DATUM;
-#define MU_DATUM_SIZE(d) (d).dsize
-#define MU_DATUM_PTR(d) (d).dptr
-
-#elif defined(WITH_BDB)
-
-#include <db.h>
-#define USE_DBM
-
-struct db2_file
-{
-  DB *db;
-  DBC *dbc;
-};
-
-typedef struct db2_file *DBM_FILE;
-typedef DBT DBM_DATUM;
-#define MU_DATUM_SIZE(d) (d).size
-#define MU_DATUM_PTR(d) (d).data
-
-#elif defined(WITH_NDBM)
-
-#include <ndbm.h>
-#define USE_DBM
-typedef DBM *DBM_FILE;
-typedef datum DBM_DATUM;
-#define MU_DATUM_SIZE(d) (d).dsize
-#define MU_DATUM_PTR(d) (d).dptr
-
-#elif defined(WITH_TOKYOCABINET)
-
-#include <tcutil.h>
-#include <tchdb.h>
-#define USE_DBM
-
-struct tokyocabinet_file
-{
-  TCHDB *hdb;
-};
-
-struct tokyocabinet_datum {
-  void *data;
-  int size;
-};
-
-typedef struct tokyocabinet_file *DBM_FILE;
-typedef struct tokyocabinet_datum DBM_DATUM;
-#define MU_DATUM_SIZE(d) (d).size
-#define MU_DATUM_PTR(d) (d).data
-
-#endif
-
-#ifdef USE_DBM
-struct stat;
-int mu_dbm_stat (char *name, struct stat *sb);
-int mu_dbm_open (char *name, DBM_FILE *db, int flags, int mode);
-int mu_dbm_close (DBM_FILE db);
-int mu_dbm_fetch (DBM_FILE db, DBM_DATUM key, DBM_DATUM *ret);
-int mu_dbm_insert (DBM_FILE db, DBM_DATUM key, DBM_DATUM contents, int 
replace);
-int mu_dbm_delete (DBM_FILE db, DBM_DATUM key);
-DBM_DATUM mu_dbm_firstkey (DBM_FILE db);
-DBM_DATUM mu_dbm_nextkey (DBM_FILE db, DBM_DATUM key);
-void mu_dbm_datum_free(DBM_DATUM *datum);
-#endif /* USE_DBM */
-
-int mu_fcheck_perm (int fd, int mode);
-int mu_check_perm (const char *name, int mode);
diff --git a/libmailutils/string/muctype.c b/libmailutils/string/muctype.c
index b2a831a..669c40a 100644
--- a/libmailutils/string/muctype.c
+++ b/libmailutils/string/muctype.c
@@ -31,10 +31,10 @@ int mu_c_tab[MU_C_TAB_MAX] = {
   MU_CTYPE_CNTRL,
   MU_CTYPE_CNTRL,
   MU_CTYPE_CNTRL|MU_CTYPE_SPACE,
+  MU_CTYPE_CNTRL|MU_CTYPE_SPACE|MU_CTYPE_ENDLN,
   MU_CTYPE_CNTRL|MU_CTYPE_SPACE,
   MU_CTYPE_CNTRL|MU_CTYPE_SPACE,
-  MU_CTYPE_CNTRL|MU_CTYPE_SPACE,
-  MU_CTYPE_CNTRL|MU_CTYPE_SPACE,
+  MU_CTYPE_CNTRL|MU_CTYPE_SPACE|MU_CTYPE_ENDLN,
   MU_CTYPE_CNTRL,
   MU_CTYPE_CNTRL,
   MU_CTYPE_CNTRL,
diff --git a/libproto/imap/Makefile.am b/libmu_dbm/Makefile.am
similarity index 56%
copy from libproto/imap/Makefile.am
copy to libmu_dbm/Makefile.am
index c280042..93335d7 100644
--- a/libproto/imap/Makefile.am
+++ b/libmu_dbm/Makefile.am
@@ -1,6 +1,5 @@
 ## This file is part of GNU Mailutils.
-## Copyright (C) 2003, 2005, 2006, 2007, 2010, 2011 Free Software
-## Foundation, Inc.
+## Copyright (C) 2011 Free Software Foundation, Inc.
 ##
 ## GNU Mailutils is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
@@ -15,32 +14,31 @@
 ## You should have received a copy of the GNU General Public License
 ## along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>.
 
-INCLUDES = @MU_LIB_COMMON_INCLUDES@ 
+INCLUDES = @MU_LIB_COMMON_INCLUDES@ @DBMINCLUDES@
 
-lib_LTLIBRARIES = libmu_imap.la
-libmu_imap_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
-libmu_imap_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@ 
+lib_LTLIBRARIES = libmu_dbm.la
 
-# FIXME: Put these back when ready
-
-#  folder.c\
-#  mbox.c\
-#  url.c
-libmu_imap_la_SOURCES = \
- fake-folder.c\
- capability.c\
- capatst.c\
- carrier.c\
- connect.c\
+libmu_dbm_la_SOURCES = \
+ close.c\
  create.c\
+ datumfree.c\
+ dbm.c\
+ delete.c\
  destroy.c\
- disconnect.c\
- err.c\
- id.c\
- login.c\
- logout.c\
- response.c\
- state.c\
- tag.c\
- trace.c
+ errstr.c\
+ fetch.c\
+ firstkey.c\
+ getfd.c\
+ nextkey.c\
+ open.c\
+ safety.c\
+ store.c\
+ berkeley.c\
+ gdbm.c\
+ ndbm.c
+
+noinst_HEADERS = mudbm.h
 
+libmu_dbm_la_LIBADD = ${MU_LIB_MAILUTILS} @MU_AUTHLIBS@ @DBMLIBS@ @LTLIBINTL@
+libmu_dbm_la_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
+libmu_dbm_la_DEPENDENCIES = @DBMLIB_DEPENDENCY@ 
diff --git a/libmu_dbm/berkeley.c b/libmu_dbm/berkeley.c
new file mode 100644
index 0000000..884a326
--- /dev/null
+++ b/libmu_dbm/berkeley.c
@@ -0,0 +1,340 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
+#include <mailutils/util.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/stream.h>
+#include "mudbm.h"
+
+#if defined(WITH_BDB)
+#include <db.h>
+
+struct bdb_file
+{
+  DB *db;
+  DBC *dbc;
+};
+
+static int
+_bdb_file_safety (mu_dbm_file_t db, int mode, uid_t owner)
+{
+  return mu_file_safety_check (db->db_name, mode, owner, NULL);
+}
+
+static int
+_bdb_get_fd (mu_dbm_file_t db, int *pag, int *dir)
+{
+  struct bdb_file *bdb_file = db->db_descr;
+  int rc = bdb_file->db->fd (bdb_file->db, pag);
+  if (rc)
+    {
+      db->db_errno.n = rc;
+      return MU_ERR_FAILURE;
+    }
+  if (dir)
+    *dir = *pag;
+  return 0;
+}
+  
+static int
+_bdb_open (mu_dbm_file_t mdb, int flags, int mode)
+{
+  struct bdb_file *bdb_file;
+  int f, rc;
+  DB *db;
+
+  switch (flags)
+    {
+    case MU_STREAM_CREAT:
+      f = DB_CREATE|DB_TRUNCATE;
+      break;
+      
+    case MU_STREAM_READ:
+      f = DB_RDONLY;
+      break;
+      
+    case MU_STREAM_RDWR:
+      f = DB_CREATE;
+      break;
+      
+    default:
+      return EINVAL;
+    }
+
+#if WITH_BDB == 2  
+  rc = db_open (db->db_name, DB_HASH, f, mode, NULL, NULL, &db);
+#else
+  rc = db_create (&db, NULL, 0);
+  if (rc != 0 || db == NULL)
+    return MU_ERR_FAILURE;
+# if DB_VERSION_MAJOR == 3
+  rc = db->open (db, mdb->db_name, NULL, DB_HASH, f, mode);
+# else
+  rc = db->open (db, NULL, mdb->db_name, NULL, DB_HASH, f, mode);
+# endif
+#endif
+  
+  if (rc)
+    return MU_ERR_FAILURE;
+
+  bdb_file = malloc (sizeof *bdb_file);
+  if (!bdb_file)
+    {
+      db->close (db, 0);
+      return ENOMEM;
+    }
+  bdb_file->db = db;
+  bdb_file->dbc = NULL;
+
+  mdb->db_descr = bdb_file;
+  
+  return 0;
+}
+
+static int
+_bdb_close (mu_dbm_file_t db)
+{
+  if (db->db_descr)
+    {
+      struct bdb_file *bdb_file = db->db_descr;
+      bdb_file->db->close (bdb_file->db, 0);
+      free (bdb_file);
+      db->db_descr = NULL;
+    }
+  return 0;
+}
+
+static int
+_bdb_fetch (mu_dbm_file_t db, struct mu_dbm_datum const *key,
+           struct mu_dbm_datum *ret)
+{
+  DBT keydat, content;
+  struct bdb_file *bdb_file = db->db_descr;
+  int rc;
+
+  memset (&keydat, 0, sizeof keydat);
+  keydat.data = key->mu_dptr;
+  keydat.size = key->mu_dsize;
+  memset (&content, 0, sizeof content);
+  content.flags = DB_DBT_MALLOC;
+  rc = bdb_file->db->get (bdb_file->db, NULL, &keydat, &content, 0);
+  mu_dbm_datum_free (ret);
+  switch (rc)
+    {
+    case 0:
+      ret->mu_dptr = content.data;
+      ret->mu_dsize = content.size;
+      ret->mu_sys = db->db_sys;
+      break;
+
+    case DB_NOTFOUND:
+      db->db_errno.n = rc;
+      rc = MU_ERR_NOENT;
+      break;
+
+    default:
+      db->db_errno.n = rc;
+      rc = MU_ERR_FAILURE;
+    }
+  return rc;
+}
+
+static int
+_bdb_store (mu_dbm_file_t db,
+           struct mu_dbm_datum const *key,
+           struct mu_dbm_datum const *contents,
+           int replace)
+{
+  struct bdb_file *bdb_file = db->db_descr;
+  int rc;
+  DBT keydat, condat;
+
+  memset (&keydat, 0, sizeof keydat);
+  keydat.data = key->mu_dptr;
+  keydat.size = key->mu_dsize;
+
+  memset (&condat, 0, sizeof condat);
+  condat.data = contents->mu_dptr;
+  condat.size = contents->mu_dsize;
+
+  rc = bdb_file->db->put (bdb_file->db, NULL, &keydat, &condat,
+                         replace ? 0 : DB_NOOVERWRITE);
+  db->db_errno.n = rc;
+  switch (rc)
+    {
+    case 0:
+      break;
+
+    case DB_KEYEXIST:
+      rc = MU_ERR_EXISTS;
+      break;
+
+    default:
+      rc = MU_ERR_FAILURE;
+      break;
+    }
+  return rc;
+}
+
+static int
+_bdb_delete (mu_dbm_file_t db, struct mu_dbm_datum const *key)
+{
+  DBT keydat;
+  struct bdb_file *bdb_file = db->db_descr;
+  int rc;
+
+  memset (&keydat, 0, sizeof keydat);
+  keydat.data = key->mu_dptr;
+  keydat.size = key->mu_dsize;
+  rc = bdb_file->db->del (bdb_file->db, NULL, &keydat, 0);
+  switch (rc)
+    {
+    case 0:
+      break;
+
+    case DB_NOTFOUND:
+      db->db_errno.n = rc;
+      rc = MU_ERR_NOENT;
+      break;
+
+    default:
+      db->db_errno.n = rc;
+      rc = MU_ERR_FAILURE;
+    }
+  return rc;
+}
+
+static int
+_bdb_firstkey (mu_dbm_file_t db, struct mu_dbm_datum *ret)
+{
+  struct bdb_file *bdb_file = db->db_descr;
+  int rc;
+  DBT key, dbt;
+
+  if (!bdb_file->dbc)
+    {
+      rc = bdb_file->db->cursor (bdb_file->db, NULL, &bdb_file->dbc
+                                BDB2_CURSOR_LASTARG);
+      if (rc)
+       {
+         db->db_errno.n = rc;
+         return MU_ERR_FAILURE;
+       }
+    }
+  memset (&key, 0, sizeof key);
+  key.flags = DB_DBT_MALLOC;
+  
+  memset (&dbt, 0, sizeof dbt);
+  dbt.flags = DB_DBT_MALLOC;
+  rc = bdb_file->dbc->c_get (bdb_file->dbc, &key, &dbt, DB_FIRST);
+  mu_dbm_datum_free (ret);
+  switch (rc)
+    {
+    case 0:
+      free (dbt.data); /* FIXME: cache it for the eventual fetch that can
+                         follow */
+      ret->mu_dptr = key.data;
+      ret->mu_dsize = key.size;
+      ret->mu_sys = db->db_sys;
+      break;
+
+    case DB_NOTFOUND:
+      db->db_errno.n = rc;
+      rc = MU_ERR_NOENT;
+      break;
+
+    default:
+      db->db_errno.n = rc;
+      rc = MU_ERR_FAILURE;
+    }
+  return rc;
+}
+
+static int
+_bdb_nextkey (mu_dbm_file_t db, struct mu_dbm_datum *ret)
+{
+  struct bdb_file *bdb_file = db->db_descr;
+  int rc;
+  DBT key, dbt;
+
+  if (!bdb_file->dbc)
+    return MU_ERR_SEQ;
+
+  memset (&key, 0, sizeof key);
+  key.flags = DB_DBT_MALLOC;
+  
+  memset (&dbt, 0, sizeof dbt);
+  dbt.flags = DB_DBT_MALLOC;
+  rc = bdb_file->dbc->c_get (bdb_file->dbc, &key, &dbt, DB_NEXT);
+  mu_dbm_datum_free (ret);
+  switch (rc)
+    {
+    case 0:
+      free (dbt.data); /* FIXME: cache it for the eventual fetch that can
+                         follow */
+      ret->mu_dptr = key.data;
+      ret->mu_dsize = key.size;
+      ret->mu_sys = db->db_sys;
+      break;
+
+    case DB_NOTFOUND:
+      db->db_errno.n = rc;
+      rc = MU_ERR_NOENT;
+      break;
+
+    default:
+      db->db_errno.n = rc;
+      rc = MU_ERR_FAILURE;
+    }
+  return rc;
+}
+
+static void
+_bdb_datum_free (struct mu_dbm_datum *datum)
+{
+  free (datum->mu_dptr);
+}
+
+static char const *
+_bdb_strerror (mu_dbm_file_t db)
+{
+  return db_strerror (db->db_errno.n);
+}
+
+struct mu_dbm_impl _mu_dbm_bdb = {
+  "bdb",
+  _bdb_file_safety,
+  _bdb_get_fd,
+  _bdb_open,
+  _bdb_close,
+  _bdb_fetch,
+  _bdb_store,
+  _bdb_delete,
+  _bdb_firstkey,
+  _bdb_nextkey,
+  _bdb_datum_free,
+  _bdb_strerror
+};
+#endif
diff --git a/lib/argp_base.c b/libmu_dbm/close.c
similarity index 72%
copy from lib/argp_base.c
copy to libmu_dbm/close.c
index e2f00f8..a84574a 100644
--- a/lib/argp_base.c
+++ b/libmu_dbm/close.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2011 Free Software Foundation, Inc.
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -18,13 +18,18 @@
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-#include <unistd.h>
-#include <string.h>
 
-char *
-__argp_base_name (const char *arg)
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
+#include <mailutils/errno.h>
+#include "mudbm.h"
+
+int
+mu_dbm_close (mu_dbm_file_t db)
 {
-  char *p = strrchr (arg, '/');
-  return (char *)(p ? p + 1 : arg);
+  DBMSYSCK (db, _dbm_close);
+  if (!db->db_descr)
+    return 0;
+  return db->db_sys->_dbm_close (db);
 }
 
diff --git a/libproto/imap/capatst.c b/libmu_dbm/create.c
similarity index 66%
copy from libproto/imap/capatst.c
copy to libmu_dbm/create.c
index 90db663..c1915a7 100644
--- a/libproto/imap/capatst.c
+++ b/libmu_dbm/create.c
@@ -1,5 +1,6 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -18,18 +19,27 @@
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-
+#include <unistd.h>
+#include <stdlib.h>
 #include <mailutils/types.h>
 #include <mailutils/list.h>
-#include <mailutils/sys/imap.h>
+#include <mailutils/url.h>
+#include <mailutils/dbm.h>
+#include <mailutils/errno.h>
+#include <mailutils/util.h>
+#include "mudbm.h"
 
 int
-mu_imap_capability_test (mu_imap_t imap, const char *name, const char **pret)
+mu_dbm_create (char *name, mu_dbm_file_t *db)
 {
   int rc;
+  mu_url_t url;
 
-  rc = mu_imap_capability (imap, 0, NULL);
+  _mu_dbm_init ();
+  rc = mu_url_create_hint (&url, name, 0, mu_dbm_hint);
   if (rc)
     return rc;
-  return mu_list_locate (imap->capa, (void*) name, (void**)pret);
+  rc = mu_dbm_create_from_url (url, db);
+  mu_url_destroy (&url);
+  return rc;
 }
diff --git a/libmailutils/cidr/match.c b/libmu_dbm/datumfree.c
similarity index 69%
copy from libmailutils/cidr/match.c
copy to libmu_dbm/datumfree.c
index dff9194..c11db26 100644
--- a/libmailutils/cidr/match.c
+++ b/libmu_dbm/datumfree.c
@@ -12,27 +12,25 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General
-   Public License along with this library.  If not, see 
+   Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-#include <mailutils/cidr.h>
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
 #include <mailutils/errno.h>
+#include "mudbm.h"
 
-int
-mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b)
+void
+mu_dbm_datum_free (struct mu_dbm_datum *datum)
 {
-  int i;
-
-  if (a->family != b->family)
-    return 1;
-  for (i = 0; i < a->len; i++)
+  if (datum && datum->mu_data &&
+      datum->mu_sys && datum->mu_sys->_dbm_datum_free)
     {
-      if (a->address[i] != (b->address[i] & a->netmask[i]))
-       return 1;
+      datum->mu_sys->_dbm_datum_free (datum);
+      datum->mu_data = NULL;
     }
-  return 0;
 }
-  
diff --git a/libmu_dbm/dbm.c b/libmu_dbm/dbm.c
new file mode 100644
index 0000000..e09cbbc
--- /dev/null
+++ b/libmu_dbm/dbm.c
@@ -0,0 +1,265 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/types.h>
+#include <mailutils/list.h>
+#include <mailutils/url.h>
+#include <mailutils/dbm.h>
+#include <mailutils/util.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/nls.h>
+#include <mailutils/mu_auth.h>
+#include "mudbm.h"
+
+static mu_list_t implist;
+mu_url_t mu_dbm_hint;
+
+static void
+_implist_free (void *p)
+{
+  struct mu_dbm_impl *impl = p;
+
+  free (impl->_dbm_name);
+  free (impl);
+}
+
+static int
+_implist_cmp (const void *a, const void *b)
+{
+  struct mu_dbm_impl const *ia = a;
+  struct mu_dbm_impl const *ib = b;
+
+  return strcmp (ia->_dbm_name, ib->_dbm_name);
+}
+
+void
+_mu_dbm_init ()
+{
+  int rc;
+
+  if (implist)
+    return;
+  
+  rc = mu_list_create (&implist);
+  if (rc)
+    {
+      mu_error (_("cannot initialize DBM subsystem: %s"),
+               mu_strerror (rc));
+      abort ();
+    }
+  mu_list_set_destroy_item (implist, _implist_free);
+  mu_list_set_comparator (implist, _implist_cmp);
+  /* Add built-in entries */
+#ifdef WITH_GDBM
+  mu_dbm_register (&_mu_dbm_gdbm);
+#endif
+#ifdef WITH_BDB
+  mu_dbm_register (&_mu_dbm_bdb);
+#endif
+#ifdef WITH_NDBM
+  mu_dbm_register (&_mu_dbm_ndbm);
+#endif
+#ifdef WITH_TOKYOCABINET
+  mu_dbm_register (&_mu_dbm_tokyokabinet);
+#endif
+  if (!mu_dbm_hint)
+    {
+      struct mu_dbm_impl *impl;
+      char *urlbuf;
+      
+      rc = mu_list_get (implist, 0, (void**) &impl);
+      if (rc)
+       {
+         mu_error (_("cannot initialize DBM hint: %s"),
+                   mu_strerror (rc));
+         abort ();
+       }
+      urlbuf = malloc (strlen (impl->_dbm_name) + 4);
+      if (urlbuf)
+       {
+         strcpy (urlbuf, impl->_dbm_name);
+         strcat (urlbuf, "://");
+         rc = mu_url_create (&mu_dbm_hint, urlbuf);
+         free (urlbuf);
+       }
+      else
+       rc = ENOMEM;
+         
+      if (rc)
+       {
+         mu_error (_("cannot initialize DBM hint: %s"),
+                     mu_strerror (rc));
+         abort ();
+       }
+    }
+}
+
+int
+mu_dbm_register (struct mu_dbm_impl *impl)
+{
+  int rc;
+  struct mu_dbm_impl *ptr;
+
+  _mu_dbm_init ();
+  ptr = calloc (1, sizeof (*ptr));
+  if (!ptr)
+    return ENOMEM;
+  *ptr = *impl;
+  ptr->_dbm_name = strdup (impl->_dbm_name);
+  if (!ptr->_dbm_name)
+    {
+      free (ptr);
+      return ENOMEM;
+    }
+  rc = mu_list_append (implist, ptr);
+  if (rc)
+    _implist_free (ptr);
+  return rc;
+}
+
+int
+mu_dbm_create_from_url (mu_url_t url, mu_dbm_file_t *db)
+{
+  mu_dbm_file_t p;
+  int flags;
+  int rc;
+  const char *db_name;
+  struct mu_dbm_impl impl_key;
+  struct mu_dbm_impl *impl;
+  struct mu_auth_data *auth;
+  int safety_flags = 0;
+  uid_t owner_uid = getuid ();
+
+  _mu_dbm_init ();
+  
+  mu_url_get_flags (url, &flags);
+  if ((flags & (MU_URL_HOST | MU_URL_PATH)) == (MU_URL_HOST | MU_URL_PATH))
+    return MU_ERR_URL_EXTRA_PARTS;
+  if (flags & MU_URL_HOST)
+    rc = mu_url_sget_host (url, &db_name);
+  else
+    rc = mu_url_sget_path (url, &db_name);
+  if (rc)
+    return rc;
+  
+  rc = mu_url_sget_scheme (url, (const char**)&impl_key._dbm_name);
+  if (rc)
+    return rc;
+  
+  rc = mu_list_locate (implist, (void *) &impl_key, (void **) &impl);
+  if (rc)
+    return rc;
+
+  if (flags & MU_URL_PARAM)
+    {
+      size_t fvc, i;
+      char **fvp;
+
+      mu_url_sget_fvpairs (url, &fvc, &fvp);
+      for (i = 0; i < fvc; i++)
+       {
+         const char *name = fvp[i];
+         int negate = 0;
+         int val;
+
+         if (*name == '-')
+           {
+             negate = 1;
+             name++;
+           }
+         else if (*name == '+')
+           name++;
+
+         if (strncmp (name, "owner", 5) == 0)
+           {
+             val = MU_FILE_SAFETY_OWNER_MISMATCH;
+             if (name[5] == '=')
+               {
+                 auth = mu_get_auth_by_name (name + 6);
+                 if (!auth)
+                   {
+                     char *end;
+                     unsigned long uid;
+
+                     errno = 0;
+                     uid = strtoul (name + 6, &end, 0);
+                     if (*end || errno)
+                       return MU_ERR_NO_SUCH_USER;
+                     auth = mu_get_auth_by_uid (uid);
+                     if (!auth)
+                       return MU_ERR_NO_SUCH_USER;
+                     owner_uid = auth->uid;
+                     mu_auth_data_free (auth);
+                   }
+               }
+             else if (name[5])
+               return MU_ERR_URL_EXTRA_PARTS;//FIXME: better error code
+           }
+         else if (strcmp (name, "none") == 0)
+           {
+             safety_flags = negate ? MU_FILE_SAFETY_ALL : MU_FILE_SAFETY_NONE;
+             continue;
+           }
+         else if (strcmp (name, "all") == 0)
+           {
+             safety_flags = negate ? MU_FILE_SAFETY_NONE : MU_FILE_SAFETY_ALL;
+             continue;
+           }
+         else if (strcmp (name, "default") == 0)
+           {
+             val = DEFAULT_DBM_SAFETY_FLAGS;
+           }
+         else if (mu_file_safety_name_to_code (name, &val))
+           return MU_ERR_URL_EXTRA_PARTS;//FIXME: better error code
+
+         if (negate)
+           safety_flags &= ~val;
+         else
+           safety_flags |= val;
+       }
+    }
+
+  p = calloc (1, sizeof (*p));
+  if (!p)
+    return ENOMEM;
+  p->db_name = strdup (db_name);
+  if (!p->db_name)
+    {
+      free (p);
+      return ENOMEM;
+    }
+  p->db_safety_flags = safety_flags;
+  p->db_owner = owner_uid;
+  p->db_sys = impl;
+
+  *db = p;
+  return 0;
+}
+
+int
+mu_dbm_impl_iterator (mu_iterator_t *itr)
+{
+  _mu_dbm_init ();
+  return mu_list_get_iterator (implist, itr);
+}
diff --git a/libmailutils/cidr/match.c b/libmu_dbm/delete.c
similarity index 71%
copy from libmailutils/cidr/match.c
copy to libmu_dbm/delete.c
index dff9194..f36f875 100644
--- a/libmailutils/cidr/match.c
+++ b/libmu_dbm/delete.c
@@ -12,27 +12,24 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General
-   Public License along with this library.  If not, see 
+   Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-#include <mailutils/cidr.h>
+
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
 #include <mailutils/errno.h>
+#include "mudbm.h"
 
 int
-mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b)
+mu_dbm_delete (mu_dbm_file_t db, struct mu_dbm_datum const *key)
 {
-  int i;
-
-  if (a->family != b->family)
-    return 1;
-  for (i = 0; i < a->len; i++)
-    {
-      if (a->address[i] != (b->address[i] & a->netmask[i]))
-       return 1;
-    }
-  return 0;
+  DBMSYSCK (db, _dbm_delete);
+  if (!db->db_descr)
+    return EINVAL;
+  return db->db_sys->_dbm_delete (db, key);
 }
-  
+
diff --git a/libmailutils/cidr/match.c b/libmu_dbm/destroy.c
similarity index 70%
copy from libmailutils/cidr/match.c
copy to libmu_dbm/destroy.c
index dff9194..c96966d 100644
--- a/libmailutils/cidr/match.c
+++ b/libmu_dbm/destroy.c
@@ -12,27 +12,28 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General
-   Public License along with this library.  If not, see 
+   Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-#include <mailutils/cidr.h>
+#include <stdlib.h>
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
 #include <mailutils/errno.h>
+#include "mudbm.h"
 
-int
-mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b)
+void
+mu_dbm_destroy (mu_dbm_file_t *pdb)
 {
-  int i;
-
-  if (a->family != b->family)
-    return 1;
-  for (i = 0; i < a->len; i++)
+  if (pdb && *pdb)
     {
-      if (a->address[i] != (b->address[i] & a->netmask[i]))
-       return 1;
+      mu_dbm_file_t db = *pdb;
+      if (db->db_descr)
+       mu_dbm_close (db);
+      free (db->db_name);
+      free (db);
+      *pdb = NULL;
     }
-  return 0;
 }
-  
diff --git a/libmailutils/sockaddr/unlink.c b/libmu_dbm/errstr.c
similarity index 67%
copy from libmailutils/sockaddr/unlink.c
copy to libmu_dbm/errstr.c
index 65808f5..f1cb372 100644
--- a/libmailutils/sockaddr/unlink.c
+++ b/libmu_dbm/errstr.c
@@ -12,34 +12,26 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General
-   Public License along with this library.  If not, see 
+   Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-
 #include <stdlib.h>
-#include <mailutils/sockaddr.h>
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
+#include <mailutils/errno.h>
+#include "mudbm.h"
 
-struct mu_sockaddr *
-mu_sockaddr_unlink (struct mu_sockaddr *addr)
+char const *
+mu_dbm_strerror (mu_dbm_file_t db)
 {
-  struct mu_sockaddr *p;
-
-  if (!addr)
+  if (!db)
     return NULL;
-
-  p = addr->prev;
-  if (p)
-    p->next = addr->next;
-  
-  p = addr->next;
-  if (p)
-    p->prev = addr->prev;
-
-  addr->prev = addr->next = NULL;
-  
-  return p;
+  if (!db->db_sys || !db->db_sys->_dbm_strerror)
+    return NULL;
+  if (!db->db_descr)
+    return mu_strerror (MU_ERR_NOT_OPEN);
+  return db->db_sys->_dbm_strerror (db);
 }
-
diff --git a/libproto/imap/capatst.c b/libmu_dbm/fetch.c
similarity index 70%
copy from libproto/imap/capatst.c
copy to libmu_dbm/fetch.c
index 90db663..772bb97 100644
--- a/libproto/imap/capatst.c
+++ b/libmu_dbm/fetch.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2011 Free Software Foundation, Inc.
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -20,16 +20,17 @@
 #endif
 
 #include <mailutils/types.h>
-#include <mailutils/list.h>
-#include <mailutils/sys/imap.h>
+#include <mailutils/dbm.h>
+#include <mailutils/errno.h>
+#include "mudbm.h"
 
 int
-mu_imap_capability_test (mu_imap_t imap, const char *name, const char **pret)
+mu_dbm_fetch (mu_dbm_file_t db, struct mu_dbm_datum const *key,
+             struct mu_dbm_datum *ret)
 {
-  int rc;
-
-  rc = mu_imap_capability (imap, 0, NULL);
-  if (rc)
-    return rc;
-  return mu_list_locate (imap->capa, (void*) name, (void**)pret);
+  DBMSYSCK (db, _dbm_fetch);
+  if (!db->db_descr)
+    return EINVAL;
+  return db->db_sys->_dbm_fetch (db, key, ret);
 }
+
diff --git a/libmailutils/cidr/match.c b/libmu_dbm/firstkey.c
similarity index 71%
copy from libmailutils/cidr/match.c
copy to libmu_dbm/firstkey.c
index dff9194..d45f9c8 100644
--- a/libmailutils/cidr/match.c
+++ b/libmu_dbm/firstkey.c
@@ -12,27 +12,23 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General
-   Public License along with this library.  If not, see 
+   Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-#include <mailutils/cidr.h>
+
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
 #include <mailutils/errno.h>
+#include "mudbm.h"
 
 int
-mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b)
+mu_dbm_firstkey (mu_dbm_file_t db, struct mu_dbm_datum *ret)
 {
-  int i;
-
-  if (a->family != b->family)
-    return 1;
-  for (i = 0; i < a->len; i++)
-    {
-      if (a->address[i] != (b->address[i] & a->netmask[i]))
-       return 1;
-    }
-  return 0;
+  DBMSYSCK (db, _dbm_firstkey);
+  if (!db->db_descr)
+    return EINVAL;
+  return db->db_sys->_dbm_firstkey (db, ret);
 }
-  
diff --git a/libmu_dbm/gdbm.c b/libmu_dbm/gdbm.c
new file mode 100644
index 0000000..84defcc
--- /dev/null
+++ b/libmu_dbm/gdbm.c
@@ -0,0 +1,290 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
+#include <mailutils/util.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/stream.h>
+#include "mudbm.h"
+
+#if defined(WITH_GDBM)
+#include <gdbm.h>
+
+struct gdbm_descr
+{
+  GDBM_FILE file;           /* GDBM file */
+  datum prev;               /* Previous key for sequential access */
+};
+
+static int
+_gdbm_file_safety (mu_dbm_file_t db, int mode, uid_t owner)
+{
+  return mu_file_safety_check (db->db_name, mode, owner, NULL);
+}
+
+int
+_gdbm_get_fd (mu_dbm_file_t db, int *pag, int *dir)
+{
+  struct gdbm_descr *gd = db->db_descr;
+  *pag = gdbm_fdesc (gd->file);
+  if (dir)
+    *dir = *pag;
+  return 0;
+}
+
+static int
+_gdbm_open (mu_dbm_file_t db, int flags, int mode)
+{
+  int f;
+  struct gdbm_descr *gd;
+  GDBM_FILE file;
+  
+  switch (flags)
+    {
+    case MU_STREAM_CREAT:
+      f = GDBM_NEWDB;
+      break;
+      
+    case MU_STREAM_READ:
+      f = GDBM_READER;
+      break;
+      
+    case MU_STREAM_RDWR:
+      f = GDBM_WRCREAT;
+      break;
+      
+    default:
+      return EINVAL;
+    }
+  file = gdbm_open (db->db_name, 512, f, mode, NULL);
+  if (!file)
+    return MU_ERR_FAILURE;
+  gd = calloc (1, sizeof (*gd));
+  gd->file = file;
+  db->db_descr = gd;
+  return 0;
+}
+
+static int
+_gdbm_close (mu_dbm_file_t db)
+{
+  if (db->db_descr)
+    {
+      struct gdbm_descr *gd = db->db_descr;
+      gdbm_close (gd->file);
+      free (gd);
+      db->db_descr = NULL;
+    }
+  return 0;
+}
+
+static int
+_gdbm_conv_datum (mu_dbm_file_t db, struct mu_dbm_datum *ret, datum content,
+                 int copy)
+{
+  if (copy)
+    {
+      ret->mu_dptr = malloc (content.dsize);
+      if (!ret->mu_dptr)
+       return errno;
+      memcpy (ret->mu_dptr, content.dptr, content.dsize);
+    }
+  else
+    {
+      ret->mu_dptr = content.dptr;
+    }
+  ret->mu_dsize = content.dsize;
+  ret->mu_sys = db->db_sys;
+  return 0;
+}
+
+static int
+_gdbm_fetch (mu_dbm_file_t db, struct mu_dbm_datum const *key,
+            struct mu_dbm_datum *ret)
+{
+  struct gdbm_descr *gd = db->db_descr;
+  int rc;
+  datum keydat, content;
+
+  keydat.dptr = key->mu_dptr;
+  keydat.dsize = key->mu_dsize;
+  gdbm_errno = 0;
+  content = gdbm_fetch (gd->file, keydat);
+  if (content.dptr == NULL)
+    {
+      if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
+       return MU_ERR_NOENT;
+      else
+       {
+         db->db_errno.n = gdbm_errno;
+         return MU_ERR_FAILURE;
+       }
+    }
+  mu_dbm_datum_free (ret);
+  rc = _gdbm_conv_datum (db, ret, content, 1);
+  if (rc)
+    {
+      free (content.dptr);
+      return rc;
+    }
+  return 0;
+}
+
+static int
+_gdbm_store (mu_dbm_file_t db,
+            struct mu_dbm_datum const *key,
+            struct mu_dbm_datum const *contents,
+            int replace)
+{
+  struct gdbm_descr *gd = db->db_descr;
+  datum keydat, condat;
+
+  keydat.dptr = key->mu_dptr;
+  keydat.dsize = key->mu_dsize;
+  condat.dptr = contents->mu_dptr;
+  condat.dsize = contents->mu_dsize;
+  switch (gdbm_store (gd->file, keydat, condat, replace))
+    {
+    case 0:
+      break;
+      
+    case 1:
+      return MU_ERR_EXISTS;
+      
+    case -1:
+      db->db_errno.n = gdbm_errno;
+      return MU_ERR_FAILURE;
+    }
+  return 0;
+}
+
+static int
+_gdbm_delete (mu_dbm_file_t db, struct mu_dbm_datum const *key)
+{
+  struct gdbm_descr *gd = db->db_descr;
+  datum keydat;
+
+  keydat.dptr = key->mu_dptr;
+  keydat.dsize = key->mu_dsize;
+  gdbm_errno = 0;
+  if (gdbm_delete (gd->file, keydat))
+    {
+      if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
+       return MU_ERR_NOENT;
+      else
+       {
+         db->db_errno.n = gdbm_errno;
+         return MU_ERR_FAILURE;
+       }
+    }
+  return 0;
+}
+
+static int
+_gdbm_firstkey (mu_dbm_file_t db, struct mu_dbm_datum *ret)
+{
+  struct gdbm_descr *gd = db->db_descr;
+  int rc;
+  datum key = gdbm_firstkey (gd->file);
+  if (key.dptr == NULL)
+    {
+      if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
+       return MU_ERR_NOENT;
+      else
+       {
+         db->db_errno.n = gdbm_errno;
+         return MU_ERR_FAILURE;
+       }
+    }
+  mu_dbm_datum_free (ret);
+  rc = _gdbm_conv_datum (db, ret, key, 0);
+  if (rc)
+    {
+      free (key.dptr);
+      return rc;
+    }
+  free (gd->prev.dptr);
+  gd->prev = key;
+  return 0;
+}
+
+static int
+_gdbm_nextkey (mu_dbm_file_t db, struct mu_dbm_datum *ret)
+{
+  struct gdbm_descr *gd = db->db_descr;
+  int rc;
+  datum key;
+
+  if (!gd->prev.dptr)
+    return MU_ERR_NOENT;
+  key = gdbm_nextkey (gd->file, gd->prev);
+  if (key.dptr == NULL)
+    {
+      if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
+       return MU_ERR_NOENT;
+      else
+       {
+         db->db_errno.n = gdbm_errno;
+         return MU_ERR_FAILURE;
+       }
+    }
+  mu_dbm_datum_free (ret);
+  rc = _gdbm_conv_datum (db, ret, key, 0);
+  if (rc)
+    {
+      free (key.dptr);
+      return rc;
+    }
+  free (gd->prev.dptr);
+  gd->prev = key;
+  return 0;
+}
+
+static void
+_gdbm_datum_free (struct mu_dbm_datum *datum)
+{
+  free (datum->mu_dptr);
+}
+
+static char const *
+_gdbm_strerror (mu_dbm_file_t db)
+{
+  return gdbm_strerror (db->db_errno.n);
+}
+
+struct mu_dbm_impl _mu_dbm_gdbm = {
+  "gdbm",
+  _gdbm_file_safety,
+  _gdbm_get_fd,
+  _gdbm_open,
+  _gdbm_close,
+  _gdbm_fetch,
+  _gdbm_store,
+  _gdbm_delete,
+  _gdbm_firstkey,
+  _gdbm_nextkey,
+  _gdbm_datum_free,
+  _gdbm_strerror
+};
+#endif
diff --git a/libmailutils/cidr/match.c b/libmu_dbm/getfd.c
similarity index 71%
copy from libmailutils/cidr/match.c
copy to libmu_dbm/getfd.c
index dff9194..2eafe9e 100644
--- a/libmailutils/cidr/match.c
+++ b/libmu_dbm/getfd.c
@@ -12,27 +12,23 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General
-   Public License along with this library.  If not, see 
+   Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-#include <mailutils/cidr.h>
+
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
 #include <mailutils/errno.h>
+#include "mudbm.h"
 
 int
-mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b)
+mu_dbm_get_fd (mu_dbm_file_t db, int *pag, int *dir)
 {
-  int i;
-
-  if (a->family != b->family)
-    return 1;
-  for (i = 0; i < a->len; i++)
-    {
-      if (a->address[i] != (b->address[i] & a->netmask[i]))
-       return 1;
-    }
-  return 0;
+  DBMSYSCK (db, _dbm_get_fd);
+  if (!db->db_descr || !pag)
+    return EINVAL;
+  return db->db_sys->_dbm_get_fd (db, pag, dir);
 }
-  
diff --git a/libproto/nntp/url.c b/libmu_dbm/mudbm.h
similarity index 52%
copy from libproto/nntp/url.c
copy to libmu_dbm/mudbm.h
index aab0566..98c2750 100644
--- a/libproto/nntp/url.c
+++ b/libmu_dbm/mudbm.h
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2004, 2007, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2011 Free Software Foundation, Inc.
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -15,36 +15,34 @@
    Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#ifdef ENABLE_NNTP
+#include <mailutils/sys/dbm.h>
 
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
+#define DBMSYSCK(db,meth) do                                   \
+    {                                                          \
+      if (!(db))                                               \
+       return EINVAL;                                          \
+      if (!(db)->db_descr)                                     \
+       return MU_ERR_NOT_OPEN;                                 \
+      if (!(db)->db_sys || !(db)->db_sys->meth)                        \
+       return ENOSYS;                                          \
+    }                                                          \
+  while (0)
 
-#include <mailutils/nntp.h>
+#define DEFAULT_DBM_SAFETY_FLAGS MU_FILE_SAFETY_ALL
 
-#include <mailutils/sys/url.h>
-
-/*
-  POP URL:
-  nntp://<host>:<port>/<newsgroup-name>/<article-number>
-*/
+#ifdef WITH_GDBM
+extern struct mu_dbm_impl _mu_dbm_gdbm;
+#endif
+#ifdef WITH_BDB
+extern struct mu_dbm_impl _mu_dbm_bdb;
+#endif
+#ifdef WITH_NDBM
+extern struct mu_dbm_impl _mu_dbm_ndbm;
+#endif
+#ifdef WITH_TOKYOCABINET
+extern struct mu_dbm_impl _mu_dbm_tokyokabinet;
+#endif
 
-int
-_nntp_url_init (mu_url_t url)
-{
-  if (url->port == 0)
-    url->port = MU_NNTP_DEFAULT_PORT;
+void _mu_dbm_init (void);
 
-  return status;
-}
 
-#endif
diff --git a/libmu_dbm/ndbm.c b/libmu_dbm/ndbm.c
new file mode 100644
index 0000000..7ccd4cd
--- /dev/null
+++ b/libmu_dbm/ndbm.c
@@ -0,0 +1,244 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General
+   Public License along with this library.  If not, see
+   <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
+#include <mailutils/util.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/stream.h>
+#include <mailutils/io.h>
+#include "mudbm.h"
+
+#if defined(WITH_NDBM)
+#include <ndbm.h>
+
+static int
+_ndbm_file_safety (mu_dbm_file_t db, int mode, uid_t owner)
+{
+  int rc;
+  char *name;
+  
+  rc = mu_asprintf (&name, "%s.pag", db->db_name);
+  if (rc)
+    return rc;
+  rc = mu_file_safety_check (name, mode, owner, NULL);
+  if (rc)
+    {
+      free (name);
+      return rc;
+    }
+
+  strcpy (name + strlen (name) - 3, "dir");
+  rc = mu_file_safety_check (name, mode, owner, NULL);
+  free (name);
+  return rc;
+}
+
+int
+_ndbm_get_fd (mu_dbm_file_t db, int *pag, int *dir)
+{
+  DBM *dbm = db->db_descr;
+  *pag = dbm_pagfno (dbm);
+  if (dir)
+    *dir = dbm_dirfno (dbm);
+  return 0;
+}
+
+static int
+_ndbm_open (mu_dbm_file_t db, int flags, int mode)
+{
+  int f;
+  DBM *dbm;
+  
+  switch (flags)
+    {
+    case MU_STREAM_CREAT:
+      f = O_CREAT|O_TRUNC|O_RDWR;
+      break;
+      
+    case MU_STREAM_READ:
+      f = O_RDONLY;
+      break;
+      
+    case MU_STREAM_RDWR:
+      f = O_CREAT|O_RDWR;
+      break;
+      
+    default:
+      errno = EINVAL;
+      return -1;
+    }
+  dbm = dbm_open (db->db_name, f, mode);
+  if (!dbm)
+    return MU_ERR_FAILURE;
+  db->db_descr = dbm;
+  return 0;
+}
+
+static int
+_ndbm_close (mu_dbm_file_t db)
+{
+  if (db->db_descr)
+    {
+      dbm_close ((DBM *) db->db_descr);
+      db->db_descr = NULL;
+    }
+  return 0;
+}
+
+static int
+_ndbm_conv_datum (mu_dbm_file_t db, struct mu_dbm_datum *ret, datum content)
+{
+  ret->mu_dptr = malloc (content.dsize);
+  if (!ret->mu_dptr)
+    return errno;
+  memcpy (ret->mu_dptr, content.dptr, content.dsize);
+  ret->mu_dsize = content.dsize;
+  ret->mu_sys = db->db_sys;
+  return 0;
+}
+
+static int
+_ndbm_fetch (mu_dbm_file_t db, struct mu_dbm_datum const *key,
+            struct mu_dbm_datum *ret)
+{
+  datum keydat, content;
+
+  keydat.dptr = key->mu_dptr;
+  keydat.dsize = key->mu_dsize;
+  errno = 0;
+  content = dbm_fetch (db->db_descr, keydat);
+  mu_dbm_datum_free (ret);
+  if (content.dptr == NULL)
+    return MU_ERR_NOENT;
+  return _ndbm_conv_datum (db, ret, content);
+}
+
+static int
+_ndbm_store (mu_dbm_file_t db,
+            struct mu_dbm_datum const *key,
+            struct mu_dbm_datum const *contents,
+            int replace)
+{
+  DBM *dbm = db->db_descr;
+  datum keydat, condat;
+  
+  keydat.dptr = key->mu_dptr;
+  keydat.dsize = key->mu_dsize;
+  condat.dptr = contents->mu_dptr;
+  condat.dsize = contents->mu_dsize;
+  errno = 0;
+  switch (dbm_store (dbm, keydat, condat,
+                    replace ? DBM_REPLACE : DBM_INSERT))
+    {
+    case 0:
+      break;
+      
+    case 1:
+      return MU_ERR_EXISTS;
+      
+    case -1:
+      db->db_errno.n = errno;
+      return MU_ERR_FAILURE;
+    }
+  return 0;
+}
+
+static int
+_ndbm_delete (mu_dbm_file_t db, struct mu_dbm_datum const *key)
+{
+  DBM *dbm = db->db_descr;
+  datum keydat;
+
+  keydat.dptr = key->mu_dptr;
+  keydat.dsize = key->mu_dsize;
+  errno = 0;
+  switch (dbm_delete (dbm, keydat))
+    {
+    case 0:
+      break;
+      
+    case 1:
+      return MU_ERR_NOENT;
+      
+    case -1:
+      db->db_errno.n = errno;
+      return MU_ERR_FAILURE;
+    }
+  return 0;
+}
+
+static int
+_ndbm_firstkey (mu_dbm_file_t db, struct mu_dbm_datum *ret)
+{
+  DBM *dbm = db->db_descr;
+  datum keydat;
+
+  errno = 0;
+  keydat = dbm_firstkey (dbm);
+  if (keydat.dptr == NULL)
+    return MU_ERR_NOENT;
+  return _ndbm_conv_datum (db, ret, keydat);
+}
+
+static int
+_ndbm_nextkey (mu_dbm_file_t db, struct mu_dbm_datum *ret)
+{
+  DBM *dbm = db->db_descr;
+  datum keydat;
+
+  keydat = dbm_nextkey (dbm);
+  if (keydat.dptr == NULL)
+    return MU_ERR_NOENT;
+  return _ndbm_conv_datum (db, ret, keydat);
+}
+
+static void
+_ndbm_datum_free (struct mu_dbm_datum *datum)
+{
+  free (datum->mu_dptr);
+}
+
+static char const *
+_ndbm_strerror (mu_dbm_file_t db)
+{
+  return strerror (db->db_errno.n);
+}
+
+struct mu_dbm_impl _mu_dbm_ndbm = {
+  "ndbm",
+  _ndbm_file_safety,
+  _ndbm_get_fd,
+  _ndbm_open,
+  _ndbm_close,
+  _ndbm_fetch,
+  _ndbm_store,
+  _ndbm_delete,
+  _ndbm_firstkey,
+  _ndbm_nextkey,
+  _ndbm_datum_free,
+  _ndbm_strerror
+};
+  
+#endif
diff --git a/libmailutils/cidr/match.c b/libmu_dbm/nextkey.c
similarity index 71%
copy from libmailutils/cidr/match.c
copy to libmu_dbm/nextkey.c
index dff9194..c7a818f 100644
--- a/libmailutils/cidr/match.c
+++ b/libmu_dbm/nextkey.c
@@ -12,27 +12,23 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General
-   Public License along with this library.  If not, see 
+   Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-#include <mailutils/cidr.h>
+
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
 #include <mailutils/errno.h>
+#include "mudbm.h"
 
 int
-mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b)
+mu_dbm_nextkey (mu_dbm_file_t db, struct mu_dbm_datum *ret)
 {
-  int i;
-
-  if (a->family != b->family)
-    return 1;
-  for (i = 0; i < a->len; i++)
-    {
-      if (a->address[i] != (b->address[i] & a->netmask[i]))
-       return 1;
-    }
-  return 0;
+  DBMSYSCK (db, _dbm_nextkey);
+  if (!db->db_descr)
+    return EINVAL;
+  return db->db_sys->_dbm_nextkey (db, ret);
 }
-  
diff --git a/libmailutils/cidr/match.c b/libmu_dbm/open.c
similarity index 71%
copy from libmailutils/cidr/match.c
copy to libmu_dbm/open.c
index dff9194..5dd4175 100644
--- a/libmailutils/cidr/match.c
+++ b/libmu_dbm/open.c
@@ -12,27 +12,25 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General
-   Public License along with this library.  If not, see 
+   Public License along with this library.  If not, see
    <http://www.gnu.org/licenses/>. */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
-#include <mailutils/cidr.h>
+
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
 #include <mailutils/errno.h>
+#include "mudbm.h"
 
 int
-mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b)
+mu_dbm_open (mu_dbm_file_t db, int flags, int mode)
 {
-  int i;
-
-  if (a->family != b->family)
-    return 1;
-  for (i = 0; i < a->len; i++)
-    {
-      if (a->address[i] != (b->address[i] & a->netmask[i]))
-       return 1;
-    }
-  return 0;
+  if (!db)
+    return EINVAL;
+  if (!db->db_sys || !db->db_sys->_dbm_open)
+    return ENOSYS;
+  return db->db_sys->_dbm_open (db, flags, mode);
 }
-  
+
diff --git a/libproto/imap/create.c b/libmu_dbm/safety.c
similarity index 52%
copy from libproto/imap/create.c
copy to libmu_dbm/safety.c
index e3d9901..411a6b8 100644
--- a/libproto/imap/create.c
+++ b/libmu_dbm/safety.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2011 Free Software Foundation, Inc.
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -19,49 +19,54 @@
 # include <config.h>
 #endif
 
-#include <stdlib.h>
-#include <errno.h>
+#include <mailutils/types.h>
+#include <mailutils/dbm.h>
 #include <mailutils/errno.h>
-#include <mailutils/sys/imap.h>
-#include <mailutils/list.h>
+#include "mudbm.h"
 
 int
-mu_imap_create (mu_imap_t *pimap)
+mu_dbm_safety_set_owner (mu_dbm_file_t db, uid_t uid)
 {
-  mu_imap_t imap;
-
-  /* Sanity check.  */
-  if (pimap == NULL)
+  if (!db)
     return EINVAL;
+  db->db_owner = uid;
+  return 0;
+}
 
-  imap = calloc (1, sizeof *imap);
-  if (imap == NULL)
-    return ENOMEM;
-
-  _mu_imap_init (imap);
+int
+mu_dbm_safety_get_owner (mu_dbm_file_t db, uid_t *uid)
+{
+  if (!db)
+    return EINVAL;
+  *uid = db->db_owner;
+  return 0;
+}
 
-  *pimap = imap;
+int
+mu_dbm_safety_set_flags (mu_dbm_file_t db, int flags)
+{
+  if (!db)
+    return EINVAL;
+  db->db_safety_flags = flags;
   return 0;
 }
 
 int
-_mu_imap_init (mu_imap_t imap)
+mu_dbm_safety_get_flags (mu_dbm_file_t db, int *flags)
 {
-  if (imap == NULL)
+  if (!db)
     return EINVAL;
-  if (imap->carrier == 0)
-    {
-      int rc;
-      
-      if (imap->untagged_resp)
-       mu_list_clear (imap->untagged_resp);
-      mu_list_destroy (&imap->capa);
-      _mu_imap_clrerrstr (imap);
-      rc = _mu_imap_tag_clr (imap);
-      imap->flags = 0;
-      if (rc)
-       return rc;
-    }
-  imap->state = MU_IMAP_NO_STATE; /* Init with no state.  */
+  *flags = db->db_safety_flags;
   return 0;
 }
+  
+int
+mu_dbm_safety_check (mu_dbm_file_t db)
+{
+  if (!db)
+    return EINVAL;
+  if (!db->db_sys || !db->db_sys->_dbm_file_safety)
+    return ENOSYS;
+  return db->db_sys->_dbm_file_safety (db, db->db_safety_flags,
+                                      db->db_owner);
+}
diff --git a/libproto/imap/capatst.c b/libmu_dbm/store.c
similarity index 68%
copy from libproto/imap/capatst.c
copy to libmu_dbm/store.c
index 90db663..a80a0af 100644
--- a/libproto/imap/capatst.c
+++ b/libmu_dbm/store.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2011 Free Software Foundation, Inc.
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -20,16 +20,16 @@
 #endif
 
 #include <mailutils/types.h>
-#include <mailutils/list.h>
-#include <mailutils/sys/imap.h>
+#include <mailutils/dbm.h>
+#include <mailutils/errno.h>
+#include "mudbm.h"
 
 int
-mu_imap_capability_test (mu_imap_t imap, const char *name, const char **pret)
+mu_dbm_store (mu_dbm_file_t db, struct mu_dbm_datum const *key,
+             struct mu_dbm_datum const *contents, int replace)
 {
-  int rc;
-
-  rc = mu_imap_capability (imap, 0, NULL);
-  if (rc)
-    return rc;
-  return mu_list_locate (imap->capa, (void*) name, (void**)pret);
+  DBMSYSCK (db, _dbm_store);
+  if (!db->db_descr)
+    return EINVAL;
+  return db->db_sys->_dbm_store (db, key, contents, replace);
 }
diff --git a/libmu_sieve/extensions/spamd.c b/libmu_sieve/extensions/spamd.c
index 58d95ee..a5c8116 100644
--- a/libmu_sieve/extensions/spamd.c
+++ b/libmu_sieve/extensions/spamd.c
@@ -248,7 +248,7 @@ spamd_read_line (mu_sieve_machine_t mach, mu_stream_t 
stream,
   size_t n;
   int rc = mu_stream_getline (stream, pbuffer, psize, &n);
   if (rc == 0)
-    mu_rtrim_cset (*pbuffer, "\r\n");
+    mu_rtrim_class (*pbuffer, MU_CTYPE_ENDLN);
   else
     {
       /* FIXME: Need an 'onabort' mechanism in Sieve machine, which
diff --git a/libmu_sieve/extensions/vacation.c 
b/libmu_sieve/extensions/vacation.c
index c255fb4..160930f 100644
--- a/libmu_sieve/extensions/vacation.c
+++ b/libmu_sieve/extensions/vacation.c
@@ -36,7 +36,6 @@
 #include <string.h>
 #include <signal.h>
 #include <regex.h>
-#include <mu_dbm.h>
 #include <mailutils/sieve.h>
 #include <mailutils/mu_auth.h>
 
diff --git a/libproto/mailer/smtp_io.c b/libproto/mailer/smtp_io.c
index a623141..f6062ad 100644
--- a/libproto/mailer/smtp_io.c
+++ b/libproto/mailer/smtp_io.c
@@ -68,7 +68,7 @@ mu_smtp_response (mu_smtp_t smtp)
   MU_SMTP_CHECK_ERROR (smtp, rc);
   if (n == 0)
     MU_SMTP_CHECK_ERROR (smtp, EIO);
-  n = mu_rtrim_cset (smtp->rdbuf, "\r\n");
+  n = mu_rtrim_class (smtp->rdbuf, MU_CTYPE_ENDLN);
   if (n < 3 || !mu_isdigit (smtp->rdbuf[0]))
     {
       mu_diag_output (MU_DIAG_NOTICE,
@@ -101,7 +101,7 @@ mu_smtp_response (mu_smtp_t smtp)
          MU_SMTP_CHECK_ERROR (smtp, rc);
          if (n == 0)
            MU_SMTP_CHECK_ERROR (smtp, EIO);
-         n = mu_rtrim_cset (smtp->rdbuf, "\r\n");
+         n = mu_rtrim_class (smtp->rdbuf, MU_CTYPE_ENDLN);
          if (n < 3 || memcmp (smtp->rdbuf, smtp->replcode, 3))
            {
              mu_diag_output (MU_DIAG_NOTICE,
diff --git a/libproto/mbox/mbox.c b/libproto/mbox/mbox.c
index b8b13db..7e65b88 100644
--- a/libproto/mbox/mbox.c
+++ b/libproto/mbox/mbox.c
@@ -28,6 +28,7 @@
 #include <mailutils/cstr.h>
 #include <mailutils/io.h>
 #include <mailutils/filter.h>
+#include <mailutils/cctype.h>
 
 #define ATTRIBUTE_IS_DELETED(flag)        (flag & MU_ATTRIBUTE_DELETED)
 #define ATTRIBUTE_IS_EQUAL(flag1, flag2)  (flag1 == flag2)
@@ -381,7 +382,7 @@ mbox_envelope_date (mu_envelope_t envelope, char *buf, 
size_t len,
                               &n);
   if (status)
     return status;
-  mu_rtrim_cset (buffer, "\r\n");
+  mu_rtrim_class (buffer, MU_CTYPE_ENDLN);
   
   /* Format:  "From [sender] [date]" */
   /* strlen ("From ") == 5 */
@@ -938,7 +939,7 @@ msg_envelope_to_stream (mu_stream_t out, mu_message_t msg)
       return status;
     }
 
-  mu_rtrim_cset (datestr, "\r\n");
+  mu_rtrim_class (datestr, MU_CTYPE_ENDLN);
 
   envarr[0] = "From ";
   envarr[1] = sender;
diff --git a/libproto/pop/mbox.c b/libproto/pop/mbox.c
index 067d244..9ce6603 100644
--- a/libproto/pop/mbox.c
+++ b/libproto/pop/mbox.c
@@ -640,7 +640,7 @@ pop_header_blurb (mu_stream_t stream, size_t maxlines,
       
   while ((status = mu_stream_getline (stream, &buf, &size, &n)) == 0 && n > 0)
     {
-      size_t len = mu_rtrim_cset (buf, "\r\n");
+      size_t len = mu_rtrim_class (buf, MU_CTYPE_ENDLN);
       if (len == 0)
        break;
       mu_opool_append (opool, buf, len);
diff --git a/maidag/Makefile.am b/maidag/Makefile.am
index 2d098ea..4f88238 100644
--- a/maidag/Makefile.am
+++ b/maidag/Makefile.am
@@ -46,6 +46,8 @@ maidag_LDADD = \
  @address@hidden
  ${MU_LIB_MAILUTILS} \
  @address@hidden
+ ../libmu_dbm/libmu_dbm.la\
+ @address@hidden
  @TCPWRAP_LIBRARIES@
 
 INCLUDES = -I${top_srcdir} @MU_APP_COMMON_INCLUDES@ @GUILE_INCLUDES@ \
diff --git a/maidag/lmtp.c b/maidag/lmtp.c
index f69ca24..f493b67 100644
--- a/maidag/lmtp.c
+++ b/maidag/lmtp.c
@@ -545,7 +545,7 @@ lmtp_loop (mu_stream_t iostr, unsigned int timeout)
       enum lmtp_command cmd = cp->cmd_code;
       enum lmtp_state next_state = transtab[cmd][state];
 
-      mu_rtrim_cset (sp, "\r\n");
+      mu_rtrim_class (sp, MU_CTYPE_ENDLN);
 
       if (next_state != state_none)
        {
diff --git a/maidag/maidag.c b/maidag/maidag.c
index 348c6da..9faa36d 100644
--- a/maidag/maidag.c
+++ b/maidag/maidag.c
@@ -457,7 +457,7 @@ struct mu_cfg_param maidag_cfg_param[] = {
   { "exit-quota-tempfail", mu_cfg_bool, &ex_quota_tempfail, 0, NULL,
     N_("Indicate temporary failure if the recipient is over his mail quota.")
   },
-#ifdef USE_DBM
+#ifdef ENABLE_DBM
   { "quota-db", mu_cfg_string, &quotadbname, 0, NULL,
     N_("Name of DBM quota database file."),
     N_("file") },
diff --git a/maidag/maidag.h b/maidag/maidag.h
index 2be3818..5125fe7 100644
--- a/maidag/maidag.h
+++ b/maidag/maidag.h
@@ -86,10 +86,9 @@
 #include <mailutils/server.h>
 #include <mailutils/cctype.h>
 #include <mailutils/io.h>
+#include <mailutils/dbm.h>
 
-#include <mu_dbm.h>
-
-#if defined (USE_DBM) || defined (USE_SQL)
+#if defined (ENABLE_DBM) || defined (USE_SQL)
 # define USE_MAILBOX_QUOTAS 1
 #endif
 
diff --git a/maidag/mailquota.c b/maidag/mailquota.c
index 1d196f9..216cc11 100644
--- a/maidag/mailquota.c
+++ b/maidag/mailquota.c
@@ -64,64 +64,85 @@ fail_retrieve_quota (char *name, mu_off_t *quota)
   return RETR_FAILURE;
 }
 
-#ifdef USE_DBM
+#ifdef ENABLE_DBM
 int
 dbm_retrieve_quota (char *name, mu_off_t *quota)
 {
-  DBM_FILE db;
-  DBM_DATUM named, contentd;
+  mu_dbm_file_t db;
+  struct mu_dbm_datum  named, contentd;
   char buffer[64];
   int unlimited = 0;
   int rc;
 
   if (!quotadbname)
     return RETR_FAILURE;
-  
-  if (mu_dbm_open (quotadbname, &db, MU_STREAM_READ, 0600))
+
+  rc = mu_dbm_create (quotadbname, &db);
+  if (rc)
+    {
+      mu_error (_("unable to create quota db"));
+      return RETR_FAILURE;
+    }
+
+  rc = mu_dbm_safety_check (db);
+  if (rc && rc != ENOENT)
     {
-      mu_error (_("cannot open file %s: %s"), quotadbname, mu_strerror 
(errno));
+      mu_error (_("quota db fails safety check: %s"),
+               mu_strerror (rc));
+      mu_dbm_destroy (&db);
+      return RETR_FAILURE;
+    }
+
+  rc = mu_dbm_open (db, MU_STREAM_READ, 0600);
+  if (rc)
+    {
+      mu_error (_("cannot open file %s: %s"),
+               quotadbname, mu_strerror (rc));
+      mu_dbm_destroy (&db);
       return RETR_FAILURE;
     }
   
   memset (&named, 0, sizeof named);
   memset (&contentd, 0, sizeof contentd);
-  MU_DATUM_PTR (named) = name;
-  MU_DATUM_SIZE (named) = strlen (name);
-  rc = mu_dbm_fetch (db, named, &contentd);
-  if (rc || !MU_DATUM_PTR (contentd))
+  named.mu_dptr = name;
+  named.mu_dsize = strlen (name);
+  rc = mu_dbm_fetch (db, &named, &contentd);
+  if (rc)
     {
       /* User not in database, try default quota */
-      memset (&named, 0, sizeof named);
-      MU_DATUM_PTR (named) = "DEFAULT";
-      MU_DATUM_SIZE (named) = strlen ("DEFAULT");
-      rc = mu_dbm_fetch (db, named, &contentd);
-      if (rc)
+      mu_dbm_datum_free (&named);
+      named.mu_dptr = "DEFAULT";
+      named.mu_dsize = strlen ("DEFAULT");
+      rc = mu_dbm_fetch (db, &named, &contentd);
+      if (rc == MU_ERR_NOENT)
        {
-         /*mu_error (_("can't fetch data: %s"), strerror (rc));*/
+         mu_dbm_destroy (&db);
+         return RETR_FAILURE;
+       }
+      else if (rc)
+       {
+         mu_error (_("can't fetch data: %s"), mu_dbm_strerror (db));
+         mu_dbm_destroy (&db);
          return RETR_FAILURE;
        }
-      if (!MU_DATUM_PTR (contentd))
-       return RETR_FAILURE;
     }
 
-  if (mu_c_strncasecmp("none",
-                      MU_DATUM_PTR (contentd),
-                      MU_DATUM_SIZE (contentd)) == 0) 
+  if (mu_c_strncasecmp("none", contentd.mu_dptr, contentd.mu_dsize) == 0) 
       unlimited = 1;
-  else if (MU_DATUM_SIZE (contentd) > sizeof(buffer)-1)
+  else if (contentd.mu_dsize > sizeof (buffer) - 1)
     {
       mu_error (ngettext ("mailbox quota for `%s' is too big: %d digit",
                          "mailbox quota for `%s' is too big: %d digits",
-                         MU_DATUM_SIZE (contentd)),
-               name, MU_DATUM_SIZE (contentd));
+                         contentd.mu_dsize),
+               name, contentd.mu_dsize);
       *quota = groupquota;
     }
   else
     {
       char *p;
                
-      strncpy(buffer, MU_DATUM_PTR (contentd), MU_DATUM_SIZE (contentd));
-      buffer[MU_DATUM_SIZE (contentd)] = 0;
+      strncpy (buffer, contentd.mu_dptr, contentd.mu_dsize);
+      buffer[contentd.mu_dsize] = 0;
       *quota = strtoul (buffer, &p, 0);
       if (get_size (buffer, quota, &p))
        {
@@ -129,8 +150,9 @@ dbm_retrieve_quota (char *name, mu_off_t *quota)
          *quota = groupquota;
        }
     }
-
-  mu_dbm_close (db);
+  
+  mu_dbm_datum_free (&contentd);
+  mu_dbm_destroy (&db);
   
   return unlimited ? RETR_UNLIMITED : RETR_OK;
 }
diff --git a/mu/Makefile.am b/mu/Makefile.am
index 5534d03..e28b984 100644
--- a/mu/Makefile.am
+++ b/mu/Makefile.am
@@ -32,9 +32,17 @@ else
  IDLE_MODULES+=imap.c
 endif
 
+if MU_COND_DBM
+ DBM_C=dbm.c
+ LIBMU_DBM=../libmu_dbm/libmu_dbm.la
+else
+ IDLE_MODULES+=dbm.c
+endif
+
 MODULES = \
  acl.c\
  cflags.c\
+ $(DBM_C)\
  $(IMAP_C)\
  filter.c\
  flt2047.c\
@@ -67,6 +75,7 @@ mu_LDADD = \
  ${MU_LIB_AUTH}\
  @address@hidden
  ${MU_LIB_MAILUTILS}\
+ ${LIBMU_DBM} @address@hidden
  @READLINE_LIBS@ @MU_COMMON_LIBRARIES@
 
 INCLUDES = @MU_APP_COMMON_INCLUDES@ @MU_AUTHINCS@
@@ -77,7 +86,8 @@ AM_CPPFLAGS = \
   -DAUTHLIBS="\"$(MU_AUTHLIBS)\"" \
   -DGUILE_LIBS="\"$(GUILE_LIBS)\"" \
   -DPYTHON_LIBS="\"$(PYTHON_LIBS)\"" \
-  -DI18NLIBS="\"$(LIBINTL)\""
+  -DI18NLIBS="\"$(LIBINTL)\"" \
+  -DDBMLIBS="\"$(DBMLIBS)\""
 
 BUILT_SOURCES=mu-setup.c mu-setup.h
 EXTRA_DIST=mu-setup.awk mu-setup.c mu-setup.h template.c
diff --git a/mu/dbm.c b/mu/dbm.c
new file mode 100644
index 0000000..7f1014f
--- /dev/null
+++ b/mu/dbm.c
@@ -0,0 +1,751 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+
+   GNU Mailutils 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 3, or (at your option)
+   any later version.
+
+   GNU Mailutils 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 GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
+
+#if defined(HAVE_CONFIG_H)
+# include <config.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <grp.h>
+#include <sysexits.h>
+#include <fnmatch.h>
+#include <regex.h>
+#include <mailutils/mailutils.h>
+#include <mailutils/dbm.h>
+#include "argp.h"
+#include "mu.h"
+#include "xalloc.h"
+
+static char dbm_doc[] = N_("mu dbm - DBM management tool");
+char dbm_docstring[] = N_("DBM management tool");
+static char dbm_args_doc[] = N_("FILE [KEY...]");
+
+enum mode
+  {
+    mode_list,
+    mode_create,
+    mode_delete,
+    mode_add,
+    mode_replace,
+  };
+
+enum key_type
+  {
+    key_literal,
+    key_glob,
+    key_regex
+  };
+
+enum mode mode;
+char *db_name;
+char *input_file;
+int permissions = 0600;
+struct mu_auth_data *auth;
+uid_t owner_uid = -1;
+gid_t owner_gid = -1;
+int copy_permissions;
+enum key_type key_type = key_literal;
+int case_sensitive = 1;
+int include_zero = -1;
+
+void
+init_datum (struct mu_dbm_datum *key, char *str)
+{
+  memset (key, 0, sizeof *key);
+  key->mu_dptr = str;
+  key->mu_dsize = strlen (str) + !!include_zero;
+}
+
+mu_dbm_file_t
+open_db_file (int mode)
+{
+  int rc;
+  mu_dbm_file_t db;
+  
+  rc = mu_dbm_create (db_name, &db);
+  if (rc)
+    {
+      mu_diag_output (MU_DIAG_ERROR, _("unable to create database %s: %s"),
+                     db_name, mu_strerror (rc));
+      exit (EX_SOFTWARE);
+    }
+
+  rc = mu_dbm_open (db, mode, permissions);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_open", db_name, rc);
+      exit (EX_SOFTWARE);
+    }
+
+  if (mode == MU_STREAM_CREAT && (owner_uid != -1 || owner_gid != -1))
+    {
+      int dirfd, pagfd;
+      
+      rc = mu_dbm_get_fd (db, &pagfd, &dirfd);
+      if (rc)
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_get_fd", db_name, rc);
+         exit (EX_SOFTWARE);
+       }
+      if (owner_uid == -1 || owner_gid == -1)
+       {
+         struct stat st;
+         
+         if (fstat (dirfd, &st))
+           {
+             mu_diag_funcall (MU_DIAG_ERROR, "fstat", db_name, errno);
+             exit (EX_SOFTWARE);
+           }
+         if (owner_uid == -1)
+           owner_uid = st.st_uid;
+         if (owner_gid == -1)
+           owner_gid = st.st_gid;
+       }
+      if (fchown (pagfd, owner_uid, owner_gid))
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "fchown", db_name, errno);
+         exit (EX_SOFTWARE);
+       }
+      if (pagfd != dirfd &&
+         fchown (dirfd, owner_uid, owner_gid))
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "fchown", db_name, errno);
+         exit (EX_SOFTWARE);
+       }
+    }
+  return db;
+}
+
+struct print_data
+{
+  mu_dbm_file_t db;
+  mu_stream_t stream;
+};
+  
+static int
+print_action (struct mu_dbm_datum const *key, void *data)
+{
+  int rc;
+  struct mu_dbm_datum contents;
+  struct print_data *pd = data;
+  size_t len;
+  
+  memset (&contents, 0, sizeof contents);
+  rc = mu_dbm_fetch (pd->db, key, &contents);
+  if (rc)
+    {
+      mu_error (_("database fetch error: %s"), mu_dbm_strerror (pd->db));
+      exit (EX_UNAVAILABLE);
+    }
+
+  len = key->mu_dsize;
+  if (key->mu_dptr[len - 1] == 0)
+    len--;
+  mu_stream_write (pd->stream, key->mu_dptr, len, NULL);
+  mu_stream_write (pd->stream, "\t", 1, NULL);
+
+  len = contents.mu_dsize;
+  if (contents.mu_dptr[len - 1] == 0)
+    len--;
+  mu_stream_write (pd->stream, contents.mu_dptr, len, NULL);
+  mu_stream_write (pd->stream, "\n", 1, NULL);
+  mu_dbm_datum_free (&contents);
+  return 0;
+}
+
+static void
+iterate_database (mu_dbm_file_t db,
+                 int (*matcher) (const char *, void *), void *matcher_data,
+                 int (*action) (struct mu_dbm_datum const *, void *),
+                 void *action_data)
+{
+  int rc;
+  struct mu_dbm_datum key;
+  char *buf = NULL;
+  size_t bufsize = 0;
+
+  memset (&key, 0, sizeof key);
+  for (rc = mu_dbm_firstkey (db, &key); rc == 0;
+       rc = mu_dbm_nextkey (db, &key))
+    {
+      if (include_zero == -1)
+       include_zero = key.mu_dptr[key.mu_dsize-1] == 0;
+
+      if (matcher)
+       {
+         if (key.mu_dsize + 1 > bufsize)
+           {
+             bufsize = key.mu_dsize + 1;
+             buf = xrealloc (buf, bufsize);
+           }
+         memcpy (buf, key.mu_dptr, key.mu_dsize);
+         buf[key.mu_dsize] = 0;
+         if (!matcher (buf, matcher_data))
+           continue;
+       }
+      if (action (&key, action_data))
+       break;
+    }
+  free (buf);
+}
+
+static int
+match_literal (const char *str, void *data)
+{
+  char **argv = data;
+
+  for (; *argv; argv++)
+    {
+      if ((case_sensitive ? strcmp : strcasecmp) (str, *argv) == 0)
+       return 1;
+    }
+  return 0;
+}
+
+#ifndef FNM_CASEFOLD
+# define FNM_CASEFOLD 0
+#endif
+
+static int
+match_glob (const char *str, void *data)
+{
+  char **argv = data;
+  
+  for (; *argv; argv++)
+    {
+      if (fnmatch (*argv, str, case_sensitive ? FNM_CASEFOLD : 0) == 0)
+       return 1;
+    }
+  return 0;
+}
+
+struct regmatch
+{
+  int regc;
+  regex_t *regs;
+};
+  
+static int
+match_regex (const char *str, void *data)
+{
+  struct regmatch *match = data;
+  int i;
+  
+  for (i = 0; i < match->regc; i++)
+    {
+      if (regexec (&match->regs[i], str, 0, NULL, 0) == 0)
+       return 1;
+    }
+  return 0;
+}
+
+void
+compile_regexes (int argc, char **argv, struct regmatch *match)
+{
+  regex_t *regs = xcalloc (argc, sizeof (regs[0]));
+  int i;
+  int cflags = (case_sensitive ? 0: REG_ICASE) | REG_EXTENDED | REG_NOSUB;
+  int errors = 0;
+  
+  for (i = 0; i < argc; i++)
+    {
+      int rc = regcomp (&regs[i], argv[i], cflags);
+      if (rc)
+       {
+         char errbuf[512];
+         regerror (rc, &regs[i], errbuf, sizeof (errbuf));
+         mu_error (_("error compiling `%s': %s"), argv[i], errbuf);
+         errors++;
+       }
+    }
+  if (errors)
+    exit (EX_USAGE);
+  match->regc = argc;
+  match->regs = regs;
+}
+
+static void
+free_regexes (struct regmatch *match)
+{
+  int i;
+  for (i = 0; i < match->regc; i++)
+    regfree (&match->regs[i]);
+  free (match->regs);
+}
+
+static void
+list_database (int argc, char **argv)
+{
+  mu_dbm_file_t db = open_db_file (MU_STREAM_READ);
+  struct print_data pdata;
+
+  pdata.db = db;
+  pdata.stream = mu_strout;
+
+  if (argc == 0)
+    iterate_database (db, NULL, NULL, print_action, &pdata);
+  else
+    {
+      switch (key_type)
+       {
+       case key_literal:
+         iterate_database (db, match_literal, argv, print_action, &pdata);
+         break;
+
+       case key_glob:
+         iterate_database (db, match_glob, argv, print_action, &pdata);
+         break;
+
+       case key_regex:
+         {
+           struct regmatch m;
+           compile_regexes (argc, argv, &m);
+           iterate_database (db, match_regex, &m, print_action, &pdata);
+           free_regexes (&m);
+         }
+       }
+    }
+  mu_dbm_destroy (&db);
+}
+
+void
+add_records (int mode, int replace)
+{
+  mu_dbm_file_t db;
+  mu_stream_t input, flt;
+  const char *flt_argv[] = { "inline-comment", "#", "-S", "-i", "#", NULL };
+  char *buf = NULL;
+  size_t size = 0;
+  size_t len;
+  unsigned long line;
+  int rc;
+  
+  if (input_file)
+    {
+      rc = mu_file_stream_create (&input, input_file, MU_STREAM_READ);
+      if (rc)
+       {
+         mu_error (_("cannot open input file %s: %s"), input_file,
+                   mu_strerror (rc));
+         exit (EX_UNAVAILABLE);
+       }
+    }
+  else
+    input = mu_strin;
+  
+  rc = mu_filter_create_args (&flt, input, "inline-comment",
+                             MU_ARRAY_SIZE (flt_argv) - 1, flt_argv,
+                             MU_FILTER_DECODE, MU_STREAM_READ);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_filter_create_args", input_file, rc);
+      exit (EX_UNAVAILABLE);
+    }
+  mu_stream_unref (input);
+  input = flt;
+
+  db = open_db_file (mode);
+
+  line = 1;
+  if (!input_file)
+    input_file = "<stdin>";
+  while ((rc = mu_stream_getline (input, &buf, &size, &len)) == 0
+        && len > 0)
+    {
+      struct mu_dbm_datum key, contents;
+      char *kstr, *val;
+      
+      mu_rtrim_class (buf, MU_CTYPE_ENDLN);
+      if (buf[0] == '#')
+       {
+         line = strtoul (buf + 1, NULL, 10);
+         continue;
+       }
+      kstr = mu_str_stripws (buf);
+      val = mu_str_skip_class_comp (kstr, MU_CTYPE_SPACE);
+      *val++ = 0;
+      val = mu_str_skip_class (val, MU_CTYPE_SPACE);
+      if (*val == 0)
+       {
+         mu_error (_("%s:%lu: malformed line"), input_file, line);
+         line++;
+         continue;
+       }
+
+      init_datum (&key, kstr);
+      init_datum (&contents, val);
+
+      rc = mu_dbm_store (db, &key, &contents, replace);
+      if (rc)
+       mu_error (_("%s:%lu: cannot store datum: %s"),
+                 input_file, line,
+                 rc == MU_ERR_FAILURE ?
+                    mu_dbm_strerror (db) : mu_strerror (rc));
+      line++;
+    }
+  mu_dbm_destroy (&db);
+
+  mu_stream_unref (input);
+}
+
+static void
+create_database ()
+{
+  if (copy_permissions)
+    {
+      struct stat st;
+      
+      if (!input_file)
+       {
+         mu_error (_("--copy-permissions used without --file"));
+         exit (EX_USAGE);
+       }
+      if (stat (input_file, &st))
+       {
+         mu_diag_funcall (MU_DIAG_ERROR, "stat", input_file, errno);
+         exit (EX_UNAVAILABLE);
+       }
+      owner_uid = st.st_uid;
+      owner_gid = st.st_gid;
+      permissions = st.st_mode & 0777;
+    }
+  else if (auth)
+    {
+      if (owner_uid == -1)
+       owner_uid = auth->uid;
+      if (owner_gid == -1)
+       owner_gid = auth->gid;
+    }
+  add_records (MU_STREAM_CREAT, 0);
+}
+
+static int
+store_to_list (struct mu_dbm_datum const *key, void *data)
+{
+  int rc;
+  mu_list_t list = data;
+  char *p = xmalloc (key->mu_dsize + 1);
+  memcpy (p, key->mu_dptr, key->mu_dsize);
+  p[key->mu_dsize] = 0;
+  rc = mu_list_append (list, p);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", p, rc);
+      exit (EX_SOFTWARE);
+    }
+  return 0;
+}
+
+static int
+do_delete (void *item, void *data)
+{
+  char *str = item;
+  mu_dbm_file_t db = data;
+  struct mu_dbm_datum key;
+  int rc;
+
+  init_datum (&key, str);
+  rc = mu_dbm_delete (db, &key);
+  if (rc == MU_ERR_NOENT)
+    {
+      mu_error (_("cannot remove record for %s: %s"),
+               str, mu_strerror (rc));
+    }
+  else if (rc)
+    {
+      mu_error (_("cannot remove record for %s: %s"),
+               str, mu_dbm_strerror (db));
+      if (rc != MU_ERR_NOENT)
+       exit (EX_UNAVAILABLE);
+    }
+  return 0;
+}
+
+static void
+delete_database (int argc, char **argv)
+{
+  mu_dbm_file_t db = open_db_file (MU_STREAM_RDWR);
+  mu_list_t templist = NULL;
+  int rc, i;
+  
+  if (argc == 0)
+    {
+      mu_error (_("not enough arguments for delete"));
+      exit (EX_USAGE);
+    }
+
+  /* Collect matching keys */
+  rc = mu_list_create (&templist);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_list_create", NULL, rc);
+      exit (EX_SOFTWARE);
+    }
+  mu_list_set_destroy_item (templist, mu_list_free_item);
+  switch (key_type)
+    {
+    case key_literal:
+      for (i = 0; i < argc; i++)
+       {
+         char *p = xstrdup (argv[i]);
+         rc = mu_list_append (templist, p);
+         if (rc)
+           {
+             mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", p, rc);
+             exit (EX_SOFTWARE);
+           }
+       }
+      break;
+
+    case key_glob:
+      iterate_database (db, match_glob, argv,
+                       store_to_list, templist);
+      break;
+
+    case key_regex:
+      {
+       struct regmatch m;
+       
+       compile_regexes (argc, argv, &m);
+       iterate_database (db, match_regex, &m, store_to_list, templist);
+       free_regexes (&m);
+      }
+    }
+  mu_list_do (templist, do_delete, db);
+  mu_list_destroy (&templist);
+  mu_dbm_destroy (&db);
+}
+
+/*
+  mu dbm --create a.db < input
+  mu dbm --list a.db
+  mu dbm --delete a.db key [key...]
+  mu dbm --add a.db < input
+  mu dbm --replace a.db < input
+ */
+
+static struct argp_option dbm_options[] = {
+  { NULL, 0, NULL, 0, N_("Operation mode"), 0},
+  { "create", 'c', NULL, 0, N_("create the database") },
+  { "list",   'l', NULL, 0, N_("list contents of the database") },
+  { "delete", 'd', NULL, 0, N_("delete specified keys from the database") },
+  { "add",    'a', NULL, 0, N_("add records to the database") },
+  { "replace",'r', NULL, 0, N_("add records replacing ones with matching 
keys") },
+  
+  { NULL, 0, NULL, 0, N_("Create modifiers"), 0},
+  { "file",   'f', N_("FILE"), 0,
+    N_("read input from FILE (with --create, --delete, --add and --replace)") 
},
+  { "permissions", 'p', N_("NUM"), 0,
+    N_("set permissions on the created database") },
+  { "user",        'u', N_("USER"), 0,
+    N_("set database owner name") },
+  { "group",       'g', N_("GROUP"), 0,
+    N_("set database owner group") },
+  { "copy-permissions", 'P', NULL, 0,
+    N_("copy database permissions and ownership from the input file") },
+  { NULL, 0, NULL, 0, N_("List and Delete modifiers"), 0},
+  { "glob",        'G', NULL, 0,
+    N_("treat keys as globbing patterns") },
+  { "regex",       'R', NULL, 0,
+    N_("treat keys as regular expressions") },
+  { "ignore-case", 'i', NULL, 0,
+    N_("case-insensitive matches") },
+  { NULL, 0, NULL, 0, N_("Data length modifiers"), 0 },
+  { "count-null",  'N', NULL, 0,
+    N_("data length accounts for terminating zero") },
+  { "no-count-null", 'n', NULL, 0,
+    N_("data length does not account for terminating zero") },
+  { NULL }
+};
+
+static error_t
+dbm_parse_opt (int key, char *arg, struct argp_state *state)
+{
+  switch (key)
+    {
+    case 'c':
+      mode = mode_create;
+      break;
+
+    case 'l':
+      mode = mode_list;
+      break;
+
+    case 'd':
+      mode = mode_delete;
+      break;
+
+    case 'a':
+      mode = mode_add;
+      break;
+
+    case 'r':
+      mode = mode_replace;
+      break;
+
+    case 'f':
+      input_file = arg;
+      break;
+
+    case 'p':
+      {
+       char *p;
+       unsigned long d = strtoul (arg, &p, 8);
+       if (*p || (d & ~0777))
+         argp_error (state, _("invalid file mode: %s"), arg);
+       permissions = d;
+      }
+      break;
+
+    case 'P':
+      copy_permissions = 1;
+      break;
+
+    case 'u':
+      auth = mu_get_auth_by_name (arg);
+      if (!auth)
+       {
+         char *p;
+         unsigned long n = strtoul (arg, &p, 0);
+         if (*p == 0)
+           owner_uid = n;
+         else
+           argp_error (state, _("no such user: %s"), arg);
+       }
+      break;
+
+    case 'g':
+      {
+       struct group *gr = getgrnam (arg);
+       if (!gr)
+         {
+           char *p;
+           unsigned long n = strtoul (arg, &p, 0);
+           if (*p == 0)
+             owner_gid = n;
+           else
+             argp_error (state, _("no such group: %s"), arg);
+         }
+       else
+         owner_gid = gr->gr_gid;
+      }
+      break;
+
+    case 'G':
+      key_type = key_glob;
+      break;
+
+    case 'R':
+      key_type = key_regex;
+      break;
+
+    case 'i':
+      case_sensitive = 0;
+      break;
+
+    case 'N':
+      include_zero = 1;
+      break;
+
+    case 'n':
+      include_zero = 0;
+      break;
+      
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+static struct argp dbm_argp = {
+  dbm_options,
+  dbm_parse_opt,
+  dbm_args_doc,
+  dbm_doc,
+  NULL,
+  NULL,
+  NULL
+};
+
+int
+mutool_dbm (int argc, char **argv)
+{
+  int index;
+  
+  if (argp_parse (&dbm_argp, argc, argv, ARGP_IN_ORDER, &index, NULL))
+    return 1;
+
+  argc -= index;
+  argv += index;
+
+  if (argc == 0)
+    {
+      mu_error (_("database name not given"));
+      exit (EX_USAGE);
+    }
+  db_name = *argv++;
+  --argc;
+
+  switch (mode)
+    {
+    case mode_list:
+      list_database (argc, argv);
+      break;
+      
+    case mode_create:
+      if (argc)
+       {
+         mu_error (_("too many arguments for create"));
+         exit (EX_USAGE);
+       }
+      create_database ();
+      break;
+      
+    case mode_delete:
+      delete_database (argc, argv);
+      break;
+      
+    case mode_add:
+      if (argc)
+       {
+         mu_error (_("too many arguments for add"));
+         exit (EX_USAGE);
+       }
+      add_records (MU_STREAM_RDWR, 0);
+      break;
+      
+    case mode_replace:
+      if (argc)
+       {
+         mu_error (_("too many arguments for replace"));
+         exit (EX_USAGE);
+       }
+      add_records (MU_STREAM_RDWR, 1);
+      break;
+    }
+  return 0;
+}
+
+/*
+  MU Setup: dbm
+  mu-handler: mutool_dbm
+  mu-docstring: dbm_docstring
+  End MU Setup:
+*/
+  
+
diff --git a/mu/ldflags.c b/mu/ldflags.c
index 3d838b5..0576c02 100644
--- a/mu/ldflags.c
+++ b/mu/ldflags.c
@@ -38,36 +38,52 @@ static struct argp ldflags_argp = {
 
 
 #ifdef WITH_TLS
-# define NEEDAUTH 1
+# define NEEDAUTH "-lmu_auth " AUTHLIBS
 #else
-# define NEEDAUTH 0
+# define NEEDAUTH NULL
 #endif
-#define NOTALL   2
+#define NOTALL   1
 
 struct lib_descr {
   char *name;
   char *libname;
+  int weight;
   int flags;
 } lib_descr[] = {
-  { "mbox",   "mu_mbox", 0 },
+  { "mbox",    "-lmu_mbox", 0 },
 #ifdef ENABLE_MH
-  { "mh",     "mu_mh",   0 },
+  { "mh",      "-lmu_mh",   0 },
 #endif
 #ifdef ENABLE_MAILDIR
-  { "maildir","mu_maildir", 0 },
+  { "maildir", "-lmu_maildir", 0 },
 #endif
 #ifdef ENABLE_IMAP  
-  { "imap",   "mu_imap", NEEDAUTH },
+  { "imap",    "-lmu_imap", 0 },
+  { "imap",    NEEDAUTH,    2 },
 #endif
 #ifdef ENABLE_POP  
-  { "pop",    "mu_pop",  NEEDAUTH },
+  { "pop",    "-lmu_pop",   0 },
+  { "pop",    NEEDAUTH,     2 },
 #endif
 #ifdef ENABLE_NNTP  
-  { "nntp",   "mu_nntp", 0 },
+  { "nntp",   "-lmu_nntp",  0 },
 #endif
-  { "mailer", "mu_mailer", 0 },
-  { "sieve",  "mu_sieve", NOTALL },
-  { "compat", "mu_compat" },
+#ifdef ENABLE_DBM
+  { "dbm",    "-lmu_dbm",   0 },
+  { "dbm",    DBMLIBS,      2 },
+#endif
+  { "mailer", "-lmu_mailer", 0 },
+  { "sieve",  "-lmu_sieve",  0, NOTALL },
+  { "compat", "-lmu_compat", 0 },
+  { "auth",   "-lmu_auth " AUTHLIBS, 2 },
+#ifdef WITH_GUILE            
+  { "guile",  "-lmu_scm " GUILE_LIBS, -1, NOTALL },
+#endif
+#ifdef WITH_PYTHON
+  { "python", "-lmu_py " PYTHON_LIBS, -1, NOTALL },
+#endif
+  { "cfg",    "-lmu_cfg",  -1, NOTALL },
+  { "argp",   "-lmu_argp", -2, NOTALL },
   { NULL }
 };
 
@@ -82,6 +98,9 @@ void
 add_entry (int level, char *ptr)
 {
   int i;
+
+  if (!ptr || !*ptr)
+    return;
   if (nentry >= sizeof(lib_entry)/sizeof(lib_entry[0]))
     {
       mu_error (_("too many arguments"));
@@ -122,7 +141,6 @@ int
 mutool_ldflags (int argc, char **argv)
 {
   int i, j;
-  char *ptr;
   
   if (argp_parse (&ldflags_argp, argc, argv, ARGP_IN_ORDER, &i, NULL))
     return 1;
@@ -140,21 +158,7 @@ mutool_ldflags (int argc, char **argv)
 
   for ( ; argc > 0; argc--, argv++)
     {
-      if (strcmp (argv[0], "auth") == 0)
-       add_entry (2, "-lmu_auth " AUTHLIBS);
-#ifdef WITH_GUILE            
-      else if (strcmp (argv[0], "guile") == 0)
-       add_entry (-1, "-lmu_scm " GUILE_LIBS);
-#endif
-#ifdef WITH_PYTHON
-      else if (strcmp (argv[0], "python") == 0)
-       add_entry (-1, "-lmu_py " PYTHON_LIBS);
-#endif
-      else if (strcmp (argv[0], "cfg") == 0)
-       add_entry (-1, "-lmu_cfg");
-      else if (strcmp (argv[0], "argp") == 0)
-       add_entry (-2, "-lmu_argp");
-      else if (strcmp (argv[0], "all") == 0)
+      if (strcmp (argv[0], "all") == 0)
        {
          struct lib_descr *p;
                  
@@ -162,28 +166,24 @@ mutool_ldflags (int argc, char **argv)
            {
              if (p->flags & NOTALL)
                continue;
-             mu_asprintf (&ptr, "-l%s", p->libname);
-             add_entry (0, ptr);
-             if (p->flags & NEEDAUTH)
-               add_entry (2, "-lmu_auth " AUTHLIBS);
+             add_entry (p->weight, p->libname);
            }
        }
       else
        {
          struct lib_descr *p;
+         int found = 0;
          
          for (p = lib_descr; p->name; p++)
-           if (mu_c_strcasecmp (p->name, argv[0]) == 0)
-             break;
-
-         if (p->name)
            {
-             mu_asprintf (&ptr, "-l%s", p->libname);
-             add_entry (0, ptr);
-             if (p->flags & NEEDAUTH)
-               add_entry (2, "-lmu_auth " AUTHLIBS);
+             if (mu_c_strcasecmp (p->name, argv[0]) == 0)
+               {
+                 add_entry (p->weight, p->libname);
+                 found = 1;
+               }
            }
-         else
+
+         if (!found)
            {
              mu_error (_("unknown keyword: %s"), argv[0]);
              return 1;
diff --git a/pop3d/Makefile.am b/pop3d/Makefile.am
index 7aeae8c..b5f6add 100644
--- a/pop3d/Makefile.am
+++ b/pop3d/Makefile.am
@@ -46,6 +46,10 @@ pop3d_SOURCES =\
  uidl.c\
  user.c
 
+if MU_COND_DBM
+  LIBMU_DBM=../libmu_dbm/libmu_dbm.la
+endif
+
 pop3d_LDADD = \
  ${MU_APP_LIBRARIES}\
  ${MU_LIB_MBOX}\
@@ -54,15 +58,25 @@ pop3d_LDADD = \
  ${MU_LIB_AUTH}\
  @MU_AUTHLIBS@ \
  ${MU_LIB_MAILUTILS}\
- @MU_COMMON_LIBRARIES@ @TCPWRAP_LIBRARIES@
+ @address@hidden
+ ${LIBMU_DBM}\
+ @address@hidden
+ @TCPWRAP_LIBRARIES@
 
 popauth_SOURCES = popauth.c
-popauth_LDADD = ${MU_APP_LIBRARIES} ${MU_LIB_MAILUTILS} @MU_COMMON_LIBRARIES@
+popauth_LDADD = \
+ ${MU_APP_LIBRARIES}\
+ ${MU_LIB_MAILUTILS}\
+ @address@hidden
+ ${LIBMU_DBM}\
+ @DBMLIBS@
+
 pop3d_DEPENDENCIES = \
  @MU_AUTHLIBS_DEPENDENCY@ \
  ../lib/libmuaux.a \
  ${MU_LIB_MBOX}\
  ${MU_LIB_MH}\
  ${MU_LIB_MAILDIR}\
- ${MU_LIB_MAILUTILS}
+ ${MU_LIB_MAILUTILS}\
+ ${LIBMU_DBM}
 
diff --git a/pop3d/apop.c b/pop3d/apop.c
index 1b89ab3..7a2697f 100644
--- a/pop3d/apop.c
+++ b/pop3d/apop.c
@@ -43,59 +43,85 @@ pop3d_apopuser (const char *user)
 {
   char *password = NULL;
   
-#ifdef USE_DBM
+#ifdef ENABLE_DBM
   {
     size_t len;
-    DBM_FILE db;
-    DBM_DATUM key, data;
+    mu_dbm_file_t db;
+    struct mu_dbm_datum key, data;
+    int rc;
 
-    int rc = mu_dbm_open (APOP_PASSFILE, &db, MU_STREAM_READ, 0600);
+    rc = mu_dbm_create (APOP_PASSFILE, &db);
+    if (rc)
+      {
+       mu_diag_output (MU_DIAG_ERROR, _("unable to create APOP db"));
+       return NULL;
+      }
+
+    rc = mu_dbm_safety_check (db);
+    if (rc)
+      {
+       mu_diag_output (MU_DIAG_ERROR,
+                       _("APOP file %s fails safety check: %s"),
+                       APOP_PASSFILE, mu_strerror (rc));
+       mu_dbm_destroy (&db);
+       return NULL;
+      }
+    
+    rc = mu_dbm_open (db, MU_STREAM_READ, 0600);
     if (rc)
       {
        mu_diag_output (MU_DIAG_ERROR, _("unable to open APOP db: %s"),
-               mu_strerror (errno));
+                       mu_strerror (rc));
        return NULL;
       }
 
     memset (&key, 0, sizeof key);
     memset (&data, 0, sizeof data);
 
-    MU_DATUM_PTR (key) = (void*) user;
-    MU_DATUM_SIZE (key) = strlen (user);
+    key.mu_dptr = (void *)user;
+    key.mu_dsize = strlen (user);
 
-    rc = mu_dbm_fetch (db, key, &data);
-    mu_dbm_close (db);
-    if (rc)
+    rc = mu_dbm_fetch (db, &key, &data);
+    if (rc == MU_ERR_NOENT)
+      {
+       mu_dbm_destroy (&db);
+       return NULL;
+      }
+    else if (rc)
       {
        mu_diag_output (MU_DIAG_ERROR,
-                       _("cannot fetch APOP data: %s"), mu_strerror (errno));
+                       _("cannot fetch APOP data: %s"),
+                       mu_dbm_strerror (db));
+       mu_dbm_destroy (&db);
        return NULL;
       }
-    len = MU_DATUM_SIZE (data);
+    mu_dbm_destroy (&db);
+    len = data.mu_dsize;
     password = malloc (len + 1);
     if (password == NULL)
       {
        mu_dbm_datum_free (&data);
        return NULL;
       }
-    memcpy (password, MU_DATUM_PTR (data), len);
+    memcpy (password, data.mu_dptr, len);
     password[len] = 0;
     mu_dbm_datum_free (&data);
     return password;
   }
-#else /* !USE_DBM */
+#else /* !ENABLE_DBM */
   {
     char *buf = NULL;
     size_t size = 0;
     size_t ulen;
     FILE *apop_file;
 
-    if (mu_check_perm (APOP_PASSFILE, 0600))
-      {
-       mu_diag_output (MU_DIAG_INFO,
-                       _("bad permissions on APOP password file"));
-       return NULL;
-    }
+    /* FIXME */    
+/*     if (mu_check_perm (APOP_PASSFILE, 0600)) */
+/*       { */
+/*     mu_diag_output (MU_DIAG_INFO, */
+/*                     _("bad permissions on APOP password file")); */
+/*     return NULL; */
+/*     } */
 
     apop_file = fopen (APOP_PASSFILE, "r");
     if (apop_file == NULL)
diff --git a/pop3d/bulletin.c b/pop3d/bulletin.c
index 90aeaea..7bfd052 100644
--- a/pop3d/bulletin.c
+++ b/pop3d/bulletin.c
@@ -113,58 +113,72 @@ write_popbull_file (size_t num)
   return rc;
 }
 
-#ifdef USE_DBM
+#ifdef ENABLE_DBM
 int
 read_bulletin_db (size_t *pnum)
 {
-  DBM_FILE db;
-  DBM_DATUM key, data;
+  mu_dbm_file_t db;
+  struct mu_dbm_datum key, data;
   int rc;
   char sbuf[128];
   char *bufptr;
   char *buf = NULL;
   size_t s;
   char *p;
-  
-  rc = mu_dbm_open (bulletin_db_name, &db, MU_STREAM_READ, 0660);
+
+  rc = mu_dbm_create (bulletin_db_name, &db);
   if (rc)
     {
-      if (errno == ENOENT)
+      mu_diag_output (MU_DIAG_ERROR, _("unable to create bulletin db"));
+      return rc;
+    }
+
+  rc = mu_dbm_safety_check (db);
+  if (rc)
+    {
+      if (rc == ENOENT)
        {
          *pnum = 0;
          return 0;
        }
-      else
-       {
-         mu_error (_("unable to open bulletin db for reading: %s"),
-                   mu_strerror (errno));
-         return rc;
-       }
+      mu_diag_output (MU_DIAG_ERROR,
+                     _("bulletin db %s fails safety check: %s"),
+                     bulletin_db_name, mu_strerror (rc));
+      mu_dbm_destroy (&db);
+      return 1;
+    }
+  
+  rc = mu_dbm_open (db, MU_STREAM_READ, 0660);
+  if (rc)
+    {
+      mu_error (_("unable to open bulletin db for reading: %s"),
+               mu_strerror (rc));
+      return rc;
     }
 
   memset (&key, 0, sizeof key);
   memset (&data, 0, sizeof data);
 
-  MU_DATUM_PTR(key) = username;
-  MU_DATUM_SIZE(key) = strlen (username);
+  key.mu_dptr = username;
+  key.mu_dsize = strlen (username);
 
-  rc = mu_dbm_fetch (db, key, &data);
+  rc = mu_dbm_fetch (db, &key, &data);
 
-  if (rc)
+  if (rc == MU_ERR_NOENT)
+    {
+      *pnum = 0;
+      return 0;
+    }
+  else if (rc)
     {
-      int ec = errno;
-      if (ec == ENOENT)
-        {
-           *pnum = 0;
-           return 0;
-        }
       mu_error (_("cannot fetch bulletin db data: %s"),
-               mu_strerror (ec));
-      mu_dbm_close (db);
+               mu_dbm_strerror (db));
+      mu_dbm_destroy (&db);
       return 1;
     }
+  mu_dbm_destroy (&db);
   
-  s = MU_DATUM_SIZE (data);
+  s = data.mu_dsize;
   if (s < sizeof sbuf)
     bufptr = sbuf;
   else
@@ -172,16 +186,15 @@ read_bulletin_db (size_t *pnum)
       buf = malloc (s + 1);
       if (!buf)
        {
-         mu_error("%s", mu_strerror (errno));
+         mu_error ("%s", mu_strerror (errno));
          return 1;
        }
       bufptr = buf;
     }
 
-  memcpy (bufptr, MU_DATUM_PTR (data), s);
+  memcpy (bufptr, data.mu_dptr, s);
   bufptr[s] = 0;
-  mu_dbm_datum_free(&data);
-  mu_dbm_close (db);
+  mu_dbm_datum_free (&data);
 
   rc = 1;
   *pnum = strtoul (bufptr, &p, 0);
@@ -189,26 +202,8 @@ read_bulletin_db (size_t *pnum)
     rc = 0;
   else
     {
-#ifdef QPOPPER_COMPAT
-      if (s == sizeof long)
-       {
-         long n;
-
-         n = *(long*)MU_DATUM_PTR (data);
-         if (n >= 0)
-           {
-             mu_diag_output (MU_DIAG_INFO,
-                     _("assuming bulletin database is in qpopper format"));
-             *pnum = n;
-             rc = 0;
-           }
-       }
-      else
-#endif /* QPOPPER_COMPAT */
-       {
-         mu_error (_("wrong bulletin database format for `%s'"),
-                   username);
-       }
+      mu_error (_("wrong bulletin database format for `%s'"),
+               username);
     }
   
   free (buf);
@@ -218,41 +213,60 @@ read_bulletin_db (size_t *pnum)
 int
 write_bulletin_db (size_t num)
 {
-  DBM_FILE db;
-  DBM_DATUM key, data;
+  mu_dbm_file_t db;
+  struct mu_dbm_datum key, data;
   int rc;
   const char *p;
   
-  rc = mu_dbm_open (bulletin_db_name, &db, MU_STREAM_RDWR, 0660);
+  rc = mu_dbm_create (bulletin_db_name, &db);
+  if (rc)
+    {
+      mu_diag_output (MU_DIAG_ERROR, _("unable to create bulletin db"));
+      return rc;
+    }
+
+  rc = mu_dbm_safety_check (db);
+  if (rc && rc != ENOENT)
+    {
+      mu_diag_output (MU_DIAG_ERROR,
+                     _("bulletin db %s fails safety check: %s"),
+                     bulletin_db_name, mu_strerror (rc));
+      mu_dbm_destroy (&db);
+      return rc;
+    }
+
+  rc = mu_dbm_open (db, MU_STREAM_RDWR, 0660);
   if (rc)
     {
       mu_error (_("unable to open bulletin db for writing: %s"),
-               mu_strerror (errno));
+               mu_strerror (rc));
+      mu_dbm_destroy (&db);
       return rc;
     }
 
   memset (&key, 0, sizeof key);
   memset (&data, 0, sizeof data);
 
-  MU_DATUM_PTR (key) = username;
-  MU_DATUM_SIZE (key) = strlen (username);
+  key.mu_dptr = username;
+  key.mu_dsize = strlen (username);
   p = mu_umaxtostr (0, num);
-  MU_DATUM_PTR (data) = (char *) p;
-  MU_DATUM_SIZE (data) = strlen (p);
+  data.mu_dptr = (char *) p;
+  data.mu_dsize = strlen (p);
 
-  rc = mu_dbm_insert (db, key, data, 1);
+  rc = mu_dbm_store (db, &key, &data, 1);
   if (rc)
-    mu_error (_("cannot store datum in bulletin db"));
-
-  mu_dbm_close (db);
+    mu_error (_("cannot store datum in bulletin db: %s"),
+             mu_dbm_strerror (db));
+  
+  mu_dbm_destroy (&db);
   return rc;
 }
-#endif /* USE_DBM */
+#endif /* ENABLE_DBM */
       
 int
 get_last_delivered_num (size_t *pret)
 {
-#ifdef USE_DBM  
+#ifdef ENABLE_DBM  
   if (bulletin_db_name && read_bulletin_db (pret) == 0)
     return 0;
 #endif
@@ -262,7 +276,7 @@ get_last_delivered_num (size_t *pret)
 void
 store_last_delivered_num (size_t num)
 {
-#ifdef USE_DBM  
+#ifdef ENABLE_DBM  
   if (bulletin_db_name && write_bulletin_db (num) == 0)
     return;
 #endif
diff --git a/pop3d/logindelay.c b/pop3d/logindelay.c
index d726c15..21794ca 100644
--- a/pop3d/logindelay.c
+++ b/pop3d/logindelay.c
@@ -19,27 +19,45 @@
 
 #ifdef ENABLE_LOGIN_DELAY
 
-static int
-open_stat_db (DBM_FILE *db, int mode)
+static mu_dbm_file_t
+open_stat_db (int mode)
 {
-  int rc = mu_dbm_open (login_stat_file, db, mode, 0660);
+  mu_dbm_file_t db;
+  int rc;
+
+  rc = mu_dbm_create (login_stat_file, &db);
   if (rc)
     {
-      if (rc == -1)
-       mu_diag_output (MU_DIAG_INFO, _("bad permissions on statistics db"));
-      else
-       mu_diag_output (MU_DIAG_ERROR, _("unable to open statistics db: %s"),
-               mu_strerror (rc));
+      mu_diag_output (MU_DIAG_ERROR, _("unable to create statistics db"));
+      return NULL;
+    }
+
+  rc = mu_dbm_safety_check (db);
+  if (rc)
+    {
+      mu_diag_output (MU_DIAG_ERROR,
+                     _("statistics db fails safety check: %s"),
+                     mu_strerror (rc));
+      mu_dbm_destroy (&db);
+      return NULL;
     }
-  return rc;
+  
+  rc = mu_dbm_open (db, mode, 0660);
+  if (rc)
+    {
+      mu_diag_output (MU_DIAG_ERROR, _("unable to open statistics db: %s"),
+                     mu_dbm_strerror (db));
+      mu_dbm_destroy (&db);
+    }
+  return db;
 }
 
 int
 check_login_delay (char *username)
 {
   time_t now, prev_time;
-  DBM_FILE db;
-  DBM_DATUM key, data;
+  mu_dbm_file_t db;
+  struct mu_dbm_datum key, data;
   char text[64], *p;
   int rc;
 
@@ -47,42 +65,45 @@ check_login_delay (char *username)
     return 0;
   
   time (&now);
-  if (open_stat_db (&db, MU_STREAM_RDWR))
+  db = open_stat_db (MU_STREAM_READ);
+  if (!db)
     return 0;
   
   memset (&key, 0, sizeof key);
-  MU_DATUM_PTR(key) = username;
-  MU_DATUM_SIZE(key) = strlen (username);
+  key.mu_dptr = username;
+  key.mu_dsize = strlen (username);
   memset (&data, 0, sizeof data);
 
-  rc = mu_dbm_fetch (db, key, &data);
+  rc = mu_dbm_fetch (db, &key, &data);
   if (rc)
     {
-      mu_diag_output (MU_DIAG_ERROR, _("cannot fetch login delay data: %s"),
-             mu_strerror (rc));
-      mu_dbm_close (db);
+      if (rc != MU_ERR_NOENT)
+       mu_diag_output (MU_DIAG_ERROR, _("cannot fetch login delay data: %s"),
+                       mu_dbm_strerror (db));
+      mu_dbm_destroy (&db);
       return 0;
     }
 
-  if (MU_DATUM_SIZE(data) > sizeof (text) - 1)
+  if (data.mu_dsize > sizeof (text) - 1)
     {
       mu_diag_output (MU_DIAG_ERROR,
                      _("invalid entry for '%s': wrong timestamp size"),
-             username);
-      mu_dbm_close (db);
+                     username);
+      mu_dbm_destroy (&db);
       return 0;
     }
+  mu_dbm_destroy (&db);
 
-  memcpy (text, MU_DATUM_PTR(data), MU_DATUM_SIZE(data));
-  text[MU_DATUM_SIZE(data)] = 0;
-  mu_dbm_close (db);
-
+  memcpy (text, data.mu_dptr, data.mu_dsize);
+  text[data.mu_dsize] = 0;
+  mu_dbm_datum_free (&data);
+  
   prev_time = strtoul (text, &p, 0);
   if (*p)
     {
       mu_diag_output (MU_DIAG_ERROR,
                      _("malformed timestamp for '%s': %s"),
-             username, text);
+                     username, text);
       return 0;
     }
 
@@ -93,40 +114,42 @@ void
 update_login_delay (char *username)
 {
   time_t now;
-  DBM_FILE db;
-  DBM_DATUM key, data;
+  mu_dbm_file_t db;
+  struct mu_dbm_datum key, data;
   char text[64];
   
   if (login_delay == 0 || username == NULL)
     return;
 
   time (&now);
-  if (open_stat_db (&db, MU_STREAM_RDWR))
+  db = open_stat_db (MU_STREAM_RDWR);
+  if (!db)
     return;
   
   memset(&key, 0, sizeof(key));
   memset(&data, 0, sizeof(data));
-  MU_DATUM_PTR(key) = username;
-  MU_DATUM_SIZE(key) = strlen (username);
+  key.mu_dptr = username;
+  key.mu_dsize = strlen (username);
   snprintf (text, sizeof text, "%lu", (unsigned long) now);
-  MU_DATUM_PTR(data) = text;
-  MU_DATUM_SIZE(data) = strlen (text);
-  if (mu_dbm_insert (db, key, data, 1))
-    mu_error (_("%s: cannot store datum %s/%s"),
-             login_stat_file, username, text);
+  data.mu_dptr = text;
+  data.mu_dsize = strlen (text);
+  if (mu_dbm_store (db, &key, &data, 1))
+    mu_error (_("%s: cannot store datum %s/%s: %s"),
+             login_stat_file, username, text,
+             mu_dbm_strerror (db));
   
-  mu_dbm_close (db);
+  mu_dbm_destroy (&db);
 }
 
 void
 login_delay_capa ()
 {
-  DBM_FILE db;
+  mu_dbm_file_t db;
   
-  if (login_delay && open_stat_db (&db, MU_STREAM_RDWR) == 0)
+  if (login_delay && (db = open_stat_db (MU_STREAM_RDWR)) != NULL)
     {
       pop3d_outf ("LOGIN-DELAY %s\n", mu_umaxtostr (0, login_delay));
-      mu_dbm_close (db);
+      mu_dbm_destroy (&db);
     }
 }
 #endif
diff --git a/pop3d/pop3d.c b/pop3d/pop3d.c
index 9a5f47d..5652b9d 100644
--- a/pop3d/pop3d.c
+++ b/pop3d/pop3d.c
@@ -77,7 +77,7 @@ cb_bulletin_source (void *data, mu_config_value_t *val)
   return 0;
 }
 
-#ifdef USE_DBM
+#ifdef ENABLE_DBM
 static int
 cb_bulletin_db (void *data, mu_config_value_t *val)
 {
@@ -111,7 +111,7 @@ static struct mu_cfg_param pop3d_cfg_param[] = {
   { "bulletin-source", mu_cfg_callback, NULL, 0, cb_bulletin_source,
     N_("Get bulletins from the specified mailbox."),
     N_("url") },
-#ifdef USE_DBM
+#ifdef ENABLE_DBM
   { "bulletin-db", mu_cfg_callback, NULL, 0, cb_bulletin_db,
     N_("Set the bulletin database file name."),
     N_("file") },
diff --git a/pop3d/pop3d.h b/pop3d/pop3d.h
index ea43fb5..833eb7f 100644
--- a/pop3d/pop3d.h
+++ b/pop3d/pop3d.h
@@ -24,7 +24,7 @@
 #include <mailutils/types.h>
 #include <mailutils/stream.h>
 #include <mailutils/io.h>
-#include <mu_dbm.h>
+#include <mailutils/dbm.h>
 #include <mu_umaxtostr.h>
 #include <muaux.h>
 
@@ -35,7 +35,7 @@
    type automatically */
 #define APOP_PASSFILE_NAME "apop"
 
-#ifdef USE_DBM
+#ifdef ENABLE_DBM
 # define APOP_PASSFILE SYSCONFDIR "/" APOP_PASSFILE_NAME
 # define ENABLE_LOGIN_DELAY
 #else
diff --git a/pop3d/popauth.c b/pop3d/popauth.c
index 9ea4ba4..8ae7c95 100644
--- a/pop3d/popauth.c
+++ b/pop3d/popauth.c
@@ -73,7 +73,7 @@ static struct argp_option options[] =
 
   { NULL, 0, NULL, 0,
     N_("Default action is:\n"
-    "  For the file owner: --list\n"
+    "  For root: --list\n"
     "  For a user: --modify --user <username>\n"), 2 },
   
   { NULL, 0, NULL, 0, N_("Options are:"), 3 },
@@ -197,7 +197,7 @@ popauth_parse_opt (int key, char *arg, struct argp_state 
*astate)
 }
 
 int
-main(int argc, char **argv)
+main (int argc, char **argv)
 {
   struct action_data adata;
 
@@ -223,41 +223,121 @@ check_action (int action)
     }
 }
 
-int
-check_user_perm (int action, struct action_data *ap)
+mu_dbm_file_t
+open_db_file (int action, struct action_data *ap, int *my_file)
 {
-  struct stat sb;
+  mu_dbm_file_t db;
   struct passwd *pw;
   uid_t uid;
+  int rc;
+  int flags = 0;
+  char *db_name = NULL;
+  int fd;
+  struct stat sb;
+  int safety_flags = MU_FILE_SAFETY_ALL & ~MU_FILE_SAFETY_OWNER_MISMATCH;
   
-  if (!ap->input_name)
-    ap->input_name = APOP_PASSFILE;
-
-  if (mu_dbm_stat (ap->input_name, &sb))
+  switch (action)
     {
-      if (ap->action == ACT_ADD)
-       {
-         DBM_FILE db;
-         if (mu_dbm_open (ap->input_name, &db, MU_STREAM_CREAT, permissions))
-           {
-             mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_open",
-                              ap->input_name, errno);
-             exit (EX_SOFTWARE);
-           }
-         mu_dbm_close (db);
-         mu_dbm_stat (ap->input_name, &sb);
-       }
-      else
-       {
-         mu_diag_funcall (MU_DIAG_ERROR, "stat", ap->input_name, errno);
-         exit (EX_OSERR);
-       }
+    case ACT_CREATE:
+      flags = MU_STREAM_CREAT;
+      safety_flags = MU_FILE_SAFETY_NONE;
+      db_name = ap->output_name;
+      break;
+
+    case ACT_ADD:
+    case ACT_DELETE:
+      if (!ap->input_name)
+       ap->input_name = APOP_PASSFILE;
+      flags = MU_STREAM_RDWR;
+      db_name = ap->input_name;
+      break;
+      
+    case ACT_LIST:
+      if (!ap->input_name)
+       ap->input_name = APOP_PASSFILE;
+      flags = MU_STREAM_READ;
+      safety_flags = MU_FILE_SAFETY_NONE;
+      db_name = ap->input_name;
+      break;
+
+    case ACT_CHPASS:
+      if (!ap->input_name)
+       ap->input_name = APOP_PASSFILE;
+      flags = MU_STREAM_RDWR;
+      db_name = ap->input_name;
+      break;
+      
+    default:
+      abort ();
     }
 
   uid = getuid ();
-  if (uid == 0 || sb.st_uid == uid)
-    return 0;
 
+  rc = mu_dbm_create (db_name, &db);
+  if (rc)
+    {
+      mu_diag_output (MU_DIAG_ERROR, _("unable to create database %s: %s"),
+                     db_name, mu_strerror (rc));
+      exit (EX_SOFTWARE);
+    }
+
+  //  mu_dbm_safety_set_owner (db, uid);
+  /* Adjust safety flags */
+  if (permissions & 0002)
+    safety_flags &= ~MU_FILE_SAFETY_WORLD_WRITABLE;
+  if (permissions & 0004)
+    safety_flags &= ~MU_FILE_SAFETY_WORLD_READABLE;
+  if (permissions & 0020)
+    safety_flags &= ~MU_FILE_SAFETY_GROUP_WRITABLE;
+  if (permissions & 0040)
+    safety_flags &= ~MU_FILE_SAFETY_GROUP_READABLE;
+  
+  mu_dbm_safety_set_flags (db, safety_flags);
+  rc = mu_dbm_safety_check (db);
+  if (rc && rc != ENOENT)
+    {
+      mu_diag_output (MU_DIAG_ERROR,
+                     _("%s fails safety check: %s"),
+                     db_name, mu_strerror (rc));
+      mu_dbm_destroy (&db);
+      exit (EX_UNAVAILABLE);
+    }
+  
+  rc = mu_dbm_open (db, flags, permissions);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_open",
+                      db_name, rc);
+      exit (EX_SOFTWARE);
+    }
+
+  if (uid == 0)
+    return db;
+
+  rc = mu_dbm_get_fd (db, &fd, NULL);
+  if (rc)
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_get_fd",
+                      db_name, rc);
+      exit (EX_SOFTWARE);
+    }
+
+  if (fstat (fd, &sb))
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "fstat",
+                      db_name, errno);
+      exit (EX_SOFTWARE);
+    }
+
+  if (sb.st_uid == uid)
+    {
+      if (my_file)
+       *my_file = 1;
+      return db;
+    }
+  if (my_file)
+    *my_file = 0;
+    
   if (ap->username)
     {
       mu_error (_("Only the file owner can use --username"));
@@ -273,41 +353,36 @@ check_user_perm (int action, struct action_data *ap)
   if (!pw)
     exit (EX_OSERR);
   ap->username = pw->pw_name;
-  return 1;
+  return db;
 }
 
 static void
-print_entry (mu_stream_t str, DBM_DATUM key, DBM_DATUM contents)
+print_entry (mu_stream_t str, struct mu_dbm_datum const *key,
+            struct mu_dbm_datum const *contents)
 {
   if (compatibility_option)
     mu_stream_printf (str, "%.*s: %.*s\n",
-                     (int) MU_DATUM_SIZE (key),
-                     (char*) MU_DATUM_PTR (key),
-                     (int) MU_DATUM_SIZE (contents),
-                     (char*) MU_DATUM_PTR (contents));
+                     (int) key->mu_dsize,
+                     (char*) key->mu_dptr,
+                     (int) contents->mu_dsize,
+                     (char*) contents->mu_dptr);
   else
     mu_stream_printf (str, "%.*s %.*s\n",
-                     (int) MU_DATUM_SIZE (key),
-                     (char*) MU_DATUM_PTR (key),
-                     (int) MU_DATUM_SIZE (contents),
-                     (char*) MU_DATUM_PTR (contents));
+                     (int) key->mu_dsize,
+                     (char*) key->mu_dptr,
+                     (int) contents->mu_dsize,
+                     (char*) contents->mu_dptr);
 }
 
 int
 action_list (struct action_data *ap)
 {
   mu_stream_t str;
-  DBM_FILE db;
-  DBM_DATUM key;
-  DBM_DATUM contents;
+  mu_dbm_file_t db;
+  struct mu_dbm_datum key, contents;
+  int rc;
   
-  check_user_perm (ACT_LIST, ap);
-  if (mu_dbm_open (ap->input_name, &db, MU_STREAM_READ, 0))
-    {
-      mu_error (_("cannot open file %s: %s"),
-               ap->input_name, mu_strerror (errno));
-      return 1;
-    }
+  db = open_db_file (ACT_LIST, ap, NULL);
   
   if (ap->output_name)
     {
@@ -331,32 +406,47 @@ action_list (struct action_data *ap)
     {
       memset (&key, 0, sizeof key);
       memset (&contents, 0, sizeof contents);
-      MU_DATUM_PTR (key) = ap->username;
-      MU_DATUM_SIZE (key) = strlen (ap->username);
-      if (mu_dbm_fetch (db, key, &contents))
+      key.mu_dptr = ap->username;
+      key.mu_dsize = strlen (ap->username);
+      rc = mu_dbm_fetch (db, &key, &contents);
+      if (rc == MU_ERR_NOENT)
        {
          mu_error (_("no such user: %s"), ap->username);
        }
+      else if (rc)
+       {
+         mu_error (_("database fetch error: %s"), mu_dbm_strerror (db));
+         exit (EX_UNAVAILABLE);
+       }
       else
        {
-         print_entry (str, key, contents);
+         print_entry (str, &key, &contents);
          mu_dbm_datum_free (&contents);
        }
     }
   else
     {
-      for (key = mu_dbm_firstkey (db); MU_DATUM_PTR(key);
-          key = mu_dbm_nextkey (db, key))
+      memset (&key, 0, sizeof key);
+      for (rc = mu_dbm_firstkey (db, &key); rc == 0;
+          rc = mu_dbm_nextkey (db, &key))
        {
          memset (&contents, 0, sizeof contents);
-         mu_dbm_fetch (db, key, &contents);
-         print_entry (str, key, contents);
-         mu_dbm_datum_free (&contents);
+         rc = mu_dbm_fetch (db, &key, &contents);
+         if (rc == 0)
+           {
+             print_entry (str, &key, &contents);
+             mu_dbm_datum_free (&contents);
+           }
+         else
+           {
+             mu_error (_("database fetch error: %s"), mu_dbm_strerror (db));
+             exit (EX_UNAVAILABLE);
+           }
+         mu_dbm_datum_free (&key);
        }
     }
   
-  mu_dbm_close (db);
-  mu_stream_destroy (&str);
+  mu_dbm_destroy (&db);
   return 0;
 }
 
@@ -365,9 +455,8 @@ action_create (struct action_data *ap)
 {
   int rc;
   mu_stream_t in;
-  DBM_FILE db;
-  DBM_DATUM key;
-  DBM_DATUM contents;
+  mu_dbm_file_t db;
+  struct mu_dbm_datum key, contents;
   char *buf = NULL;
   size_t size = 0, len;
   int line = 0;
@@ -399,12 +488,8 @@ action_create (struct action_data *ap)
   
   if (!ap->output_name)
     ap->output_name = APOP_PASSFILE;
-  if (mu_dbm_open (ap->output_name, &db, MU_STREAM_CREAT, permissions))
-    {
-      mu_error (_("cannot create database %s: %s"),
-               ap->output_name, mu_strerror (errno));
-      return 1;
-    }
+
+  db = open_db_file (ACT_CREATE, ap, NULL);
 
   line = 0;
   while ((rc = mu_stream_getline (in, &buf, &size, &len)) == 0
@@ -435,20 +520,25 @@ action_create (struct action_data *ap)
       
       memset (&key, 0, sizeof key);
       memset (&contents, 0, sizeof contents);
-      MU_DATUM_PTR (key) = str;
-      MU_DATUM_SIZE (key) = strlen (str);
-      MU_DATUM_PTR (contents) = pass;
-      MU_DATUM_SIZE (contents) = strlen (pass);
+      key.mu_dptr = str;
+      key.mu_dsize = strlen (str);
+      contents.mu_dptr = pass;
+      contents.mu_dsize = strlen (pass);
 
-      if (mu_dbm_insert (db, key, contents, 1))
-       mu_error (_("%s:%d: cannot store datum"), ap->input_name, line);
+      rc = mu_dbm_store (db, &key, &contents, 1);
+      if (rc)
+       mu_error (_("%s:%d: cannot store datum: %s"),
+                 ap->input_name, line,
+                 rc == MU_ERR_FAILURE ?
+                    mu_dbm_strerror (db) : mu_strerror (rc));
     }
   free (buf);
-  mu_dbm_close (db);
+  mu_dbm_destroy (&db);
   mu_stream_destroy (&in);
   return 0;
 }
 
+/*FIXME
 int
 open_io (int action, struct action_data *ap, DBM_FILE *db, int *not_owner)
 {
@@ -463,6 +553,7 @@ open_io (int action, struct action_data *ap, DBM_FILE *db, 
int *not_owner)
     }
   return 0;
 }
+*/
 
 void
 fill_pass (struct action_data *ap)
@@ -527,9 +618,8 @@ fill_pass (struct action_data *ap)
 int
 action_add (struct action_data *ap)
 {
-  DBM_FILE db;
-  DBM_DATUM key;
-  DBM_DATUM contents;
+  mu_dbm_file_t db;
+  struct mu_dbm_datum key, contents;
   int rc;
   
   if (!ap->username)
@@ -538,31 +628,32 @@ action_add (struct action_data *ap)
       return 1;
     }
 
-  if (open_io (ACT_ADD, ap, &db, NULL))
-    return 1;
+  db = open_db_file (ACT_ADD, ap, NULL);
 
   fill_pass (ap);
   
   memset (&key, 0, sizeof key);
   memset (&contents, 0, sizeof contents);
-  MU_DATUM_PTR (key) = ap->username;
-  MU_DATUM_SIZE (key) = strlen (ap->username);
-  MU_DATUM_PTR (contents) = ap->passwd;
-  MU_DATUM_SIZE (contents) = strlen (ap->passwd);
+  key.mu_dptr = ap->username;
+  key.mu_dsize = strlen (ap->username);
+  contents.mu_dptr = ap->passwd;
+  contents.mu_dsize = strlen (ap->passwd);
 
-  rc = mu_dbm_insert (db, key, contents, 1);
+  rc = mu_dbm_store (db, &key, &contents, 1);
   if (rc)
-    mu_error (_("cannot store datum"));
+    mu_error (_("cannot store datum: %s"),
+             rc == MU_ERR_FAILURE ?
+                    mu_dbm_strerror (db) : mu_strerror (rc));
 
-  mu_dbm_close (db);
+  mu_dbm_destroy (&db);
   return rc;
 }
 
 int
 action_delete (struct action_data *ap)
 {
-  DBM_FILE db;
-  DBM_DATUM key;
+  mu_dbm_file_t db;
+  struct mu_dbm_datum key;
   int rc;
   
   if (!ap->username)
@@ -571,56 +662,64 @@ action_delete (struct action_data *ap)
       return 1;
     }
 
-  if (open_io (ACT_DELETE, ap, &db, NULL))
-    return 1;
-  
-  MU_DATUM_PTR (key) = ap->username;
-  MU_DATUM_SIZE (key) = strlen (ap->username);
+  db = open_db_file (ACT_DELETE, ap, NULL);
+
+  memset (&key, 0, sizeof key);
+  key.mu_dptr = ap->username;
+  key.mu_dsize = strlen (ap->username);
 
-  rc = mu_dbm_delete (db, key);
+  rc = mu_dbm_delete (db, &key);
   if (rc)
-    mu_error (_("cannot remove record for %s"), ap->username);
+    mu_error (_("cannot remove record for %s: %s"),
+             ap->username,
+             rc == MU_ERR_FAILURE ?
+                    mu_dbm_strerror (db) : mu_strerror (rc));
 
-  mu_dbm_close (db);
+  mu_dbm_destroy (&db);
   return rc;
 }
 
 int
 action_chpass (struct action_data *ap)
 {
-  DBM_FILE db;
-  DBM_DATUM key;
-  DBM_DATUM contents;
+  mu_dbm_file_t db;
+  struct mu_dbm_datum key, contents;
   int rc;
-  int not_owner;
+  int my_file;
   
-  if (open_io (ACT_CHPASS, ap, &db, &not_owner))
-    return 1;
+  db = open_db_file (ACT_CHPASS, ap, &my_file);
 
   if (!ap->username)
     {
-      mu_error (_("missing username"));
-      return 1;
+      struct passwd *pw = getpwuid (getuid ());
+      ap->username = pw->pw_name;
+      printf ("Changing password for %s\n", ap->username);
     }
 
   memset (&key, 0, sizeof key);
   memset (&contents, 0, sizeof contents);
 
-  MU_DATUM_PTR (key) = ap->username;
-  MU_DATUM_SIZE (key) = strlen (ap->username);
-  if (mu_dbm_fetch (db, key, &contents))
+  key.mu_dptr = ap->username;
+  key.mu_dsize = strlen (ap->username);
+  rc = mu_dbm_fetch (db, &key, &contents);
+  if (rc == MU_ERR_NOENT)
     {
       mu_error (_("no such user: %s"), ap->username);
       return 1;
     }
-
-  if (not_owner)
+  else if (rc)
+    {
+      mu_error (_("database fetch error: %s"), mu_dbm_strerror (db));
+      exit (EX_UNAVAILABLE);
+    }
+      
+  if (!my_file)
     {
       char *oldpass, *p;
       
-      oldpass = xmalloc (MU_DATUM_SIZE (contents) + 1);
-      memcpy (oldpass, MU_DATUM_PTR (contents), MU_DATUM_SIZE (contents));
-      oldpass[MU_DATUM_SIZE (contents)] = 0;
+      oldpass = xmalloc (contents.mu_dsize + 1);
+      memcpy (oldpass, contents.mu_dptr, contents.mu_dsize);
+      oldpass[contents.mu_dsize] = 0;
       p = getpass (_("Old Password:"));
       if (!p)
        return 1;
@@ -634,32 +733,49 @@ action_chpass (struct action_data *ap)
   fill_pass (ap);
   
   mu_dbm_datum_free (&contents);
-  MU_DATUM_PTR (contents) = ap->passwd;
-  MU_DATUM_SIZE (contents) = strlen (ap->passwd);
-  rc = mu_dbm_insert (db, key, contents, 1);
+  contents.mu_dptr = ap->passwd;
+  contents.mu_dsize = strlen (ap->passwd);
+  rc = mu_dbm_store (db, &key, &contents, 1);
   if (rc)
-    mu_error (_("cannot replace datum"));
+    mu_error (_("cannot replace datum: %s"),
+             rc == MU_ERR_FAILURE ?
+                    mu_dbm_strerror (db) : mu_strerror (rc));
 
-  mu_dbm_close (db);
+  mu_dbm_destroy (&db);
   return rc;
 }
 
 void
 popauth_version (FILE *stream, struct argp_state *state)
 {
-#if defined(WITH_GDBM)
-# define FORMAT "GDBM"
-#elif defined(WITH_BDB)
-# define FORMAT "Berkeley DB"
-#elif defined(WITH_NDBM)
-# define FORMAT "NDBM"
-#elif defined(WITH_OLD_DBM)
-# define FORMAT "Old DBM"
-#elif defined(WITH_TOKYOCABINET)
-# define FORMAT "Tokyo Cabinet"
-#endif
+  mu_iterator_t itr;
+  int rc;
+
   mu_program_version_hook (stream, state);
-  fprintf (stream, _("Database format: %s\n"), FORMAT);
-  fprintf (stream, _("Database location: %s\n"), APOP_PASSFILE);
+  fprintf (stream, _("Database formats: "));
+
+  rc = mu_dbm_impl_iterator (&itr);
+  if (rc)
+    {
+      fprintf (stream, "%s\n", _("unknown"));
+      mu_error ("%s", mu_strerror (rc));
+    }
+  else
+    {
+      int i;
+      for (mu_iterator_first (itr), i = 0; !mu_iterator_is_done (itr);
+          mu_iterator_next (itr), i++)
+       {
+         struct mu_dbm_impl *impl;
+
+         mu_iterator_current (itr, (void**)&impl);
+         if (i)
+           fprintf (stream, ", ");
+         fprintf (stream, "%s", impl->_dbm_name);
+       }
+      fputc ('\n', stream);
+      mu_iterator_destroy (&itr);
+    }
+  fprintf (stream, _("Default database location: %s\n"), APOP_PASSFILE);
   exit (EX_OK);
 }


hooks/post-receive
-- 
GNU Mailutils



reply via email to

[Prev in Thread] Current Thread [Next in Thread]