Merge provisioning fix from sogo branch
[jelmer/openchange.git] / mapiproxy / servers / default / emsmdb / oxcfold.c
1 /*
2    OpenChange Server implementation
3
4    EMSMDBP: EMSMDB Provider implementation
5
6    Copyright (C) Julien Kerihuel 2009-2010
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /**
23    \file oxcfold.c
24
25    \brief Folder object routines and Rops
26  */
27
28 #include "mapiproxy/dcesrv_mapiproxy.h"
29 #include "mapiproxy/libmapiproxy/libmapiproxy.h"
30 #include "mapiproxy/libmapiserver/libmapiserver.h"
31 #include "dcesrv_exchange_emsmdb.h"
32
33
34 /**
35    \details EcDoRpc OpenFolder (0x02) Rop. This operation opens an
36    existing folder.
37
38    \param mem_ctx pointer to the memory context
39    \param emsmdbp_ctx pointer to the emsmdb provider context
40    \param mapi_req pointer to the OpenFolder EcDoRpc_MAPI_REQ
41    structure
42    \param mapi_repl pointer to the OpenFolder EcDoRpc_MAPI_REPL
43    structure
44    \param handles pointer to the MAPI handles array
45    \param size pointer to the mapi_response size to update
46
47    \return MAPI_E_SUCCESS on success, otherwise MAPI error
48  */
49 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopOpenFolder(TALLOC_CTX *mem_ctx,
50                                                struct emsmdbp_context *emsmdbp_ctx,
51                                                struct EcDoRpc_MAPI_REQ *mapi_req,
52                                                struct EcDoRpc_MAPI_REPL *mapi_repl,
53                                                uint32_t *handles, uint16_t *size)
54 {
55         enum MAPISTATUS                 retval;
56         struct mapi_handles             *parent = NULL;
57         struct mapi_handles             *rec = NULL;
58         void                            *private_data;
59         struct emsmdbp_object           *object, *parent_object;
60         uint32_t                        handle;
61         struct OpenFolder_req           *request;
62         struct OpenFolder_repl          *response;
63
64         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] OpenFolder (0x02)\n"));
65
66         /* Sanity checks */
67         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
68         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
69         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
70         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
71         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
72
73         request = &mapi_req->u.mapi_OpenFolder;
74         response = &mapi_repl->u.mapi_OpenFolder;
75
76         mapi_repl->opnum = mapi_req->opnum;
77         mapi_repl->error_code = MAPI_E_SUCCESS;
78         mapi_repl->handle_idx = request->handle_idx;
79
80         /* Step 1. Retrieve parent handle in the hierarchy */
81         handle = handles[mapi_req->handle_idx];
82         retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent);
83         if (retval) {
84                 DEBUG(5, ("  handle (%x) not found: %x\n", handle, mapi_req->handle_idx));
85                 mapi_repl->error_code = MAPI_E_INVALID_OBJECT;
86                 goto end;
87         }
88
89         /* With OpenFolder, the parent object may NOT BE the direct parent folder of the folder */
90         mapi_handles_get_private_data(parent, &private_data);
91         parent_object = private_data;
92         if (!parent_object || (parent_object->type != EMSMDBP_OBJECT_FOLDER && parent_object->type != EMSMDBP_OBJECT_MAILBOX)) {
93                 DEBUG(5, ("  invalid handle (%x): %x\n", handle, mapi_req->handle_idx));
94                 mapi_repl->error_code = MAPI_E_INVALID_OBJECT;
95                 goto end;
96         }
97
98         /* Fill EcDoRpc_MAPI_REPL reply */
99         response->HasRules = 0;
100         response->IsGhosted = 0;
101
102         mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
103         object = emsmdbp_object_open_folder_by_fid(rec, emsmdbp_ctx, parent_object, request->folder_id);
104         if (!object) {
105                 mapi_repl->error_code = MAPI_E_NOT_FOUND;
106                 goto end;
107         }
108         retval = mapi_handles_set_private_data(rec, object);
109         handles[mapi_repl->handle_idx] = rec->handle;
110
111 end:
112         *size += libmapiserver_RopOpenFolder_size(mapi_repl);
113
114         return MAPI_E_SUCCESS;
115 }
116
117
118 /**
119    \details EcDoRpc GetHierarchyTable (0x04) Rop. This operation gets
120    the subfolder hierarchy table for a folder.
121
122    \param mem_ctx pointer to the memory context
123    \param emsmdbp_ctx pointer to the emsmdb provider context
124    \param mapi_req pointer to the GetHierarchyTable EcDoRpc_MAPI_REQ
125    structure
126    \param mapi_repl pointer to the GetHierarchyTable EcDoRpc_MAPI_REPL
127    structure
128    \param handles pointer to the MAPI handles array
129    \param size pointer to the mapi_response size to update
130
131    \return MAPI_E_SUCCESS on success, otherwise MAPI error
132  */
133 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetHierarchyTable(TALLOC_CTX *mem_ctx,
134                                                       struct emsmdbp_context *emsmdbp_ctx,
135                                                       struct EcDoRpc_MAPI_REQ *mapi_req,
136                                                       struct EcDoRpc_MAPI_REPL *mapi_repl,
137                                                       uint32_t *handles, uint16_t *size)
138 {
139         enum MAPISTATUS         retval;
140         struct mapi_handles     *parent;
141         struct mapi_handles     *rec = NULL;
142         struct emsmdbp_object   *object = NULL, *parent_object = NULL;
143         struct mapistore_subscription_list *subscription_list;
144         struct mapistore_subscription *subscription;
145         struct mapistore_table_subscription_parameters subscription_parameters;
146         void                    *data;
147         uint64_t                folderID;
148         uint32_t                handle;
149
150         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] GetHierarchyTable (0x04)\n"));
151
152         /* Sanity checks */
153         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
154         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
155         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
156         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
157         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
158
159         /* Initialize default empty GetHierarchyTable reply */
160         mapi_repl->opnum = mapi_req->opnum;
161         mapi_repl->error_code = MAPI_E_SUCCESS;
162         mapi_repl->handle_idx = mapi_req->u.mapi_GetHierarchyTable.handle_idx;
163
164         /* GetHierarchyTable can only be called for mailbox/folder objects */
165         handle = handles[mapi_req->handle_idx];
166         retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent);
167         if (retval) {
168                 DEBUG(5, ("  handle (%x) not found: %x\n", handle, mapi_req->handle_idx));
169                 mapi_repl->error_code = MAPI_E_INVALID_OBJECT;
170                 goto end;
171         }
172
173         mapi_handles_get_private_data(parent, &data);
174         parent_object = (struct emsmdbp_object *)data;
175         if (!parent_object) {
176                 DEBUG(5, ("  no object found\n"));
177                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
178                 goto end;
179         }
180
181         switch (parent_object->type) {
182         case EMSMDBP_OBJECT_MAILBOX:
183                 folderID = parent_object->object.mailbox->folderID;
184                 break;
185         case EMSMDBP_OBJECT_FOLDER:
186                 folderID = parent_object->object.folder->folderID;
187                 break;
188         default:
189                 DEBUG(5, ("  unsupported object type\n"));
190                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
191                 goto end;
192         }
193
194         /* Initialize Table object */
195         retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
196         handles[mapi_repl->handle_idx] = rec->handle;
197
198         object = emsmdbp_folder_open_table(rec, parent_object, EMSMDBP_TABLE_FOLDER_TYPE, rec->handle);
199         if (!object) {
200                 mapi_repl->error_code = MAPI_E_INVALID_OBJECT;
201                 goto end;
202         }
203         mapi_handles_set_private_data(rec, object);
204         mapi_repl->u.mapi_GetHierarchyTable.RowCount = object->object.table->denominator;
205
206         /* notifications */
207         if ((mapi_req->u.mapi_GetHierarchyTable.TableFlags & TableFlags_NoNotifications)) {
208                 DEBUG(5, ("  notifications skipped\n"));
209         }
210         else {
211                 /* we attach the subscription to the session object */
212                 subscription_list = talloc_zero(emsmdbp_ctx->mstore_ctx, struct mapistore_subscription_list);
213                 DLIST_ADD(emsmdbp_ctx->mstore_ctx->subscriptions, subscription_list);
214
215                 subscription_parameters.table_type = MAPISTORE_FOLDER_TABLE;
216                 subscription_parameters.folder_id = folderID;
217
218                 /* note that a mapistore_subscription can exist without a corresponding emsmdbp_object (tables) */
219                 subscription = mapistore_new_subscription(subscription_list, rec->handle, fnevTableModified, &subscription_parameters);
220                 subscription_list->subscription = subscription;
221                 object->object.table->subscription_list = subscription_list;
222         }
223
224 end:
225         *size += libmapiserver_RopGetHierarchyTable_size(mapi_repl);
226
227         return MAPI_E_SUCCESS;
228 }
229
230
231 /**
232    \details EcDoRpc GetContentsTable (0x05) Rop. This operation get
233    the content table of a container.
234
235    \param mem_ctx pointer to the memory context
236    \param emsmdbp_ctx pointer to the emsmdb provider context
237    \param mapi_req pointer to the GetContentsTable EcDoRpc_MAPI_REQ
238    structure
239    \param mapi_repl pointer to the GetContentsTable EcDoRpc_MAPI_REPL
240    structure
241    \param handles pointer to the MAPI handles array
242    \param size pointer to the mapi_response size to update
243
244    \return MAPI_E_SUCCESS on success, otherwise MAPI error
245  */
246 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetContentsTable(TALLOC_CTX *mem_ctx,
247                                                      struct emsmdbp_context *emsmdbp_ctx,
248                                                      struct EcDoRpc_MAPI_REQ *mapi_req,
249                                                      struct EcDoRpc_MAPI_REPL *mapi_repl,
250                                                      uint32_t *handles, uint16_t *size)
251 {
252         enum MAPISTATUS         retval;
253         struct mapi_handles     *parent;
254         struct mapi_handles     *rec = NULL;
255         struct emsmdbp_object   *object = NULL, *parent_object;
256         struct mapistore_subscription_list *subscription_list;
257         struct mapistore_subscription *subscription;
258         struct mapistore_table_subscription_parameters subscription_parameters;
259         void                    *data;
260         uint64_t                folderID;
261         uint32_t                handle;
262         uint8_t                 table_type;
263
264         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] GetContentsTable (0x05)\n"));
265
266         /* Sanity checks */
267         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
268         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
269         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
270         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
271         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
272
273         /* Initialize default empty GetContentsTable reply */
274         mapi_repl->opnum = mapi_req->opnum;
275         mapi_repl->handle_idx = mapi_req->u.mapi_GetContentsTable.handle_idx;
276         mapi_repl->error_code = MAPI_E_SUCCESS;
277         mapi_repl->u.mapi_GetContentsTable.RowCount = 0;
278
279         handle = handles[mapi_req->handle_idx];
280         retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent);
281         if (retval) {
282                 DEBUG(5, ("  handle (%x) not found: %x\n", handle, mapi_req->handle_idx));
283                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
284                 goto end;
285         }
286
287         /* GetContentsTable can only be called for folder objects */
288         retval = mapi_handles_get_private_data(parent, &data);
289         if (retval) {
290                 mapi_repl->error_code = retval;
291                 DEBUG(5, ("  handle data not found, idx = %x\n", mapi_req->handle_idx));
292                 goto end;
293         }
294
295         parent_object = (struct emsmdbp_object *)data;
296         if (!parent_object) {
297                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
298                 DEBUG(5, ("  handle data not found, idx = %x\n", mapi_req->handle_idx));
299                 goto end;
300         }
301
302         switch (parent_object->type) {
303         case EMSMDBP_OBJECT_FOLDER:
304                 folderID = parent_object->object.folder->folderID;
305                 break;
306         default:
307                 mapi_repl->u.mapi_GetContentsTable.RowCount = 0;
308         }
309
310         if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_Associated)) {
311                 DEBUG(5, ("  table is FAI table\n"));
312                 table_type = EMSMDBP_TABLE_FAI_TYPE;
313         }
314         else {
315                 DEBUG(5, ("  table is contents table\n"));
316                 table_type = EMSMDBP_TABLE_MESSAGE_TYPE;
317         }
318
319         /* Initialize Table object */
320         retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
321         handles[mapi_repl->handle_idx] = rec->handle;
322
323         object = emsmdbp_folder_open_table(rec, parent_object, table_type, rec->handle);
324         if (!object) {
325                 mapi_repl->error_code = MAPI_E_INVALID_OBJECT;
326                 goto end;
327         }
328         mapi_handles_set_private_data(rec, object);
329         mapi_repl->u.mapi_GetContentsTable.RowCount = object->object.table->denominator;
330
331         /* notifications */
332         if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_NoNotifications)) {
333                 DEBUG(5, ("  notifications skipped\n"));
334         }
335         else {
336                 /* we attach the subscription to the session object */
337                 subscription_list = talloc_zero(emsmdbp_ctx->mstore_ctx, struct mapistore_subscription_list);
338                 DLIST_ADD(emsmdbp_ctx->mstore_ctx->subscriptions, subscription_list);
339                 
340                 if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_Associated)) {
341                         subscription_parameters.table_type = MAPISTORE_FAI_TABLE;
342                 }
343                 else {
344                         subscription_parameters.table_type = MAPISTORE_MESSAGE_TABLE;
345                 }
346                 subscription_parameters.folder_id = folderID; 
347                 
348                 /* note that a mapistore_subscription can exist without a corresponding emsmdbp_object (tables) */
349                 subscription = mapistore_new_subscription(subscription_list, rec->handle, fnevTableModified, &subscription_parameters);
350                 subscription_list->subscription = subscription;
351                 object->object.table->subscription_list = subscription_list;
352         }
353
354 end:
355         
356         *size += libmapiserver_RopGetContentsTable_size(mapi_repl);
357
358         return MAPI_E_SUCCESS;
359 }
360
361 static enum MAPISTATUS EcDoRpc_RopCreateSystemSpecialFolder(struct emsmdbp_context *emsmdbp_ctx,
362                                                             struct SRow *aRow, 
363                                                             enum FOLDER_FLAGS folderFlags,
364                                                             uint64_t parentFolder,
365                                                             struct CreateFolder_repl *response)
366 {
367         TALLOC_CTX                      *mem_ctx;
368         enum MAPISTATUS                 retval;
369         struct ldb_message              *msg;
370         struct ldb_dn                   *basedn;
371         char                            *dn;
372         char                            *parentfid;
373         int                             ret = 0;
374         char                            *displayName;
375         char                            *comment;
376         uint32_t                        *folderType;
377
378         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateSystemSpecialFolder\n"));
379
380         displayName = (char *) find_SPropValue_data(aRow, PR_DISPLAY_NAME);
381         if (!displayName) {
382                 displayName = (char *) find_SPropValue_data(aRow, PR_DISPLAY_NAME_UNICODE);
383         }
384
385         DEBUG(0, ("[OXCFOLD] CreateSystemSpecialFolder: %s\n", displayName));
386
387         /* Step 0. Determine if the folder already exists */
388         if (openchangedb_get_fid_by_name(emsmdbp_ctx->oc_ctx, parentFolder,
389                                          displayName, &response->folder_id) == MAPI_E_SUCCESS) {
390                 /* this folder already exists */
391                 if ( folderFlags & OPEN_IF_EXISTS ) {
392                         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder Duplicate Folder\n"));
393                         response->IsExistingFolder = true;
394                         return MAPI_E_SUCCESS;
395                 } else {
396                         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder Duplicate Folder error\n"));
397                         return MAPI_E_COLLISION;
398                 }
399         }
400
401         mem_ctx = talloc_named(NULL, 0, "RopCreateSystemSpecialFolder");
402
403         /* Step 1. Retrieve the next available folderID */
404         retval = openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &response->folder_id);
405         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
406
407         /* Retrieve dn of parentfolder */
408         retval = openchangedb_get_distinguishedName(mem_ctx, emsmdbp_ctx->oc_ctx, parentFolder, &parentfid);
409         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
410
411         /* Step 2. Create the folder LDB record for openchange.ldb */
412         dn = talloc_asprintf(mem_ctx, "CN=%016"PRId64",%s", response->folder_id, parentfid);
413
414         /* Ensure dn is within user mailbox / prevent from creating
415          * folders in other mailboxes: check dn vs emsmdbp_ctx->username */
416
417         basedn = ldb_dn_new(mem_ctx, (struct ldb_context *)emsmdbp_ctx->oc_ctx, dn);
418         talloc_free(dn);
419         OPENCHANGE_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
420         
421         msg = ldb_msg_new(mem_ctx);
422         msg->dn = ldb_dn_copy(mem_ctx, basedn);
423         ldb_msg_add_string(msg, "objectClass", "systemfolder");
424         ldb_msg_add_fmt(msg, "cn", "%.16"PRId64, response->folder_id);
425         ldb_msg_add_string(msg, "PidTagContentUnreadCount", "0");
426         ldb_msg_add_string(msg, "PidTagContentCount", "0");
427         ldb_msg_add_string(msg, "PidTagContainerClass", "IPF.Note");
428         ldb_msg_add_string(msg, "PidTagAttrHidden", "0");
429         ldb_msg_add_string(msg, "PidTagAccess", "63");
430         ldb_msg_add_string(msg, "PidTagRights", "2043");
431         ldb_msg_add_string(msg, "PidTagDisplayName", displayName);
432
433         folderType = (uint32_t *) find_SPropValue_data(aRow, PR_FOLDER_TYPE);
434         ldb_msg_add_fmt(msg, "PidTagFolderType", "%d", *folderType);
435
436         comment = (char *) find_SPropValue_data(aRow, PR_COMMENT);
437         if (!comment) {
438                 comment = (char *) find_SPropValue_data(aRow, PR_COMMENT_UNICODE);
439         }
440         ldb_msg_add_string(msg, "PidTagComment", comment);
441
442         ldb_msg_add_fmt(msg, "PidTagParentFolderId", "%.16"PRId64, parentFolder);
443         ldb_msg_add_fmt(msg, "PidTagFolderId", "%.16"PRId64, response->folder_id);
444         ldb_msg_add_fmt(msg, "mapistore_uri", "sogo://%s:%s@fallback/0x%.16"PRIx64, 
445                         emsmdbp_ctx->username, emsmdbp_ctx->username, response->folder_id);
446         ldb_msg_add_string(msg, "PidTagSubFolders", "0");
447         ldb_msg_add_string(msg, "FolderType", "1");
448         ldb_msg_add_fmt(msg, "distinguishedName", "%s", ldb_dn_get_linearized(msg->dn));
449
450         msg->elements[0].flags = LDB_FLAG_MOD_ADD;
451
452         ret = ldb_add((struct ldb_context *)emsmdbp_ctx->oc_ctx, msg);
453         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
454
455         talloc_free(parentfid);
456         talloc_free(mem_ctx);
457
458         return MAPI_E_SUCCESS;
459 }
460
461
462
463 /**
464    \details EcDoRpc CreateFolder (0x1c) Rop. This operation creates a
465    folder on the remote server.
466
467    \param mem_ctx pointer to the memory context
468    \param emsmdbp_ctx pointer to the emsmdb provider context
469    \param mapi_req pointer to the CreateFolder EcDoRpc_MAPI_REQ
470    structure
471    \param mapi_repl pointer to the CreateFolder EcDoRpc_MAPI_REPL
472    structure
473    \param handles pointer to the MAPI handles array
474    \param size pointer to the mapi_response size to update
475
476    \return MAPI_E_SUCCESS on success, otherwise MAPI error
477
478    \note We do not provide support for GhostInfo
479  */
480 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopCreateFolder(TALLOC_CTX *mem_ctx,
481                                                  struct emsmdbp_context *emsmdbp_ctx,
482                                                  struct EcDoRpc_MAPI_REQ *mapi_req,
483                                                  struct EcDoRpc_MAPI_REPL *mapi_repl,
484                                                  uint32_t *handles, uint16_t *size)
485 {
486         enum MAPISTATUS                 retval;
487         struct mapi_handles             *parent = NULL;
488         uint32_t                        handle;
489         uint64_t                        parent_fid, fid;
490         struct emsmdbp_object           *parent_object = NULL;
491         struct emsmdbp_object           *object = NULL;
492         struct emsmbbp_object           *new_folder = NULL;
493         struct SRow                     *aRow = NULL;
494         void                            *data;
495         struct mapi_handles             *rec = NULL;
496         bool                            mapistore = false;
497
498         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder (0x1c)\n"));
499
500         /* Sanity checks */
501         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
502         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
503         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
504         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
505         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
506
507         /* Set up sensible values for the reply */
508         mapi_repl->opnum = mapi_req->opnum;
509         mapi_repl->error_code = MAPI_E_SUCCESS;
510         mapi_repl->handle_idx = mapi_req->u.mapi_CreateFolder.handle_idx;
511         mapi_repl->u.mapi_CreateFolder.IsExistingFolder = false;
512
513         /* Step 1. Retrieve parent handle in the hierarchy */
514         handle = handles[mapi_req->handle_idx];
515         retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent);
516         OPENCHANGE_RETVAL_IF(retval, retval, NULL);
517
518         /* With CreateFolder, the parent object really IS the parent object */
519         mapi_handles_get_private_data(parent, &data);
520         parent_object = (struct emsmdbp_object *)data;
521         if (!parent_object) {
522                 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder null object\n"));
523                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
524                 goto end;
525         }
526
527         if (parent_object->type != EMSMDBP_OBJECT_FOLDER && parent_object->type != EMSMDBP_OBJECT_MAILBOX) {
528                 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder wrong object type: 0x%x\n", parent_object->type));
529                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
530                 goto end;
531         }
532         parent_fid = parent_object->object.folder->folderID;
533         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder parent: 0x%.16"PRIx64"\n", parent_fid));
534         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] Creating %s\n", mapi_req->u.mapi_CreateFolder.FolderName.lpszA));
535
536         /* Step 3. Turn CreateFolder parameters into MAPI property array */
537         aRow = libmapiserver_ROP_request_to_properties(mem_ctx, (void *)&mapi_req->u.mapi_CreateFolder, op_MAPI_CreateFolder);
538         aRow->lpProps = add_SPropValue(mem_ctx, aRow->lpProps, &(aRow->cValues), PR_PARENT_FID, (void *)(&parent_fid));
539
540         /* Step 4. Do effective work here */
541         mapistore = emsmdbp_is_mapistore(parent_object);
542         switch (mapistore) {
543         case false:
544                 switch (mapi_req->u.mapi_CreateFolder.ulFolderType) {
545                 case FOLDER_GENERIC:
546                         mapi_repl->error_code = EcDoRpc_RopCreateSystemSpecialFolder(emsmdbp_ctx, aRow, 
547                                                                                      mapi_req->u.mapi_CreateFolder.ulFlags,
548                                                                                      parent_fid, &mapi_repl->u.mapi_CreateFolder);
549                         break;
550                 case FOLDER_SEARCH:
551                         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] FOLDER_SEARCH not implemented\n"));
552                         mapi_repl->error_code = MAPI_E_NO_SUPPORT;
553                         break;
554                 default:
555                         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] Unexpected folder type 0x%x\n", mapi_req->u.mapi_CreateFolder.ulType));
556                         mapi_repl->error_code = MAPI_E_NO_SUPPORT;
557                 }
558                 break;
559         case true:
560                 retval = openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &fid);
561                 if (retval != MAPI_E_SUCCESS) {
562                         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] Could not obtain a new folder id\n"));
563                         mapi_repl->error_code = MAPI_E_NO_SUPPORT;
564                         goto end;
565                 }
566                 retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
567                 retval = emsmdbp_object_create_folder(emsmdbp_ctx, 
568                                                       parent_object, rec, fid, aRow, &object);
569                 if (retval == MAPISTORE_ERR_EXIST) {
570                         /* folder with this name already exists */
571                         DEBUG(4, ("emsmdbp_object: CreateFolder Duplicate Folder error\n"));
572                         talloc_free(new_folder);
573                         return MAPI_E_COLLISION;
574                 }
575                 OPENCHANGE_RETVAL_IF(retval, MAPI_E_CALL_FAILED, new_folder);
576                 break;
577
578                 /* mapi_repl->error_code = EcDoRpc_RopCreateGenericFolder(emsmdbp_ctx, parent, aRow, */
579                 /*                                                     mapi_req->u.mapi_CreateFolder.ulFlags, */
580                 /*                                                     &mapi_repl->u.mapi_CreateFolder); */
581                 break;
582         }
583
584         mapi_repl->handle_idx = mapi_req->u.mapi_CreateFolder.handle_idx;
585
586         if (mapi_repl->u.mapi_CreateFolder.IsExistingFolder == true) {
587                 mapi_repl->u.mapi_CreateFolder.GhostUnion.GhostInfo.HasRules = false;
588                 mapi_repl->u.mapi_CreateFolder.GhostUnion.GhostInfo.IsGhosted = false;
589         }
590
591         if (!mapi_repl->error_code) {
592                 retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
593                 object = emsmdbp_object_folder_init((TALLOC_CTX *)rec, emsmdbp_ctx,
594                                                     mapi_repl->u.mapi_CreateFolder.folder_id, parent_object);
595                 if (object) {
596                         retval = mapi_handles_set_private_data(rec, object);
597                 }
598
599                 handles[mapi_repl->handle_idx] = rec->handle;
600         }
601 end:
602         *size += libmapiserver_RopCreateFolder_size(mapi_repl);
603
604         if (aRow) {
605                 talloc_free(aRow);
606         }
607
608         return MAPI_E_SUCCESS;
609
610         /* if (mapi_req->u.mapi_CreateFolder.ulFolderType != FOLDER_GENERIC) { */
611         /*      DEBUG(4, ("exchange_emsmdb: [OXCFOLD] Unexpected folder type 0x%x\n", mapi_req->u.mapi_CreateFolder.ulType)); */
612         /*      mapi_repl->error_code = MAPI_E_NO_SUPPORT; */
613         /*      goto end; */
614         /* } */
615
616         /* retval = openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &fid); */
617         /* if (retval != MAPI_E_SUCCESS) { */
618         /*      DEBUG(4, ("exchange_emsmdb: [OXCFOLD] Could not obtain a new folder id\n")); */
619         /*      mapi_repl->error_code = MAPI_E_NO_SUPPORT; */
620         /*      goto end; */
621         /* } */
622         
623         /* Step 3. Turn CreateFolder parameters into MAPI property array */
624 /*      aRow = libmapiserver_ROP_request_to_properties(mem_ctx, (void *)&mapi_req->u.mapi_CreateFolder, op_MAPI_CreateFolder); */
625 /*      aRow->lpProps = add_SPropValue(mem_ctx, aRow->lpProps, &(aRow->cValues), PR_PARENT_FID, (void *)(&parent_fid)); */
626
627 /*      /\* Step 4. Do effective work here *\/ */
628 /*      mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec); */
629 /*      retval = emsmdbp_object_create_folder(emsmdbp_ctx, parent_object, rec, fid, aRow, &object); */
630 /*      if (retval != MAPI_E_SUCCESS) { */
631 /*              mapi_handles_delete(emsmdbp_ctx->handles_ctx, rec->handle); */
632 /*              mapi_repl->error_code = retval; */
633 /*              goto end; */
634 /*      } */
635 /*      handles[mapi_repl->handle_idx] = rec->handle; */
636 /*      mapi_handles_set_private_data(rec, object); */
637
638 /*      mapi_repl->u.mapi_CreateFolder.folder_id = fid; */
639
640 /*      if (mapi_repl->u.mapi_CreateFolder.IsExistingFolder == true) { */
641 /*              mapi_repl->u.mapi_CreateFolder.GhostUnion.GhostInfo.HasRules = false; */
642 /*              mapi_repl->u.mapi_CreateFolder.GhostUnion.GhostInfo.IsGhosted = false; */
643 /*      } */
644
645 /* end: */
646 /*      *size += libmapiserver_RopCreateFolder_size(mapi_repl); */
647
648 /*      if (aRow) { */
649 /*              talloc_free(aRow); */
650 /*      } */
651
652         /* return MAPI_E_SUCCESS; */
653 }
654
655 static enum MAPISTATUS DoDeleteSystemFolder(struct emsmdbp_context *emsmdbp_ctx,
656                                             uint64_t parent_fid, uint64_t fid,
657                                             uint8_t flags)
658 {
659         TALLOC_CTX                      *mem_ctx;
660         char                            *parentdn;
661         enum MAPISTATUS                 retval;
662         struct ldb_dn                   *dn;
663         char                            *dn_str;
664         int                             ret = 0;
665
666         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] DeleteFolder parent FID: 0x%"PRIx64"\n", parent_fid));
667         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] DeleteFolder target FID: 0x%"PRIx64"\n", fid));
668
669         mem_ctx = talloc_named(NULL, 0, "DoDeleteFolder");
670
671         /* TODO:
672                 1. We should be careful not to delete special folders
673                 2. We need to handle deleting associated folders and messages (based on the flags)
674         */
675         /* Retrieve dn of parentfolder */
676         retval = openchangedb_get_distinguishedName(mem_ctx, emsmdbp_ctx->oc_ctx, parent_fid, &parentdn);
677         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
678
679         /* Create the folder dn record for openchange.ldb */
680         dn_str = talloc_asprintf(mem_ctx, "CN=%"PRId64",%s", fid, parentdn);
681         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] DeleteFolder target DN: %s\n", dn_str));
682         dn = ldb_dn_new(mem_ctx, emsmdbp_ctx->oc_ctx, dn_str);
683         talloc_free(dn_str);
684         OPENCHANGE_RETVAL_IF(!ldb_dn_validate(dn), MAPI_E_BAD_VALUE, mem_ctx);
685
686         ret = ldb_delete(emsmdbp_ctx->oc_ctx, dn);
687         if (ret != LDB_SUCCESS) {
688                 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] DeleteFolder failed ldb_delete, ret: 0x%x\n", ret));
689                 talloc_free(mem_ctx);
690                 return MAPI_E_NO_SUPPORT;
691         }
692
693         talloc_free(mem_ctx);
694         return MAPI_E_SUCCESS;
695 }
696
697
698 /**
699    \details EcDoRpc DeleteFolder (0x1d) Rop. This operation deletes a
700    folder on the remote server.
701
702    \param mem_ctx pointer to the memory context
703    \param emsmdbp_ctx pointer to the emsmdb provider context
704    \param mapi_req pointer to the DeleteFolder EcDoRpc_MAPI_REQ
705    structure
706    \param mapi_repl pointer to the DeleteFolder EcDoRpc_MAPI_REPL
707    structure
708    \param handles pointer to the MAPI handles array
709    \param size pointer to the mapi_response size to update
710    \return MAPI_E_SUCCESS on success, otherwise MAPI error
711  */
712 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopDeleteFolder(TALLOC_CTX *mem_ctx,
713                                                  struct emsmdbp_context *emsmdbp_ctx,
714                                                  struct EcDoRpc_MAPI_REQ *mapi_req,
715                                                  struct EcDoRpc_MAPI_REPL *mapi_repl,
716                                                  uint32_t *handles, uint16_t *size)
717 {
718         enum MAPISTATUS         retval;
719         struct mapi_handles     *rec = NULL;
720         uint32_t                handle;
721         void                    *handle_priv_data;
722         struct emsmdbp_object   *handle_object = NULL;
723         uint64_t                parent_fid = 0;
724         bool                    mapistore = false;
725         uint32_t                context_id;
726
727         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] DeleteFolder (0x1d)\n"));
728
729         /* Sanity checks */
730         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
731         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
732         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
733         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
734         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
735
736         /* Initialize default empty DeleteFolder reply */
737         mapi_repl->opnum = mapi_req->opnum;
738         mapi_repl->error_code = MAPI_E_SUCCESS;
739         mapi_repl->handle_idx = mapi_req->handle_idx;
740
741         /* TODO: factor this out to be convenience API */
742         /* Convert the handle index into a handle, and then get the folder id */
743         handle = handles[mapi_req->handle_idx];
744         retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &rec);
745         OPENCHANGE_RETVAL_IF(retval, retval, NULL);
746
747         mapi_handles_get_private_data(rec, &handle_priv_data);
748         handle_object = (struct emsmdbp_object *)handle_priv_data;
749         if (!handle_object) {
750                 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] DeleteFolder null object\n"));
751                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
752                 return MAPI_E_SUCCESS;
753         }
754
755         if (handle_object->type != EMSMDBP_OBJECT_FOLDER) {
756                 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] DeleteFolder wrong object type: 0x%x\n", handle_object->type));
757                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
758                 return MAPI_E_SUCCESS;
759         }
760
761         mapistore = emsmdbp_is_mapistore(handle_object);
762         switch (mapistore) {
763         case false:
764                 /* system/special folder */
765                 DEBUG(0, ("Deleting system/special folder\n"));
766                 parent_fid = handle_object->object.folder->folderID;
767                 mapi_repl->error_code = DoDeleteSystemFolder(emsmdbp_ctx, parent_fid,
768                                                              mapi_req->u.mapi_DeleteFolder.FolderId,
769                                                              mapi_req->u.mapi_DeleteFolder.DeleteFolderFlags);
770
771                 break;
772         case true:
773                 DEBUG(0, ("Deleting mapistore folder\n"));
774                 /* handled by mapistore */
775                 context_id = emsmdbp_get_contextID(handle_object);
776                 retval = mapistore_folder_delete_folder(emsmdbp_ctx->mstore_ctx, context_id, handle_object->backend_object,
777                                                         mapi_req->u.mapi_DeleteFolder.FolderId,
778                                                         mapi_req->u.mapi_DeleteFolder.DeleteFolderFlags);
779                 if (retval) {
780                           DEBUG(4, ("exchange_emsmdb: [OXCFOLD] DeleteFolder failed to delete fid 0x%.16"PRIx64" (0x%x)",
781                                     mapi_req->u.mapi_DeleteFolder.FolderId, retval));
782                           mapi_repl->error_code = MAPI_E_NOT_FOUND;
783                 } else {
784                         mapi_repl->error_code = MAPI_E_SUCCESS;
785                 }
786                 break;
787         }
788
789         *size += libmapiserver_RopDeleteFolder_size(mapi_repl);
790
791         return retval;
792 }
793
794
795 /**
796    \details EcDoRpc DeleteMessage (0x1e) Rop. This operation (soft) deletes
797    a message on the server.
798
799    \param mem_ctx pointer to the memory context
800    \param emsmdbp_ctx pointer to the emsmdb provider context
801    \param mapi_req pointer to the DeleteMessage EcDoRpc_MAPI_REQ
802    structure
803    \param mapi_repl pointer to the DeleteMessage EcDoRpc_MAPI_REPL
804    structure
805    \param handles pointer to the MAPI handles array
806    \param size pointer to the mapi_response size to update
807
808    \return MAPI_E_SUCCESS on success, otherwise MAPI error
809  */
810 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopDeleteMessages(TALLOC_CTX *mem_ctx,
811                                                    struct emsmdbp_context *emsmdbp_ctx,
812                                                    struct EcDoRpc_MAPI_REQ *mapi_req,
813                                                    struct EcDoRpc_MAPI_REPL *mapi_repl,
814                                                    uint32_t *handles, uint16_t *size)
815 {
816         uint32_t                parent_folder_handle;
817         struct mapi_handles     *parent_folder = NULL;
818         void                    *parent_folder_private_data;
819         struct emsmdbp_object   *parent_object;
820         enum MAPISTATUS         retval;
821         uint32_t                contextID;
822         int                     i;
823
824         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] DeleteMessage (0x1e)\n"));
825
826         /* Sanity checks */
827         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
828         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
829         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
830         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
831         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
832
833         mapi_repl->opnum = mapi_req->opnum;
834         mapi_repl->error_code = MAPI_E_SUCCESS;
835         mapi_repl->u.mapi_DeleteMessages.PartialCompletion = false;
836
837         parent_folder_handle = handles[mapi_req->handle_idx];
838         retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, parent_folder_handle, &parent_folder);
839         if (retval != MAPI_E_SUCCESS) {
840                 mapi_repl->error_code = MAPI_E_NOT_FOUND;
841                 goto delete_message_response;
842         }
843
844         retval = mapi_handles_get_private_data(parent_folder, &parent_folder_private_data);
845         parent_object = (struct emsmdbp_object *)parent_folder_private_data;
846         if (!parent_object || parent_object->type != EMSMDBP_OBJECT_FOLDER) {
847                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
848                 goto delete_message_response;
849         }
850
851         if (!emsmdbp_is_mapistore(parent_object) ) {
852                 DEBUG(0, ("Got parent folder not in mapistore\n"));
853                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
854                 goto delete_message_response;
855         }
856
857         contextID = emsmdbp_get_contextID(parent_object);
858
859         for (i = 0; i < mapi_req->u.mapi_DeleteMessages.cn_ids; ++i) {
860                 int ret;
861                 uint64_t mid = mapi_req->u.mapi_DeleteMessages.message_ids[i];
862                 DEBUG(0, ("MID %i to delete: 0x%.16"PRIx64"\n", i, mid));
863                 ret = mapistore_folder_delete_message(emsmdbp_ctx->mstore_ctx, contextID, parent_object->backend_object, mid, MAPISTORE_SOFT_DELETE);
864                 if (ret != MAPISTORE_SUCCESS) {
865                         mapi_repl->error_code = MAPI_E_CALL_FAILED;
866                         goto delete_message_response;
867                 }
868                 ret = mapistore_indexing_record_del_mid(emsmdbp_ctx->mstore_ctx, contextID, mid, MAPISTORE_SOFT_DELETE);
869                 if (ret != MAPISTORE_SUCCESS) {
870                         mapi_repl->error_code = MAPI_E_CALL_FAILED;
871                         goto delete_message_response;
872                 }
873         }
874
875 delete_message_response:
876         *size += libmapiserver_RopDeleteMessage_size(mapi_repl);
877
878         return MAPI_E_SUCCESS;
879 }
880
881
882 /**
883    \details EcDoRpc SetSearchCriteria (0x30) Rop. This operation sets
884    the search criteria for a search folder.
885
886    \param mem_ctx pointer to the memory context
887    \param emsmdbp_ctx pointer to the emsmdb provider context
888    \param mapi_req pointer to the SetSearchCriteria EcDoRpc_MAPI_REQ
889    structure
890    \param mapi_repl pointer to the SetSearchCriteria EcDoRpc_MAPI_REPL
891    structure
892    \param handles pointer to the MAPI handles array
893    \param size pointer to the mapi_response size to update
894
895    \return MAPI_E_SUCCESS on success, otherwise MAPI error  
896  */
897 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopSetSearchCriteria(TALLOC_CTX *mem_ctx,
898                                                       struct emsmdbp_context *emsmdbp_ctx,
899                                                       struct EcDoRpc_MAPI_REQ *mapi_req,
900                                                       struct EcDoRpc_MAPI_REPL *mapi_repl,
901                                                       uint32_t *handles, uint16_t *size)
902 {
903         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] SetSearchCriteria (0x30)\n"));
904
905         /* Sanity checks */
906         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
907         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
908         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
909         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
910         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
911
912         mapi_repl->opnum = mapi_req->opnum;
913         mapi_repl->handle_idx = mapi_req->handle_idx;
914         mapi_repl->error_code = MAPI_E_SUCCESS;
915
916         /* TODO: actually implement this */
917
918         *size += libmapiserver_RopSetSearchCriteria_size(mapi_repl);
919
920         return MAPI_E_SUCCESS;
921 }
922
923
924 /**
925    \details EcDoRpc GetSearchCriteria (0x31) Rop. This operation gets
926    the search criteria for a search folder.
927
928    \param mem_ctx pointer to the memory context
929    \param emsmdbp_ctx pointer to the emsmdb provider context
930    \param mapi_req pointer to the GetSearchCriteria EcDoRpc_MAPI_REQ
931    structure
932    \param mapi_repl pointer to the GetSearchCriteria EcDoRpc_MAPI_REPL
933    structure
934    \param handles pointer to the MAPI handles array
935    \param size pointer to the mapi_response size to update
936
937    \return MAPI_E_SUCCESS on success, otherwise MAPI error  
938  */
939 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetSearchCriteria(TALLOC_CTX *mem_ctx,
940                                                       struct emsmdbp_context *emsmdbp_ctx,
941                                                       struct EcDoRpc_MAPI_REQ *mapi_req,
942                                                       struct EcDoRpc_MAPI_REPL *mapi_repl,
943                                                       uint32_t *handles, uint16_t *size)
944 {
945         /* struct mapi_SRestriction *res; */
946
947         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] GetSearchCriteria (0x31)\n"));
948
949         /* Sanity checks */
950         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
951         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
952         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
953         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
954         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
955
956         mapi_repl->opnum = mapi_req->opnum;
957         mapi_repl->handle_idx = mapi_req->handle_idx;
958         mapi_repl->error_code = MAPI_E_SUCCESS;
959
960         /* res = NULL; */
961         mapi_repl->u.mapi_GetSearchCriteria.RestrictionDataSize = 0;
962         mapi_repl->u.mapi_GetSearchCriteria.LogonId = mapi_req->logon_id;
963         mapi_repl->u.mapi_GetSearchCriteria.FolderIdCount = 0;
964         mapi_repl->u.mapi_GetSearchCriteria.FolderIds = NULL;
965         mapi_repl->u.mapi_GetSearchCriteria.SearchFlags = 0;
966
967         /* TODO: actually implement this */
968
969         *size += libmapiserver_RopGetSearchCriteria_size(mapi_repl);
970
971         return MAPI_E_SUCCESS;
972 }
973
974 static enum MAPISTATUS RopEmptyFolder_GenericFolder(TALLOC_CTX *mem_ctx,
975                                                     struct emsmdbp_context *emsmdbp_ctx,
976                                                     struct EmptyFolder_req request,
977                                                     struct EmptyFolder_repl *response,
978                                                     struct mapi_handles *folder)
979 {
980         void                    *folder_priv;
981         struct emsmdbp_object   *folder_object = NULL;
982         uint32_t                context_id;
983         int                     retval;
984         uint64_t                *childFolders;
985         uint32_t                childFolderCount;
986         uint32_t                i;
987         uint8_t                 flags = DELETE_HARD_DELETE| DEL_MESSAGES | DEL_FOLDERS;
988         TALLOC_CTX              *local_mem_ctx;
989
990         /* Step 1. Retrieve the fid for the folder, given the handle */
991         mapi_handles_get_private_data(folder, &folder_priv);
992         folder_object = (struct emsmdbp_object *) folder_priv;
993         if (!folder_object) {
994                 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] EmptyFolder null object"));
995                 return MAPI_E_NO_SUPPORT;
996         }
997
998         if (folder_object->type != EMSMDBP_OBJECT_FOLDER) {
999                 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] EmptyFolder wrong object type: 0x%x\n", folder_object->type));
1000                 return MAPI_E_NO_SUPPORT;
1001         }
1002         context_id = emsmdbp_get_contextID(folder_object);
1003
1004         local_mem_ctx = talloc_zero(NULL, TALLOC_CTX);
1005
1006         retval = mapistore_folder_get_child_fids(emsmdbp_ctx->mstore_ctx, context_id, folder_object, local_mem_ctx,
1007                                                  &childFolders, &childFolderCount);
1008         if (retval) {
1009                 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] EmptyFolder bad retval: 0x%x", retval));
1010                 return MAPI_E_NOT_FOUND;
1011         }
1012
1013         /* Step 3. Delete contents of the folder in mapistore */
1014         for (i = 0; i < childFolderCount; ++i) {
1015                 retval = mapistore_folder_delete_folder(emsmdbp_ctx->mstore_ctx, context_id, folder_object, childFolders[i],
1016                                                         flags);
1017                 if (retval) {
1018                           DEBUG(4, ("exchange_emsmdb: [OXCFOLD] EmptyFolder failed to delete fid 0x%.16"PRIx64" (0x%x)", childFolders[i], retval));
1019                           talloc_free(local_mem_ctx);
1020                           return MAPI_E_NOT_FOUND;
1021                 }
1022         }
1023         talloc_free(local_mem_ctx);
1024
1025         return MAPI_E_SUCCESS;
1026 }
1027
1028 /**
1029    \details EcDoRpc EmptyFolder (0x58) Rop. This operation removes the sub-folders
1030    and messages from a given parent folder.
1031
1032    \param mem_ctx pointer to the memory context
1033    \param emsmdbp_ctx pointer to the emsmdb provider context
1034    \param mapi_req pointer to the EmptyFolder EcDoRpc_MAPI_REQ
1035    structure
1036    \param mapi_repl pointer to the EmptyFolder EcDoRpc_MAPI_REPL
1037    structure
1038    \param handles pointer to the MAPI handles array
1039    \param size pointer to the mapi_response size to update
1040
1041    \return MAPI_E_SUCCESS on success, otherwise MAPI error
1042  */
1043 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopEmptyFolder(TALLOC_CTX *mem_ctx,
1044                                                 struct emsmdbp_context *emsmdbp_ctx,
1045                                                 struct EcDoRpc_MAPI_REQ *mapi_req,
1046                                                 struct EcDoRpc_MAPI_REPL *mapi_repl,
1047                                                 uint32_t *handles, uint16_t *size)
1048 {
1049         enum MAPISTATUS                 retval;
1050         struct mapi_handles             *folder = NULL;
1051         struct emsmdbp_object           *folder_object;
1052         void                            *private_data;
1053         bool                            mapistore = false;
1054
1055         DEBUG(4, ("exchange_emsmdb: [OXCFOLD] EmptyFolder (0x58)\n"));
1056
1057         /* Sanity checks */
1058         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1059         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
1060         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
1061         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
1062         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
1063
1064         mapi_repl->opnum = mapi_req->opnum;
1065         mapi_repl->handle_idx = mapi_req->handle_idx;
1066         mapi_repl->u.mapi_EmptyFolder.PartialCompletion = 0;
1067
1068         /* Step 1. Retrieve folder handle */
1069         retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handles[mapi_req->handle_idx], &folder);
1070         OPENCHANGE_RETVAL_IF(retval, retval, NULL);
1071         mapi_handles_get_private_data(folder, &private_data);
1072         folder_object = private_data;
1073
1074         mapistore = emsmdbp_is_mapistore(folder_object);
1075         switch (mapistore) {
1076         case false:
1077                 /* system/special folder */
1078                 DEBUG(0, ("TODO Empty system/special folder\n"));
1079 #if 0
1080                 retval = RopEmptyFolder_SystemSpecialFolder(mem_ctx, emsmdbp_ctx,
1081                                                            mapi_req->u.mapi_EmptyFolder,
1082                                                            &mapi_repl->u.mapi_EmptyFolder);
1083 #endif
1084                 retval = MAPI_E_SUCCESS; // TODO: temporary hack.
1085                 mapi_repl->error_code = retval;
1086                 break;
1087         case true:
1088                 /* handled by mapistore */
1089                 retval = RopEmptyFolder_GenericFolder(mem_ctx, emsmdbp_ctx,
1090                                                       mapi_req->u.mapi_EmptyFolder,
1091                                                       &mapi_repl->u.mapi_EmptyFolder,
1092                                                       folder);
1093                 mapi_repl->error_code = retval;
1094                 break;
1095         }
1096
1097         *size += libmapiserver_RopEmptyFolder_size(mapi_repl);
1098
1099         /* reply filled in above */
1100
1101         return MAPI_E_SUCCESS;
1102 }