/** \details EcDoRpc EmptyFolder (0x58) Rop. This operation removes the sub-folders and messages from a given parent folder. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the EmptyFolder EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the EmptyFolder EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopEmptyFolder(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; struct mapi_handles *folder = NULL; struct emsmdbp_object *folder_object; void *private_data; bool mapistore = false; OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] EmptyFolder (0x58)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); mapi_repl->opnum = mapi_req->opnum; mapi_repl->handle_idx = mapi_req->handle_idx; mapi_repl->u.mapi_EmptyFolder.PartialCompletion = 0; /* Step 1. Retrieve folder handle */ retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handles[mapi_req->handle_idx], &folder); OPENCHANGE_RETVAL_IF(retval, retval, NULL); mapi_handles_get_private_data(folder, &private_data); folder_object = private_data; mapistore = emsmdbp_is_mapistore(folder_object); switch ((int)mapistore) { case false: /* system/special folder */ OC_DEBUG(0, "TODO Empty system/special folder\n"); #if 0 retval = RopEmptyFolder_SystemSpecialFolder(mem_ctx, emsmdbp_ctx, mapi_req->u.mapi_EmptyFolder, &mapi_repl->u.mapi_EmptyFolder); #endif retval = MAPI_E_SUCCESS; // TODO: temporary hack. mapi_repl->error_code = retval; break; case true: /* handled by mapistore */ retval = RopEmptyFolder_GenericFolder(mem_ctx, emsmdbp_ctx, mapi_req->u.mapi_EmptyFolder, &mapi_repl->u.mapi_EmptyFolder, folder); mapi_repl->error_code = retval; break; } *size += libmapiserver_RopEmptyFolder_size(mapi_repl); /* reply filled in above */ return MAPI_E_SUCCESS; }
/** \details EcDoRpc GetPermissionsTable (0x3e) Rop. This operation get the permissions table of a folder. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the GetPermissionsTable EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the GetPermissionsTable EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetPermissionsTable(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; struct mapi_handles *parent; struct mapi_handles *rec; struct emsmdbp_object *parent_object, *object; void *data = NULL; uint32_t handle; OC_DEBUG(4, "exchange_emsmdb: [OXCPERM] GetPermissionsTable (0x3e)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); mapi_repl->opnum = mapi_req->opnum; mapi_repl->handle_idx = mapi_req->u.mapi_GetPermissionsTable.handle_idx; mapi_repl->error_code = MAPI_E_SUCCESS; /* Ensure parent handle references a folder object */ handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent); if (retval) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); goto end; } retval = mapi_handles_get_private_data(parent, &data); if (retval || !data) { mapi_repl->error_code = MAPI_E_NOT_FOUND; OC_DEBUG(5, " handle data not found, idx = %x\n", mapi_req->handle_idx); goto end; } parent_object = (struct emsmdbp_object *) data; if (parent_object->type != EMSMDBP_OBJECT_FOLDER) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " unhandled object type: %d\n", parent_object->type); goto end; } /* Initialize Table object */ retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec); handles[mapi_repl->handle_idx] = rec->handle; if (emsmdbp_is_mapistore(parent_object)) { object = emsmdbp_folder_open_table(rec, parent_object, MAPISTORE_PERMISSIONS_TABLE, mapi_repl->handle_idx); } else { object = emsmdbp_object_table_init((TALLOC_CTX *)rec, emsmdbp_ctx, parent_object); } if (object) { retval = mapi_handles_set_private_data(rec, object); } else { mapi_handles_delete(emsmdbp_ctx->handles_ctx, rec->handle); mapi_repl->error_code = MAPI_E_NOT_FOUND; goto end; } end: *size += libmapiserver_RopGetPermissionsTable_size(mapi_repl); return MAPI_E_SUCCESS; }
/** \details EcDoRpc ModifyPermissions (0x40) Rop. This operation gets the GUID of a public folder's per-user information. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the GetPerUserLongTermIds EcDoRpc_MAPI_REQ \param mapi_repl pointer to the GetPerUserLongTermIds EcDoRpc_MAPI_REPL \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopModifyPermissions(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; enum mapistore_error mretval; struct mapi_handles *folder; struct emsmdbp_object *folder_object; void *data = NULL; uint32_t handle; struct ModifyPermissions_req *request; OC_DEBUG(4, "exchange_emsmdb: [OXCSTOR] ModifyPermissions (0x40)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); mapi_repl->opnum = mapi_req->opnum; mapi_repl->handle_idx = mapi_req->handle_idx; mapi_repl->error_code = MAPI_E_SUCCESS; /* Ensure handle references a folder object */ handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &folder); if (retval) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); goto end; } retval = mapi_handles_get_private_data(folder, &data); if (retval || !data) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " handle data not found, idx = %x\n", mapi_req->handle_idx); goto end; } folder_object = (struct emsmdbp_object *) data; if (folder_object->type != EMSMDBP_OBJECT_FOLDER) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " unhandled object type: %d\n", folder_object->type); goto end; } request = &mapi_req->u.mapi_ModifyPermissions; if (emsmdbp_is_mapistore(folder_object)) { mretval = mapistore_folder_modify_permissions(emsmdbp_ctx->mstore_ctx, emsmdbp_get_contextID(folder_object), folder_object->backend_object, request->rowList.ModifyFlags, request->rowList.ModifyCount, request->rowList.PermissionsData); if (mretval != MAPISTORE_SUCCESS) { OC_DEBUG(5, "mapistore_folder_modify_permissions: %s\n", mapistore_errstr(mretval)); mapi_repl->error_code = mapistore_error_to_mapi(mretval); } } else { mapi_repl->error_code = MAPI_E_NOT_FOUND; } end: *size += libmapiserver_RopModifyPermissions_size(mapi_repl); return MAPI_E_SUCCESS; }
/** \details EcDoRpc RegisterNotification (0x29) Rop. This operation subscribes for specified notifications on the server and returns a handle of the subscription to the client. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the RegisterNotification EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the RegisterNotification EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopRegisterNotification(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; struct mapi_handles *parent_rec = NULL; struct mapi_handles *subscription_rec = NULL; uint32_t handle; struct emsmdbp_object *parent_object; struct emsmdbp_object *subscription_object; struct mapistore_subscription *subscription; struct mapistore_subscription_list *subscription_list; struct mapistore_object_subscription_parameters subscription_parameters; void *data; DEBUG(4, ("exchange_emsmdb: [OXCNOTIF] RegisterNotification (0x29)\n")); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); mapi_repl->opnum = mapi_req->opnum; mapi_repl->handle_idx = mapi_req->u.mapi_RegisterNotification.handle_idx; mapi_repl->error_code = MAPI_E_SUCCESS; handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent_rec); if (retval) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; DEBUG(5, (" handle (%x) not found: %x\n", handle, mapi_req->handle_idx)); goto end; } retval = mapi_handles_get_private_data(parent_rec, &data); if (retval) { mapi_repl->error_code = retval; DEBUG(5, (" handle data not found, idx = %x\n", mapi_req->handle_idx)); goto end; } parent_object = (struct emsmdbp_object *) data; retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &subscription_rec); if (retval) { mapi_repl->error_code = retval; goto end; } handles[mapi_repl->handle_idx] = subscription_rec->handle; /* emsmdb_object */ subscription_object = emsmdbp_object_subscription_init(subscription_rec, emsmdbp_ctx, parent_object); mapi_handles_set_private_data(subscription_rec, subscription_object); /* we attach the subscription to the session object. note: a mapistore_subscription can exist without a corresponding emsmdbp_object (tables) */ subscription_list = talloc_zero(emsmdbp_ctx->mstore_ctx, struct mapistore_subscription_list); DLIST_ADD(emsmdbp_ctx->mstore_ctx->subscriptions, subscription_list); subscription_parameters.folder_id = mapi_req->u.mapi_RegisterNotification.FolderId.ID; subscription_parameters.object_id = mapi_req->u.mapi_RegisterNotification.MessageId.ID; subscription_parameters.whole_store = mapi_req->u.mapi_RegisterNotification.WantWholeStore; subscription = mapistore_new_subscription(subscription_list, emsmdbp_ctx->mstore_ctx, emsmdbp_ctx->username, subscription_rec->handle, mapi_req->u.mapi_RegisterNotification.NotificationFlags, &subscription_parameters); subscription_list->subscription = subscription; subscription_object->object.subscription->subscription_list = subscription_list; end: *size += libmapiserver_RopRegisterNotification_size(); return MAPI_E_SUCCESS; }
_PUBLIC_ enum MAPISTATUS EcDoRpc_RopMoveCopyMessages(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; uint32_t handle; uint32_t contextID; struct mapi_handles *rec = NULL; void *private_data = NULL; struct emsmdbp_object *destination_object; struct emsmdbp_object *source_object; uint64_t *targetMIDs; uint32_t i; bool mapistore = false; OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] RopMoveCopyMessages (0x33)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); mapi_repl->opnum = mapi_req->opnum; mapi_repl->error_code = MAPI_E_SUCCESS; mapi_repl->handle_idx = mapi_req->handle_idx; mapi_repl->u.mapi_MoveCopyMessages.PartialCompletion = 0; /* Get the destionation information */ handle = handles[mapi_req->u.mapi_MoveCopyMessages.handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &rec); if (retval) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); goto end; } retval = mapi_handles_get_private_data(rec, &private_data); /* object is our destination folder */ destination_object = private_data; if (!destination_object) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " object (%x) not found: %x\n", handle, mapi_req->handle_idx); goto end; } /* Get the source folder information */ handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &rec); if (retval) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); goto end; } retval = mapi_handles_get_private_data(rec, &private_data); source_object = private_data; if (!source_object) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " object (%x) not found: %x\n", handle, mapi_req->u.mapi_MoveCopyMessages.handle_idx); goto end; } contextID = emsmdbp_get_contextID(destination_object); mapistore = emsmdbp_is_mapistore(source_object); if (mapistore) { /* We prepare a set of new MIDs for the backend */ targetMIDs = talloc_array(NULL, uint64_t, mapi_req->u.mapi_MoveCopyMessages.count); for (i = 0; i < mapi_req->u.mapi_MoveCopyMessages.count; i++) { mapistore_indexing_get_new_folderID(emsmdbp_ctx->mstore_ctx, &targetMIDs[i]); } /* We invoke the backend method */ mapistore_folder_move_copy_messages(emsmdbp_ctx->mstore_ctx, contextID, destination_object->backend_object, source_object->backend_object, mem_ctx, mapi_req->u.mapi_MoveCopyMessages.count, mapi_req->u.mapi_MoveCopyMessages.message_id, targetMIDs, NULL, NULL, mapi_req->u.mapi_MoveCopyMessages.WantCopy); talloc_free(targetMIDs); /* /\* The backend might do this for us. In any case, we try to add it ourselves *\/ */ /* mapistore_indexing_record_add_mid(emsmdbp_ctx->mstore_ctx, contextID, targetMID); */ } else { OC_DEBUG(0, "mapistore support not implemented yet - shouldn't occur\n"); mapi_repl->error_code = MAPI_E_NO_SUPPORT; } end: *size += libmapiserver_RopMoveCopyMessages_size(mapi_repl); return MAPI_E_SUCCESS; }
/** \details EcDoRpc DeleteFolder (0x1d) Rop. This operation deletes a folder on the remote server. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the DeleteFolder EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the DeleteFolder EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopDeleteFolder(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; enum mapistore_error ret; struct mapi_handles *rec = NULL; uint32_t handle; void *handle_priv_data; struct emsmdbp_object *handle_object = NULL; OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] DeleteFolder (0x1d)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); /* Initialize default empty DeleteFolder reply */ mapi_repl->opnum = mapi_req->opnum; mapi_repl->error_code = MAPI_E_SUCCESS; mapi_repl->handle_idx = mapi_req->handle_idx; /* TODO: factor this out to be convenience API */ /* Convert the handle index into a handle, and then get the folder id */ handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &rec); OPENCHANGE_RETVAL_IF(retval, retval, NULL); mapi_handles_get_private_data(rec, &handle_priv_data); handle_object = (struct emsmdbp_object *)handle_priv_data; if (!handle_object) { OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] DeleteFolder null object\n"); mapi_repl->error_code = MAPI_E_NO_SUPPORT; return MAPI_E_SUCCESS; } if (handle_object->type != EMSMDBP_OBJECT_FOLDER) { OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] DeleteFolder wrong object type: 0x%x\n", handle_object->type); mapi_repl->error_code = MAPI_E_NO_SUPPORT; return MAPI_E_SUCCESS; } retval = MAPI_E_SUCCESS; ret = emsmdbp_folder_delete(emsmdbp_ctx, handle_object, mapi_req->u.mapi_DeleteFolder.FolderId, mapi_req->u.mapi_DeleteFolder.DeleteFolderFlags); if (ret == MAPISTORE_ERR_EXIST) { mapi_repl->u.mapi_DeleteFolder.PartialCompletion = true; } else if (ret != MAPISTORE_SUCCESS) { OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] DeleteFolder failed to delete fid 0x%.16"PRIx64" (%s)", mapi_req->u.mapi_DeleteFolder.FolderId, mapistore_errstr(ret)); if (ret == MAPISTORE_ERR_DENIED) { retval = MAPI_E_NO_ACCESS; } else { retval = MAPI_E_NOT_FOUND; } } mapi_repl->error_code = retval; *size += libmapiserver_RopDeleteFolder_size(mapi_repl); return MAPI_E_SUCCESS; }
/** \details EcDoRpc DeleteMessage (0x1e) Rop. This operation (soft) deletes a message on the server. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the DeleteMessage EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the DeleteMessage EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopDeleteMessages(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { uint32_t parent_folder_handle; struct mapi_handles *parent_folder = NULL; void *parent_folder_private_data; struct emsmdbp_object *parent_object; char *owner; enum MAPISTATUS retval; uint32_t contextID; int i; OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] DeleteMessage (0x1e)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); mapi_repl->opnum = mapi_req->opnum; mapi_repl->error_code = MAPI_E_SUCCESS; mapi_repl->u.mapi_DeleteMessages.PartialCompletion = false; parent_folder_handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, parent_folder_handle, &parent_folder); if (retval != MAPI_E_SUCCESS) { mapi_repl->error_code = MAPI_E_NOT_FOUND; goto delete_message_response; } retval = mapi_handles_get_private_data(parent_folder, &parent_folder_private_data); parent_object = (struct emsmdbp_object *)parent_folder_private_data; if (!parent_object || parent_object->type != EMSMDBP_OBJECT_FOLDER) { mapi_repl->error_code = MAPI_E_NO_SUPPORT; goto delete_message_response; } if (!emsmdbp_is_mapistore(parent_object) ) { OC_DEBUG(0, "Got parent folder not in mapistore\n"); mapi_repl->error_code = MAPI_E_NO_SUPPORT; goto delete_message_response; } contextID = emsmdbp_get_contextID(parent_object); owner = emsmdbp_get_owner(parent_object); for (i = 0; i < mapi_req->u.mapi_DeleteMessages.cn_ids; ++i) { int ret; uint64_t mid = mapi_req->u.mapi_DeleteMessages.message_ids[i]; OC_DEBUG(0, "MID %i to delete: 0x%.16"PRIx64"\n", i, mid); ret = mapistore_folder_delete_message(emsmdbp_ctx->mstore_ctx, contextID, parent_object->backend_object, mid, MAPISTORE_SOFT_DELETE); if (ret != MAPISTORE_SUCCESS && ret != MAPISTORE_ERR_NOT_FOUND) { if (ret == MAPISTORE_ERR_DENIED) { mapi_repl->error_code = MAPI_E_NO_ACCESS; } else { mapi_repl->error_code = MAPI_E_CALL_FAILED; } goto delete_message_response; } ret = mapistore_indexing_record_del_mid(emsmdbp_ctx->mstore_ctx, contextID, owner, mid, MAPISTORE_SOFT_DELETE); if (ret != MAPISTORE_SUCCESS) { mapi_repl->error_code = MAPI_E_CALL_FAILED; goto delete_message_response; } } delete_message_response: *size += libmapiserver_RopDeleteMessage_size(mapi_repl); return MAPI_E_SUCCESS; }
/** \details EcDoRpc CreateFolder (0x1c) Rop. This operation creates a folder on the remote server. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the CreateFolder EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the CreateFolder EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error \note We do not provide support for GhostInfo */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopCreateFolder(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; enum mapistore_error ret; struct mapi_handles *parent = NULL; uint32_t handle; uint64_t parent_fid, fid, cn; struct SPropValue cnValue; struct emsmdbp_object *parent_object = NULL; struct emsmdbp_object *object = NULL; struct CreateFolder_req *request; struct CreateFolder_repl *response; struct SRow *aRow = NULL; void *data; struct mapi_handles *rec = NULL; OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] CreateFolder (0x1c)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); /* Set up sensible values for the reply */ mapi_repl->opnum = mapi_req->opnum; mapi_repl->error_code = MAPI_E_SUCCESS; mapi_repl->handle_idx = mapi_req->u.mapi_CreateFolder.handle_idx; if (!mapi_req->u.mapi_CreateFolder.ulFolderType || mapi_req->u.mapi_CreateFolder.ulFolderType > 0x2) { mapi_repl->error_code = MAPI_E_INVALID_PARAMETER; goto end; } /* Step 1. Retrieve parent handle in the hierarchy */ handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent); OPENCHANGE_RETVAL_IF(retval, retval, NULL); /* With CreateFolder, the parent object really IS the parent object */ mapi_handles_get_private_data(parent, &data); parent_object = (struct emsmdbp_object *)data; if (!parent_object) { OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] CreateFolder null object\n"); mapi_repl->error_code = MAPI_E_NO_SUPPORT; goto end; } if (parent_object->type == EMSMDBP_OBJECT_MAILBOX) { mapi_repl->error_code = MAPI_E_NO_SUPPORT; goto end; } if (parent_object->type != EMSMDBP_OBJECT_FOLDER && parent_object->type != EMSMDBP_OBJECT_MAILBOX) { OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] CreateFolder wrong object type: 0x%x\n", parent_object->type); mapi_repl->error_code = MAPI_E_NO_SUPPORT; goto end; } request = &mapi_req->u.mapi_CreateFolder; response = &mapi_repl->u.mapi_CreateFolder; /* OC_DEBUG(4, ("exchange_emsmdb: [OXCFOLD] CreateFolder parent: 0x%.16"PRIx64"\n", parent_fid)); */ /* OC_DEBUG(4, ("exchange_emsmdb: [OXCFOLD] Creating %s\n", request->FolderName.lpszW)); */ /* if (request->ulFolderType != FOLDER_GENERIC) { */ /* OC_DEBUG(4, ("exchange_emsmdb: [OXCFOLD] Unexpected folder type 0x%x\n", request->ulType)); */ /* mapi_repl->error_code = MAPI_E_NO_SUPPORT; */ /* goto end; */ /* } */ response->IsExistingFolder = false; ret = emsmdbp_object_get_fid_by_name(emsmdbp_ctx, parent_object, request->FolderName.lpszW, &fid); if (ret == MAPISTORE_SUCCESS) { if (oxosfld_is_special_folder(emsmdbp_ctx, fid) || request->ulFlags == OPEN_IF_EXISTS) { response->IsExistingFolder = true; } else { if (emsmdbp_is_mapistore(parent_object)) { OC_DEBUG(5, "Folder %s exists in MAPIStore", request->FolderName.lpszW); } else { OC_DEBUG(5, "Folder %s exists in OpenChangeDB", request->FolderName.lpszW); } mapi_repl->error_code = MAPI_E_COLLISION; goto end; } } mapi_handles_add(emsmdbp_ctx->handles_ctx, 0, &rec); if (response->IsExistingFolder) { retval = emsmdbp_object_open_folder_by_fid(rec, emsmdbp_ctx, parent_object, fid, &object); if (retval != MAPI_E_SUCCESS) { OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] Failure opening existing folder: %s\n", mapi_get_errstr(retval)); mapi_handles_delete(emsmdbp_ctx->handles_ctx, rec->handle); mapi_repl->error_code = retval; goto end; } } else { /* Step 3. Turn CreateFolder parameters into MAPI property array */ parent_fid = parent_object->object.folder->folderID; if (openchangedb_is_public_folder_id(emsmdbp_ctx->oc_ctx, parent_fid)) { retval = openchangedb_get_new_public_folderID(emsmdbp_ctx->oc_ctx, emsmdbp_ctx->username, &fid); } else { retval = mapistore_error_to_mapi(mapistore_indexing_get_new_folderID(emsmdbp_ctx->mstore_ctx, &fid)); } if (retval != MAPI_E_SUCCESS) { OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] Could not obtain a new folder id\n"); mapi_repl->error_code = MAPI_E_NO_SUPPORT; goto end; } retval = openchangedb_get_new_changeNumber(emsmdbp_ctx->oc_ctx, emsmdbp_ctx->username, &cn); if (retval != MAPI_E_SUCCESS) { OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] Could not obtain a new folder cn\n"); mapi_repl->error_code = MAPI_E_NO_SUPPORT; goto end; } aRow = libmapiserver_ROP_request_to_properties(mem_ctx, (void *)&mapi_req->u.mapi_CreateFolder, op_MAPI_CreateFolder); aRow->lpProps = add_SPropValue(mem_ctx, aRow->lpProps, &(aRow->cValues), PR_PARENT_FID, (void *)(&parent_fid)); cnValue.ulPropTag = PidTagChangeNumber; cnValue.value.d = cn; SRow_addprop(aRow, cnValue); retval = emsmdbp_object_create_folder(emsmdbp_ctx, parent_object, rec, fid, aRow, true, &object); if (retval != MAPI_E_SUCCESS) { OC_DEBUG(5, "folder creation failed\n"); mapi_handles_delete(emsmdbp_ctx->handles_ctx, rec->handle); mapi_repl->error_code = retval; goto end; } } handles[mapi_repl->handle_idx] = rec->handle; mapi_handles_set_private_data(rec, object); response->folder_id = fid; if (response->IsExistingFolder == true) { response->GhostUnion.GhostInfo.HasRules = false; response->GhostUnion.GhostInfo.IsGhosted = false; } end: *size += libmapiserver_RopCreateFolder_size(mapi_repl); if (aRow) { talloc_free(aRow); } return MAPI_E_SUCCESS; }
/** \details EcDoRpc OpenFolder (0x02) Rop. This operation opens an existing folder. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the OpenFolder EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the OpenFolder EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopOpenFolder(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; struct mapi_handles *parent = NULL; struct mapi_handles *rec = NULL; void *private_data; struct emsmdbp_object *object, *parent_object; uint32_t handle; struct OpenFolder_req *request; struct OpenFolder_repl *response; OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] OpenFolder (0x02)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); request = &mapi_req->u.mapi_OpenFolder; response = &mapi_repl->u.mapi_OpenFolder; mapi_repl->opnum = mapi_req->opnum; mapi_repl->error_code = MAPI_E_SUCCESS; mapi_repl->handle_idx = request->handle_idx; /* Step 1. Retrieve parent handle in the hierarchy */ handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent); if (retval) { OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } /* With OpenFolder, the parent object may NOT BE the direct parent folder of the folder */ mapi_handles_get_private_data(parent, &private_data); parent_object = private_data; if (!parent_object || (parent_object->type != EMSMDBP_OBJECT_FOLDER && parent_object->type != EMSMDBP_OBJECT_MAILBOX)) { OC_DEBUG(5, " invalid handle (%x): %x\n", handle, mapi_req->handle_idx); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } /* Fill EcDoRpc_MAPI_REPL reply */ response->HasRules = 0; response->IsGhosted = 0; mapi_handles_add(emsmdbp_ctx->handles_ctx, 0, &rec); retval = emsmdbp_object_open_folder_by_fid(rec, emsmdbp_ctx, parent_object, request->folder_id, &object); if (retval != MAPI_E_SUCCESS) { mapi_repl->error_code = retval; goto end; } retval = mapi_handles_set_private_data(rec, object); handles[mapi_repl->handle_idx] = rec->handle; end: *size += libmapiserver_RopOpenFolder_size(mapi_repl); return MAPI_E_SUCCESS; }
/** \details EcDoRpc GetHierarchyTable (0x04) Rop. This operation gets the subfolder hierarchy table for a folder. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the GetHierarchyTable EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the GetHierarchyTable EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetHierarchyTable(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; struct mapi_handles *parent; struct mapi_handles *rec = NULL; struct emsmdbp_object *object = NULL, *parent_object = NULL; void *data; uint32_t handle; uint32_t count = 0; OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] GetHierarchyTable (0x04)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); /* Initialize default empty GetHierarchyTable reply */ mapi_repl->opnum = mapi_req->opnum; mapi_repl->error_code = MAPI_E_SUCCESS; mapi_repl->handle_idx = mapi_req->u.mapi_GetHierarchyTable.handle_idx; /* GetHierarchyTable can only be called for mailbox/folder objects */ handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent); if (retval) { OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } mapi_handles_get_private_data(parent, &data); parent_object = (struct emsmdbp_object *)data; if (!parent_object) { OC_DEBUG(5, " no object found\n"); mapi_repl->error_code = MAPI_E_NO_SUPPORT; goto end; } if ((parent_object->type != EMSMDBP_OBJECT_MAILBOX) && (parent_object->type != EMSMDBP_OBJECT_FOLDER)) { OC_DEBUG(5, "unsupported object type"); mapi_repl->error_code = MAPI_E_NO_SUPPORT; goto end; } /* Initialize Table object */ retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec); handles[mapi_repl->handle_idx] = rec->handle; object = emsmdbp_folder_open_table(rec, parent_object, MAPISTORE_FOLDER_TABLE, rec->handle); if (!object) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } object->object.table->flags = mapi_req->u.mapi_GetHierarchyTable.TableFlags; mapi_handles_set_private_data(rec, object); if (object->object.table->flags & TableFlags_Depth) { retval = emsmdbp_folder_get_recursive_folder_count(emsmdbp_ctx, parent_object, &count); if (retval != MAPI_E_SUCCESS) { mapi_repl->error_code = MAPI_E_CALL_FAILED; goto end; } object->object.table->denominator = count; } mapi_repl->u.mapi_GetHierarchyTable.RowCount = object->object.table->denominator; /* notifications */ if ((mapi_req->u.mapi_GetHierarchyTable.TableFlags & TableFlags_NoNotifications)) { OC_DEBUG(5, " notifications skipped\n"); } end: *size += libmapiserver_RopGetHierarchyTable_size(mapi_repl); return MAPI_E_SUCCESS; }
/** \details EcDoRpc GetContentsTable (0x05) Rop. This operation get the content table of a container. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the GetContentsTable EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the GetContentsTable EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetContentsTable(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; struct mapi_handles *parent; struct mapi_handles *rec = NULL; struct emsmdbp_object *object = NULL, *parent_object; void *data; uint32_t handle; uint8_t table_type; OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] GetContentsTable (0x05)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); /* Initialize default empty GetContentsTable reply */ mapi_repl->opnum = mapi_req->opnum; mapi_repl->handle_idx = mapi_req->u.mapi_GetContentsTable.handle_idx; mapi_repl->error_code = MAPI_E_SUCCESS; mapi_repl->u.mapi_GetContentsTable.RowCount = 0; handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent); if (retval != MAPI_E_SUCCESS) { OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); mapi_repl->error_code = MAPI_E_NO_SUPPORT; goto end; } /* GetContentsTable can only be called for folder objects */ retval = mapi_handles_get_private_data(parent, &data); if (retval != MAPI_E_SUCCESS) { mapi_repl->error_code = retval; OC_DEBUG(5, " handle data not found, idx = %x\n", mapi_req->handle_idx); goto end; } parent_object = (struct emsmdbp_object *)data; if (!parent_object) { mapi_repl->error_code = MAPI_E_NO_SUPPORT; OC_DEBUG(5, " handle data not found, idx = %x\n", mapi_req->handle_idx); goto end; } if (parent_object->type != EMSMDBP_OBJECT_FOLDER) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_Associated)) { OC_DEBUG(5, " table is FAI table\n"); table_type = MAPISTORE_FAI_TABLE; } else { OC_DEBUG(5, " table is contents table\n"); table_type = MAPISTORE_MESSAGE_TABLE; } /* Initialize Table object */ retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec); if (retval != MAPI_E_SUCCESS) { mapi_repl->error_code = retval; goto end; } handles[mapi_repl->handle_idx] = rec->handle; object = emsmdbp_folder_open_table(rec, parent_object, table_type, rec->handle); if (!object) { mapi_handles_delete(emsmdbp_ctx->handles_ctx, rec->handle); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } mapi_handles_set_private_data(rec, object); mapi_repl->u.mapi_GetContentsTable.RowCount = object->object.table->denominator; /* notifications */ if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_NoNotifications)) { OC_DEBUG(5, " notifications skipped\n"); } end: *size += libmapiserver_RopGetContentsTable_size(mapi_repl); return MAPI_E_SUCCESS; }
/** \details EcDoRpc EmptyFolder (0x58) Rop. This operation removes the sub-folders and messages from a given parent folder. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the EmptyFolder EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the EmptyFolder EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ enum MAPISTATUS EcDoRpc_RopCopyFolder(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; enum mapistore_error ret; uint32_t handle; struct mapi_handles *handle_object; void *private_data; struct CopyFolder_req *request; struct CopyFolder_repl *response; struct emsmdbp_object *source_parent; struct emsmdbp_object *copy_folder; struct emsmdbp_object *target_folder; uint32_t contextID; OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] CopyFolder (0x36)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); mapi_repl->opnum = mapi_req->opnum; mapi_repl->handle_idx = mapi_req->handle_idx; mapi_repl->error_code = MAPI_E_SUCCESS; request = &mapi_req->u.mapi_CopyFolder; response = &mapi_repl->u.mapi_CopyFolder; /* Retrieve the source parent handle in the hierarchy */ handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &handle_object); if (retval) { OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } mapi_handles_get_private_data(handle_object, &private_data); source_parent = private_data; if (!source_parent || source_parent->type != EMSMDBP_OBJECT_FOLDER) { OC_DEBUG(5, " invalid handle (%x): %x\n", handle, mapi_req->handle_idx); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } /* Open the folder being copied as it will be the actor object in this process */ ret = emsmdbp_object_open_folder(mem_ctx, emsmdbp_ctx, source_parent, request->FolderId, ©_folder); if (ret != MAPISTORE_SUCCESS) { mapi_repl->error_code = mapistore_error_to_mapi(ret); goto end; } /* TODO: we should provide the ability to perform this operation between non-mapistore objects or between mapistore and non-mapistore objects */ if (!emsmdbp_is_mapistore(copy_folder)) { mapi_repl->error_code = MAPI_E_NO_ACCESS; goto end; } /* Retrieve the destination parent handle in the hierarchy */ handle = handles[request->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &handle_object); if (retval) { OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } mapi_handles_get_private_data(handle_object, &private_data); target_folder = private_data; if (!target_folder || target_folder->type != EMSMDBP_OBJECT_FOLDER) { OC_DEBUG(5, " invalid handle (%x): %x\n", handle, mapi_req->handle_idx); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } if (!emsmdbp_is_mapistore(target_folder)) { mapi_repl->error_code = MAPI_E_NO_ACCESS; goto end; } contextID = emsmdbp_get_contextID(copy_folder); ret = mapistore_folder_copy_folder(emsmdbp_ctx->mstore_ctx, contextID, copy_folder->backend_object, target_folder->backend_object, mem_ctx, request->WantRecursive, request->NewFolderName.lpszW); mapi_repl->error_code = mapistore_error_to_mapi(ret); response->PartialCompletion = false; end: *size += libmapiserver_RopCopyFolder_size(mapi_repl); handles[mapi_repl->handle_idx] = handles[mapi_req->handle_idx]; return MAPI_E_SUCCESS; }
/** \details EcDoRpc RegisterNotification (0x29) Rop. This operation subscribes for specified notifications on the server and returns a handle of the subscription to the client. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the RegisterNotification EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the RegisterNotification EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopRegisterNotification(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; enum mapistore_error mretval; struct emsmdbp_object *parent_object; struct emsmdbp_object *subscription_object; struct mapi_handles *parent_rec = NULL; struct mapi_handles *subscription_rec = NULL; uint32_t handle; void *data; uint16_t flags; uint64_t fid = 0; uint64_t mid = 0; OC_DEBUG(4, "exchange_emsmdb: [OXCNOTIF] RegisterNotification (0x29)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); mapi_repl->opnum = mapi_req->opnum; mapi_repl->handle_idx = mapi_req->u.mapi_RegisterNotification.handle_idx; mapi_repl->error_code = MAPI_E_SUCCESS; handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent_rec); if (retval) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); goto end; } retval = mapi_handles_get_private_data(parent_rec, &data); if (retval) { mapi_repl->error_code = retval; OC_DEBUG(5, " handle data not found, idx = %x\n", mapi_req->handle_idx); goto end; } parent_object = (struct emsmdbp_object *) data; retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &subscription_rec); if (retval) { mapi_repl->error_code = retval; goto end; } /* Notification subscriptions */ flags = mapi_req->u.mapi_RegisterNotification.NotificationFlags; if (mapi_req->u.mapi_RegisterNotification.WantWholeStore) { flags |= sub_WholeStore; } else { fid = mapi_req->u.mapi_RegisterNotification.FolderId.ID; mid = mapi_req->u.mapi_RegisterNotification.MessageId.ID; } mretval = mapistore_notification_subscription_add(emsmdbp_ctx->mstore_ctx, emsmdbp_ctx->session_uuid, subscription_rec->handle, flags, fid, mid, 0, NULL); if (mretval != MAPISTORE_SUCCESS) { /* MS-OXCROPS section 2.2.14.1 does not describe a * failure response buffer for RegisterNotification * Rop */ OC_DEBUG(0, "Failed to add subscription: %s", mapistore_errstr(mretval)); } handles[mapi_repl->handle_idx] = subscription_rec->handle; /* Create emsmdbp subscription object */ subscription_object = emsmdbp_object_subscription_init(subscription_rec, emsmdbp_ctx, parent_object); if (!subscription_object) { OC_DEBUG(0, "Unable to create subscription object"); } mapi_handles_set_private_data(subscription_rec, subscription_object); subscription_object->object.subscription->handle = subscription_rec->handle; end: *size += libmapiserver_RopRegisterNotification_size(); return MAPI_E_SUCCESS; }
/** \details EcDoRpc GetPropertiesSpecific (0x07) Rop. This operation retrieves from properties data from specified object. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the GetPropertiesSpecific EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the GetPropertiesSpecific EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetPropertiesSpecific(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { TALLOC_CTX *local_mem_ctx; enum MAPISTATUS retval; struct GetProps_req *request; struct GetProps_repl *response; uint32_t handle; uint16_t property_id, property_type; struct mapi_handles *rec = NULL; void *private_data = NULL; struct emsmdbp_object *object; struct SPropTagArray *properties; void **data_pointers; enum MAPISTATUS *retvals = NULL; bool *untyped_status; uint16_t i, propType; uint32_t stream_size; struct emsmdbp_stream_data *stream_data; OC_DEBUG(4, "exchange_emsmdb: [OXCPRPT] GetPropertiesSpecific (0x07)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); request = &mapi_req->u.mapi_GetProps; response = &mapi_repl->u.mapi_GetProps; /* Initialize GetProps response blob */ response->prop_data.length = 0; response->prop_data.data = NULL; /* Fill EcDoRpc_MAPI_REPL reply */ mapi_repl->opnum = mapi_req->opnum; mapi_repl->handle_idx = mapi_req->handle_idx; mapi_repl->error_code = MAPI_E_NOT_FOUND; handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &rec); if (retval) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); goto end; } retval = mapi_handles_get_private_data(rec, &private_data); object = private_data; if (!object) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " object (%x) not found: %x\n", handle, mapi_req->handle_idx); goto end; } if (!(object->type == EMSMDBP_OBJECT_MAILBOX || object->type == EMSMDBP_OBJECT_FOLDER || object->type == EMSMDBP_OBJECT_MESSAGE || object->type == EMSMDBP_OBJECT_ATTACHMENT)) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " GetProperties cannot occur on an object of type '%s' (%d)\n", emsmdbp_getstr_type(object), object->type); goto end; } local_mem_ctx = talloc_new(NULL); OPENCHANGE_RETVAL_IF(!local_mem_ctx, MAPI_E_NOT_ENOUGH_MEMORY, NULL); properties = talloc_zero(local_mem_ctx, struct SPropTagArray); properties->cValues = request->prop_count; properties->aulPropTag = talloc_array(properties, enum MAPITAGS, request->prop_count); untyped_status = talloc_array(local_mem_ctx, bool, request->prop_count); for (i = 0; i < request->prop_count; i++) { properties->aulPropTag[i] = request->properties[i]; if ((request->properties[i] & 0xffff) == 0) { property_id = request->properties[i] >> 16; if (property_id < 0x8000) { property_type = get_property_type(property_id); } else { property_type = 0; mapistore_namedprops_get_nameid_type(emsmdbp_ctx->mstore_ctx->nprops_ctx, property_id, &property_type); } if (property_type) { properties->aulPropTag[i] |= property_type; untyped_status[i] = true; } else { properties->aulPropTag[i] |= PT_ERROR; /* fail with a MAPI_E_NOT_FOUND */ untyped_status[i] = false; } } else {
/** \details EcDoRpc GetContentsTable (0x05) Rop. This operation get the content table of a container. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the GetContentsTable EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the GetContentsTable EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetContentsTable(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; struct mapi_handles *parent; struct mapi_handles *rec = NULL; struct emsmdbp_object *object = NULL, *parent_object; struct mapistore_subscription_list *subscription_list; struct mapistore_subscription *subscription; struct mapistore_table_subscription_parameters subscription_parameters; void *data; uint64_t folderID; uint32_t handle; uint8_t table_type; DEBUG(4, ("exchange_emsmdb: [OXCFOLD] GetContentsTable (0x05)\n")); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); /* Initialize default empty GetContentsTable reply */ mapi_repl->opnum = mapi_req->opnum; mapi_repl->handle_idx = mapi_req->u.mapi_GetContentsTable.handle_idx; mapi_repl->error_code = MAPI_E_SUCCESS; mapi_repl->u.mapi_GetContentsTable.RowCount = 0; handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent); if (MAPI_STATUS_IS_ERR(retval)) { DEBUG(5, (" handle (%x) not found: %x\n", handle, mapi_req->handle_idx)); mapi_repl->error_code = MAPI_E_NO_SUPPORT; goto end; } /* GetContentsTable can only be called for folder objects */ retval = mapi_handles_get_private_data(parent, &data); if (MAPI_STATUS_IS_ERR(retval)) { mapi_repl->error_code = retval; DEBUG(5, (" handle data not found, idx = %x\n", mapi_req->handle_idx)); goto end; } parent_object = (struct emsmdbp_object *)data; if (!parent_object) { mapi_repl->error_code = MAPI_E_NO_SUPPORT; DEBUG(5, (" handle data not found, idx = %x\n", mapi_req->handle_idx)); goto end; } if (parent_object->type != EMSMDBP_OBJECT_FOLDER) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } folderID = parent_object->object.folder->folderID; if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_Associated)) { DEBUG(5, (" table is FAI table\n")); table_type = MAPISTORE_FAI_TABLE; } else { DEBUG(5, (" table is contents table\n")); table_type = MAPISTORE_MESSAGE_TABLE; } /* Initialize Table object */ retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec); if (MAPI_STATUS_IS_ERR(retval)) { mapi_repl->error_code = retval; goto end; } handles[mapi_repl->handle_idx] = rec->handle; object = emsmdbp_folder_open_table(rec, parent_object, table_type, rec->handle); if (!object) { mapi_handles_delete(emsmdbp_ctx->handles_ctx, rec->handle); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } mapi_handles_set_private_data(rec, object); mapi_repl->u.mapi_GetContentsTable.RowCount = object->object.table->denominator; /* notifications */ if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_NoNotifications)) { DEBUG(5, (" notifications skipped\n")); } else { /* we attach the subscription to the session object */ subscription_list = talloc_zero(emsmdbp_ctx->mstore_ctx, struct mapistore_subscription_list); DLIST_ADD(emsmdbp_ctx->mstore_ctx->subscriptions, subscription_list); if ((mapi_req->u.mapi_GetContentsTable.TableFlags & TableFlags_Associated)) { subscription_parameters.table_type = MAPISTORE_FAI_TABLE; } else { subscription_parameters.table_type = MAPISTORE_MESSAGE_TABLE; } subscription_parameters.folder_id = folderID; /* note that a mapistore_subscription can exist without a corresponding emsmdbp_object (tables) */ subscription = mapistore_new_subscription(subscription_list, emsmdbp_ctx->mstore_ctx, emsmdbp_ctx->username, rec->handle, fnevTableModified, &subscription_parameters); subscription_list->subscription = subscription; object->object.table->subscription_list = subscription_list; } end: *size += libmapiserver_RopGetContentsTable_size(mapi_repl); return MAPI_E_SUCCESS; }
/** \details EcDoRpc EmptyFolder (0x58) Rop. This operation removes the sub-folders and messages from a given parent folder. \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the emsmdb provider context \param mapi_req pointer to the EmptyFolder EcDoRpc_MAPI_REQ structure \param mapi_repl pointer to the EmptyFolder EcDoRpc_MAPI_REPL structure \param handles pointer to the MAPI handles array \param size pointer to the mapi_response size to update \return MAPI_E_SUCCESS on success, otherwise MAPI error */ enum MAPISTATUS EcDoRpc_RopMoveFolder(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; enum mapistore_error ret; uint32_t handle; struct mapi_handles *handle_object; void *private_data; struct MoveFolder_req *request; struct MoveFolder_repl *response; struct emsmdbp_object *source_parent; struct emsmdbp_object *move_folder; struct emsmdbp_object *target_folder; DEBUG(4, ("exchange_emsmdb: [OXCFOLD] MoveFolder (0x35)\n")); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); mapi_repl->opnum = mapi_req->opnum; mapi_repl->handle_idx = mapi_req->handle_idx; mapi_repl->error_code = MAPI_E_SUCCESS; request = &mapi_req->u.mapi_MoveFolder; response = &mapi_repl->u.mapi_MoveFolder; /* Retrieve the source parent handle in the hierarchy */ handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &handle_object); if (retval) { DEBUG(5, (" handle (%x) not found: %x\n", handle, mapi_req->handle_idx)); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } mapi_handles_get_private_data(handle_object, &private_data); source_parent = private_data; if (!source_parent || source_parent->type != EMSMDBP_OBJECT_FOLDER) { DEBUG(5, (" invalid handle (%x): %x\n", handle, mapi_req->handle_idx)); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } /* Open the folder being moved as it will be the actor object in this process */ ret = emsmdbp_object_open_folder(mem_ctx, emsmdbp_ctx, source_parent, request->FolderId, &move_folder); if (ret != MAPISTORE_SUCCESS) { mapi_repl->error_code = mapistore_error_to_mapi(ret); goto end; } /* Retrieve the destination parent handle in the hierarchy */ handle = handles[request->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &handle_object); if (retval) { DEBUG(5, (" handle (%x) not found: %x\n", handle, mapi_req->handle_idx)); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } mapi_handles_get_private_data(handle_object, &private_data); target_folder = private_data; if (!target_folder || target_folder->type != EMSMDBP_OBJECT_FOLDER) { DEBUG(5, (" invalid handle (%x): %x\n", handle, mapi_req->handle_idx)); mapi_repl->error_code = MAPI_E_INVALID_OBJECT; goto end; } ret = emsmdbp_folder_move_folder(emsmdbp_ctx, move_folder, target_folder, mem_ctx, request->NewFolderName.lpszW); mapi_repl->error_code = mapistore_error_to_mapi(ret); response->PartialCompletion = false; end: *size += libmapiserver_RopMoveFolder_size(mapi_repl); handles[mapi_repl->handle_idx] = handles[mapi_req->handle_idx]; return MAPI_E_SUCCESS; }