Beispiel #1
0
/**
   \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;
}
Beispiel #2
0
} 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);
}
Beispiel #3
0
/**
   \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;
}
Beispiel #4
0
/**
   \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;
}
Beispiel #5
0
/**
   \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;
}
Beispiel #6
0
/**
   \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;
}