Replace deprecated talloc_init calls with talloc_named
[jelmer/openchange.git] / libmapi / emsmdb.c
index bec9f82005b9ae4eb00a3c433b390928f06d68b4..0c70b55b991ac4ab064959ed5a8464ef7e4f267e 100644 (file)
@@ -1,7 +1,7 @@
 /*
    OpenChange MAPI implementation.
 
-   Copyright (C) Julien Kerihuel 2005 - 2007.
+   Copyright (C) Julien Kerihuel 2005 - 2008.
    Copyright (C) Jelmer Vernooij 2005.
  
    This program is free software; you can redistribute it and/or modify
 #include <param.h>
 #include <credentials.h>
 
-#define        ECDOCONNECT_FORMAT      "/o=%s/ou=%s/cn=Recipients/cn=%s"
+/**
+   \file emsmdb.c
+
+   \brief EMSMDB stack functions
+ */
+
 
 /**
- * Create a connection on the exchange_emsmdb pipe
+   \details Hash a string and returns a unsigned integer hash value
+
+   \param str the string to hash
+
+   \return a hash value greater than 0 on success, otherwise 0
+
+   \note This function is based on the hash algorithm from gdbm and
+   from Samba4 TDB code.
  */
+static unsigned int emsmdb_hash(const char *str)
+{
+       uint32_t        value;  /* Used to compute the hash value.  */
+       uint32_t        i;      /* Used to cycle through random values. */
+       uint32_t        len;
+
+       /* Sanity check */
+       if (!str) return 0;
+
+       len = strlen(str);
+
+       /* Set the initial value from the key size. */
+       for (value = 0x238F13AF * len, i = 0; i < len; i++)
+               value = (value + (str[i] << (i * 5 % 24)));
+
+       return (1103515243 * value + 12345);  
+}
 
-struct emsmdb_context *emsmdb_connect(TALLOC_CTX *mem_ctx, struct dcerpc_pipe *p, struct cli_credentials *cred)
+
+/**
+   \details Establishes a new Session Context with the server on the
+   exchange_emsmdb pipe
+
+   \param mem_ctx pointer to the memory context
+   \param session pointer to the MAPI session context
+   \param p pointer to the DCERPC pipe
+   \param cred pointer to the user credentials
+
+   \return an allocated emsmdb_context on success, otherwise NULL
+ */
+struct emsmdb_context *emsmdb_connect(TALLOC_CTX *mem_ctx, 
+                                     struct mapi_session *session,
+                                     struct dcerpc_pipe *p, 
+                                     struct cli_credentials *cred)
 {
        struct EcDoConnect      r;
-       NTSTATUS                status;
        struct emsmdb_context   *ret;
-       mapi_ctx_t              *mapi_ctx;
+       NTSTATUS                status;
+       enum MAPISTATUS         retval;
+       uint32_t                pullTimeStamp = 0;
 
-       mapi_ctx = global_mapi_ctx;
-       if (mapi_ctx == 0) return NULL;
+       /* Sanity Checks */
+       if (!session) return NULL;
+       if (!p) return NULL;
+       if (!cred) return NULL;
 
        ret = talloc_zero(mem_ctx, struct emsmdb_context);
        ret->rpc_connection = p;
@@ -49,45 +96,39 @@ struct emsmdb_context *emsmdb_connect(TALLOC_CTX *mem_ctx, struct dcerpc_pipe *p
 
        ret->cache_requests = talloc(mem_ctx, struct EcDoRpc_MAPI_REQ *);
 
-       r.in.name = mapi_ctx->session->profile->mailbox;
-       r.in.unknown1[0] = 0x0;
-       r.in.unknown1[1] = 0x1eeebaac;
-       r.in.unknown1[2] = 0x0;
-       r.in.code_page = mapi_ctx->session->profile->codepage;
-       r.in.input_locale.language = mapi_ctx->session->profile->language;
-       r.in.input_locale.method = mapi_ctx->session->profile->method;
-       r.in.unknown2 = 0xffffffff;
-       r.in.unknown3 = 0x1;
-       r.in.emsmdb_client_version[0] = 0x000a;
-       r.in.emsmdb_client_version[1] = 0x0000;
-       r.in.emsmdb_client_version[2] = 0x1013;
-
-       r.in.alloc_space = talloc(mem_ctx, uint32_t);
-       *r.in.alloc_space = 0;
-
-       r.out.unknown4[0] = (uint32_t)talloc(mem_ctx, uint32_t);
-       r.out.unknown4[1] = (uint32_t)talloc(mem_ctx, uint32_t);
-       r.out.unknown4[2] = (uint32_t)talloc(mem_ctx, uint32_t);
-       r.out.session_nb = talloc(mem_ctx, uint16_t);
-       r.out.alloc_space = talloc(mem_ctx, uint32_t);
+       r.in.szUserDN = session->profile->mailbox;
+       r.in.ulFlags = 0x00000000;
+       r.in.ulConMod = emsmdb_hash(r.in.szUserDN);
+       r.in.cbLimit = 0x00000000;
+       r.in.ulCpid = session->profile->codepage;
+       r.in.ulLcidString = session->profile->language;
+       r.in.ulLcidSort = session->profile->method;
+       r.in.ulIcxrLink = 0xFFFFFFFF;
+       r.in.usFCanConvertCodePages = 0x1;
+       r.in.rgwClientVersion[0] = 0x000c;
+       r.in.rgwClientVersion[1] = 0x183e;
+       r.in.rgwClientVersion[2] = 0x03e8;
+       r.in.pullTimeStamp = &pullTimeStamp;
+
        r.out.handle = &ret->handle;
+       r.out.pcmsPollsMax = &ret->info.pcmsPollsMax;
+       r.out.pcRetry = &ret->info.pcRetry;
+       r.out.pcmsRetryDelay = &ret->info.pcmsRetryDelay;
+       r.out.picxr = &ret->info.picxr;
+       r.out.rgwServerVersion[0] = ret->info.rgwServerVersion[0];
+       r.out.rgwServerVersion[1] = ret->info.rgwServerVersion[1];
+       r.out.rgwServerVersion[2] = ret->info.rgwServerVersion[2];
+       r.out.pullTimeStamp = &pullTimeStamp;
 
        status = dcerpc_EcDoConnect(p, mem_ctx, &r);
-
-       if (!MAPI_STATUS_IS_OK(NT_STATUS_V(status))) {
-               mapi_errstr("EcDoConnect", r.out.result);
+       retval = r.out.result;
+       if (!NT_STATUS_IS_OK(status) || retval) {
+               mapi_errstr("EcDoConnect", retval);
                return NULL;
        }
 
-       ret->info.username = talloc_strdup(mem_ctx, r.out.user);
-       ret->info.mailbox = talloc_strdup(mem_ctx, r.out.org_group);
-       ret->info.store_version[0] = r.out.store_version[0];
-       ret->info.store_version[1] = r.out.store_version[1];
-       ret->info.store_version[2] = r.out.store_version[2];
-       
-       DEBUG(3, ("emsmdb_connect\n"));
-       DEBUG(3, ("\t\t user = %s\n", r.out.user));
-       DEBUG(3, ("\t\t organization = %s\n", r.out.org_group));
+       ret->info.szDisplayName = talloc_strdup(mem_ctx, r.out.szDisplayName);
+       ret->info.szDNPrefix = talloc_strdup(mem_ctx, r.out.szDNPrefix);
        
        ret->cred = cred;
        ret->max_data = 0xFFF0;
@@ -96,48 +137,63 @@ struct emsmdb_context *emsmdb_connect(TALLOC_CTX *mem_ctx, struct dcerpc_pipe *p
        return ret;
 }
 
+
 /**
- * Destructor
- */
+   \details Destructor for the EMSMDB context. Call the EcDoDisconnect
+   function.
+
+   \param data generic pointer to data with mapi_provider information
 
+   \return MAPI_E_SUCCESS on success, otherwise -1
+ */
 int emsmdb_disconnect_dtor(void *data)
 {
-       NTSTATUS                status;
        struct mapi_provider    *provider = (struct mapi_provider *)data;
        struct emsmdb_context   *emsmdb_ctx;
 
        emsmdb_ctx = (struct emsmdb_context *)provider->ctx;
-       status = emsmdb_disconnect(provider->ctx);      
-               
-       return 0;
+       return emsmdb_disconnect(provider->ctx);        
 }
 
+
 /**
- * Close the connection on the initialized exchange_emsmdb pipe
- */
+   \details Destroy the EMSMDB context handle
 
-NTSTATUS emsmdb_disconnect(struct emsmdb_context *emsmdb)
+   \param emsmdb_ctx pointer to the EMSMDB context
+
+   \return MAPI_E_SUCCESS on success, otherwise MAPI error
+ */
+enum MAPISTATUS emsmdb_disconnect(struct emsmdb_context *emsmdb_ctx)
 {
        NTSTATUS                status;
+       enum MAPISTATUS         retval;
        struct EcDoDisconnect   r;
 
-       r.in.handle = r.out.handle = &emsmdb->handle;
+       /* Sanity Checks */
+       OPENCHANGE_RETVAL_IF(!emsmdb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
 
-       status = dcerpc_EcDoDisconnect(emsmdb->rpc_connection, emsmdb, &r);
-       if (!MAPI_STATUS_IS_OK(NT_STATUS_V(status))) {
-               mapi_errstr("EcDoDisconnect", r.out.result);
-               return status;
-       }
+       r.in.handle = r.out.handle = &emsmdb_ctx->handle;
+
+       status = dcerpc_EcDoDisconnect(emsmdb_ctx->rpc_connection, emsmdb_ctx, &r);
+       retval = r.out.result;
+       OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), retval, NULL);
+       OPENCHANGE_RETVAL_IF(retval, retval, NULL);
 
-       return NT_STATUS_OK;
+       return MAPI_E_SUCCESS;
 }
 
+
 /**
- * Send a null MAPI packet. 
- * Useful to keep connection up or force notifications
- */
+   \details Send an empty MAPI packet - useful to keep connection up
+   or force notifications.
 
-_PUBLIC_ NTSTATUS emsmdb_transaction_null(struct emsmdb_context *emsmdb, struct mapi_response **res)
+   \param emsmdb_ctx pointer to the EMSMDB connection context
+   \param res pointer on pointer to a MAPI response structure
+
+   \return NT_STATUS_OK on success, otherwise NT status error
+ */
+_PUBLIC_ NTSTATUS emsmdb_transaction_null(struct emsmdb_context *emsmdb_ctx, 
+                                         struct mapi_response **res)
 {
        struct EcDoRpc          r;
        struct mapi_request     *mapi_request;
@@ -145,25 +201,28 @@ _PUBLIC_ NTSTATUS emsmdb_transaction_null(struct emsmdb_context *emsmdb, struct
        NTSTATUS                status;
        uint16_t                *length;
 
-       mapi_request = talloc_zero(emsmdb->mem_ctx, struct mapi_request);
-       mapi_response = talloc_zero(emsmdb->mem_ctx, struct mapi_response);
+       /* Sanity checks */
+       if(!emsmdb_ctx) return NT_STATUS_INVALID_PARAMETER;
+       if (!res) return NT_STATUS_INVALID_PARAMETER;
+
+       mapi_request = talloc_zero(emsmdb_ctx->mem_ctx, struct mapi_request);
+       mapi_response = talloc_zero(emsmdb_ctx->mem_ctx, struct mapi_response);
 
        r.in.mapi_request = mapi_request;
        r.in.mapi_request->mapi_len = 2;
        r.in.mapi_request->length = 2;
 
-       r.in.handle = r.out.handle = &emsmdb->handle;
-       r.in.size = emsmdb->max_data;
+       r.in.handle = r.out.handle = &emsmdb_ctx->handle;
+       r.in.size = emsmdb_ctx->max_data;
        r.in.offset = 0x0;
-       r.in.max_data = emsmdb->max_data;
-       length = talloc_zero(emsmdb->mem_ctx, uint16_t);
+       r.in.max_data = emsmdb_ctx->max_data;
+       length = talloc_zero(emsmdb_ctx->mem_ctx, uint16_t);
        *length = r.in.mapi_request->mapi_len;
        r.in.length = r.out.length = length;
 
        r.out.mapi_response = mapi_response;
 
-       status = dcerpc_EcDoRpc(emsmdb->rpc_connection, emsmdb->mem_ctx, &r);
-
+       status = dcerpc_EcDoRpc(emsmdb_ctx->rpc_connection, emsmdb_ctx->mem_ctx, &r);
        if (!MAPI_STATUS_IS_OK(NT_STATUS_V(status))) {
                return status;
        }
@@ -173,7 +232,20 @@ _PUBLIC_ NTSTATUS emsmdb_transaction_null(struct emsmdb_context *emsmdb, struct
        return status;
 }
 
-NTSTATUS emsmdb_transaction(struct emsmdb_context *emsmdb, struct mapi_request *req, struct mapi_response **repl)
+
+/**
+   \details Make a EMSMDB transaction.
+
+   \param emsmdb_ctx pointer to the EMSMDB connection context
+   \param req pointer to the MAPI request to send
+   \param repl pointer on pointer to the MAPI reply returned by the
+   server
+
+   \return NT_STATUS_OK on success, otherwise NT status error
+ */
+_PUBLIC_ NTSTATUS emsmdb_transaction(struct emsmdb_context *emsmdb_ctx, 
+                                    struct mapi_request *req, 
+                                    struct mapi_response **repl)
 {
        struct EcDoRpc          r;
        struct mapi_response    *mapi_response;
@@ -183,58 +255,63 @@ NTSTATUS emsmdb_transaction(struct emsmdb_context *emsmdb, struct mapi_request *
        uint8_t                 i = 0;
 
 start:
-       r.in.handle = r.out.handle = &emsmdb->handle;
-       r.in.size = emsmdb->max_data;
+       r.in.handle = r.out.handle = &emsmdb_ctx->handle;
+       r.in.size = emsmdb_ctx->max_data;
        r.in.offset = 0x0;
 
-       mapi_response = talloc_zero(emsmdb->mem_ctx, struct mapi_response);     
+       mapi_response = talloc_zero(emsmdb_ctx->mem_ctx, struct mapi_response); 
        r.out.mapi_response = mapi_response;
 
        /* process cached data */
-       if (emsmdb->cache_count) {
-               multi_req = talloc_array(emsmdb->mem_ctx, struct EcDoRpc_MAPI_REQ, emsmdb->cache_count + 2);
-               for (i = 0; i < emsmdb->cache_count; i++) {
-                       multi_req[i] = *emsmdb->cache_requests[i];
+       if (emsmdb_ctx->cache_count) {
+               multi_req = talloc_array(emsmdb_ctx->mem_ctx, struct EcDoRpc_MAPI_REQ, emsmdb_ctx->cache_count + 2);
+               for (i = 0; i < emsmdb_ctx->cache_count; i++) {
+                       multi_req[i] = *emsmdb_ctx->cache_requests[i];
                }
                multi_req[i] = req->mapi_req[0];
                req->mapi_req = multi_req;
        }
 
-       req->mapi_req = talloc_realloc(emsmdb->mem_ctx, req->mapi_req, struct EcDoRpc_MAPI_REQ, emsmdb->cache_count + 2);
+       req->mapi_req = talloc_realloc(emsmdb_ctx->mem_ctx, req->mapi_req, struct EcDoRpc_MAPI_REQ, emsmdb_ctx->cache_count + 2);
        req->mapi_req[i+1].opnum = 0;
 
        r.in.mapi_request = req;
-       r.in.mapi_request->mapi_len += emsmdb->cache_size;
-       r.in.mapi_request->length += emsmdb->cache_size;
-       length = talloc_zero(emsmdb->mem_ctx, uint16_t);
+       r.in.mapi_request->mapi_len += emsmdb_ctx->cache_size;
+       r.in.mapi_request->length += emsmdb_ctx->cache_size;
+       length = talloc_zero(emsmdb_ctx->mem_ctx, uint16_t);
        *length = r.in.mapi_request->mapi_len;
        r.in.length = r.out.length = length;
-       r.in.max_data = (*length >= 0x4000) ? 0x7FFF : emsmdb->max_data;
+       r.in.max_data = (*length >= 0x4000) ? 0x7FFF : emsmdb_ctx->max_data;
 
-       status = dcerpc_EcDoRpc(emsmdb->rpc_connection, emsmdb->mem_ctx, &r);
-
-       if (!MAPI_STATUS_IS_OK(NT_STATUS_V(status))) {
-               if (emsmdb->setup == false) {
+       status = dcerpc_EcDoRpc(emsmdb_ctx->rpc_connection, emsmdb_ctx->mem_ctx, &r);
+       if (!NT_STATUS_IS_OK(status)) {
+               if (emsmdb_ctx->setup == false) {
                        errno = 0;
-                       emsmdb->max_data = 0x7FFF;
-                       emsmdb->setup = true;
+                       emsmdb_ctx->max_data = 0x7FFF;
+                       emsmdb_ctx->setup = true;
                        goto start;
                } else {
                        return status;
                }
        } else {
-               emsmdb->setup = true;
+               emsmdb_ctx->setup = true;
        }
-       emsmdb->cache_size = emsmdb->cache_count = 0;
+       emsmdb_ctx->cache_size = emsmdb_ctx->cache_count = 0;
 
        *repl = r.out.mapi_response;
 
        return status;
 }
 
+
 /**
- * initialize notify context structure and bind a local udp port for
- * notifications
+   \details Initialize the notify context structure and bind a local
+   UDP port to receive notifications from the server
+
+   \param mem_ctx pointer to the memory context
+
+   \return an allocated mapi_notify_ctx structure on success,
+   otherwise NULL
  */
 struct mapi_notify_ctx *emsmdb_bind_notification(TALLOC_CTX *mem_ctx)
 {
@@ -244,6 +321,7 @@ struct mapi_notify_ctx *emsmdb_bind_notification(TALLOC_CTX *mem_ctx)
        const char              *ipaddr = NULL;
        uint32_t                try = 0;
 
+       /* Sanity Checks */
        if (!global_mapi_ctx) return NULL;
        if (!global_mapi_ctx->session) return NULL;
        if (!global_mapi_ctx->session->profile) return NULL;
@@ -256,7 +334,11 @@ struct mapi_notify_ctx *emsmdb_bind_notification(TALLOC_CTX *mem_ctx)
 
        load_interfaces(mem_ctx, lp_interfaces(global_mapi_ctx->lp_ctx), &ifaces);
        ipaddr = iface_best_ip(ifaces, global_mapi_ctx->session->profile->server);
-       if (!ipaddr) return NULL;
+       if (!ipaddr) {
+               talloc_free(notify_ctx->notifications);
+               talloc_free(notify_ctx);
+               return NULL;
+       }
        notify_ctx->addr = talloc_zero(mem_ctx, struct sockaddr);
        notify_ctx->addr->sa_family = AF_INET;
        ((struct sockaddr_in *)(notify_ctx->addr))->sin_addr.s_addr = inet_addr(ipaddr);
@@ -266,6 +348,9 @@ retry:
 
        notify_ctx->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
        if (notify_ctx->fd == -1) {
+               talloc_free(notify_ctx->notifications);
+               talloc_free(notify_ctx->addr);
+               talloc_free(notify_ctx);
                return NULL;
        }
 
@@ -277,164 +362,260 @@ retry:
                        errno = 0;
                        goto retry;
                }
+
+               talloc_free(notify_ctx->notifications);
+               talloc_free(notify_ctx->addr);
+               talloc_free(notify_ctx);
                return NULL;
        }
 
        return notify_ctx;
 }
 
+
 /**
- * Register for notifications on a Exchange server
+   \details Register for notifications on the server
+   
+   \param notifkey The opaque client-generated context data
+   \param ulEventMask Notification flags. Exchange completely ignores
+   this value and it should be set to 0
+
+   \return NTSTATUS_OK on success, otherwise NT status error
  */
-NTSTATUS emsmdb_register_notification(struct NOTIFKEY *notifkey, uint32_t ulEventMask)
+NTSTATUS emsmdb_register_notification(struct NOTIFKEY *notifkey, 
+                                     uint16_t ulEventMask)
 {
        struct EcRRegisterPushNotification      request;
        NTSTATUS                                status;
-       struct emsmdb_context                   *emsmdb;
+       enum MAPISTATUS                         retval;
+       TALLOC_CTX                              *mem_ctx;
+       struct emsmdb_context                   *emsmdb_ctx;
        struct mapi_session                     *session;
        struct mapi_notify_ctx                  *notify_ctx;
        struct policy_handle                    handle;
+       uint32_t                                hNotification = 0;
 
-       if (!global_mapi_ctx) return NT_STATUS_UNSUCCESSFUL;
-       if (!global_mapi_ctx->session) return NT_STATUS_UNSUCCESSFUL;
-       if (!global_mapi_ctx->session->emsmdb) return NT_STATUS_UNSUCCESSFUL;
-       if (!global_mapi_ctx->session->emsmdb->ctx) return NT_STATUS_UNSUCCESSFUL;
+       /* Sanity Checks*/
+       if (!global_mapi_ctx) return NT_STATUS_INVALID_PARAMETER;
+       if (!global_mapi_ctx->session) return NT_STATUS_INVALID_PARAMETER;
+       if (!global_mapi_ctx->session->emsmdb) return NT_STATUS_INVALID_PARAMETER;
+       if (!global_mapi_ctx->session->emsmdb->ctx) return NT_STATUS_INVALID_PARAMETER;
+       if (!notifkey) return NT_STATUS_INVALID_PARAMETER;
 
        session = (struct mapi_session *)global_mapi_ctx->session;
-       emsmdb = (struct emsmdb_context *)session->emsmdb->ctx;
+       emsmdb_ctx = (struct emsmdb_context *)session->emsmdb->ctx;
        notify_ctx = (struct mapi_notify_ctx *)session->notify_ctx;
+       mem_ctx = talloc_named(NULL, 0, "emsmdb_register_notification");
 
-       /* in */
-       request.in.handle = &emsmdb->handle;
+       request.in.handle = &emsmdb_ctx->handle;
        request.in.ulEventMask = ulEventMask;
-
-       request.in.notifkey = talloc_array(emsmdb->mem_ctx, uint8_t, request.in.notif_len);
-       memcpy(request.in.notifkey, notifkey->ab, request.in.notif_len);
-       request.in.notif_len = notifkey->cb;
-
-       request.in.unknown2 = 0xffffffff;
-
-       request.in.sockaddr = talloc_array(emsmdb->mem_ctx, uint8_t, sizeof (struct sockaddr));
+       request.in.cbContext = notifkey->cb;
+       request.in.rgbContext = talloc_array(mem_ctx, uint8_t, request.in.cbContext);
+       memcpy(request.in.rgbContext, notifkey->ab, request.in.cbContext);
+       request.in.grbitAdviseBits = 0xffffffff;
+       request.in.rgCallbackAddress = talloc_array(mem_ctx, uint8_t, sizeof (struct sockaddr));
        /* cp address family and length */
-       request.in.sockaddr[0] = (notify_ctx->addr->sa_family & 0xFF);
-       request.in.sockaddr[1] = (notify_ctx->addr->sa_family & 0xFF00) >> 8;
-       memcpy(&request.in.sockaddr[2], notify_ctx->addr->sa_data, 14);
-       request.in.sockaddr_len = sizeof (struct sockaddr);
+       request.in.rgCallbackAddress[0] = (notify_ctx->addr->sa_family & 0xFF);
+       request.in.rgCallbackAddress[1] = (notify_ctx->addr->sa_family & 0xFF00) >> 8;
+       memcpy(&request.in.rgCallbackAddress[2], notify_ctx->addr->sa_data, 14);
+       request.in.cbCallbackAddress = sizeof (struct sockaddr);
 
-       /* out */
        request.out.handle = &handle;
-       request.out.retval = talloc_zero(emsmdb->mem_ctx, uint32_t);
+       request.out.hNotification = &hNotification;
 
-       status = dcerpc_EcRRegisterPushNotification(emsmdb->rpc_connection, emsmdb->mem_ctx, &request);
-       if (!MAPI_STATUS_IS_OK(NT_STATUS_V(status))) {
+       status = dcerpc_EcRRegisterPushNotification(emsmdb_ctx->rpc_connection, emsmdb_ctx->mem_ctx, &request);
+       retval = request.out.result;
+       if (!NT_STATUS_IS_OK(status) || retval) {
+               talloc_free(mem_ctx);
                return status;
        }
 
-       if (request.out.result != MAPI_E_SUCCESS) {
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       if (request.out.retval && *request.out.retval != MAPI_E_SUCCESS) {
-               return NT_STATUS_UNSUCCESSFUL;
-       }
+       talloc_free(mem_ctx);
 
-       return NT_STATUS_OK;
+       return status;
 }
 
 
 /**
- * Retrieve the emsmdb server info structure
+   \details Retrieves the EMSMDB context server information structure
+
+   \param session pointer to the MAPI session context
+
+   \return the server info structure on success, otherwise NULL
  */
-_PUBLIC_ struct emsmdb_info *emsmdb_get_info(void)
+_PUBLIC_ struct emsmdb_info *emsmdb_get_info(struct mapi_session *session)
 {
-       if (!global_mapi_ctx || !global_mapi_ctx->session->emsmdb->ctx) {
+       if (!global_mapi_ctx || !session->emsmdb->ctx) {
                return NULL;
        }
 
-       return &((struct emsmdb_context *)global_mapi_ctx->session->emsmdb->ctx)->info;
+       return &((struct emsmdb_context *)session->emsmdb->ctx)->info;
 }
 
-const void *pull_emsmdb_property(TALLOC_CTX *mem_ctx, uint32_t *offset, enum MAPITAGS tag, DATA_BLOB *data)
+
+/**
+   \details Retrieves a property value from a DATA blob
+
+   \param mem_ctx pointer to the memory context
+   \param lp_ctx pointer to the loadparm context
+   \param offset pointer on pointer to the current offset
+   \param tag the property tag which value is to be retrieved
+   \param data pointer to the data
+
+   \return pointer on constant generic data on success, otherwise NULL
+ */
+const void *pull_emsmdb_property(TALLOC_CTX *mem_ctx,
+                                struct loadparm_context *lp_ctx,
+                                uint32_t *offset, 
+                                enum MAPITAGS tag, 
+                                DATA_BLOB *data)
 {
-       struct ndr_pull         *ndr;
-       const char              *pt_string8;
-       const char              *pt_unicode;
-       uint16_t                *pt_i2;
-       uint64_t                *pt_i8;
-       uint32_t                *pt_long;
-       uint8_t                 *pt_boolean;
-       struct FILETIME         *pt_filetime;
-       struct GUID             *pt_clsid;
-       struct SBinary_short    pt_binary;
-       struct SBinary          *sbin;
+       struct ndr_pull                 *ndr;
+       const char                      *pt_string8;
+       const char                      *pt_unicode;
+       uint16_t                        *pt_i2;
+       uint64_t                        *pt_i8;
+       uint32_t                        *pt_long;
+       uint8_t                         *pt_boolean;
+       struct FILETIME                 *pt_filetime;
+       struct GUID                     *pt_clsid;
+       struct SBinary_short            pt_binary;
+       struct Binary_r                 *sbin;
+       struct mapi_SLPSTRArray         pt_slpstr;
+       struct StringArray_r            *slpstr;
+       struct mapi_MV_LONG_STRUCT      pt_MVl;
+       struct LongArray_r              *MVl;
+       struct mapi_SBinaryArray        pt_MVbin;
+       struct BinaryArray_r            *MVbin;
+       uint32_t                        i;
 
        ndr = talloc_zero(mem_ctx, struct ndr_pull);
        ndr->offset = *offset;
        ndr->data = data->data;
        ndr->data_size = data->length;
        ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
-       ndr->iconv_convenience = smb_iconv_convenience_init(mem_ctx, "CP850", "UTF8", true);
+       ndr->iconv_convenience = lp_iconv_convenience(lp_ctx);
 
        switch(tag & 0xFFFF) {
        case PT_I2:
                pt_i2 = talloc_zero(mem_ctx, uint16_t);
                ndr_pull_uint16(ndr, NDR_SCALARS, pt_i2);
                *offset = ndr->offset;
+               talloc_free(ndr);
                return (void *) pt_i2;
        case PT_ERROR:
        case PT_LONG:
                pt_long = talloc_zero(mem_ctx, uint32_t);
                ndr_pull_uint32(ndr, NDR_SCALARS, pt_long);
                *offset = ndr->offset;
+               talloc_free(ndr);
                return (void *) pt_long;
        case PT_BOOLEAN:
                pt_boolean = talloc_zero(mem_ctx, uint8_t);
                ndr_pull_uint8(ndr, NDR_SCALARS, pt_boolean);
                *offset = ndr->offset;
+               talloc_free(ndr);
                return (void *) pt_boolean;
        case PT_I8:
                pt_i8 = talloc_zero(mem_ctx, uint64_t);
                ndr_pull_hyper(ndr, NDR_SCALARS, pt_i8);
                *offset = ndr->offset;
+               talloc_free(ndr);
                return (void *) pt_i8;
        case PT_UNICODE:
                ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
                ndr_pull_string(ndr, NDR_SCALARS, &pt_unicode);
                *offset = ndr->offset;
+               talloc_free(ndr);
                return (const void *) pt_unicode;
        case PT_STRING8:
                ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
                ndr_pull_string(ndr, NDR_SCALARS, &pt_string8);
                *offset = ndr->offset;
+               talloc_free(ndr);
                return (const void *) pt_string8;
        case PT_SYSTIME:
                pt_filetime = talloc_zero(mem_ctx, struct FILETIME);
                ndr_pull_hyper(ndr, NDR_SCALARS, (uint64_t *) pt_filetime);
                *offset = ndr->offset;
-               return (void*) pt_filetime;
+               talloc_free(ndr);
+               return (void *) pt_filetime;
        case PT_CLSID:
                pt_clsid = talloc_zero(mem_ctx, struct GUID);
                ndr_pull_GUID(ndr, NDR_SCALARS, pt_clsid);
                *offset = ndr->offset;
+               talloc_free(ndr);
                return (void *) pt_clsid;
        case 0xFB:
        case PT_BINARY:
                ndr_pull_SBinary_short(ndr, NDR_SCALARS, &pt_binary);
                *offset = ndr->offset;
-               sbin = talloc_zero(mem_ctx, struct SBinary);
+               sbin = talloc_zero(mem_ctx, struct Binary_r);
                sbin->cb = pt_binary.cb;
-               sbin->lpb = pt_binary.lpb;
+               sbin->lpb = talloc_memdup(sbin, pt_binary.lpb, pt_binary.cb);
+               talloc_free(ndr);
                return (void *) sbin;
+       case PT_MV_LONG:
+               ndr_pull_mapi_MV_LONG_STRUCT(ndr, NDR_SCALARS, &pt_MVl);
+               *offset = ndr->offset;
+               MVl = talloc_zero(mem_ctx, struct LongArray_r);
+               MVl->cValues = pt_MVl.cValues;
+               MVl->lpl = talloc_array(mem_ctx, uint32_t, pt_MVl.cValues);
+               for (i = 0; i < MVl->cValues; i++) {
+                       MVl->lpl[i] = pt_MVl.lpl[i];
+               }
+               talloc_free(ndr);
+               return (const void *) MVl;
+       case PT_MV_STRING8:
+               ndr_pull_mapi_SLPSTRArray(ndr, NDR_SCALARS, &pt_slpstr);
+               *offset = ndr->offset;
+               slpstr = talloc_zero(mem_ctx, struct StringArray_r);
+               slpstr->cValues = pt_slpstr.cValues;
+               slpstr->lppszA = talloc_array(mem_ctx, const char *, pt_slpstr.cValues);
+               for (i = 0; i < slpstr->cValues; i++) {
+                       slpstr->lppszA[i] = talloc_strdup(mem_ctx, pt_slpstr.strings[i].lppszA);
+               }
+               talloc_free(ndr);
+               return (const void *) slpstr;
+       case PT_MV_BINARY:
+               ndr_pull_mapi_SBinaryArray(ndr, NDR_SCALARS, &pt_MVbin);
+               *offset = ndr->offset;
+               MVbin = talloc_zero(mem_ctx, struct BinaryArray_r);
+               MVbin->cValues = pt_MVbin.cValues;
+               MVbin->lpbin = talloc_array(mem_ctx, struct Binary_r, pt_MVbin.cValues);
+               for (i = 0; i < MVbin->cValues; i++) {
+                       MVbin->lpbin[i].cb = pt_MVbin.bin[i].cb;
+                       MVbin->lpbin[i].lpb = talloc_size(mem_ctx, MVbin->lpbin[i].cb);
+                       memcpy(MVbin->lpbin[i].lpb, pt_MVbin.bin[i].lpb, MVbin->lpbin[i].cb);
+               }
+               talloc_free(ndr);
+               return (const void *) MVbin;
        default:
                return NULL;
        }       
 }
 
+
+/**
+   \details Get a SPropValue array from a DATA blob
+
+   \param mem_ctx pointer to the memory context
+   \param lp_ctx pointer to the loadparm context
+   \param content pointer to the DATA blob content
+   \param tags pointer to a list of property tags to lookup
+   \param propvals pointer on pointer to the returned SPropValues
+   \param cn_propvals pointer to the number of propvals
+   \param flag describes the type data
+
+   \return MAPI_E_SUCCESS on success
+ */
 enum MAPISTATUS emsmdb_get_SPropValue(TALLOC_CTX *mem_ctx,
+                                     struct loadparm_context *lp_ctx,
                                      DATA_BLOB *content,
                                      struct SPropTagArray *tags,
-                                     struct SPropValue **propvals, uint32_t *cn_propvals,
-                                     uint8_t layout)
+                                     struct SPropValue **propvals, 
+                                     uint32_t *cn_propvals,
+                                     uint8_t flag)
 {
        struct SPropValue       *p_propval;
        uint32_t                i_propval;
@@ -446,10 +627,10 @@ enum MAPISTATUS emsmdb_get_SPropValue(TALLOC_CTX *mem_ctx,
        i_propval = 0;
        cn_tags = tags->cValues;
        *cn_propvals = 0;
-       *propvals = talloc_array(mem_ctx, struct SPropValue, cn_tags);
+       *propvals = talloc_array(mem_ctx, struct SPropValue, cn_tags + 1);
 
        for (i_tag = 0; i_tag < cn_tags; i_tag++) {
-               if (layout) { 
+               if (flag) { 
                        if (((uint8_t)(*(content->data + offset))) == PT_ERROR) {
                                tags->aulPropTag[i_tag] &= 0xFFFF0000;
                                tags->aulPropTag[i_tag] |= PT_ERROR;
@@ -457,7 +638,7 @@ enum MAPISTATUS emsmdb_get_SPropValue(TALLOC_CTX *mem_ctx,
                        offset += sizeof (uint8_t);
                }
 
-               data = pull_emsmdb_property(mem_ctx, &offset, tags->aulPropTag[i_tag], content);
+               data = pull_emsmdb_property(mem_ctx, lp_ctx, &offset, tags->aulPropTag[i_tag], content);
                if (data) {
                        p_propval = &((*propvals)[i_propval]);
                        p_propval->ulPropTag = tags->aulPropTag[i_tag];
@@ -467,13 +648,31 @@ enum MAPISTATUS emsmdb_get_SPropValue(TALLOC_CTX *mem_ctx,
                }
        }
 
+       (*propvals)[i_propval].ulPropTag = 0x0;
        *cn_propvals = i_propval;
        return MAPI_E_SUCCESS;
 }
 
-/* TODO: this doesn't yet handle the TypedPropertyValue and
-   FlaggedPropertyValueWithTypeSpecified variants. */
-_PUBLIC_ void  emsmdb_get_SRowSet(TALLOC_CTX *mem_ctx, struct SRowSet *rowset, struct SPropTagArray *proptags, DATA_BLOB *content)
+
+/**
+   \details Get a SRowSet from a DATA blob
+
+   \param mem_ctx pointer on the memory context
+   \param lp_ctx pointer on the loadparm context
+   \param rowset pointer on the returned SRowSe
+   \param proptags pointer on a list of property tags to lookup
+   \param content pointer on the DATA blob content
+
+   \return MAPI_E_SUCCESS on success
+
+   \note TODO: this doesn't yet handle the TypedPropertyValue and
+   FlaggedPropertyValueWithTypeSpecified variants
+ */
+_PUBLIC_ void emsmdb_get_SRowSet(TALLOC_CTX *mem_ctx,
+                                struct loadparm_context *lp_ctx,
+                                struct SRowSet *rowset, 
+                                struct SPropTagArray *proptags, 
+                                DATA_BLOB *content)
 {
        struct SRow             *rows;
        struct SPropValue       *lpProps;
@@ -513,10 +712,10 @@ _PUBLIC_ void     emsmdb_get_SRowSet(TALLOC_CTX *mem_ctx, struct SRowSet *rowset, st
                                        /* Property Value is not present */
                                        havePropertyValue = false;
                                        break;
-                               case 0xa:
+                               case PT_ERROR:
                                        lpProps[prop].ulPropTag = proptags->aulPropTag[prop];
                                        lpProps[prop].ulPropTag &= 0xFFFF0000;
-                                       lpProps[prop].ulPropTag |= 0x000a;
+                                       lpProps[prop].ulPropTag |= PT_ERROR;
                                        break;
                                default:
                                        /* unknown FlaggedPropertyValue flag */
@@ -526,7 +725,7 @@ _PUBLIC_ void       emsmdb_get_SRowSet(TALLOC_CTX *mem_ctx, struct SRowSet *rowset, st
                        }
                        if (havePropertyValue) {
                                lpProps[prop].dwAlignPad = 0x0;
-                               data = pull_emsmdb_property(mem_ctx, &offset, lpProps[prop].ulPropTag, content);
+                               data = pull_emsmdb_property(mem_ctx, lp_ctx, &offset, lpProps[prop].ulPropTag, content);
                                set_SPropValue(&lpProps[prop], data);
                        }
                }
@@ -538,7 +737,30 @@ _PUBLIC_ void      emsmdb_get_SRowSet(TALLOC_CTX *mem_ctx, struct SRowSet *rowset, st
 }
 
 
-void emsmdb_get_SRow(TALLOC_CTX *mem_ctx, struct SRow *aRow, struct SPropTagArray *proptags, uint16_t propcount, DATA_BLOB *content, uint8_t layout, uint8_t align)
+/**
+   \details Get a SRow from a DATA blob
+
+   \param mem_ctx pointer on the memory context
+   \param lp_ctx pointer on the loadparm context
+   \param aRow pointer on the returned SRow
+   \param proptags pointer on a list of property tags to lookup
+   \param propcount number of SPropValue entries in aRow
+   \param content pointer on the DATA blob content
+   \param flag the type data
+   \param align alignment pad
+
+   \return MAPI_E_SUCCESS on success
+
+   \note TODO: We shouldn't have any alignment pad here
+ */
+void emsmdb_get_SRow(TALLOC_CTX *mem_ctx,
+                    struct loadparm_context *lp_ctx,
+                    struct SRow *aRow, 
+                    struct SPropTagArray *proptags, 
+                    uint16_t propcount, 
+                    DATA_BLOB *content, 
+                    uint8_t flag, 
+                    uint8_t align)
 {
        uint32_t                i;
        uint32_t                offset = 0;
@@ -550,7 +772,7 @@ void emsmdb_get_SRow(TALLOC_CTX *mem_ctx, struct SRow *aRow, struct SPropTagArra
 
        for (i = 0; i < propcount; i++) {
                aulPropTag = proptags->aulPropTag[i];
-               if (layout) {
+               if (flag) {
                        if (((uint8_t)(*(content->data + offset))) == PT_ERROR) {
                                aulPropTag &= 0xFFFF0000;
                                aulPropTag |= 0xA;                      
@@ -558,7 +780,7 @@ void emsmdb_get_SRow(TALLOC_CTX *mem_ctx, struct SRow *aRow, struct SPropTagArra
                        offset += align;
                } 
 
-               data = pull_emsmdb_property(mem_ctx, &offset, aulPropTag, content);
+               data = pull_emsmdb_property(mem_ctx, lp_ctx, &offset, aulPropTag, content);
                aRow->lpProps[i].ulPropTag = aulPropTag;
                aRow->lpProps[i].dwAlignPad = 0x0;
                set_SPropValue(&(aRow->lpProps[i]), data);