2 OpenChange Server implementation
4 EMSMDBP: EMSMDB Provider implementation
6 Copyright (C) Julien Kerihuel 2009-2010
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.
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.
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/>.
25 \brief Folder object routines and Rops
28 #include "mapiproxy/dcesrv_mapiproxy.h"
29 #include "mapiproxy/libmapiproxy/libmapiproxy.h"
30 #include "mapiproxy/libmapiserver/libmapiserver.h"
31 #include "dcesrv_exchange_emsmdb.h"
35 \details EcDoRpc OpenFolder (0x02) Rop. This operation opens an
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
42 \param mapi_repl pointer to the OpenFolder EcDoRpc_MAPI_REPL
44 \param handles pointer to the MAPI handles array
45 \param size pointer to the mapi_response size to update
47 \return MAPI_E_SUCCESS on success, otherwise MAPI error
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)
55 enum MAPISTATUS retval;
56 struct mapi_handles *parent = NULL;
57 struct mapi_handles *rec = NULL;
59 struct emsmdbp_object *object, *parent_object;
61 struct OpenFolder_req *request;
62 struct OpenFolder_repl *response;
64 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] OpenFolder (0x02)\n"));
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);
73 request = &mapi_req->u.mapi_OpenFolder;
74 response = &mapi_repl->u.mapi_OpenFolder;
76 mapi_repl->opnum = mapi_req->opnum;
77 mapi_repl->error_code = MAPI_E_SUCCESS;
78 mapi_repl->handle_idx = request->handle_idx;
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);
84 DEBUG(5, (" handle (%x) not found: %x\n", handle, mapi_req->handle_idx));
85 mapi_repl->error_code = MAPI_E_INVALID_OBJECT;
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;
98 /* Fill EcDoRpc_MAPI_REPL reply */
99 response->HasRules = 0;
100 response->IsGhosted = 0;
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);
105 mapi_repl->error_code = MAPI_E_NOT_FOUND;
108 retval = mapi_handles_set_private_data(rec, object);
109 handles[mapi_repl->handle_idx] = rec->handle;
112 *size += libmapiserver_RopOpenFolder_size(mapi_repl);
114 return MAPI_E_SUCCESS;
119 \details EcDoRpc GetHierarchyTable (0x04) Rop. This operation gets
120 the subfolder hierarchy table for a folder.
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
126 \param mapi_repl pointer to the GetHierarchyTable EcDoRpc_MAPI_REPL
128 \param handles pointer to the MAPI handles array
129 \param size pointer to the mapi_response size to update
131 \return MAPI_E_SUCCESS on success, otherwise MAPI error
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)
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;
150 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] GetHierarchyTable (0x04)\n"));
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);
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;
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);
168 DEBUG(5, (" handle (%x) not found: %x\n", handle, mapi_req->handle_idx));
169 mapi_repl->error_code = MAPI_E_INVALID_OBJECT;
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;
181 switch (parent_object->type) {
182 case EMSMDBP_OBJECT_MAILBOX:
183 folderID = parent_object->object.mailbox->folderID;
185 case EMSMDBP_OBJECT_FOLDER:
186 folderID = parent_object->object.folder->folderID;
189 DEBUG(5, (" unsupported object type\n"));
190 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
194 /* Initialize Table object */
195 retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
196 handles[mapi_repl->handle_idx] = rec->handle;
198 object = emsmdbp_folder_open_table(rec, parent_object, EMSMDBP_TABLE_FOLDER_TYPE, rec->handle);
200 mapi_repl->error_code = MAPI_E_INVALID_OBJECT;
203 mapi_handles_set_private_data(rec, object);
204 mapi_repl->u.mapi_GetHierarchyTable.RowCount = object->object.table->denominator;
207 if ((mapi_req->u.mapi_GetHierarchyTable.TableFlags & TableFlags_NoNotifications)) {
208 DEBUG(5, (" notifications skipped\n"));
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);
215 subscription_parameters.table_type = MAPISTORE_FOLDER_TABLE;
216 subscription_parameters.folder_id = folderID;
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;
225 *size += libmapiserver_RopGetHierarchyTable_size(mapi_repl);
227 return MAPI_E_SUCCESS;
232 \details EcDoRpc GetContentsTable (0x05) Rop. This operation get
233 the content table of a container.
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
239 \param mapi_repl pointer to the GetContentsTable EcDoRpc_MAPI_REPL
241 \param handles pointer to the MAPI handles array
242 \param size pointer to the mapi_response size to update
244 \return MAPI_E_SUCCESS on success, otherwise MAPI error
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)
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;
264 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] GetContentsTable (0x05)\n"));
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);
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;
279 handle = handles[mapi_req->handle_idx];
280 retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent);
282 DEBUG(5, (" handle (%x) not found: %x\n", handle, mapi_req->handle_idx));
283 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
287 /* GetContentsTable can only be called for folder objects */
288 retval = mapi_handles_get_private_data(parent, &data);
290 mapi_repl->error_code = retval;
291 DEBUG(5, (" handle data not found, idx = %x\n", mapi_req->handle_idx));
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));
302 switch (parent_object->type) {
303 case EMSMDBP_OBJECT_FOLDER:
304 folderID = parent_object->object.folder->folderID;
307 mapi_repl->u.mapi_GetContentsTable.RowCount = 0;
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;
315 DEBUG(5, (" table is contents table\n"));
316 table_type = EMSMDBP_TABLE_MESSAGE_TYPE;
319 /* Initialize Table object */
320 retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
321 handles[mapi_repl->handle_idx] = rec->handle;
323 object = emsmdbp_folder_open_table(rec, parent_object, table_type, rec->handle);
325 mapi_repl->error_code = MAPI_E_INVALID_OBJECT;
328 mapi_handles_set_private_data(rec, object);
329 mapi_repl->u.mapi_GetContentsTable.RowCount = object->object.table->denominator;
332 if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_NoNotifications)) {
333 DEBUG(5, (" notifications skipped\n"));
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);
340 if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_Associated)) {
341 subscription_parameters.table_type = MAPISTORE_FAI_TABLE;
344 subscription_parameters.table_type = MAPISTORE_MESSAGE_TABLE;
346 subscription_parameters.folder_id = folderID;
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;
356 *size += libmapiserver_RopGetContentsTable_size(mapi_repl);
358 return MAPI_E_SUCCESS;
361 static enum MAPISTATUS EcDoRpc_RopCreateSystemSpecialFolder(struct emsmdbp_context *emsmdbp_ctx,
363 enum FOLDER_FLAGS folderFlags,
364 uint64_t parentFolder,
365 struct CreateFolder_repl *response)
368 enum MAPISTATUS retval;
369 struct ldb_message *msg;
370 struct ldb_dn *basedn;
376 uint32_t *folderType;
378 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateSystemSpecialFolder\n"));
380 displayName = (char *) find_SPropValue_data(aRow, PR_DISPLAY_NAME);
382 displayName = (char *) find_SPropValue_data(aRow, PR_DISPLAY_NAME_UNICODE);
385 DEBUG(0, ("[OXCFOLD] CreateSystemSpecialFolder: %s\n", displayName));
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;
396 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder Duplicate Folder error\n"));
397 return MAPI_E_COLLISION;
401 mem_ctx = talloc_named(NULL, 0, "RopCreateSystemSpecialFolder");
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);
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);
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);
414 /* Ensure dn is within user mailbox / prevent from creating
415 * folders in other mailboxes: check dn vs emsmdbp_ctx->username */
417 basedn = ldb_dn_new(mem_ctx, (struct ldb_context *)emsmdbp_ctx->oc_ctx, dn);
419 OPENCHANGE_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
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);
433 folderType = (uint32_t *) find_SPropValue_data(aRow, PR_FOLDER_TYPE);
434 ldb_msg_add_fmt(msg, "PidTagFolderType", "%d", *folderType);
436 comment = (char *) find_SPropValue_data(aRow, PR_COMMENT);
438 comment = (char *) find_SPropValue_data(aRow, PR_COMMENT_UNICODE);
440 ldb_msg_add_string(msg, "PidTagComment", comment);
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));
450 msg->elements[0].flags = LDB_FLAG_MOD_ADD;
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);
455 talloc_free(parentfid);
456 talloc_free(mem_ctx);
458 return MAPI_E_SUCCESS;
464 \details EcDoRpc CreateFolder (0x1c) Rop. This operation creates a
465 folder on the remote server.
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
471 \param mapi_repl pointer to the CreateFolder EcDoRpc_MAPI_REPL
473 \param handles pointer to the MAPI handles array
474 \param size pointer to the mapi_response size to update
476 \return MAPI_E_SUCCESS on success, otherwise MAPI error
478 \note We do not provide support for GhostInfo
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)
486 enum MAPISTATUS retval;
487 struct mapi_handles *parent = NULL;
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;
495 struct mapi_handles *rec = NULL;
496 bool mapistore = false;
498 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder (0x1c)\n"));
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);
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;
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);
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;
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;
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));
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));
540 /* Step 4. Do effective work here */
541 mapistore = emsmdbp_is_mapistore(parent_object);
544 switch (mapi_req->u.mapi_CreateFolder.ulFolderType) {
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);
551 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] FOLDER_SEARCH not implemented\n"));
552 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
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;
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;
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;
575 OPENCHANGE_RETVAL_IF(retval, MAPI_E_CALL_FAILED, new_folder);
578 /* mapi_repl->error_code = EcDoRpc_RopCreateGenericFolder(emsmdbp_ctx, parent, aRow, */
579 /* mapi_req->u.mapi_CreateFolder.ulFlags, */
580 /* &mapi_repl->u.mapi_CreateFolder); */
584 mapi_repl->handle_idx = mapi_req->u.mapi_CreateFolder.handle_idx;
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;
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);
596 retval = mapi_handles_set_private_data(rec, object);
599 handles[mapi_repl->handle_idx] = rec->handle;
602 *size += libmapiserver_RopCreateFolder_size(mapi_repl);
608 return MAPI_E_SUCCESS;
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; */
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; */
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)); */
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; */
635 /* handles[mapi_repl->handle_idx] = rec->handle; */
636 /* mapi_handles_set_private_data(rec, object); */
638 /* mapi_repl->u.mapi_CreateFolder.folder_id = fid; */
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; */
646 /* *size += libmapiserver_RopCreateFolder_size(mapi_repl); */
649 /* talloc_free(aRow); */
652 /* return MAPI_E_SUCCESS; */
655 static enum MAPISTATUS DoDeleteSystemFolder(struct emsmdbp_context *emsmdbp_ctx,
656 uint64_t parent_fid, uint64_t fid,
661 enum MAPISTATUS retval;
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));
669 mem_ctx = talloc_named(NULL, 0, "DoDeleteFolder");
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)
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);
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);
684 OPENCHANGE_RETVAL_IF(!ldb_dn_validate(dn), MAPI_E_BAD_VALUE, mem_ctx);
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;
693 talloc_free(mem_ctx);
694 return MAPI_E_SUCCESS;
699 \details EcDoRpc DeleteFolder (0x1d) Rop. This operation deletes a
700 folder on the remote server.
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
706 \param mapi_repl pointer to the DeleteFolder EcDoRpc_MAPI_REPL
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
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)
718 enum MAPISTATUS retval;
719 struct mapi_handles *rec = NULL;
721 void *handle_priv_data;
722 struct emsmdbp_object *handle_object = NULL;
723 uint64_t parent_fid = 0;
724 bool mapistore = false;
727 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] DeleteFolder (0x1d)\n"));
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);
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;
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);
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;
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;
761 mapistore = emsmdbp_is_mapistore(handle_object);
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);
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);
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;
784 mapi_repl->error_code = MAPI_E_SUCCESS;
789 *size += libmapiserver_RopDeleteFolder_size(mapi_repl);
796 \details EcDoRpc DeleteMessage (0x1e) Rop. This operation (soft) deletes
797 a message on the server.
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
803 \param mapi_repl pointer to the DeleteMessage EcDoRpc_MAPI_REPL
805 \param handles pointer to the MAPI handles array
806 \param size pointer to the mapi_response size to update
808 \return MAPI_E_SUCCESS on success, otherwise MAPI error
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)
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;
824 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] DeleteMessage (0x1e)\n"));
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);
833 mapi_repl->opnum = mapi_req->opnum;
834 mapi_repl->error_code = MAPI_E_SUCCESS;
835 mapi_repl->u.mapi_DeleteMessages.PartialCompletion = false;
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;
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;
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;
857 contextID = emsmdbp_get_contextID(parent_object);
859 for (i = 0; i < mapi_req->u.mapi_DeleteMessages.cn_ids; ++i) {
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;
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;
875 delete_message_response:
876 *size += libmapiserver_RopDeleteMessage_size(mapi_repl);
878 return MAPI_E_SUCCESS;
883 \details EcDoRpc SetSearchCriteria (0x30) Rop. This operation sets
884 the search criteria for a search folder.
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
890 \param mapi_repl pointer to the SetSearchCriteria EcDoRpc_MAPI_REPL
892 \param handles pointer to the MAPI handles array
893 \param size pointer to the mapi_response size to update
895 \return MAPI_E_SUCCESS on success, otherwise MAPI error
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)
903 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] SetSearchCriteria (0x30)\n"));
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);
912 mapi_repl->opnum = mapi_req->opnum;
913 mapi_repl->handle_idx = mapi_req->handle_idx;
914 mapi_repl->error_code = MAPI_E_SUCCESS;
916 /* TODO: actually implement this */
918 *size += libmapiserver_RopSetSearchCriteria_size(mapi_repl);
920 return MAPI_E_SUCCESS;
925 \details EcDoRpc GetSearchCriteria (0x31) Rop. This operation gets
926 the search criteria for a search folder.
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
932 \param mapi_repl pointer to the GetSearchCriteria EcDoRpc_MAPI_REPL
934 \param handles pointer to the MAPI handles array
935 \param size pointer to the mapi_response size to update
937 \return MAPI_E_SUCCESS on success, otherwise MAPI error
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)
945 /* struct mapi_SRestriction *res; */
947 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] GetSearchCriteria (0x31)\n"));
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);
956 mapi_repl->opnum = mapi_req->opnum;
957 mapi_repl->handle_idx = mapi_req->handle_idx;
958 mapi_repl->error_code = MAPI_E_SUCCESS;
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;
967 /* TODO: actually implement this */
969 *size += libmapiserver_RopGetSearchCriteria_size(mapi_repl);
971 return MAPI_E_SUCCESS;
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)
981 struct emsmdbp_object *folder_object = NULL;
984 uint64_t *childFolders;
985 uint32_t childFolderCount;
987 uint8_t flags = DELETE_HARD_DELETE| DEL_MESSAGES | DEL_FOLDERS;
988 TALLOC_CTX *local_mem_ctx;
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;
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;
1002 context_id = emsmdbp_get_contextID(folder_object);
1004 local_mem_ctx = talloc_zero(NULL, TALLOC_CTX);
1006 retval = mapistore_folder_get_child_fids(emsmdbp_ctx->mstore_ctx, context_id, folder_object, local_mem_ctx,
1007 &childFolders, &childFolderCount);
1009 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] EmptyFolder bad retval: 0x%x", retval));
1010 return MAPI_E_NOT_FOUND;
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],
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;
1023 talloc_free(local_mem_ctx);
1025 return MAPI_E_SUCCESS;
1029 \details EcDoRpc EmptyFolder (0x58) Rop. This operation removes the sub-folders
1030 and messages from a given parent folder.
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
1036 \param mapi_repl pointer to the EmptyFolder EcDoRpc_MAPI_REPL
1038 \param handles pointer to the MAPI handles array
1039 \param size pointer to the mapi_response size to update
1041 \return MAPI_E_SUCCESS on success, otherwise MAPI error
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)
1049 enum MAPISTATUS retval;
1050 struct mapi_handles *folder = NULL;
1051 struct emsmdbp_object *folder_object;
1053 bool mapistore = false;
1055 DEBUG(4, ("exchange_emsmdb: [OXCFOLD] EmptyFolder (0x58)\n"));
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);
1064 mapi_repl->opnum = mapi_req->opnum;
1065 mapi_repl->handle_idx = mapi_req->handle_idx;
1066 mapi_repl->u.mapi_EmptyFolder.PartialCompletion = 0;
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;
1074 mapistore = emsmdbp_is_mapistore(folder_object);
1075 switch (mapistore) {
1077 /* system/special folder */
1078 DEBUG(0, ("TODO Empty system/special folder\n"));
1080 retval = RopEmptyFolder_SystemSpecialFolder(mem_ctx, emsmdbp_ctx,
1081 mapi_req->u.mapi_EmptyFolder,
1082 &mapi_repl->u.mapi_EmptyFolder);
1084 retval = MAPI_E_SUCCESS; // TODO: temporary hack.
1085 mapi_repl->error_code = retval;
1088 /* handled by mapistore */
1089 retval = RopEmptyFolder_GenericFolder(mem_ctx, emsmdbp_ctx,
1090 mapi_req->u.mapi_EmptyFolder,
1091 &mapi_repl->u.mapi_EmptyFolder,
1093 mapi_repl->error_code = retval;
1097 *size += libmapiserver_RopEmptyFolder_size(mapi_repl);
1099 /* reply filled in above */
1101 return MAPI_E_SUCCESS;