From 9e64cec572b52d2716704fc7cc277226c248d6d5 Mon Sep 17 00:00:00 2001 From: Julien Kerihuel Date: Mon, 9 Feb 2009 17:13:52 +0000 Subject: [PATCH] - Add a very preliminary and light libmapistore implementation. mapistore only supplies init/release and add/del backend contexts. This commit also includes a sqlite3 backend skeleton (open/close sqlite db) - A temporary mapistore testing tool has been added locally for implementation checks. --- Makefile | 117 ++++++- config.mk.in | 14 +- configure.ac | 27 +- mapiproxy/libmapistore.pc.in | 14 + .../libmapistore/backends/mapistore_sqlite3.c | 126 +++++++ .../libmapistore/backends/mapistore_sqlite3.h | 43 +++ mapiproxy/libmapistore/mapistore.h | 110 +++++++ mapiproxy/libmapistore/mapistore_backend.c | 307 ++++++++++++++++++ mapiproxy/libmapistore/mapistore_errors.h | 109 +++++++ mapiproxy/libmapistore/mapistore_interface.c | 233 +++++++++++++ mapiproxy/libmapistore/mapistore_private.h | 106 ++++++ mapiproxy/libmapistore/mapistore_processing.c | 259 +++++++++++++++ mapiproxy/libmapistore/tests/mapistore_test.c | 112 +++++++ 13 files changed, 1562 insertions(+), 15 deletions(-) create mode 100644 mapiproxy/libmapistore.pc.in create mode 100644 mapiproxy/libmapistore/backends/mapistore_sqlite3.c create mode 100644 mapiproxy/libmapistore/backends/mapistore_sqlite3.h create mode 100644 mapiproxy/libmapistore/mapistore.h create mode 100644 mapiproxy/libmapistore/mapistore_backend.c create mode 100644 mapiproxy/libmapistore/mapistore_errors.h create mode 100644 mapiproxy/libmapistore/mapistore_interface.c create mode 100644 mapiproxy/libmapistore/mapistore_private.h create mode 100644 mapiproxy/libmapistore/mapistore_processing.c create mode 100644 mapiproxy/libmapistore/tests/mapistore_test.c diff --git a/Makefile b/Makefile index ac4b7645..ae33f7b7 100644 --- a/Makefile +++ b/Makefile @@ -708,23 +708,37 @@ LIBMAPISERVER_SO_VERSION = 0 .PHONY: mapiproxy -mapiproxy: idl \ - libmapiproxy \ - libmapiserver \ - mapiproxy/dcesrv_mapiproxy.$(SHLIBEXT) \ - mapiproxy-modules \ - mapiproxy-servers - -mapiproxy-install: mapiproxy mapiproxy-modules-install mapiproxy-servers-install libmapiproxy-install libmapiserver-install +mapiproxy: idl \ + libmapiproxy \ + libmapiserver \ + libmapistore \ + mapiproxy/dcesrv_mapiproxy.$(SHLIBEXT) \ + mapiproxy-modules \ + mapiproxy-servers + +mapiproxy-install: mapiproxy \ + mapiproxy-modules-install \ + mapiproxy-servers-install \ + libmapiproxy-install \ + libmapiserver-install \ + libmapistore-install $(INSTALL) -d $(DESTDIR)$(SERVER_MODULESDIR) $(INSTALL) -m 0755 mapiproxy/dcesrv_mapiproxy.$(SHLIBEXT) $(DESTDIR)$(SERVER_MODULESDIR) -mapiproxy-uninstall: mapiproxy-modules-uninstall mapiproxy-servers-uninstall libmapiproxy-uninstall libmapiserver-uninstall +mapiproxy-uninstall: mapiproxy-modules-uninstall \ + mapiproxy-servers-uninstall \ + libmapiproxy-uninstall \ + libmapiserver-uninstall \ + libmapistore-uninstall rm -f $(DESTDIR)$(SERVER_MODULESDIR)/dcesrv_mapiproxy.* rm -f $(DESTDIR)$(libdir)/libmapiproxy.* rm -f $(DESTDIR)$(includedir)/libmapiproxy.h -mapiproxy-clean:: mapiproxy-modules-clean mapiproxy-servers-clean libmapiproxy-clean libmapiserver-clean +mapiproxy-clean:: mapiproxy-modules-clean \ + mapiproxy-servers-clean \ + libmapiproxy-clean \ + libmapiserver-clean \ + libmapistore-clean rm -f mapiproxy/*.o mapiproxy/*.po rm -f mapiproxy/dcesrv_mapiproxy.$(SHLIBEXT) @@ -817,6 +831,89 @@ mapiproxy/libmapiserver.$(SHLIBEXT).$(LIBMAPISERVER_SO_VERSION): libmapiserver.$ ln -fs $< $@ +################ +# libmapistore +################ + +libmapistore: mapiproxy/libmapistore.$(SHLIBEXT).$(PACKAGE_VERSION) \ + $(OC_MAPISTORE) \ + mapistore_test + +libmapistore-install: $(OC_MAPISTORE_INSTALL) + $(INSTALL) -m 0755 mapiproxy/libmapistore.$(SHLIBEXT).$(PACKAGE_VERSION) $(DESTDIR)$(libdir) + ln -sf libmapistore.$(SHLIBEXT).$(PACKAGE_VERSION) $(DESTDIR)$(libdir)/libmapistore.$(SHLIBEXT) + $(INSTALL) -d $(DESTDIR)$(includedir)/mapistore + $(INSTALL) -m 0644 mapiproxy/libmapistore/mapistore.h $(DESTDIR)$(includedir)/mapistore/ + $(INSTALL) -m 0644 mapiproxy/libmapistore/mapistore_errors.h $(DESTDIR)$(includedir)/mapistore/ + $(INSTALL) -m 0644 mapiproxy/libmapiserver.pc $(DESTDIR)$(libdir)/pkgconfig + +libmapistore-clean: $(OC_MAPISTORE_CLEAN) + rm -f mapiproxy/libmapistore/*.po mapiproxy/libmapistore/*.o + rm -f mapiproxy/libmapistore.$(SHLIBEXT).$(PACKAGE_VERSION) + rm -f mapiproxy/libmapistore.$(SHLIBEXT).$(LIBMAPISTORE_SO_VERSION) + +libmapistore-uninstall: $(OC_MAPISTORE_UNINSTALL) + rm -f $(DESTDIR)$(libdir)/libmapistore.* + rm -rf $(DESTDIR)$(includedir)/mapistore + rm -f $(DESTDIR)$(libdir)/pkgconfig/libmapistore.pc + +libmapistore-distclean: libmapistore-clean + rm -f mapiproxy/libmapistore.pc + +distclean:: libmapistore-distclean + +mapiproxy/libmapistore.$(SHLIBEXT).$(PACKAGE_VERSION): mapiproxy/libmapistore/mapistore_interface.po \ + mapiproxy/libmapistore/mapistore_processing.po \ + mapiproxy/libmapistore/mapistore_backend.po + @$(CC) -o $@ $(DSOOPT) -Wl,-soname,libmapistore.$(SHLIBEXT).$(LIBMAPISTORE_SO_VERSION) $^ -L. $(LIBS) + +mapiproxy/libmapistore.$(SHLIBEXT).$(LIBMAPISTORE_SO_VERSION): libmapistore.$(SHLIBEXT).$(PACKAGE_VERSION) + +##################### +# mapistore backends +##################### + +mapistore_sqlite3: mapiproxy/libmapistore/backends/mapistore_sqlite3.$(SHLIBEXT) + +mapistore_sqlite3-install: + $(INSTALL) -d $(DESTDIR)$(libdir)/mapistore_backends + $(INSTALL) -m 0755 mapiproxy/libmapistore/backends/mapistore_sqlite3.$(SHLIBEXT) $(DESTDIR)$(libdir)/mapistore_backends/ + +mapistore_sqlite3-uninstall: + rm -rf $(DESTDIR)$(libdir)/mapistore_backends + +mapistore_sqlite3-clean: + rm -f mapiproxy/libmapistore/backends/mapistore_sqlite3.o + rm -f mapiproxy/libmapistore/backends/mapistore_sqlite3.po + +clean:: mapistore_sqlite3-clean + +mapistore_sqlite3-distclean: mapistore_sqlite3-clean + rm -f mapiproxy/libmapistore/backends/mapistore_sqlite3.so + +distclean:: mapistore_sqlite3-distclean + +mapiproxy/libmapistore/backends/mapistore_sqlite3.$(SHLIBEXT): mapiproxy/libmapistore/backends/mapistore_sqlite3.po + @echo "Linking mapistore module $@" + @$(CC) $(SQLITE_CFLAGS) -o $@ $(DSOOPT) $^ -L. $(LIBS) $(SQLITE_LIBS) + +####################### +# mapistore test tools +####################### + +mapistore_test: bin/mapistore_test + +bin/mapistore_test: mapiproxy/libmapistore/tests/mapistore_test.o \ + mapiproxy/libmapistore.$(SHLIBEXT).$(PACKAGE_VERSION) + @echo "Linking $@" + @$(CC) -o $@ $^ $(LIBS) -lpopt + +mapistore_clean: + rm -f mapiproxy/libmapistore/tests/*.o + rm -f bin/mapistore_test + +clean:: mapistore_clean + #################### # mapiproxy modules #################### diff --git a/config.mk.in b/config.mk.in index 2f8e37bc..72de2628 100644 --- a/config.mk.in +++ b/config.mk.in @@ -29,8 +29,10 @@ pythondir=@pythondir@ sambaprefix=@sambaprefix@ DSOOPT=-shared -fPIC -CFLAGS=@CFLAGS@ -I. -Wall -Wmissing-prototypes -Wstrict-prototypes -g3 \ - -DDEFAULT_LDIF=\"$(datadir)/setup/profiles\" +CFLAGS=@CFLAGS@ -I. -Wall -Wmissing-prototypes -Wstrict-prototypes -g3 \ + -DDEFAULT_LDIF=\"$(datadir)/setup/profiles\" \ + -DMAPISTORE_BACKEND_INSTALLDIR=\"$(libdir)/mapistore_backends\" \ + -DMAPISTORE_MAPPING_PATH=\"$(prefix)/private/mapistore\" # This value should be determined by configure at some point SHLIBEXT=so @@ -78,6 +80,14 @@ OC_SERVER=@OC_SERVER@ OC_SERVER_INSTALL=@OC_SERVER_INSTALL@ OC_SERVER_UNINSTALL=@OC_SERVER_UNINSTALL@ +# MAPISTORE BACKENDS +OC_MAPISTORE=@OC_MAPISTORE@ +OC_MAPISTORE_CLEAN=@OC_MAPISTORE_CLEAN@ +OC_MAPISTORE_INSTALL=@OC_MAPISTORE_INSTALL@ +OC_MAPISTORE_UNINSTALL=@OC_MAPISTORE_UNINSTALL@ + +SQLITE_CFLAGS=@SQLITE_CFLAGS@ +SQLITE_LIBS=@SQLITE_LIBS@ # SWIG SWIGDIRS-ALL=@SWIGDIRSALL@ diff --git a/configure.ac b/configure.ac index ebdfbf3c..798c3786 100644 --- a/configure.ac +++ b/configure.ac @@ -92,14 +92,16 @@ if test "x$1_set" != "xset"; then OC_$2_INSTALL+=" $1-install" OC_$2_UNINSTALL+=" $1-uninstall" ;; - SERVER) + SERVER|MAPISTORE) OC_$2+=" $1" + OC_$2_CLEAN+="$1-clean" OC_$2_INSTALL+=" $1-install" OC_$2_UNINSTALL+=" $1-uninstall" ;; esac AC_SUBST(OC_$2) + AC_SUBST(OC_$2_CLEAN) AC_SUBST(OC_$2_INSTALL) AC_SUBST(OC_$2_UNINSTALL) @@ -357,6 +359,21 @@ if test x"$enable_libmagic" = x"yes"; then fi +dnl ########################################################################## +dnl libmapistore backends dependencies +dnl ########################################################################## + +dnl -------------------------------------------------------------------------- +dnl Check for sqlite3 +dnl -------------------------------------------------------------------------- +PKG_CHECK_MODULES(SQLITE, sqlite3, SQLITEFOUND=yes, [SQLITEFOUND=no]) +AC_SUBST(SQLITE_CFLAGS) +AC_SUBST(SQLITE_LIBS) + +if test x"$SQLITEFOUND" = x"yes"; then + OC_RULE_ADD(mapistore_sqlite3, MAPISTORE) +fi + dnl ########################################################################## dnl torture dependencies @@ -448,8 +465,9 @@ dnl *********************** dnl Makefiles dnl *********************** AC_CONFIG_FILES([config.mk libmapi.pc libmapiadmin.pc libocpf.pc mapiproxy/libmapiproxy.pc - mapiproxy/libmapiserver.pc Doxyfile libmapi++/Doxyfile libocpf/Doxyfile - libmapiadmin/Doxyfile libmapi/Doxyfile mapiproxy/Doxyfile utils/mapitest/Doxyfile]) + mapiproxy/libmapiserver.pc mapiproxy/libmapistore.pc Doxyfile libmapi++/Doxyfile + libocpf/Doxyfile libmapiadmin/Doxyfile libmapi/Doxyfile mapiproxy/Doxyfile + utils/mapitest/Doxyfile]) AC_OUTPUT @@ -495,6 +513,9 @@ OpenChange Configuration (Please review) * OpenChange Server: - mapiproxy: $enable_mapiproxy + * OpenChange mapistore backends: + - sqlite3: $enable_mapistore_sqlite3 + * OpenChange Tools: - openchangeclient: $enable_openchangeclient - mapiprofile: $enable_mapiprofile diff --git a/mapiproxy/libmapistore.pc.in b/mapiproxy/libmapistore.pc.in new file mode 100644 index 00000000..af14e93b --- /dev/null +++ b/mapiproxy/libmapistore.pc.in @@ -0,0 +1,14 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +datarootdir=@prefix@/share +datadir=@datadir@ + +Name: MAPISTORE +Description: MAPI Storage Abstraction Layer library +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lmapistore +Libs.private: @LIBS@ +Cflags: -I${includedir} +Requires: talloc tdb diff --git a/mapiproxy/libmapistore/backends/mapistore_sqlite3.c b/mapiproxy/libmapistore/backends/mapistore_sqlite3.c new file mode 100644 index 00000000..2b3a3694 --- /dev/null +++ b/mapiproxy/libmapistore/backends/mapistore_sqlite3.c @@ -0,0 +1,126 @@ +/* + OpenChange Storage Abstraction Layer library + MAPIStore SQLite backend + + OpenChange Project + + Copyright (C) Julien Kerihuel 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "mapistore_sqlite3.h" + + +/** + \details Initialize sqlite3 mapistore backend + + \return MAPISTORE_SUCCESS on success + */ +static int sqlite3_init(void) +{ + DEBUG(0, ("sqlite3 backend initialized\n")); + + return MAPISTORE_SUCCESS; +} + + +/** + \details Create a connection context to the sqlite3 backend + + \param mem_ctx pointer to the memory context + \param uri pointer to the database path + \param context_id pointer to the context identifier the function + returns + + \return MAPISTORE_SUCCESS on success + */ +static int sqlite3_create_context(TALLOC_CTX *mem_ctx, const char *uri, void **private_data) +{ + struct sqlite3_context *sqlite_ctx; + sqlite3 *db; + int ret; + + DEBUG(0, ("[%s:%d]\n", __FUNCTION__, __LINE__)); + + ret = sqlite3_open(uri, &db); + if (ret) { + DEBUG(3, ("[%s:%d]: %s\n", __FUNCTION__, __LINE__, + sqlite3_errmsg(db))); + sqlite3_close(db); + return -1; + } + + sqlite_ctx = talloc_zero(mem_ctx, struct sqlite3_context); + sqlite_ctx->db = db; + sqlite_ctx->private_data = NULL; + + *private_data = (void *)sqlite_ctx; + + return MAPISTORE_SUCCESS; +} + + +/** + \details Delete a connection context from the sqlite3 backend + + \return MAPISTORE_SUCCESS on success + */ +static int sqlite3_delete_context(void *private_data) +{ + struct sqlite3_context *sqlite_ctx = (struct sqlite3_context *)private_data; + int ret; + + DEBUG(5, ("[%s:%d]\n", __FUNCTION__, __LINE__)); + + if (!private_data) { + return MAPISTORE_SUCCESS; + } + + ret = sqlite3_close(sqlite_ctx->db); + if (ret) return MAPISTORE_ERROR; + + return MAPISTORE_SUCCESS; +} + + +/** + \details Entry point for mapistore SQLite backend + + \return MAPISTORE_SUCCESS on success, otherwise -1 + */ +int mapistore_init_backend(void) +{ + struct mapistore_backend backend; + int ret; + + /* Fill in our name */ + backend.name = "sqlite3"; + backend.description = "mapistore sqlite3 backend"; + backend.namespace = "sqlite://"; + + /* Fill in all the operations */ + backend.init = sqlite3_init; + backend.create_context = sqlite3_create_context; + backend.delete_context = sqlite3_delete_context; + + /* Register ourselves with the MAPIPROXY subsystem */ + ret = mapistore_backend_register(&backend); + if (ret != MAPISTORE_SUCCESS) { + DEBUG(0, ("Failed to register the '%s' mapistore backend!\n", backend.name)); + return ret; + } + + return MAPISTORE_SUCCESS; +} diff --git a/mapiproxy/libmapistore/backends/mapistore_sqlite3.h b/mapiproxy/libmapistore/backends/mapistore_sqlite3.h new file mode 100644 index 00000000..9363cbca --- /dev/null +++ b/mapiproxy/libmapistore/backends/mapistore_sqlite3.h @@ -0,0 +1,43 @@ +/* + OpenChange Storage Abstraction Layer library + MAPIStore SQLite backend + + OpenChange Project + + Copyright (C) Julien Kerihuel 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef __MAPISTORE_SQLITE3_H +#define __MAPISTORE_SQLITE3_H + +#include +#include +#include +#include + +struct sqlite3_context { + sqlite3 *db; + void *private_data; +}; + + +__BEGIN_DECLS + +int mapistore_init_backend(void); + +__END_DECLS + +#endif /* ! __MAPISTORE_SQLITE3_H */ diff --git a/mapiproxy/libmapistore/mapistore.h b/mapiproxy/libmapistore/mapistore.h new file mode 100644 index 00000000..cd62e52c --- /dev/null +++ b/mapiproxy/libmapistore/mapistore.h @@ -0,0 +1,110 @@ +/* + OpenChange Storage Abstraction Layer library + + OpenChange Project + + Copyright (C) Julien Kerihuel 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef __MAPISTORE_H +#define __MAPISTORE_H + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef _PUBLIC_ +#define _PUBLIC_ +#endif + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define MAPISTORE_SUCCESS 0 + +typedef int (*init_backend_fn) (void); + +#define MAPISTORE_INIT_MODULE "mapistore_init_backend" + +struct mapistore_backend { + const char *name; + const char *description; + const char *namespace; + + int (*init)(void); + int (*create_context)(TALLOC_CTX *, const char *, void **); + int (*delete_context)(void *); +}; + +struct backend_context { + const struct mapistore_backend *backend; + void *private_data; + uint32_t context_id; +}; + +struct backend_context_list { + struct backend_context *ctx; + struct backend_context_list *prev; + struct backend_context_list *next; +}; + +struct processing_context; + +struct mapistore_context { + struct processing_context *processing_ctx; + struct backend_context_list *context_list; +}; + +#ifndef __BEGIN_DECLS +#ifdef __cplusplus +#define __BEGIN_DECLS extern "C" { +#define __END_DECLS } +#else +#define __BEGIN_DECLS +#define __END_DECLS +#endif +#endif + +__BEGIN_DECLS + +/* definitions from mapistore_interface.c */ +struct mapistore_context *mapistore_init(TALLOC_CTX *, const char *); +int mapistore_release(struct mapistore_context *); +int mapistore_add_context(struct mapistore_context *, const char *uri, uint32_t *); +int mapistore_del_context(struct mapistore_context *, uint32_t); +const char *mapistore_errstr(int); + +/* definitions from mapistore_processing.c */ +int mapistore_set_mapping_path(const char *); + +/* definitions from mapistore_backend.c */ +extern int mapistore_backend_register(const void *); +const char *mapistore_backend_get_installdir(void); +init_backend_fn *mapistore_backend_load(TALLOC_CTX *, const char *); + +bool mapistore_backend_run_init(init_backend_fn *); + +__END_DECLS + +#endif /* ! __MAPISTORE_H */ diff --git a/mapiproxy/libmapistore/mapistore_backend.c b/mapiproxy/libmapistore/mapistore_backend.c new file mode 100644 index 00000000..24283168 --- /dev/null +++ b/mapiproxy/libmapistore/mapistore_backend.c @@ -0,0 +1,307 @@ +/* + OpenChange Storage Abstraction Layer library + + OpenChange Project + + Note: init and load functions have been copied from + samba4/source4/param/util.c initially wrote by Jelmer. + + Copyright (C) Jelmer Vernooij 2005-2007 + Copyright (C) Julien Kerihuel 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include "mapistore.h" +#include "mapistore_errors.h" +#include "mapistore_private.h" +#include + +#include +#include + +/** + \file mapistore_backend.c + + \brief mapistore backends management API + */ + + +static struct mstore_backend { + struct mapistore_backend *backend; +} *backends = NULL; + +int num_backends; + + +/** + \details Register mapistore backends + + \param _backend pointer to the mapistore backend to register + + \return MAPISTORE_SUCCESS on success + */ +_PUBLIC_ extern int mapistore_backend_register(const void *_backend) +{ + const struct mapistore_backend *backend = _backend; + + backends = realloc_p(backends, struct mstore_backend, num_backends + 1); + if (!backends) { + smb_panic("out of memory in mapistore_backend_register"); + } + + backends[num_backends].backend = smb_xmemdup(backend, sizeof (*backend)); + backends[num_backends].backend->name = smb_xstrdup(backend->name); + + num_backends++; + + DEBUG(3, ("MAPISTORE backend '%s' registered\n", backend->name)); + + return MAPISTORE_SUCCESS; +} + + +/** + \details Return the full path where mapistore backends are + installed. + + \return Pointer to the full path where backends are installed. + */ +_PUBLIC_ const char *mapistore_backend_get_installdir(void) +{ + return MAPISTORE_BACKEND_INSTALLDIR; +} + + +/** + \details Obtain the backend init function from a shared library + file + + \param path full path to the backend shared library + + \return Pointer to the initialization function on success, + otherwise NULL. + */ +static init_backend_fn load_backend(const char *path) +{ + void *handle; + void *init_fn; + + handle = dlopen(path, RTLD_NOW); + if (handle == NULL) { + DEBUG(0, ("Unable to open %s: %s\n", path, dlerror())); + return NULL; + } + + init_fn = dlsym(handle, MAPISTORE_INIT_MODULE); + + if (init_fn == NULL) { + DEBUG(0, ("Unable to find %s() in %s: %s\n", + MAPISTORE_INIT_MODULE, path, dlerror())); + DEBUG(1, ("Loading mapistore backend '%s' failed\n", path)); + dlclose(handle); + return NULL; + } + + return (init_backend_fn) init_fn; +} + + +/** + \details Load backends from specified directory + + \param mem_ctx pointer to the memory context + \param pointer to the backends shared library folder + + \return allocated array of functions pointers to initialization + functions on success, otherwise NULL. + */ +static init_backend_fn *load_backends(TALLOC_CTX *mem_ctx, const char *path) +{ + DIR *dir; + struct dirent *entry; + char *filename; + int success = 0; + init_backend_fn *ret; + + ret = talloc_array(mem_ctx, init_backend_fn, 2); + ret[0] = NULL; + + dir = opendir(path); + if (dir == NULL) { + talloc_free(ret); + return NULL; + } + + while ((entry = readdir(dir))) { + if (ISDOT(entry->d_name) || ISDOTDOT(entry->d_name)) { + continue; + } + + filename = talloc_asprintf(mem_ctx, "%s/%s", path, entry->d_name); + ret[success] = load_backend(filename); + if (ret[success]) { + ret = talloc_realloc(mem_ctx, ret, init_backend_fn, success + 2); + success++; + ret[success] = NULL; + } + + talloc_free(filename); + } + + closedir(dir); + + return ret; +} + + +/** + \details Load the initialization functions from backends DSO + + \param mem_ctx pointer to the memory context + \param path pointer to the backend's DSO folder + + \return allocated array of functions pointers to initialization + functions on success, otherwise NULL. + */ +_PUBLIC_ init_backend_fn *mapistore_backend_load(TALLOC_CTX *mem_ctx, const char *path) +{ + if (!path) { + path = mapistore_backend_get_installdir(); + } + + return load_backends(mem_ctx, path); +} + + +/** + \details Run specified initialization functions. + + \param fns pointer to an array of mapistore backends initialization + functions + + \return true on success, otherwise false + */ +_PUBLIC_ bool mapistore_backend_run_init(init_backend_fn *fns) +{ + int i; + bool ret = true; + + if (fns == NULL) { + return true; + } + + for (i = 0; fns[i]; i++) { + ret &= (bool)fns[i](); + } + + return ret; +} + + +/** + \details Initialize mapistore backends + + \param mem_ctx pointer to the memory context + \param path pointer to folder where mapistore backends are + installed + + \return MAPISTORE_SUCCESS on success, otherwise + MAPISTORE_ERR_BACKEND_INIT + */ +int mapistore_backend_init(TALLOC_CTX *mem_ctx, const char *path) +{ + init_backend_fn *ret; + bool status; + int retval; + int i; + + ret = mapistore_backend_load(mem_ctx, path); + status = mapistore_backend_run_init(ret); + talloc_free(ret); + + for (i = 0; i < num_backends; i++) { + if (backends[i].backend) { + DEBUG(3, ("MAPISTORE backend '%s' loaded\n", backends[i].backend->name)); + retval = backends[i].backend->init(); + } + } + + return (status != true) ? MAPISTORE_SUCCESS : MAPISTORE_ERR_BACKEND_INIT; +} + + +/** + \details Create backend context + + \param mem_ctx pointer to the memory context + \param namespace the backend namespace + \param uri the backend parameters which can be passes inline + + \return a valid backend_context pointer on success, otherwise NULL + */ +struct backend_context *mapistore_backend_create_context(TALLOC_CTX *mem_ctx, const char *namespace, + const char *uri) +{ + struct backend_context *context; + int retval; + bool found; + void *private_data = NULL; + int i; + + DEBUG(0, ("namespace is %s and backend_uri is '%s'\n", namespace, uri)); + for (i = 0; i < num_backends; i++) { + if (backends[i].backend->namespace && + !strcmp(namespace, backends[i].backend->namespace)) { + found = true; + retval = backends[i].backend->create_context(mem_ctx, uri, &private_data); + if (retval != MAPISTORE_SUCCESS) { + return NULL; + } + + break; + } + } + if (found == false) { + DEBUG(0, ("MAPISTORE: no backend with namespace '%s' is available\n", namespace)); + return NULL; + } + + context = talloc_zero(mem_ctx, struct backend_context); + context->backend = backends[i].backend; + context->private_data = private_data; + talloc_steal(context, context->private_data); + + return context; +} + + +/** + \details Delete a context from the specified backend + + \param bctx pointer to the backend context + + \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error + */ +_PUBLIC_ int mapistore_backend_delete_context(struct backend_context *bctx) +{ + if (!bctx->backend->delete_context) return MAPISTORE_ERROR; + + return bctx->backend->delete_context(bctx->private_data); +} diff --git a/mapiproxy/libmapistore/mapistore_errors.h b/mapiproxy/libmapistore/mapistore_errors.h new file mode 100644 index 00000000..97b21e71 --- /dev/null +++ b/mapiproxy/libmapistore/mapistore_errors.h @@ -0,0 +1,109 @@ +/* + OpenChange Storage Abstraction Layer library + + OpenChange Project + + Copyright (C) Julien Kerihuel 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/** + \file mapistore_errors.h + + \brief Thie header providers a set of result codes for MAPISTORE + function calls. + */ + +#ifndef __MAPISTORE_ERRORS_H +#define __MAPISTORE_ERRORS_H + +/** + The function call succeeded. + */ +#define MAPISTORE_SUCCESS 0 + +/** + The function call failed for some non-specific reason. + */ +#define MAPISTORE_ERROR 1 + +/** + The function call failed because it was unable to allocate the + memory required by underlying operations. + */ +#define MAPISTORE_ERR_NO_MEMORY 2 + +/** + The function call failed because underlying context has already + been initialized + */ +#define MAPISTORE_ERR_ALREADY_INITIALIZED 3 + +/** + The function call failed because context has not been initialized. + */ +#define MAPISTORE_ERR_NOT_INITIALIZED 4 + +/** + The function call failed because an internal mapistore storage + component has corrupted data. + */ +#define MAPISTORE_ERR_CORRUPTED 5 + +/** + The function call failed because one of the function parameters is + invalid + */ +#define MAPISTORE_ERR_INVALID_PARAMETER 6 + +/** + The function call failed because the directory doesn't exist + */ +#define MAPISTORE_ERR_NO_DIRECTORY 7 + +/** + The function call failed because the underlying function couldn't + open a database. + */ +#define MAPISTORE_ERR_DATABASE_INIT 8 + +/** + The function call failed because the underlying function didn't run + a database operation successfully. + */ +#define MAPISTORE_ERR_DATABASE_OPS 9 + +/** + The function failed to register a storage backend + */ +#define MAPISTORE_ERR_BACKEND_REGISTER 10 + +/** + One of more storage backend initialization functions failed to + complete successfully. + */ +#define MAPISTORE_ERR_BACKEND_INIT 11 + +/** + The function failed because mapistore failed to create a context + */ +#define MAPISTORE_ERR_CONTEXT_FAILED 12 + +/** + The function failed because the provided namespace is invalid + */ +#define MAPISTORE_ERR_INVALID_NAMESPACE 13 + +#endif /* ! __MAPISTORE_ERRORS_H */ diff --git a/mapiproxy/libmapistore/mapistore_interface.c b/mapiproxy/libmapistore/mapistore_interface.c new file mode 100644 index 00000000..c2a87c58 --- /dev/null +++ b/mapiproxy/libmapistore/mapistore_interface.c @@ -0,0 +1,233 @@ +/* + OpenChange Storage Abstraction Layer library + + OpenChange Project + + Copyright (C) Julien Kerihuel 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "mapistore.h" +#include "mapistore_errors.h" +#include "mapistore_private.h" +#include + +#include + +/** + \details Initialize the mapistore context + + \param mem_ctx pointer to the memory context + + \return allocate mapistore context on success, otherwise NULL + */ +_PUBLIC_ struct mapistore_context *mapistore_init(TALLOC_CTX *mem_ctx, const char *path) +{ + int retval; + struct mapistore_context *mstore_ctx; + + mstore_ctx = talloc_zero(mem_ctx, struct mapistore_context); + if (!mstore_ctx) { + return NULL; + } + + mstore_ctx->processing_ctx = talloc_zero(mstore_ctx, struct processing_context); + retval = mapistore_init_mapping_context(mstore_ctx->processing_ctx); + if (retval != MAPISTORE_SUCCESS) { + DEBUG(5, ("[%s:%d]: %s\n", __FUNCTION__, __LINE__, mapistore_errstr(retval))); + talloc_free(mstore_ctx); + return NULL; + } + + retval = mapistore_backend_init(mem_ctx, path); + if (retval != MAPISTORE_SUCCESS) { + DEBUG(5, ("[%s:%d]: %s\n", __FUNCTION__, __LINE__, mapistore_errstr(retval))); + talloc_free(mstore_ctx); + return NULL; + } + + mstore_ctx->context_list = NULL; + + return mstore_ctx; +} + + +/** + \details Release the mapistore context and destroy any data + associated + + \param mstore_ctx pointer to the mapistore context + + \note The function needs to rely on talloc destructors which is not + implemented in code yet. + + \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error + */ +_PUBLIC_ int mapistore_release(struct mapistore_context *mstore_ctx) +{ + if (!mstore_ctx) return MAPISTORE_ERR_NOT_INITIALIZED; + + talloc_free(mstore_ctx->processing_ctx); + talloc_free(mstore_ctx->context_list); + talloc_free(mstore_ctx); + + return MAPISTORE_SUCCESS; +} + + +/** + \details Add a new connection context to mapistore + + \param mstore_ctx pointer to the mapistore context + \param uri the connection context URI + \param pointer to the context identifier the function returns + + \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error + */ +_PUBLIC_ int mapistore_add_context(struct mapistore_context *mstore_ctx, + const char *uri, uint32_t *context_id) +{ + TALLOC_CTX *mem_ctx; + int retval; + struct backend_context *backend_ctx; + struct backend_context_list *backend_list; + char *namespace; + char *namespace_start; + char *backend_uri; + + /* Step 1. Perform Sanity Checks on URI */ + if (!uri || strlen(uri) < 4) { + return MAPISTORE_ERR_INVALID_NAMESPACE; + } + + mem_ctx = talloc_named(NULL, 0, "mapistore_add_context"); + namespace = talloc_strdup(mem_ctx, uri); + namespace_start = namespace; + namespace = strchr(namespace, ':'); + if (!namespace) { + DEBUG(0, ("[%s:%d]: Error - Invalid namespace '%s'\n", __FUNCTION__, __LINE__, namespace_start)); + talloc_free(mem_ctx); + return MAPISTORE_ERR_INVALID_NAMESPACE; + } + + if (namespace[1] && namespace[1] == '/' && + namespace[2] && namespace[2] == '/' && + namespace[3]) { + backend_uri = talloc_strdup(mem_ctx, &namespace[3]); + namespace[3] = '\0'; + backend_ctx = mapistore_backend_create_context((TALLOC_CTX *)mstore_ctx, namespace_start, backend_uri); + if (!backend_ctx) { + return MAPISTORE_ERR_CONTEXT_FAILED; + } + + backend_list = talloc_zero((TALLOC_CTX *) mstore_ctx, struct backend_context_list); + talloc_steal(backend_list, backend_ctx); + backend_list->ctx = backend_ctx; + retval = mapistore_get_context_id(mstore_ctx->processing_ctx, &backend_list->ctx->context_id); + if (retval != MAPISTORE_SUCCESS) { + talloc_free(mem_ctx); + return MAPISTORE_ERR_CONTEXT_FAILED; + } + *context_id = backend_list->ctx->context_id; + DLIST_ADD_END(mstore_ctx->context_list, backend_list, struct backend_context_list *); + + } else { + DEBUG(0, ("[%s:%d]: Error - Invalid URI '%s'\n", __FUNCTION__, __LINE__, uri)); + talloc_free(mem_ctx); + return MAPISTORE_ERR_INVALID_NAMESPACE; + } + + talloc_free(mem_ctx); + return MAPISTORE_SUCCESS; +} + + +/** + \details Delete an existing connection context from mapistore + + \param mstore_ctx pointer to the mapistore context + \param context_id the context identifier referencing the context to + delete + + \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error + */ +_PUBLIC_ int mapistore_del_context(struct mapistore_context *mstore_ctx, + uint32_t context_id) +{ + struct backend_context_list *el; + int retval; + bool found = false; + + /* Sanity checks */ + if (!mstore_ctx) return MAPISTORE_ERR_NOT_INITIALIZED; + if (!mstore_ctx->processing_ctx) return MAPISTORE_ERR_NOT_INITIALIZED; + if (!mstore_ctx->context_list) return MAPISTORE_ERR_NOT_INITIALIZED; + + /* Step 0. Ensure the context exists */ + for (el = mstore_ctx->context_list; el; el = el->next) { + if (el->ctx && el->ctx->context_id == context_id) { + found = true; + break; + } + } + if (found == false) return MAPISTORE_ERR_INVALID_PARAMETER; + + /* Step 1. Delete the context within backend */ + retval = mapistore_backend_delete_context(el->ctx); + if (retval) return retval; + + /* Step 2. Delete the context from the processing layer */ + + /* Step 2. Add the free'd context id to the free list */ + retval = mapistore_free_context_id(mstore_ctx->processing_ctx, context_id); + return retval; +} + + +/** + \details return a string explaining what a mapistore error constant + means. + + \param mapistore_err the mapistore error constant + + \return constant string + */ +_PUBLIC_ const char *mapistore_errstr(int mapistore_err) +{ + switch (mapistore_err) { + case MAPISTORE_SUCCESS: + return "Success"; + case MAPISTORE_ERROR: + return "Non-specific error"; + case MAPISTORE_ERR_NO_MEMORY: + return "No memory available"; + case MAPISTORE_ERR_ALREADY_INITIALIZED: + return "Already initialized"; + case MAPISTORE_ERR_NOT_INITIALIZED: + return "Not initialized"; + case MAPISTORE_ERR_NO_DIRECTORY: + return "No such file or directory"; + case MAPISTORE_ERR_DATABASE_INIT: + return "Database initialization failed"; + case MAPISTORE_ERR_DATABASE_OPS: + return "database operation failed"; + case MAPISTORE_ERR_BACKEND_REGISTER: + return "storage backend registration failed"; + case MAPISTORE_ERR_BACKEND_INIT: + return "storage backend initialization failed"; + } + + return "Unknown error"; +} diff --git a/mapiproxy/libmapistore/mapistore_private.h b/mapiproxy/libmapistore/mapistore_private.h new file mode 100644 index 00000000..c401ab2b --- /dev/null +++ b/mapiproxy/libmapistore/mapistore_private.h @@ -0,0 +1,106 @@ +/* + OpenChange Storage Abstraction Layer library + + OpenChange Project + + Copyright (C) Julien Kerihuel 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef __MAPISTORE_PRIVATE_H__ +#define __MAPISTORE_PRIVATE_H__ + +#ifndef ISDOT +#define ISDOT(path) ( \ + *((const char *)(path)) == '.' && \ + *(((const char *)(path)) + 1) == '\0' \ + ) +#endif + +#ifndef ISDOTDOT +#define ISDOTDOT(path) ( \ + *((const char *)(path)) == '.' && \ + *(((const char *)(path)) + 1) == '.' && \ + *(((const char *)(path)) + 2) == '\0' \ + ) +#endif + + +/** + Identifier mapping context. + + This structure stores PR_MID and PR_FID identifiers to backend + identifiers mapping. It points on 2 databases, one with "in use" + identifiers and another one with a list of "free identifiers" which + are added when an object is deleted, moved, etc. + + The last_id structure member references the last identifier value + which got created. There is no identifier available with a value + higher than last_id. + */ +struct id_mapping_context { + TDB_CONTEXT *used_ctx; + TDB_CONTEXT *free_ctx; + uint64_t last_id; +}; + + +/** + Free context identifier list + + This structure is a double chained list storing unused context + identifiers. + */ +struct context_id_list { + uint32_t context_id; + struct context_id_list *prev; + struct context_id_list *next; +}; + + +struct processing_context { + struct id_mapping_context *mapping_ctx; + struct context_id_list *free_ctx; + uint32_t last_context_id; + uint64_t dflt_start_id; +}; + + +/** + The database name where in use ID mappings are stored + */ +#define MAPISTORE_DB_LAST_ID_KEY "mapistore_last_id" +#define MAPISTORE_DB_LAST_ID_VAL 0x15000 + +#define MAPISTORE_DB_NAME_USED_ID "mapistore_id_mapping_used.tdb" +#define MAPISTORE_DB_NAME_FREE_ID "mapistore_id_mapping_free.tdb" + +__BEGIN_DECLS + +/* definitions from mapistore_processing.c */ +const char *mapistore_get_mapping_path(void); +int mapistore_init_mapping_context(struct processing_context *); +int mapistore_get_context_id(struct processing_context *, uint32_t *); +int mapistore_free_context_id(struct processing_context *, uint32_t); + + +/* definitions from mapistore_backend.c */ +int mapistore_backend_init(TALLOC_CTX *, const char *); +struct backend_context *mapistore_backend_create_context(TALLOC_CTX *, const char *, const char *); +int mapistore_backend_delete_context(struct backend_context *); + +__END_DECLS + +#endif /* ! __MAPISTORE_PRIVATE_H__ */ diff --git a/mapiproxy/libmapistore/mapistore_processing.c b/mapiproxy/libmapistore/mapistore_processing.c new file mode 100644 index 00000000..c1c18f74 --- /dev/null +++ b/mapiproxy/libmapistore/mapistore_processing.c @@ -0,0 +1,259 @@ +/* + OpenChange Storage Abstraction Layer library + + OpenChange Project + + Copyright (C) Julien Kerihuel 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "mapistore.h" +#include "mapistore_errors.h" +#include "mapistore_private.h" +#include + +#include + +static struct id_mapping_context *mapping_ctx = NULL; +char *mapping_path = NULL; + + +/** + \details Set the mapping path + + \param path pointer to the mapping path + + \note The mapping path can be set unless id_mapping_context is + initialized. If path is NULL and mapping path is not yet + initialized, then mapping_path will be reset to its default value + when the initialization routine is called. + + \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error + */ +_PUBLIC_ int mapistore_set_mapping_path(const char *path) +{ + TALLOC_CTX *mem_ctx; + DIR *dir; + + /* Sanity checks */ + if (mapping_ctx) { + return MAPISTORE_ERR_ALREADY_INITIALIZED; + } + + /* Case 1. Path is set to NULL */ + if (!path) { + if (mapping_path) { + talloc_free(mapping_path); + } + mapping_path = NULL; + return MAPISTORE_SUCCESS; + } + + if (mapping_path) { + talloc_free(mapping_path); + } + + /* Case 2. path is initialized */ + + /* Step 1. Check if path is valid path */ + dir = opendir(path); + if (!dir) { + return MAPISTORE_ERR_NO_DIRECTORY; + } + + /* Step 2. TODO: Check for write permissions */ + + mem_ctx = talloc_autofree_context(); + mapping_path = talloc_strdup(mem_ctx, path); + return MAPISTORE_SUCCESS; +} + +/** + \details Return the current mapping path + + \return pointer to the mapping path. + */ +const char *mapistore_get_mapping_path(void) +{ + return (!mapping_path) ? MAPISTORE_MAPPING_PATH : (const char *)mapping_path; +} + + +/** + \details Initialize the ID mapping context or return the existing + one if already initialized. + + \param pctx pointer to the processing context + + \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error + */ +int mapistore_init_mapping_context(struct processing_context *pctx) +{ + TDB_DATA key; + TDB_DATA dbuf; + TALLOC_CTX *mem_ctx; + char *dbpath; + uint64_t last_id; + char *tmp_buf; + int ret; + + if (!pctx) return MAPISTORE_ERR_NOT_INITIALIZED; + + /* Step 0. return existing mapping context if already initialized */ + if (mapping_ctx) { + pctx->mapping_ctx = mapping_ctx; + return MAPISTORE_SUCCESS; + } else { + mapping_ctx = talloc_named(NULL, 0, "mapping_context"); + if (!mapping_ctx) return MAPISTORE_ERR_NO_MEMORY; + } + + mem_ctx = talloc_named(NULL, 0, "mapistore_init_mapping_context"); + + /* Step 1. Open/Create the used ID database */ + if (!mapping_ctx->used_ctx) { + dbpath = talloc_asprintf(mem_ctx, "%s/%s", mapistore_get_mapping_path(), MAPISTORE_DB_NAME_USED_ID); + mapping_ctx->used_ctx = tdb_open(dbpath, 0, 0, O_RDWR|O_CREAT, 0600); + talloc_free(dbpath); + if (!mapping_ctx->used_ctx) { + DEBUG(3, ("[%s:%d]: %s\n", __FUNCTION__, __LINE__, strerror(errno))); + talloc_free(mem_ctx); + talloc_free(mapping_ctx); + return MAPISTORE_ERR_DATABASE_INIT; + } + } + + /* Step 2. Open/Create the free ID database */ + if (!mapping_ctx->free_ctx) { + dbpath = talloc_asprintf(mem_ctx, "%s/%s", mapistore_get_mapping_path(), MAPISTORE_DB_NAME_FREE_ID); + mapping_ctx->free_ctx = tdb_open(dbpath, 0, 0, O_RDWR|O_CREAT, 0600); + talloc_free(dbpath); + if (!mapping_ctx->free_ctx) { + DEBUG(3, ("[%s:%d]: %s\n", __FUNCTION__, __LINE__, strerror(errno))); + talloc_free(mem_ctx); + talloc_free(mapping_ctx); + return MAPISTORE_ERR_DATABASE_INIT; + } + } + + /* Step 3. Retrieve the last ID value */ + key.dptr = (unsigned char *) MAPISTORE_DB_LAST_ID_KEY; + key.dsize = strlen(MAPISTORE_DB_LAST_ID_KEY); + + dbuf = tdb_fetch(mapping_ctx->used_ctx, key); + + /* If the record doesn't exist, insert it */ + if (!dbuf.dptr || !dbuf.dsize) { + dbuf.dptr = (unsigned char *) talloc_asprintf(mem_ctx, "0x%llx", (uint64_t) MAPISTORE_DB_LAST_ID_VAL); + dbuf.dsize = strlen((const char *) dbuf.dptr); + last_id = MAPISTORE_DB_LAST_ID_VAL; + + ret = tdb_store(mapping_ctx->used_ctx, key, dbuf, TDB_INSERT); + talloc_free(dbuf.dptr); + if (ret == -1) { + DEBUG(3, ("[%s:%d]: Unable to create %s record: %s\n", __FUNCTION__, __LINE__, + MAPISTORE_DB_LAST_ID_KEY, tdb_errorstr(mapping_ctx->used_ctx))); + talloc_free(mem_ctx); + talloc_free(mapping_ctx); + + return MAPISTORE_ERR_DATABASE_OPS; + } + + } else { + tmp_buf = talloc_strndup(mem_ctx, (char *)dbuf.dptr, dbuf.dsize); + free(dbuf.dptr); + last_id = strtoull(tmp_buf, NULL, 16); + talloc_free(tmp_buf); + } + + mapping_ctx->last_id = last_id; + + pctx->mapping_ctx = mapping_ctx; + talloc_free(mem_ctx); + + return MAPISTORE_SUCCESS; +} + + +/** + \details Return an unused or new context identifier + + \param pctx pointer to the processing context + \param context_id pointer to the context identifier the function + returns + + \return a non zero context identifier on success, otherwise 0. + */ +int mapistore_get_context_id(struct processing_context *pctx, uint32_t *context_id) +{ + struct context_id_list *el; + + /* Sanity checks */ + if (!pctx) return MAPISTORE_ERR_NOT_INITIALIZED; + + /* Step 1. The free context list doesn't exist yet */ + if (!pctx->free_ctx) { + pctx->last_context_id++; + *context_id = pctx->last_context_id; + } + + /* Step 2. We have a free list */ + for (el = pctx->free_ctx; el; el = el->next) { + if (el->context_id) { + *context_id = el->context_id; + DLIST_REMOVE(pctx->free_ctx, el); + break; + } + } + + return MAPISTORE_SUCCESS; +} + + +/** + \details Add a context identifier to the list + + \param pctx pointer to the processing context + \param context_id the identifier referencing the context to free + + \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error + */ +int mapistore_free_context_id(struct processing_context *pctx, uint32_t context_id) +{ + struct context_id_list *el; + + /* Sanity checks */ + if (!pctx) return MAPISTORE_ERR_NOT_INITIALIZED; + + /* Step 1. Ensure the list is not corrupted */ + for (el = pctx->free_ctx; el; el = el->next) { + if (el->context_id == context_id) { + return MAPISTORE_ERR_CORRUPTED; + } + } + + /* Step 2. Create the element and add it to the list */ + el = talloc_zero((TALLOC_CTX *)pctx, struct context_id_list); + el->context_id = context_id; + DLIST_ADD_END(pctx->free_ctx, el, struct context_id_list *); + + return MAPISTORE_SUCCESS; +} diff --git a/mapiproxy/libmapistore/tests/mapistore_test.c b/mapiproxy/libmapistore/tests/mapistore_test.c new file mode 100644 index 00000000..7745d195 --- /dev/null +++ b/mapiproxy/libmapistore/tests/mapistore_test.c @@ -0,0 +1,112 @@ +/* + OpenChange Storage Abstraction Layer library test tool + + OpenChange Project + + Copyright (C) Julien Kerihuel 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "mapiproxy/libmapistore/mapistore.h" +#include +#include +#include +#include +#include + +/** + \file mapistore_test.c + + \brief Test mapistore implementation + */ + + +int main(int argc, const char *argv[]) +{ + TALLOC_CTX *mem_ctx; + int retval; + struct mapistore_context *mstore_ctx; + struct loadparm_context *lp_ctx; + poptContext pc; + int opt; + const char *opt_debug = NULL; + uint32_t context_id = 0; + uint32_t context_id2 = 0; + + enum { OPT_DEBUG=1000 }; + + struct poptOption long_options[] = { + POPT_AUTOHELP + { "debuglevel", 'd', POPT_ARG_STRING, NULL, OPT_DEBUG, "set the debug level", NULL }, + { NULL, 0, 0, NULL, 0, NULL, NULL } + }; + + mem_ctx = talloc_named(NULL, 0, "mapistore_test"); + lp_ctx = loadparm_init(mem_ctx); + lp_load_default(lp_ctx); + setup_logging(NULL, DEBUG_STDOUT); + + pc = poptGetContext("mapistore_test", argc, argv, long_options, 0); + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_DEBUG: + opt_debug = poptGetOptArg(pc); + break; + } + } + + poptFreeContext(pc); + + if (opt_debug) { + lp_set_cmdline(lp_ctx, "log level", opt_debug); + } + + retval = mapistore_set_mapping_path("/tmp"); + if (retval != MAPISTORE_SUCCESS) { + DEBUG(0, ("%s\n", mapistore_errstr(retval))); + exit (1); + } + + mstore_ctx = mapistore_init(mem_ctx, NULL); + if (!mstore_ctx) { + DEBUG(0, ("%s\n", mapistore_errstr(retval))); + exit (1); + } + + retval = mapistore_add_context(mstore_ctx, "sqlite:///tmp/test.db", &context_id); + if (retval != MAPISTORE_SUCCESS) { + DEBUG(0, ("%s\n", mapistore_errstr(retval))); + exit (1); + } + + retval = mapistore_add_context(mstore_ctx, "sqlite:///tmp/test2.db", &context_id2); + if (retval != MAPISTORE_SUCCESS) { + DEBUG(0, ("%s\n", mapistore_errstr(retval))); + exit (1); + } + + DEBUG(0, ("Context ID: [1] = %d and [2] = %d\n", context_id, context_id2)); + + retval = mapistore_del_context(mstore_ctx, context_id); + retval = mapistore_del_context(mstore_ctx, context_id2); + + retval = mapistore_release(mstore_ctx); + if (retval != MAPISTORE_SUCCESS) { + DEBUG(0, ("%s\n", mapistore_errstr(retval))); + exit (1); + } + + return 0; +} -- 2.34.1