/** \details Test dump using mapidump_SRowSet This function: -# Tests the mapidump_SRowSet() function -# Indirectly tests the mapidump_SRow() function \param mt pointer to the top-level mapitest structure \return true on success, otherwise false \note This currently doesn't check the results are sane, so manual inspection is required */ _PUBLIC_ bool mapitest_mapidump_srowset(struct mapitest *mt) { struct SRowSet srowset; struct SPropValue SPropValue; srowset.cRows = 2; srowset.aRow = talloc_array(mt->mem_ctx, struct SRow, srowset.cRows); srowset.aRow[0].cValues = 0; srowset.aRow[0].lpProps = talloc_zero(mt->mem_ctx, struct SPropValue); SPropValue.ulPropTag = PR_OBJECT_TYPE; SPropValue.value.l = MAPI_MAILUSER; SRow_addprop(&(srowset.aRow[0]), SPropValue); SPropValue.ulPropTag = PR_DISPLAY_TYPE; SPropValue.value.l = 0; SRow_addprop(&(srowset.aRow[0]), SPropValue); SPropValue.ulPropTag = PR_GIVEN_NAME; SPropValue.value.lpszA = "gname"; SRow_addprop(&(srowset.aRow[0]), SPropValue); srowset.aRow[1].cValues = 0; srowset.aRow[1].lpProps = talloc_zero(mt->mem_ctx, struct SPropValue); SPropValue.ulPropTag = PR_GIVEN_NAME; SPropValue.value.lpszA = "kname"; SRow_addprop(&(srowset.aRow[1]), SPropValue); SPropValue.ulPropTag = PR_7BIT_DISPLAY_NAME; SPropValue.value.lpszA = "lname"; SRow_addprop(&(srowset.aRow[1]), SPropValue); mapidump_SRowSet(&srowset, "[sep]"); return true; }
} END_TEST // ^ unit tests --------------------------------------------------------------- // v suite definition --------------------------------------------------------- static void _make_test_srow(TALLOC_CTX *mem_ctx) { struct SPropValue prop_val; ZERO_STRUCT(prop_val); /* PT_I8 */ prop_val.ulPropTag = PR_FID; prop_val.value.d = 0x0123456789ABCDEFul; SRow_addprop(test_srow, prop_val); /* PT_MV_STRING8 */ prop_val.ulPropTag = PR_EMS_AB_PROXY_ADDRESSES; prop_val.value.MVszA.cValues = 2; prop_val.value.MVszA.lppszA = talloc_array(test_srow, const char *, prop_val.value.MVszA.cValues); prop_val.value.MVszA.lppszA[0] = "string 1"; prop_val.value.MVszA.lppszA[1] = "string 2"; SRow_addprop(test_srow, prop_val); /* PT_MV_UNICODE - same layout as PT_MV_STRING8 */ prop_val.ulPropTag = PR_EMS_AB_PROXY_ADDRESSES_UNICODE; SRow_addprop(test_srow, prop_val); /* PT_MV_BINARY */ prop_val.ulPropTag = PR_FREEBUSY_ENTRYIDS; prop_val.value.MVbin.cValues = 2; prop_val.value.MVbin.lpbin = talloc_array(test_srow, struct Binary_r, prop_val.value.MVbin.cValues); prop_val.value.MVbin.lpbin[0].cb = 9; prop_val.value.MVbin.lpbin[0].lpb = (uint8_t *)"string 1"; prop_val.value.MVbin.lpbin[1].cb = 9; prop_val.value.MVbin.lpbin[1].lpb = (uint8_t *)"string 2"; SRow_addprop(test_srow, prop_val); }
/** \details Test dump of a set of recipients This function: -# builds a recipient list -# dumps out the recipient list using mapidump_Recipients() \param mt pointer to the top-level mapitest structure \return true on success, otherwise false \note This currently doesn't check the results are sane, so manual inspection is required */ _PUBLIC_ bool mapitest_mapidump_recipients(struct mapitest *mt) { const char **userlist; struct SRowSet resolved; struct PropertyTagArray_r flaglist; struct SPropValue SPropValue; userlist = talloc_array(mt->mem_ctx, const char*, 3); userlist[0] = "Mr. Unresolved"; userlist[1] = "Mr/Ms. Ambiguous"; userlist[2] = "Mrs. Resolved"; resolved.cRows = 1; resolved.aRow = talloc_array(mt->mem_ctx, struct SRow, resolved.cRows); resolved.aRow[0].cValues = 0; resolved.aRow[0].lpProps = talloc_zero(mt->mem_ctx, struct SPropValue); SPropValue.ulPropTag = PR_OBJECT_TYPE; SPropValue.value.l = MAPI_MAILUSER; SRow_addprop(&(resolved.aRow[0]), SPropValue); SPropValue.ulPropTag = PR_GIVEN_NAME; SPropValue.value.lpszA = "gname"; SRow_addprop(&(resolved.aRow[0]), SPropValue); flaglist.cValues = 3; flaglist.aulPropTag = talloc_zero_array(mt->mem_ctx, uint32_t, flaglist.cValues); flaglist.aulPropTag[0] = MAPI_UNRESOLVED; flaglist.aulPropTag[1] = MAPI_AMBIGUOUS; flaglist.aulPropTag[2] = MAPI_RESOLVED; mapidump_Recipients(userlist, &resolved, &flaglist); talloc_free(flaglist.aulPropTag); return true; }
/** \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 Opens a specific message and retrieves a MAPI object that can be used to get or set message properties. This function opens a specific message defined by a combination of object store, folder ID, and message ID and which read/write access is defined by ulFlags. \param obj_store the store to read from \param id_folder the folder ID \param id_message the message ID \param obj_message the resulting message object \param ulFlags Possible ulFlags values: - 0x0: read only access - 0x1: ReadWrite - 0x3: Create - 0x4: OpenSoftDeleted \return MAPI_E_SUCCESS on success, otherwise MAPI error. \note Developers may also call GetLastError() to retrieve the last MAPI error code. Possible MAPI error codes are: - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized - MAPI_E_INVALID_PARAMETER: obj_store is undefined - MAPI_E_CALL_FAILED: A network problem was encountered during the transaction \sa MAPIInitialize, GetLastError */ _PUBLIC_ enum MAPISTATUS OpenMessage(mapi_object_t *obj_store, mapi_id_t id_folder, mapi_id_t id_message, mapi_object_t *obj_message, uint8_t ulFlags) { struct mapi_context *mapi_ctx; struct mapi_request *mapi_request; struct mapi_response *mapi_response; struct EcDoRpc_MAPI_REQ *mapi_req; struct OpenMessage_req request; struct OpenMessage_repl *reply; struct mapi_session *session; mapi_object_message_t *message; struct SPropValue lpProp; const char *tstring; NTSTATUS status; enum MAPISTATUS retval; uint32_t size = 0; TALLOC_CTX *mem_ctx; uint32_t i = 0; uint8_t logon_id; /* Sanity checks */ OPENCHANGE_RETVAL_IF(!obj_store, MAPI_E_INVALID_PARAMETER, NULL); session = mapi_object_get_session(obj_store); OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL); mapi_ctx = session->mapi_ctx; OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL); if ((retval = mapi_object_get_logon_id(obj_store, &logon_id)) != MAPI_E_SUCCESS) return retval; mem_ctx = talloc_named(session, 0, "OpenMessage"); /* Fill the OpenMessage operation */ request.handle_idx = 0x1; request.CodePageId = 0xfff; request.FolderId = id_folder; request.OpenModeFlags = (enum OpenMessage_OpenModeFlags)ulFlags; request.MessageId = id_message; size = sizeof (uint8_t) + sizeof(uint16_t) + sizeof(mapi_id_t) + sizeof(uint8_t) + sizeof(mapi_id_t); /* Fill the MAPI_REQ request */ mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ); mapi_req->opnum = op_MAPI_OpenMessage; mapi_req->logon_id = logon_id; mapi_req->handle_idx = 0; mapi_req->u.mapi_OpenMessage = request; size += 5; /* Fill the mapi_request structure */ mapi_request = talloc_zero(mem_ctx, struct mapi_request); mapi_request->mapi_len = size + sizeof (uint32_t) * 2; mapi_request->length = size; mapi_request->mapi_req = mapi_req; mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2); mapi_request->handles[0] = mapi_object_get_handle(obj_store); mapi_request->handles[1] = 0xffffffff; status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response); OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx); OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx); retval = mapi_response->mapi_repl->error_code; OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx); OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response); /* Set object session and handle */ mapi_object_set_session(obj_message, session); mapi_object_set_handle(obj_message, mapi_response->handles[1]); mapi_object_set_logon_id(obj_message, logon_id); /* Store OpenMessage reply data */ reply = &mapi_response->mapi_repl->u.mapi_OpenMessage; message = talloc_zero((TALLOC_CTX *)session, mapi_object_message_t); tstring = get_TypedString(&reply->SubjectPrefix); if (tstring) { message->SubjectPrefix = talloc_strdup((TALLOC_CTX *)message, tstring); } tstring = get_TypedString(&reply->NormalizedSubject); if (tstring) { message->NormalizedSubject = talloc_strdup((TALLOC_CTX *)message, tstring); } message->cValues = reply->RecipientColumns.cValues; message->SRowSet.cRows = reply->RowCount; message->SRowSet.aRow = talloc_array((TALLOC_CTX *)message, struct SRow, reply->RowCount + 1); message->SPropTagArray.cValues = reply->RecipientColumns.cValues; message->SPropTagArray.aulPropTag = talloc_steal(message, reply->RecipientColumns.aulPropTag); for (i = 0; i < reply->RowCount; i++) { emsmdb_get_SRow((TALLOC_CTX *)message, &(message->SRowSet.aRow[i]), &message->SPropTagArray, reply->RecipientRows[i].RecipientRow.prop_count, &reply->RecipientRows[i].RecipientRow.prop_values, reply->RecipientRows[i].RecipientRow.layout, 1); lpProp.ulPropTag = PR_RECIPIENT_TYPE; lpProp.value.l = reply->RecipientRows[i].RecipientType; SRow_addprop(&(message->SRowSet.aRow[i]), lpProp); lpProp.ulPropTag = PR_INTERNET_CPID; lpProp.value.l = reply->RecipientRows[i].CodePageId; SRow_addprop(&(message->SRowSet.aRow[i]), lpProp); } /* add SPropTagArray elements we automatically append to SRow */ SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_RECIPIENT_TYPE); SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_INTERNET_CPID); obj_message->private_data = (void *) message; talloc_free(mapi_response); talloc_free(mem_ctx); return MAPI_E_SUCCESS; }
/** \details Retrieve the message properties for an already open message. This function is very similar to OpenMessage, but works on an already open message object. \param obj_message the message object to retrieve the properties for. \return MAPI_E_SUCCESS on success, otherwise MAPI error. \note Developers may also call GetLastError() to retrieve the last MAPI error code. Possible MAPI error codes are: - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized - MAPI_E_INVALID_PARAMETER: obj_store is undefined - MAPI_E_CALL_FAILED: A network problem was encountered during the transaction \sa OpenMessage */ _PUBLIC_ enum MAPISTATUS ReloadCachedInformation(mapi_object_t *obj_message) { struct mapi_context *mapi_ctx; struct mapi_request *mapi_request; struct mapi_response *mapi_response; struct EcDoRpc_MAPI_REQ *mapi_req; struct ReloadCachedInformation_req request; struct ReloadCachedInformation_repl *reply; struct mapi_session *session; mapi_object_message_t *message; struct SPropValue lpProp; NTSTATUS status; enum MAPISTATUS retval; uint32_t size = 0; TALLOC_CTX *mem_ctx; uint32_t i = 0; uint8_t logon_id; /* Sanity checks */ OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL); session = mapi_object_get_session(obj_message); OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL); mapi_ctx = session->mapi_ctx; OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL); if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS) return retval; mem_ctx = talloc_named(session, 0, "ReloadCachedInformation"); /* Fill the ReloadCachedInformation operation */ request.Reserved = 0x0000; size += sizeof (uint16_t); /* Fill the MAPI_REQ request */ mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ); mapi_req->opnum = op_MAPI_ReloadCachedInformation; mapi_req->logon_id = logon_id; mapi_req->handle_idx = 0; mapi_req->u.mapi_ReloadCachedInformation = request; size += 5; /* Fill the mapi_request structure */ mapi_request = talloc_zero(mem_ctx, struct mapi_request); mapi_request->mapi_len = size + sizeof (uint32_t); mapi_request->length = size; mapi_request->mapi_req = mapi_req; mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1); mapi_request->handles[0] = mapi_object_get_handle(obj_message); status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response); OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx); OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx); retval = mapi_response->mapi_repl->error_code; OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx); OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response); /* Store ReloadCachedInformation reply data */ reply = &mapi_response->mapi_repl->u.mapi_ReloadCachedInformation; message = talloc_zero((TALLOC_CTX *)session, mapi_object_message_t); message->cValues = reply->RecipientColumns.cValues; message->SRowSet.cRows = reply->RowCount; message->SRowSet.aRow = talloc_array((TALLOC_CTX *)message, struct SRow, reply->RowCount + 1); message->SPropTagArray.cValues = reply->RecipientColumns.cValues; message->SPropTagArray.aulPropTag = talloc_steal(message, reply->RecipientColumns.aulPropTag); for (i = 0; i < reply->RowCount; i++) { emsmdb_get_SRow((TALLOC_CTX *)message, &(message->SRowSet.aRow[i]), &message->SPropTagArray, reply->RecipientRows[i].RecipientRow.prop_count, &reply->RecipientRows[i].RecipientRow.prop_values, reply->RecipientRows[i].RecipientRow.layout, 1); lpProp.ulPropTag = PR_RECIPIENT_TYPE; lpProp.value.l = reply->RecipientRows[i].RecipientType; SRow_addprop(&(message->SRowSet.aRow[i]), lpProp); lpProp.ulPropTag = PR_INTERNET_CPID; lpProp.value.l = reply->RecipientRows[i].CodePageId; SRow_addprop(&(message->SRowSet.aRow[i]), lpProp); } /* add SPropTagArray elements we automatically append to SRow */ SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_RECIPIENT_TYPE); SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_INTERNET_CPID); talloc_free(obj_message->private_data); obj_message->private_data = (void *) message; talloc_free(mapi_response); talloc_free(mem_ctx); errno = 0; return MAPI_E_SUCCESS; }