- Implement mkdir operation at mapistore level
authorJulien Kerihuel <j.kerihuel@openchange.org>
Thu, 27 May 2010 15:05:55 +0000 (15:05 +0000)
committerJulien Kerihuel <j.kerihuel@openchange.org>
Thu, 27 May 2010 15:05:55 +0000 (15:05 +0000)
- Update PidTagFolderChildCount of parent folder when parent is the
  root folder of a mapistore context (folder attributes stored in
  openchange.ldb)

- Improve RopCreateFolder implementation

- Clean-up emsmdb_object_folder_init implementation

- Add a convenient function to turn ROPs parameters into MAPI
  properties. This prevents from having endless number of parameters.

- Commit remaining parts of the provision changes

mapiproxy/libmapiserver/libmapiserver.h
mapiproxy/libmapiserver/libmapiserver_oxcprpt.c
mapiproxy/libmapistore/backends/mapistore_fsocpf.c
mapiproxy/libmapistore/backends/mapistore_sqlite3.c
mapiproxy/libmapistore/mapistore.h
mapiproxy/libmapistore/mapistore_backend.c
mapiproxy/libmapistore/mapistore_interface.c
mapiproxy/libmapistore/mapistore_private.h
mapiproxy/servers/default/emsmdb/dcesrv_exchange_emsmdb.h
mapiproxy/servers/default/emsmdb/emsmdbp_object.c
mapiproxy/servers/default/emsmdb/oxcfold.c

index dffb0940407a1807fa1755cdfccc34c36c50ab5a..770b94a0bc03c0763cbb64f50971ebe26ca8f87b 100644 (file)
@@ -250,6 +250,7 @@ uint16_t libmapiserver_RopSetProperties_size(struct EcDoRpc_MAPI_REPL *);
 uint16_t libmapiserver_RopGetPropertiesSpecific_size(struct EcDoRpc_MAPI_REQ *, struct EcDoRpc_MAPI_REPL *);
 uint16_t libmapiserver_RopGetPropertyIdsFromNames_size(struct EcDoRpc_MAPI_REPL *);
 int libmapiserver_push_property(TALLOC_CTX *, struct smb_iconv_convenience *, uint32_t, const void *, DATA_BLOB *, uint8_t, uint8_t);
+struct SRow *libmapiserver_ROP_request_to_properties(TALLOC_CTX *, void *, uint8_t);
 
 /* definitions from libmapiserver_oxcstor.c */
 uint16_t libmapiserver_RopLogon_size(struct EcDoRpc_MAPI_REQ *, struct EcDoRpc_MAPI_REPL *);
index da5307e63d5d6d9877865844851edf97f06b5f8e..19f7eadb90d68c8c5a493f6cecc1ecead557852e 100644 (file)
  */
 
 #include "libmapiserver.h"
+#include <libmapi/libmapi.h>
 #include <libmapi/mapidefs.h>
 #include <gen_ndr/ndr_exchange.h>
+#include <util/debug.h>
 
 /**
    \details Calculate GetPropertiesSpecific Rop size
@@ -222,3 +224,60 @@ end:
        talloc_free(ndr);
        return 0;
 }
+
+
+/**
+   \details Turn request parameters to SPropValue array. This
+   convenient function should be used among MAPI ROPs that have
+   parameters which can be turned to MAPI properties and are stored
+   within backends.
+
+   \param mem_ctx pointer to the memory context
+   \param request generic pointer to the ROP request
+   \param opnum MAPI opnum identifying ROP contents
+
+   \note Developers must talloc_free returned SRow after they finish
+   using it.
+
+   \return Allocated SRow on success, otherwise NULL
+ */
+_PUBLIC_ struct SRow *libmapiserver_ROP_request_to_properties(TALLOC_CTX *mem_ctx, 
+                                                             void *request, 
+                                                             uint8_t opnum)
+{
+       struct SRow                     *aRow;
+       struct CreateFolder_req         *CreateFolder_req;
+
+       aRow = talloc_zero(mem_ctx, struct SRow);
+       aRow->lpProps = talloc_array(aRow, struct SPropValue, 2);
+       aRow->cValues = 0;
+
+       switch (opnum) {
+       case op_MAPI_CreateFolder:
+               CreateFolder_req = (struct CreateFolder_req *) request;
+               aRow->lpProps = add_SPropValue(mem_ctx, aRow->lpProps, &(aRow->cValues),
+                                              PR_FOLDER_TYPE, (void *)&(CreateFolder_req->ulFolderType));
+               switch (CreateFolder_req->ulType) {
+               case MAPI_FOLDER_ANSI:
+                       aRow->lpProps = add_SPropValue(mem_ctx, aRow->lpProps, &(aRow->cValues),
+                                                      PR_DISPLAY_NAME, (void *)(CreateFolder_req->FolderName.lpszA));
+                       aRow->lpProps = add_SPropValue(mem_ctx, aRow->lpProps, &(aRow->cValues),
+                                                      PR_COMMENT, (void *)(CreateFolder_req->FolderComment.lpszA));
+                       break;
+               case MAPI_FOLDER_UNICODE:
+                       aRow->lpProps = add_SPropValue(mem_ctx, aRow->lpProps, &(aRow->cValues),
+                                                      PR_DISPLAY_NAME_UNICODE, (void *)(CreateFolder_req->FolderName.lpszW));
+                       aRow->lpProps = add_SPropValue(mem_ctx, aRow->lpProps, &(aRow->cValues),
+                                                      PR_COMMENT_UNICODE, (void *)(CreateFolder_req->FolderComment.lpszW));
+                       break;
+               }
+               
+               break;
+       default:
+               DEBUG(0, ("[%s:%d]: opnum %d not implemented yet\n", __FUNCTION__, __LINE__, opnum));
+               talloc_free(aRow);
+               return NULL;
+       }
+       
+       return aRow;
+}
index 984af0ebd46595f9250e4728fe7a3b78cdbf57b2..ebb870ec2b8bbbb57b6e3ce0e909afdc6672042e 100644 (file)
@@ -51,6 +51,7 @@ static int fsocpf_create_context(TALLOC_CTX *mem_ctx, const char *uri, void **pr
 {
        DIR                             *top_dir;
        struct fsocpf_context           *fsocpf_ctx;
+       struct folder_list_context      *el;
        int                             len;
        int                             i;
 
@@ -90,6 +91,15 @@ static int fsocpf_create_context(TALLOC_CTX *mem_ctx, const char *uri, void **pr
                }
        }
 
+       /* Create the entry in the list for top mapistore folders */
+       el = talloc_zero((TALLOC_CTX *)fsocpf_ctx->folders, struct folder_list_context);
+       el->ctx = talloc_zero((TALLOC_CTX *)el, struct folder_list);
+       el->ctx->fid = fsocpf_ctx->fid;
+       el->ctx->path = talloc_strdup(fsocpf_ctx, uri);
+       el->ctx->dir = top_dir;
+       DLIST_ADD_END(fsocpf_ctx->folders, el, struct folder_list_context *);
+       DEBUG(0, ("Element added to the list 0x%.16"PRIx64"\n", el->ctx->fid));
+
        /* Step 3. Store fsocpf context within the opaque private_data pointer */
        *private_data = (void *)fsocpf_ctx;
 
@@ -125,7 +135,9 @@ static int fsocpf_delete_context(void *private_data)
                return MAPISTORE_SUCCESS;
        }
 
-       closedir(fsocpf_ctx->dir);
+       if (fsocpf_ctx->dir) {
+               closedir(fsocpf_ctx->dir);
+       }
        talloc_free(fsocpf_ctx);
 
        return MAPISTORE_SUCCESS;
@@ -139,14 +151,68 @@ static int fsocpf_delete_context(void *private_data)
 
    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR
  */
-static int fsocpf_op_mkdir(void *private_data)
+static int fsocpf_op_mkdir(void *private_data, uint64_t parent_fid, uint64_t fid,
+                          struct SRow *aRow)
 {
-       struct fsocpf_context   *fsocpf_ctx = (struct fsocpf_context *)private_data;
+       TALLOC_CTX                      *mem_ctx;
+       struct fsocpf_context           *fsocpf_ctx = (struct fsocpf_context *)private_data;
+       struct folder_list_context      *el;
+       struct mapi_SPropValue_array    mapi_lpProps;
+       bool                            found = false;
+       char                            *newfolder;
+       char                            *propfile;
+       int                             ret;
+       int                             i;
+
+       DEBUG(5, ("[%s:%d]\n", __FUNCTION__, __LINE__));
 
        if (!fsocpf_ctx) {
+               DEBUG(0, ("No fsocpf context found :-(\n"));
                return MAPISTORE_ERROR;
        }
 
+       /* Step 1. Search for the parent fid */
+       for (el = fsocpf_ctx->folders; el; el = el->next) {
+               if (el->ctx && el->ctx->fid == parent_fid) {
+                       found = true;
+                       break;
+               }
+       }
+       if (found == false) {
+               DEBUG(0, ("parent context for folder 0x%.16llx not found\n", parent_fid));
+               return MAPISTORE_ERR_NO_DIRECTORY;
+       }
+
+       mem_ctx = talloc_named(NULL, 0, "fsocpf_op_mkdir");
+
+       /* Step 2. Stringify fid and create directory */
+       newfolder = talloc_asprintf(mem_ctx, "%s/0x%.16"PRIx64, el->ctx->path, fid);
+       DEBUG(0, ("newfolder = %s\n", newfolder));
+       ret = mkdir(newfolder, 0700);
+       if (ret) {
+               DEBUG(0, ("mkdir failed with ret = %d\n", ret));
+               talloc_free(mem_ctx);
+               return MAPISTORE_ERROR;
+       }
+
+       /* Step 3. Create the array of mapi properties */
+       mapi_lpProps.lpProps = talloc_array(mem_ctx, struct mapi_SPropValue, aRow->cValues);
+       mapi_lpProps.cValues = aRow->cValues;
+       for (i = 0; i < aRow->cValues; i++) {
+               cast_mapi_SPropValue(&(mapi_lpProps.lpProps[i]), &(aRow->lpProps[i]));
+       }
+
+       /* Step 3. Create the .properties file */
+       ocpf_init();
+       propfile = talloc_asprintf(mem_ctx, "%s/.properties", newfolder);
+       talloc_free(newfolder);
+
+       ocpf_write_init(propfile, fid);
+       DEBUG(0, ("Writing %s\n", propfile));
+       ocpf_write_auto(NULL, &mapi_lpProps);
+       ocpf_write_commit();
+       ocpf_release();
+
        return MAPISTORE_SUCCESS;
 }
 
@@ -194,7 +260,7 @@ static int fsocpf_op_opendir(void *private_data, uint64_t parent_fid, uint64_t f
                return MAPISTORE_ERROR;
        }
 
-       /* Step 0. If fid equals top folder fid, it is already open*/
+       /* Step 0. If fid equals top folder fid, it is already open */
        if (fsocpf_ctx->fid == fid) {
                /* If we access it for the first time, just add an entry to the folder list */
                if (!fsocpf_ctx->folders->ctx) {
@@ -358,6 +424,8 @@ static int fsocpf_get_property_from_folder_table(struct folder_list *ctx,
        uint32_t                cValues = 0;
        struct SPropValue       *lpProps;
 
+       DEBUG(5, ("[%s:%d]\n", __FUNCTION__, __LINE__));
+
        /* Set dir listing to current position */
        rewinddir(ctx->dir);
        errno = 0;
@@ -398,11 +466,6 @@ static int fsocpf_get_property_from_folder_table(struct folder_list *ctx,
        /* process the file */
        ret = ocpf_parse(propfile);
        talloc_free(propfile);
-       if (ret == -1) {
-               ocpf_release();
-               *data = NULL;
-               return MAPI_E_INVALID_OBJECT;
-       }
        
        ocpf_set_SPropValue_array(ctx);
        lpProps = ocpf_get_SPropValue(&cValues);
@@ -411,7 +474,13 @@ static int fsocpf_get_property_from_folder_table(struct folder_list *ctx,
        talloc_steal(ctx, lpProps);
 
        *data = (void *) get_SPropValue(lpProps, proptag);
-       if ((proptag & 0xFFFF) == PT_STRING8 || (proptag & 0xFFFF) == PT_UNICODE) {
+       if (((proptag & 0xFFFF) == PT_STRING8) || ((proptag & 0xFFFF) == PT_UNICODE)) {
+               /* Hack around PT_STRING8 and PT_UNICODE */
+               if (*data == NULL && ((proptag & 0xFFFF) == PT_STRING8)) {
+                       *data = (void *) get_SPropValue(lpProps, (proptag & 0xFFFF0000) + PT_UNICODE);
+               } else if (*data == NULL && (proptag & 0xFFFF) == PT_UNICODE) {
+                       *data = (void *) get_SPropValue(lpProps, (proptag & 0xFFFF0000) + PT_STRING8);
+               }
                *data = talloc_strdup(ctx, (char *)*data);
        }
 
index a540bc8d06f3158045a3216bff7b7fbe9fd6be51..d1def7f8be489a9049bae43c5cfad91d44e7e93f 100644 (file)
@@ -104,7 +104,8 @@ static int sqlite3_delete_context(void *private_data)
 
    \return MAPI_E_SUCCESS on success
  */
-static int sqlite3_op_mkdir(void *private_data)
+static int sqlite3_op_mkdir(void *private_data, uint64_t parent_fid, uint64_t fid,
+                           const char *displayName)
 {
        struct sqlite3_context          *sqlite_ctx = (struct sqlite3_context *)private_data;
 
index a74c6ae07362ef5a3d2bf793dfcf99e38b361ec4..d3510c5fa0e57c91c56693f55056d1e3a9c684cf 100644 (file)
@@ -61,7 +61,7 @@ struct mapistore_backend {
        int (*create_context)(TALLOC_CTX *, const char *, void **);
        int (*delete_context)(void *);
        /* folders semantic */
-       int (*op_mkdir)(void *);
+  int (*op_mkdir)(void *, uint64_t, uint64_t, struct SRow *);
        int (*op_rmdir)(void *);
        int (*op_opendir)(void *, uint64_t, uint64_t);
        int (*op_closedir)(void *);
@@ -108,7 +108,7 @@ int mapistore_del_context(struct mapistore_context *, uint32_t);
 const char *mapistore_errstr(int);
 int mapistore_opendir(struct mapistore_context *, uint32_t, uint64_t, uint64_t);
 int mapistore_closedir(struct mapistore_context *mstore_ctx, uint32_t, uint64_t);
-int mapistore_mkdir(struct mapistore_context *, uint32_t, uint64_t, uint64_t, struct mapi_SPropValue *);
+int mapistore_mkdir(struct mapistore_context *, uint32_t, uint64_t, uint64_t, struct SRow *);
 int mapistore_rmdir(struct mapistore_context *, uint32_t, uint64_t, uint64_t, uint8_t);
 int mapistore_get_folder_count(struct mapistore_context *, uint32_t, uint64_t, uint32_t *);
 int mapistore_get_table_property(struct mapistore_context *, uint32_t, uint8_t, uint64_t, 
index 1fea50fcf47e2296930b27ae9f31d44532bcf168..984211b1d85135b92dad62367096167ec60efd07 100644 (file)
@@ -363,6 +363,15 @@ int mapistore_backend_opendir(struct backend_context *bctx, uint64_t parent_fid,
 }
 
 
+int mapistore_backend_mkdir(struct backend_context *bctx, 
+                           uint64_t parent_fid, 
+                           uint64_t fid,
+                           struct SRow *aRow)
+{
+       return bctx->backend->op_mkdir(bctx->private_data, parent_fid, fid, aRow);
+}
+
+
 int mapistore_backend_readdir_count(struct backend_context *bctx, uint64_t fid, uint8_t table_type, 
                                    uint32_t *RowCount)
 {
@@ -381,3 +390,5 @@ int mapistore_backend_get_table_property(struct backend_context *bctx, uint64_t
 {
        return bctx->backend->op_get_table_property(bctx->private_data, fid, table_type, pos, proptag, data);
 }
+
+
index 3b7c151e8103a514eb9f250cd596cdebd156a4ef..e28d0bd0ebee9aadbf4d922c3485261d5981181b 100644 (file)
@@ -174,6 +174,8 @@ _PUBLIC_ int mapistore_del_context(struct mapistore_context *mstore_ctx,
        /* Sanity checks */
        MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
 
+       if (context_id == -1) return MAPISTORE_ERROR;
+
        /* Step 0. Ensure the context exists */
        DEBUG(0, ("mapistore_del_context: context_id to del is %d\n", context_id));
        backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
@@ -304,27 +306,31 @@ _PUBLIC_ int mapistore_closedir(struct mapistore_context *mstore_ctx,
    where the directory will be created
    \param parent_fid the parent folder identifier
    \param new_fid the folder identifier for the new folder
-   \param properties pointer to MAPI data structures with properties
-   applied to the new folder
+   \param aRow pointer to MAPI data structures with properties to be
+   added to the new folder
 
    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE errors
  */
 _PUBLIC_ int mapistore_mkdir(struct mapistore_context *mstore_ctx,
                             uint32_t context_id,
                             uint64_t parent_fid,
-                            uint64_t new_fid,
-                            struct mapi_SPropValue *properties)
+                            uint64_t fid,
+                            struct SRow *aRow)
 {
        struct backend_context          *backend_ctx;
+       int                             ret;
 
        /* Sanity checks */
        MAPISTORE_SANITY_CHECKS(mstore_ctx, NULL);
 
-       /* Step 0. Ensure the context exists */
+       /* Step 1. Search the context */
        backend_ctx = mapistore_backend_lookup(mstore_ctx->context_list, context_id);
        MAPISTORE_RETVAL_IF(!backend_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);       
+       
+       /* Step 2. Call backend mkdir */
+       ret = mapistore_backend_mkdir(backend_ctx, parent_fid, fid, aRow);
 
-       return MAPISTORE_SUCCESS;
+       return !ret ? MAPISTORE_SUCCESS : MAPISTORE_ERROR;
 }
 
 
index 37cd64ba3eb177ea6d155beec3bcb0a2e4a17fe2..d20430b1b7fc1df9543410252981715b056f747b 100644 (file)
@@ -128,6 +128,7 @@ 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 *);
 int mapistore_backend_opendir(struct backend_context *, uint64_t, uint64_t);
+int mapistore_backend_mkdir(struct backend_context *, uint64_t, uint64_t, struct SRow *);
 int mapistore_backend_readdir_count(struct backend_context *, uint64_t, uint8_t, uint32_t *);
 int mapistore_backend_get_table_property(struct backend_context *, uint64_t, uint8_t, uint32_t, 
                                         uint32_t, void **);
index a2b545342d39aa30c33fdffe697aed8a34f70812..ae4db6f03a09047b1b4d46384e66486f7cd29c14 100644 (file)
@@ -120,16 +120,17 @@ struct emsmdbp_object {
 #define        EMSMDBP_MAILBOX_ROOT            0x1
 #define        EMSMDBP_DEFERRED_ACTIONS        0x2
 #define        EMSMDBP_SPOOLER_QUEUE           0x3
-#define        EMSMDBP_TOP_INFORMATION_STORE   0x4
-#define        EMSMDBP_INBOX                   0x5
-#define        EMSMDBP_OUTBOX                  0x6
-#define        EMSMDBP_SENT_ITEMS              0x7
-#define        EMSMDBP_DELETED_ITEMS           0x8
-#define        EMSMDBP_COMMON_VIEWS            0x9
-#define        EMSMDBP_SCHEDULE                0xA
-#define        EMSMDBP_SEARCH                  0xB
-#define        EMSMDBP_VIEWS                   0xC
-#define        EMSMDBP_SHORTCUTS               0xD
+#define        EMSMDBP_TODO_SEARCH             0x4
+#define        EMSMDBP_TOP_INFORMATION_STORE   0x5
+#define        EMSMDBP_INBOX                   0x6
+#define        EMSMDBP_OUTBOX                  0x7
+#define        EMSMDBP_SENT_ITEMS              0x8
+#define        EMSMDBP_DELETED_ITEMS           0x9
+#define        EMSMDBP_COMMON_VIEWS            0xA
+#define        EMSMDBP_SCHEDULE                0xB
+#define        EMSMDBP_SEARCH                  0xC
+#define        EMSMDBP_VIEWS                   0xD
+#define        EMSMDBP_SHORTCUTS               0xE
 
 #define        EMSMDBP_TABLE_FOLDER_TYPE       0x1
 #define        EMSMDBP_TABLE_MESSAGE_TYPE      0x2
@@ -151,7 +152,7 @@ const char        *emsmdbp_getstr_type(struct emsmdbp_object *);
 bool                 emsmdbp_is_mapistore(struct mapi_handles *);
 struct emsmdbp_object *emsmdbp_object_init(TALLOC_CTX *, struct emsmdbp_context *);
 struct emsmdbp_object *emsmdbp_object_mailbox_init(TALLOC_CTX *, struct emsmdbp_context *, struct EcDoRpc_MAPI_REQ *);
-struct emsmdbp_object *emsmdbp_object_folder_init(TALLOC_CTX *, struct emsmdbp_context *, struct EcDoRpc_MAPI_REQ *, struct mapi_handles *);
+struct emsmdbp_object *emsmdbp_object_folder_init(TALLOC_CTX *, struct emsmdbp_context *, uint64_t);
 struct emsmdbp_object *emsmdbp_object_table_init(TALLOC_CTX *, struct emsmdbp_context *, struct mapi_handles *);
 
 /* definitions from oxcfold.c */
index 94637ac249ef63cd0e9e632944ff95cadf54b3e7..f46a4cac8797ba5c0111c0bdf348b3785d9ec0b1 100644 (file)
@@ -211,15 +211,13 @@ _PUBLIC_ struct emsmdbp_object *emsmdbp_object_mailbox_init(TALLOC_CTX *mem_ctx,
 
    \param mem_ctx pointer to the memory context
    \param emsmdbp_ctx pointer to the emsmdb provider context
-   \param request pointer to the OpenFolder MAPI request
-   \param parent pointer to the parent MAPI handle
+   \param folderID the folder identifier
 
    \return Allocated emsmdbp object on success, otherwise NULL
  */
 _PUBLIC_ struct emsmdbp_object *emsmdbp_object_folder_init(TALLOC_CTX *mem_ctx,
                                                           struct emsmdbp_context *emsmdbp_ctx,
-                                                          struct EcDoRpc_MAPI_REQ *request,
-                                                          struct mapi_handles *parent)
+                                                          uint64_t folderID)
 {
        enum MAPISTATUS                 retval;
        struct emsmdbp_object           *object;
@@ -229,7 +227,6 @@ _PUBLIC_ struct emsmdbp_object *emsmdbp_object_folder_init(TALLOC_CTX *mem_ctx,
 
        /* Sanity checks */
        if (!emsmdbp_ctx) return NULL;
-       if (!request) return NULL;
 
        object = emsmdbp_object_init(mem_ctx, emsmdbp_ctx);
        if (!object) return NULL;
@@ -242,7 +239,7 @@ _PUBLIC_ struct emsmdbp_object *emsmdbp_object_folder_init(TALLOC_CTX *mem_ctx,
 
        object->type = EMSMDBP_OBJECT_FOLDER;
        object->object.folder->contextID = -1;
-       object->object.folder->folderID = request->u.mapi_OpenFolder.folder_id;
+       object->object.folder->folderID = folderID;
        object->object.folder->mapistore_root = false;
 
        /* system folders acting as containers don't have
@@ -267,6 +264,8 @@ _PUBLIC_ struct emsmdbp_object *emsmdbp_object_folder_init(TALLOC_CTX *mem_ctx,
                        object->object.folder->contextID = context_id;
                }
        } else {
+               /* object->object.folder->mapistore = false; */
+               DEBUG(0, ("error in emsmdbp_object_folder_init, retval = 0x%.8x\n", retval));
                talloc_free(object);
                return NULL;
        }
index 2e7ace85ab4efd264c3b0ceda2a38a7fbde446a0..8c2f480e077389d0eedcfa6e822cba164a4bf1db 100644 (file)
@@ -130,8 +130,8 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopOpenFolder(TALLOC_CTX *mem_ctx,
        request = mapi_req->u.mapi_OpenFolder;
        response = mapi_repl->u.mapi_OpenFolder;
 
-       mapi_repl->u.mapi_OpenFolder.HasRules = 0;
-       mapi_repl->u.mapi_OpenFolder.IsGhosted = 0;
+       response.HasRules = 0;
+       response.IsGhosted = 0;
 
        /* Step 1. Retrieve parent handle in the hierarchy */
        handle = handles[mapi_req->handle_idx];
@@ -160,7 +160,7 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopOpenFolder(TALLOC_CTX *mem_ctx,
        if (!mapi_repl->error_code) {
                retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
 
-               object = emsmdbp_object_folder_init((TALLOC_CTX *)emsmdbp_ctx, emsmdbp_ctx, mapi_req, parent);
+               object = emsmdbp_object_folder_init((TALLOC_CTX *)emsmdbp_ctx, emsmdbp_ctx, request.folder_id);
                if (object) {
                        retval = mapi_handles_set_private_data(rec, object);
                }
@@ -327,31 +327,37 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetContentsTable(TALLOC_CTX *mem_ctx,
 }
 
 
-static enum MAPISTATUS EcDoRpc_RopCreateGenericFolder(struct emsmdbp_context *emsmdbp_ctx,
-                                                     union LPTSTR folderName, uint32_t parentFolder,
-                                                     enum FOLDER_FLAGS folderFlags,
-                                                     uint64_t *folderID, uint8_t *isExisting)
+static enum MAPISTATUS EcDoRpc_RopCreateSystemSpecialFolder(struct emsmdbp_context *emsmdbp_ctx,
+                                                           struct SRow *aRow, 
+                                                           enum FOLDER_FLAGS folderFlags,
+                                                           uint64_t parentFolder,
+                                                           struct CreateFolder_repl *response)
 {
        TALLOC_CTX                      *mem_ctx;
        enum MAPISTATUS                 retval;
        struct ldb_message              *msg;
        struct ldb_dn                   *basedn;
-       uint64_t                        fid = 0;
        char                            *dn;
-       char                            *fid_formatted;
-       char                            *parentfid_formatted;
+       char                            *parentfid;
        int                             ret = 0;
+       char                            *displayName;
+       char                            *comment;
+       uint32_t                        *folderType;
 
-       DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateGenericFolder\n"));
+       DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateSystemSpecialFolder\n"));
+
+       displayName = (char *) find_SPropValue_data(aRow, PR_DISPLAY_NAME);
+       if (!displayName) {
+               displayName = (char *) find_SPropValue_data(aRow, PR_DISPLAY_NAME_UNICODE);
+       }
 
        /* Step 0. Determine if the folder already exists */
        if (openchangedb_get_fid_by_name(emsmdbp_ctx->oc_ctx, parentFolder,
-                                        folderName.lpszA, &fid) == MAPI_E_SUCCESS) {
+                                        displayName, &response->folder_id) == MAPI_E_SUCCESS) {
                /* this folder already exists */
                if ( folderFlags & OPEN_IF_EXISTS ) {
                        DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder Duplicate Folder\n"));
-                       *isExisting = true;
-                       *folderID = fid;
+                       response->IsExistingFolder = true;
                        return MAPI_E_SUCCESS;
                } else {
                        DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder Duplicate Folder error\n"));
@@ -359,26 +365,22 @@ static enum MAPISTATUS EcDoRpc_RopCreateGenericFolder(struct emsmdbp_context *em
                }
        }
 
-       mem_ctx = talloc_named(NULL, 0, "RopCreateGenericFolder");
-
-       /* TODO:
-          - We need to pass more information to underlying functions
-             so folder creation also include customizable folder
-             comment, class and so on.
-        */
+       mem_ctx = talloc_named(NULL, 0, "RopCreateSystemSpecialFolder");
 
        /* Step 1. Retrieve the next available folderID */
-       retval = openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &fid);
+       retval = openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &response->folder_id);
+       OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
+
+       /* Retrieve dn of parentfolder */
+       retval = openchangedb_get_distinguishedName(mem_ctx, emsmdbp_ctx->oc_ctx, parentFolder, &parentfid);
        OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
 
        /* Step 2. Create the folder LDB record for openchange.ldb */
-       fid_formatted = talloc_asprintf(mem_ctx, "0x%016"PRIx64, fid);
-       parentfid_formatted = talloc_asprintf(mem_ctx, "0x%016x", parentFolder);
-       *folderID = fid;
-       
-       dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,CN=%s,%s", fid_formatted, 
-                            parentfid_formatted, emsmdbp_ctx->username,
-                            ldb_dn_get_linearized(ldb_get_root_basedn(emsmdbp_ctx->oc_ctx)));
+       dn = talloc_asprintf(mem_ctx, "CN=%016"PRIx64",%s", response->folder_id, parentfid);
+
+       /* Ensure dn is within user mailbox / prevent from creating
+        * folders in other mailboxes: check dn vs emsmdbp_ctx->username */
+
        basedn = ldb_dn_new(mem_ctx, emsmdbp_ctx->oc_ctx, dn);
        talloc_free(dn);
        OPENCHANGE_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
@@ -386,30 +388,117 @@ static enum MAPISTATUS EcDoRpc_RopCreateGenericFolder(struct emsmdbp_context *em
        msg = ldb_msg_new(mem_ctx);
        msg->dn = ldb_dn_copy(mem_ctx, basedn);
        ldb_msg_add_string(msg, "objectClass", "systemfolder");
-       ldb_msg_add_string(msg, "cn", fid_formatted);
+       ldb_msg_add_fmt(msg, "cn", "0x%.16"PRIx64, response->folder_id);
        ldb_msg_add_string(msg, "PidTagContentUnreadCount", "0");
        ldb_msg_add_string(msg, "PidTagContentCount", "0");
        ldb_msg_add_string(msg, "PidTagContainerClass", "IPF.Note");
        ldb_msg_add_string(msg, "PidTagAttrHidden", "0");
-       ldb_msg_add_string(msg, "PidTagDisplayName", folderName.lpszA);
-       ldb_msg_add_string(msg, "PidTagParentFolderId", parentfid_formatted);
-       ldb_msg_add_string(msg, "PidTagFolderId", fid_formatted);
-       ldb_msg_add_fmt(msg, "mapistore_uri", "fsocpf:///usr/local/samba/private/mapistore/%s/%s", 
-                       emsmdbp_ctx->username, fid_formatted);
+       ldb_msg_add_string(msg, "PidTagDisplayName", displayName);
+
+       folderType = (uint32_t *) find_SPropValue_data(aRow, PR_FOLDER_TYPE);
+       ldb_msg_add_fmt(msg, "PidTagFolderType", "%d", *folderType);
+
+       comment = (char *) find_SPropValue_data(aRow, PR_COMMENT);
+       if (!comment) {
+               comment = (char *) find_SPropValue_data(aRow, PR_COMMENT_UNICODE);
+       }
+       ldb_msg_add_string(msg, "PidTagComment", comment);
+
+       ldb_msg_add_fmt(msg, "PidTagParentFolderId", "0x%.16"PRIx64, parentFolder);
+       ldb_msg_add_fmt(msg, "PidTagFolderId", "0x%.16"PRIx64, response->folder_id);
+       ldb_msg_add_fmt(msg, "mapistore_uri", "fsocpf:///usr/local/samba/private/mapistore/%s/%.16"PRIx64, 
+                       emsmdbp_ctx->username, response->folder_id);
        ldb_msg_add_string(msg, "PidTagSubFolders", "0");
        ldb_msg_add_string(msg, "FolderType", "1");
        ldb_msg_add_fmt(msg, "distinguishedName", "%s", ldb_dn_get_linearized(msg->dn));
 
+       msg->elements[0].flags = LDB_FLAG_MOD_ADD;
+
        ret = ldb_add(emsmdbp_ctx->oc_ctx, msg);
        OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
 
-       talloc_free(fid_formatted);
-       talloc_free(parentfid_formatted);
+       talloc_free(parentfid);
        talloc_free(mem_ctx);
 
        return MAPI_E_SUCCESS;
 }
 
+
+static enum MAPISTATUS EcDoRpc_RopCreateGenericFolder(struct emsmdbp_context *emsmdbp_ctx,
+                                                     struct mapi_handles *parent,
+                                                     struct SRow *aRow,
+                                                     enum FOLDER_FLAGS folderFlags,
+                                                     struct CreateFolder_repl *response)
+{
+       TALLOC_CTX              *mem_ctx;
+       enum MAPISTATUS         retval;
+       int                     ret;
+       struct ldb_result       *res = NULL;
+       struct ldb_message      *msg;
+       
+       struct ldb_dn           *ldb_dn;
+       struct emsmdbp_object   *parent_object = NULL;
+       const char * const      attrs[] = { "*", NULL };
+       void                    *data;
+       uint64_t                parent_fid;
+       uint32_t                context_id;
+       char                    *parentfid;
+       int                     count;
+
+       DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateGenericFolder\n"));
+
+       /* Step 1. Retrieve the parent fid given the handle */
+       mapi_handles_get_private_data(parent, &data);
+       parent_object = (struct emsmdbp_object *) data;
+       /* checks are already done in upper function / code factorization required */
+
+       parent_fid = parent_object->object.folder->folderID;
+       context_id = parent_object->object.folder->contextID;
+
+       /* Step 0. Determine if the folder already exists */
+
+       /* Step 1. Retrieve the next available folderID */
+       retval = openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &response->folder_id);
+       OPENCHANGE_RETVAL_IF(retval, retval, NULL);
+
+       /* Step 2. Create folder in mapistore */
+       retval = mapistore_mkdir(emsmdbp_ctx->mstore_ctx, context_id, parent_fid, response->folder_id, 
+                                aRow);
+       OPENCHANGE_RETVAL_IF(retval, retval, NULL);
+
+       /* Step 3. Update openchangedb record if needed */
+       if (parent_object->type == EMSMDBP_OBJECT_FOLDER && parent_object->object.folder->mapistore_root == true) {
+               mem_ctx = talloc_named(NULL, 0, "RopCreateGenericFolder");
+
+               /* Retrieve previous value */
+               ret = ldb_search(emsmdbp_ctx->oc_ctx, mem_ctx, &res, ldb_get_default_basedn(emsmdbp_ctx->oc_ctx),
+                                LDB_SCOPE_SUBTREE, attrs, "PidTagFolderId=0x%.16"PRIx64, parent_fid);
+               OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_NOT_FOUND, mem_ctx);
+
+               count = ldb_msg_find_attr_as_int(res->msgs[0], "PidTagFolderChildCount", 0);
+               
+               /* Update record */
+               retval = openchangedb_get_distinguishedName(mem_ctx, emsmdbp_ctx->oc_ctx, parent_fid, &parentfid);
+               OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
+
+               ldb_dn = ldb_dn_new(mem_ctx, emsmdbp_ctx->oc_ctx, parentfid);
+               OPENCHANGE_RETVAL_IF(!ldb_dn_validate(ldb_dn), MAPI_E_BAD_VALUE, mem_ctx);
+
+               msg = ldb_msg_new(mem_ctx);
+               msg->dn = ldb_dn_copy(mem_ctx, ldb_dn);
+               ldb_msg_add_fmt(msg, "PidTagFolderChildCount", "%d", count + 1);
+               msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
+
+               ret = ldb_modify(emsmdbp_ctx->oc_ctx, msg);
+               OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
+
+               talloc_free(mem_ctx);
+       }
+
+       return MAPI_E_SUCCESS;
+}
+
+
 /**
    \details EcDoRpc CreateFolder (0x1c) Rop. This operation creates a
    folder on the remote server.
@@ -433,17 +522,16 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopCreateFolder(TALLOC_CTX *mem_ctx,
                                                 struct EcDoRpc_MAPI_REPL *mapi_repl,
                                                 uint32_t *handles, uint16_t *size)
 {
-       enum MAPISTATUS         retval;
-       struct mapi_handles     *parent = NULL;
-       uint32_t                handle;
-       uint64_t                parent_fid;
-       uint64_t                fid = 0;
-       struct emsmdbp_object   *parent_object = NULL;
-       struct emsmdbp_object   *object = NULL;
-       void                    *data;
-       struct mapi_handles     *rec = NULL;
-       uint32_t                folder_handle;
-       uint8_t                 isExisting = 0;
+       enum MAPISTATUS                 retval;
+       struct mapi_handles             *parent = NULL;
+       uint32_t                        handle;
+       uint64_t                        parent_fid;
+       struct emsmdbp_object           *parent_object = NULL;
+       struct emsmdbp_object           *object = NULL;
+       struct SRow                     *aRow;
+       void                            *data;
+       struct mapi_handles             *rec = NULL;
+       bool                            mapistore = false;
 
        DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder (0x1c)\n"));
 
@@ -454,7 +542,11 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopCreateFolder(TALLOC_CTX *mem_ctx,
        OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
        OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
 
-       /* Step 1. Search for the parent FID using handles */
+       mapi_repl->u.mapi_CreateFolder.IsExistingFolder = false;
+
+       mapi_repl->opnum = mapi_req->opnum;
+
+       /* Step 1. Retrieve parent handle in the hierarchy */
        handle = handles[mapi_req->handle_idx];
        retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent);
        OPENCHANGE_RETVAL_IF(retval, retval, NULL);
@@ -476,54 +568,63 @@ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopCreateFolder(TALLOC_CTX *mem_ctx,
        DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder parent: 0x%"PRIx64"\n", parent_fid));
        DEBUG(4, ("exchange_emsmdb: [OXCFOLD] Creating %s\n", mapi_req->u.mapi_CreateFolder.FolderName.lpszA));
        
-       /* Step 2. Initialize default empty CreateFolder reply */
-       mapi_repl->opnum = mapi_req->opnum;
-       mapi_repl->handle_idx = mapi_req->u.mapi_CreateFolder.handle_idx;
-       mapi_repl->error_code = MAPI_E_SUCCESS;
-       mapi_repl->u.mapi_CreateFolder.folder_id = 0;
-       mapi_repl->u.mapi_CreateFolder.IsExistingFolder = false;
+       /* Step 3. Turn CreateFolder parameters into MAPI property array */
+       aRow = libmapiserver_ROP_request_to_properties(mem_ctx, (void *)&mapi_req->u.mapi_CreateFolder, op_MAPI_CreateFolder);
 
-       /* Step 3. Do effective work here */
-       switch (mapi_req->u.mapi_CreateFolder.ulFolderType) {
-       case FOLDER_GENERIC:
-               mapi_repl->error_code = EcDoRpc_RopCreateGenericFolder(emsmdbp_ctx,
-                                                                      mapi_req->u.mapi_CreateFolder.FolderName,
-                                                                      parent_fid,
-                                                                      mapi_req->u.mapi_CreateFolder.ulFlags,
-                                                                      &fid, &isExisting);
+       /* Step 4. Do effective work here */
+       mapistore = emsmdbp_is_mapistore(parent);
+       switch (mapistore) {
+       case false:
+               switch (mapi_req->u.mapi_CreateFolder.ulType) {
+               case FOLDER_GENERIC:
+                       mapi_repl->error_code = EcDoRpc_RopCreateSystemSpecialFolder(emsmdbp_ctx, aRow,
+                                                                                    mapi_req->u.mapi_CreateFolder.ulFlags,
+                                                                                    parent_fid, &mapi_repl->u.mapi_CreateFolder);
+                       break;
+               case FOLDER_SEARCH:
+                       DEBUG(4, ("exchange_emsmdb: [OXCFOLD] FOLDER_SEARCH not implemented\n"));
+                       break;
+               default:
+                       DEBUG(4, ("exchange_emsmdb: [OXCFOLD] Unexpected folder type\n"));
+               }
                break;
-       case FOLDER_SEARCH:
-               DEBUG(4, ("exchange_emsmdb: [OXCFOLD] FOLDER_SEARCH not implemented\n"));
+       case true:
+               mapi_repl->error_code = EcDoRpc_RopCreateGenericFolder(emsmdbp_ctx, parent, aRow,
+                                                                      mapi_req->u.mapi_CreateFolder.ulFlags,
+                                                                      &mapi_repl->u.mapi_CreateFolder);
                break;
-       default:
-               DEBUG(4, ("exchange_emsmdb: [OXCFOLD] Unexpected folder type\n"));
        }
 
-       if (isExisting) {
-               mapi_repl->u.mapi_CreateFolder.IsExistingFolder = true;
+       if (mapi_repl->error_code == MAPI_E_COLLISION) {
+               mapi_repl->error_code = MAPI_E_SUCCESS;
+       }
+
+       if (mapi_repl->u.mapi_CreateFolder.IsExistingFolder == true) {
                mapi_repl->u.mapi_CreateFolder.GhostUnion.GhostInfo.HasRules = false;
                mapi_repl->u.mapi_CreateFolder.GhostUnion.GhostInfo.IsGhosted = false;
        }
 
-       *size += libmapiserver_RopCreateFolder_size(mapi_repl);
-
        if (!mapi_repl->error_code) {
-               /* Set the created folder FID */
-               mapi_repl->u.mapi_CreateFolder.folder_id = fid;
+               *size += libmapiserver_RopCreateFolder_size(mapi_repl);
+               retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
+               if (mapistore == true) {
+                       object = emsmdbp_object_folder_init((TALLOC_CTX *)rec, emsmdbp_ctx, 
+                                                           mapi_repl->u.mapi_CreateFolder.folder_id);
+                       if (object) {
+                               retval = mapi_handles_set_private_data(rec, object);
+                       }
+               }
+               mapi_repl->opnum = mapi_req->opnum;
+               mapi_repl->handle_idx = mapi_req->u.mapi_CreateFolder.handle_idx;
 
-               /* Step 4. Create a new handle */
-               folder_handle = handles[mapi_req->handle_idx];
-               retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, folder_handle, &rec);
                handles[mapi_repl->handle_idx] = rec->handle;
+       }
 
-               /* Step 5. Initialize the internal folder object */
-               object = emsmdbp_object_folder_init((TALLOC_CTX *)rec, emsmdbp_ctx, mapi_req, parent);
-               if (object) {
-                       retval = mapi_handles_set_private_data(rec, object);
-               }
+       if (aRow) {
+               talloc_free(aRow);
        }
 
-       return retval;
+       return MAPI_E_SUCCESS;
 }
 
 static enum MAPISTATUS DoDeleteFolder(struct emsmdbp_context *emsmdbp_ctx,