/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2008 OMC Denmark ApS.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma warning(disable : 4996)
#pragma warning(disable : 6011)

#include "IMAPISessionS_impl.h"

#include "utils/fileops.h"

#include "obj_utils.h"
#include "conv_utils.h"
#include "istream_utils.h"
#include "edkguid.h"
#include "guid.h"
#include "brutus_defines.h"

#include "IMAPITableS_impl.h"
#include "IMsgStoreS_impl.h"
#include "IAddrBookS_impl.h"
#include "IProfSectS_impl.h"
#include "IMAPIFolderS_impl.h"
#include "IABContainerS_impl.h"
#include "IMessageS_impl.h"
#include "IAttachS_impl.h"
#include "IDistListS_impl.h"
#include "IMAPIStatusS_impl.h"
#include "IMailUserS_impl.h"
#include "IMsgServiceAdminS_impl.h"
#include "ITnefS_impl.h"
#include "IProfAdminS_impl.h"
#include "IPropDataS_impl.h"

#include "templates.i"

#include <lm.h>
#include <mapiutil.h>

#include <iostream>
#include <fstream>
using namespace std;

// from conv_utils.h
unsigned long local_code_page = 0;

static HANDLE CLIENT_DEAD_HANDLE = NULL;

static inline unsigned long
native_message_store_flags(const ::BRUTUS::BDEFINE Flags)
{
	if (Flags & ::BRUTUS::BRUTUS_MAPI_DEFAULT_STORE)
		return MAPI_DEFAULT_STORE;

	if (Flags & ::BRUTUS::BRUTUS_MAPI_SIMPLE_STORE_TEMPORARY)
		return MAPI_SIMPLE_STORE_TEMPORARY;

	if (Flags & ::BRUTUS::BRUTUS_MAPI_SIMPLE_STORE_PERMANENT)
		return MAPI_SIMPLE_STORE_PERMANENT;

	if (Flags & ::BRUTUS::BRUTUS_MAPI_PRIMARY_STORE)
		return MAPI_PRIMARY_STORE;

	if (Flags & ::BRUTUS::BRUTUS_MAPI_SECONDARY_STORE)
		return MAPI_SECONDARY_STORE;

	{
		char msg[128] = {0};
		sprintf_s(msg, sizeof(msg), "Unknown message store flag from BRUTUS : %X", Flags);
		BRUTUS_LOG_BUG(msg);

		return 0;
	}
}

static inline ULONG
native_flags(const ::BRUTUS::BDEFINE ulFlags)
{
	::BRUTUS::BDEFINE flags = ulFlags;
	ULONG retval = 0;

	if (!ulFlags)
		return 0;

	if (flags & ::BRUTUS::BRUTUS_MAPI_UNICODE) {
		retval |= MAPI_UNICODE;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_UNICODE);
	}
	if (flags & ::BRUTUS::BRUTUS_MAPI_BEST_ACCESS) {
		retval |= MAPI_BEST_ACCESS;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_BEST_ACCESS);
	}
	if (flags & ::BRUTUS::BRUTUS_MAPI_DEFERRED_ERRORS) {
		retval |= MAPI_DEFERRED_ERRORS;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_DEFERRED_ERRORS);
	}
	if (flags & ::BRUTUS::BRUTUS_MDB_ONLINE) {
		retval |= MDB_ONLINE;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MDB_ONLINE);
	}
	if (flags & ::BRUTUS::BRUTUS_MDB_NO_MAIL) {
		retval |= MDB_NO_MAIL;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MDB_NO_MAIL);
	}
	if (flags & ::BRUTUS::BRUTUS_MDB_TEMPORARY) {
		retval |= MDB_TEMPORARY;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MDB_TEMPORARY);
	}
	if (flags & ::BRUTUS::BRUTUS_MDB_WRITE) {
		retval |= MDB_WRITE;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MDB_WRITE);
	}
	if (flags & ::BRUTUS::BRUTUS_MAPI_MODIFY) {
		retval |= MAPI_MODIFY;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_MODIFY);
	}
	if (flags & ::BRUTUS::BRUTUS_OPENSTORE_HOME_LOGON) {
		retval |= OPENSTORE_HOME_LOGON;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_OPENSTORE_HOME_LOGON);
	}
	if (flags & ::BRUTUS::BRUTUS_OPENSTORE_OVERRIDE_HOME_MDB) {
		retval |= OPENSTORE_OVERRIDE_HOME_MDB;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_OPENSTORE_OVERRIDE_HOME_MDB);
	}
	if (flags & ::BRUTUS::BRUTUS_OPENSTORE_PUBLIC) {
		retval |= OPENSTORE_PUBLIC;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_OPENSTORE_PUBLIC);
	}
	if (flags & ::BRUTUS::BRUTUS_OPENSTORE_TAKE_OWNERSHIP) {
		retval |= OPENSTORE_TAKE_OWNERSHIP;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_OPENSTORE_TAKE_OWNERSHIP);
	}
	if (flags & ::BRUTUS::BRUTUS_OPENSTORE_USE_ADMIN_PRIVILEGE) {
		retval |= OPENSTORE_USE_ADMIN_PRIVILEGE;
		FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_OPENSTORE_USE_ADMIN_PRIVILEGE);
	}

	if (flags) {
		char msg[128] = {0};
		sprintf_s(msg, sizeof(msg), "Unknown flag(s) from BRUTUS : %X", flags);
		BRUTUS_LOG_BUG(msg);
	}

	return retval;
}

static inline ULONG
native_eventmask(const ::BRUTUS::BDEFINE EventMask)
{
	::BRUTUS::BDEFINE event_mask = EventMask;
	ULONG retval = 0;

	if (!EventMask)
		return 0;

	if (event_mask & ::BRUTUS::BRUTUS_fnevCriticalError) {
		retval |= fnevCriticalError;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevCriticalError);
	}

	if (event_mask & ::BRUTUS::BRUTUS_fnevNewMail) {
		retval |= fnevNewMail;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevNewMail);
	}

	if (event_mask & ::BRUTUS::BRUTUS_fnevObjectCreated) {
		retval |= fnevObjectCreated;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevObjectCreated);
	}

	if (event_mask & ::BRUTUS::BRUTUS_fnevObjectDeleted) {
		retval |= fnevObjectDeleted;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevObjectDeleted);
	}

	if (event_mask & ::BRUTUS::BRUTUS_fnevObjectModified) {
		retval |= fnevObjectModified;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevObjectModified);
	}

	if (event_mask & ::BRUTUS::BRUTUS_fnevObjectMoved) {
		retval |= fnevObjectMoved;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevObjectMoved);
	}

	if (event_mask & ::BRUTUS::BRUTUS_fnevObjectCopied) {
		retval |= fnevObjectCopied;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevObjectCopied);
	}

	if (event_mask & ::BRUTUS::BRUTUS_fnevSearchComplete) {
		retval |= fnevSearchComplete;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevSearchComplete);
	}

	if (event_mask & ::BRUTUS::BRUTUS_fnevTableModified) {
		retval |= fnevTableModified;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevTableModified);
	}

	if (event_mask & ::BRUTUS::BRUTUS_fnevStatusObjectModified) {
		retval |= fnevStatusObjectModified;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevStatusObjectModified);
	}

	if (event_mask & ::BRUTUS::BRUTUS_fnevReservedForMapi) {
		retval |= fnevReservedForMapi;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevReservedForMapi);
	}

	if (event_mask & ::BRUTUS::BRUTUS_fnevExtended) {
		retval |= fnevExtended;
		FLAGS_OFF(::BRUTUS::BDEFINE, event_mask, ::BRUTUS::BRUTUS_fnevExtended);
	}

	if (event_mask) {
		char msg[128] = {0};
		sprintf_s(msg, sizeof(msg), "Unknown event mask flag(s) from BRUTUS : %X", event_mask);
		BRUTUS_LOG_BUG(msg);
	}


	return retval;
}

static HRESULT
get_default_message_store(LPMAPISESSION Session,
			  LPMDB *DefMsgStore)
{
	BRUTUS_LOG_INF("Entering get_default_message_store()");

	ULONG cRows = 0;
	LPSRowSet lpRows = NULL;
	LPENTRYID entry_id = NULL;
	ULONG entry_id_size = 0;
	ULONG i;

	// Columns to return from the table
	SizedSPropTagArray(2, prop_tags) = {2, {PR_DEFAULT_STORE, PR_ENTRYID} };

	// Get list of available message stores
	HRESULT hr;
	LPMAPITABLE mapi_table = NULL;
	hr = Session->GetMsgStoresTable(0, &mapi_table);
	if (S_OK != hr)
		goto exit;

	// Get row count
	hr = mapi_table->GetRowCount(0, &cRows);
	if ((S_OK != hr) || !cRows)
		goto exit;

	// Select columns to return from the table
	hr = mapi_table->SetColumns((LPSPropTagArray)&prop_tags, 0);
	if (S_OK != hr)
		goto exit;

	// Go to the beginning of the recipient table for the envelope
	hr = mapi_table->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
	if (S_OK != hr)
		goto exit;

	// Read all the rows of the table
	hr = mapi_table->QueryRows(cRows, 0, &lpRows);
	if ((S_OK == hr) && lpRows && (lpRows->cRows == 0))
		goto exit;

	mapi_table->Release();
	mapi_table = NULL;

	for (i = 0; i < cRows; i++) {
		// check PR_DEFAULT_STORE boolean
		if (lpRows && (TRUE == lpRows->aRow[i].lpProps[0].Value.b)) {
			entry_id = (LPENTRYID)lpRows->aRow[i].lpProps[1].Value.bin.lpb;
			entry_id_size = lpRows->aRow[i].lpProps[1].Value.bin.cb;
			break;
		}
	}

	ULONG flags = MAPI_BEST_ACCESS | MDB_NO_DIALOG | MDB_ONLINE;
	do {
		hr = Session->OpenMsgStore(0,
					   entry_id_size,
					   entry_id,
					   NULL,
					   flags,
					   DefMsgStore);
		if (S_OK == hr)
			break;

		if (MAPI_E_UNKNOWN_FLAGS != hr)
			break;

		flags &= ~MDB_ONLINE; // Exchange 5.5/2000 does not understand this flag
		hr = Session->OpenMsgStore(0,
					   entry_id_size,
					   entry_id,
					   NULL,
					   flags,
					   DefMsgStore);
	} while (false);

exit:
	if (S_OK != hr)
		BRUTUS_LOG_HR;

	if (lpRows)
		FreeProws(lpRows);
	if (mapi_table)
		mapi_table->Release();

	BRUTUS_LOG_INF("Leaving get_default_message_store()");

	return hr;
}

struct life_line_thread_args {
	unsigned long delay;
	BRUTUS_IMAPISession_i *session;
	HANDLE client_handle;
};

unsigned __stdcall
LifeLineThreadProc(LPVOID lpParameter)
{
	struct life_line_thread_args *args = (struct life_line_thread_args*)lpParameter;
	BRUTUS_IMAPISession_i *session = args->session;
	unsigned long delay = 0;

	if (!args->delay) // minimum supervising
		args->delay = 86400;
	else if (args->delay > 86400) // (24 hours) we won't wait for eternity
		args->delay = 86400;

	delay = args->delay * 1000; // to miliseconds - 0x7FFFFFFF is the maximum number which is not equal to infinity

	do {
		if (WAIT_TIMEOUT != WaitForSingleObject(args->client_handle, delay))
			break;

		session->checkLifelines();
	} while (true);

 	CloseHandle(args->client_handle);
 	HeapFree(GetProcessHeap(), 0, lpParameter);

	return 0;
}


BRUTUS_IMAPISession_i::BRUTUS_IMAPISession_i(LPMAPISESSION MAPISession,
					     ::PortableServer::POA_ptr Poa,
					     ::CORBA::ORB_ptr orb,
					     ::BRUTUS::BrutusCheck_ptr LifeLine,
					     const unsigned long LifeCheckDelay,
					     void (*shutDown)(void))
	: mapi_session_(MAPISession),
	  poa_(::PortableServer::POA::_duplicate(Poa)),
	  refcount_(1),
	  orb_(::CORBA::ORB::_duplicate(orb)),
	  shutdown_(shutDown),
	  life_line_counter_(0)
{
	advise_sinks_.Clear();

	{ // add the first lifeline
		ACE_Write_Guard<ACE_RW_Mutex> guard(life_check_mutex_);
		life_lines_.clear();
		life_lines_.push_back(new LifeCheck(LifeLine, life_line_counter_));
	}

	/*********************************************/
	/* Create a thread to check for dead clients */
	/*********************************************/

	CLIENT_DEAD_HANDLE = CreateEvent(NULL, true, false, NULL);
	if (!CLIENT_DEAD_HANDLE)
		throw ::CORBA::NO_MEMORY();

	HANDLE life_thread = NULL;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);

		// launch thread to validate the lifeline
		struct life_line_thread_args *args = NULL;
		try {
			args = (struct life_line_thread_args*)HeapAlloc(GetProcessHeap(),
									0,
									sizeof(struct life_line_thread_args));
		}
		catch (...) {
			throw ::CORBA::NO_MEMORY();
		}
		if (!args) {
			throw ::CORBA::NO_MEMORY();
		}
		args->delay = LifeCheckDelay;
		args->session = this;
		args->client_handle = CLIENT_DEAD_HANDLE;

		life_thread = (HANDLE)_beginthreadex(NULL,
						     0,
						     LifeLineThreadProc,
						     (void*)args,
						     CREATE_SUSPENDED,
						     NULL);
		if (!life_thread)
			throw ::CORBA::NO_MEMORY();
		SetThreadPriority(life_thread, THREAD_PRIORITY_LOWEST);
	}
	if (life_thread) {
		ResumeThread(life_thread);
	}
}


::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::GetLastError(::BRUTUS::BRESULT ReturnCode,
				    ::BRUTUS::BDEFINE ulFlags,
				    ::BRUTUS::MAPIERROR_out lppMAPIError)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::GetLastError()");

	::BRUTUS::MAPIERROR_var error;
	try {
		error = new ::BRUTUS::MAPIERROR;
	}
	catch (std::bad_alloc &) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}
	error->ulVersion = (::CORBA::ULong)0;
	error->ulLowLevelError = (::CORBA::ULong)0;
	error->ulContext = (::CORBA::ULong)0;

	LPMAPIERROR mapi_error = NULL;
	unsigned long flags = native_flags(ulFlags);

	HRESULT hr;
	::BRUTUS::BRESULT br;
	if (!bresult_to_hresult(ReturnCode, hr)) {
		lppMAPIError = error._retn();
		BRUTUS_LOG_BUG("Could not convert BRESULT into HRESULT");
		br = ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
		BRUTUS_EXIT;
	}

	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->GetLastError(hr, flags, &mapi_error);
	}

	if (!hresult_to_bresult(hr, br)) {
		MAPIFreeBuffer(mapi_error);
		lppMAPIError = error._retn();
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}
	if (!mapi_error)
		BRUTUS_LOG_INF("No applicable error information from MAPI");

	mapierror_mapi_to_brutus(mapi_error, error, true);

	lppMAPIError = error._retn();

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::GetLastError()");
	return br;
}


::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::GetMsgStoresTable(::BRUTUS::BDEFINE ulFlags,
					 ::BRUTUS::IMAPITable_out lppTable)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::GetMsgStoresTable()");

	lppTable = ::BRUTUS::IMAPITable::_nil();
	LPMAPITABLE mapi_table = NULL;
	unsigned long flags = native_flags(ulFlags);

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->GetMsgStoresTable(flags, &mapi_table);
	}

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

	if (S_OK == hr) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lppTable = create_object<BRUTUS_IMAPITable_i, ::BRUTUS::IMAPITable, LPMAPITABLE>
			(mapi_table, poa_.in(), mapi_session_);
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::GetMsgStoresTable()");
	return br;
}


::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::OpenMsgStore(const ::BRUTUS::ENTRYID &lpEntryID,
				    const char *lpInterface,
				    ::BRUTUS::BDEFINE ulFlags,
				    ::BRUTUS::IMsgStore_out lppMDB)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::OpenMsgStore()");

	lppMDB = ::BRUTUS::IMsgStore::_nil();
	unsigned long flags = native_flags(ulFlags) | MDB_NO_DIALOG;

	GUID* i_id;
	if (!guid_brutus_to_mapi(lpInterface, NULL, i_id)) {
		BRUTUS_LOG_BUG("Could not convert ::BRUTUS::GUID into MAPI GUID");
		return ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
	}

	ENTRYID *entry_id;
	unsigned long entry_id_size;
	if (!entryid_brutus_to_mapi(&lpEntryID, 0, entry_id_size, entry_id)) {
		MAPIFreeBuffer(i_id);
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	LPMDB msg_store = NULL;
	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->OpenMsgStore(0,
						 entry_id_size,
						 entry_id,
						 i_id,
						 flags,
						 &msg_store);
	}
	if (S_OK != hr)
		BRUTUS_LOG_HR;
	MAPIFreeBuffer(entry_id);
	MAPIFreeBuffer(i_id);

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

	if ((S_OK == hr) || (MAPI_W_ERRORS_RETURNED == hr)) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lppMDB = create_object<BRUTUS_IMsgStore_i, ::BRUTUS::IMsgStore, LPMDB>
			(msg_store, poa_.in(), mapi_session_);
	}
exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::OpenMsgStore()");
	return br;
}


::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::OpenAddressBook(const char *lpInterface,
				       ::BRUTUS::BDEFINE ulFlags,
				       ::BRUTUS::IAddrBook_out lppAdrBook)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::OpenAddressBook()");

	lppAdrBook = ::BRUTUS::IAddrBook::_nil();

	unsigned long flags = native_flags(ulFlags);
	flags |= AB_NO_DIALOG;

	GUID *i_id;
	if (!guid_brutus_to_mapi(lpInterface, NULL, i_id)) {
		BRUTUS_LOG_BUG("Could not convert ::BRUTUS::GUID into MAPI GUID");
		return ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
	}

	LPADRBOOK addr_book = NULL;

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->OpenAddressBook(0,
						    i_id,
						    flags,
						    &addr_book);
	}
	MAPIFreeBuffer(i_id);

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}
	if ((S_OK == hr) || (MAPI_W_ERRORS_RETURNED == hr)) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lppAdrBook = create_object<BRUTUS_IAddrBook_i, ::BRUTUS::IAddrBook, LPADRBOOK>
			(addr_book, poa_.in(), mapi_session_);
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::OpenAddressBook()");
	return br;
}


::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::OpenProfileSection(const char *lpUID,
					  const char *lpInterface,
					  ::BRUTUS::BDEFINE ulFlags,
					  ::BRUTUS::IProfSect_out lppProfSect)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::OpenProfileSection()");

	lppProfSect = ::BRUTUS::IProfSect::_nil();

	MAPIUID u_id;
	mapiuid_brutus_to_mapi_no_alloc(lpUID, u_id);


	GUID *i_id;
	if (!guid_brutus_to_mapi(lpInterface, NULL, i_id)) {
		BRUTUS_LOG_BUG("Could not convert ::BRUTUS::GUID into MAPI GUID");
		return ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
	}

	unsigned long flags = native_flags(ulFlags);
	LPPROFSECT prof_sect = NULL;

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->OpenProfileSection(&u_id,
						       i_id,
						       flags,
						       &prof_sect);
	}
	MAPIFreeBuffer(i_id);

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

	if (S_OK == hr) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lppProfSect = create_object<BRUTUS_IProfSect_i, ::BRUTUS::IProfSect, LPPROFSECT>
			(prof_sect, poa_.in(), mapi_session_);
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::OpenProfileSection()");
	return br;
}


::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::GetStatusTable(::BRUTUS::BDEFINE ulFlags,
				      ::BRUTUS::IMAPITable_out lppTable)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::GetStatusTable()");

	lppTable = ::BRUTUS::IMAPITable::_nil();

	LPMAPITABLE mapi_table = NULL;
	unsigned long flags = native_flags(ulFlags);

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->GetStatusTable(flags,
						   &mapi_table);
	}

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

	if (S_OK == hr) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lppTable = create_object<BRUTUS_IMAPITable_i, ::BRUTUS::IMAPITable, LPMAPITABLE>
			(mapi_table, poa_.in(), mapi_session_);
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::GetStatusTable()");
	return br;
}


::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::OpenEntry(const ::BRUTUS::ENTRYID &lpEntryID,
				 const char *lpInterface,
				 ::BRUTUS::BDEFINE ulFlags,
				 ::BRUTUS::BDEFINE_out lpulObjType,
				 ::BRUTUS::IUnknown_out lppUnk)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::OpenEntry()");

	lpulObjType = ::BRUTUS::BRUTUS_MAPI_UNKNOWN_OBJECT;
	lppUnk = ::BRUTUS::IUnknown::_nil();
	::BRUTUS::IUnknown_var obj = ::BRUTUS::IUnknown::_nil();

	unsigned long flags = native_flags(ulFlags);

	GUID *i_id = NULL;
	if (!guid_brutus_to_mapi(lpInterface, NULL, i_id)) {
		BRUTUS_LOG_BUG("Could not convert ::BRUTUS::GUID into MAPI GUID");
		return ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
	}

	unsigned long obj_type;
	LPUNKNOWN unk_object = NULL;
	ENTRYID *entry_id = NULL;

	unsigned long entry_id_size;
	if (!entryid_brutus_to_mapi(&lpEntryID, 0, entry_id_size, entry_id)) {
		MAPIFreeBuffer(i_id);
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->OpenEntry(entry_id_size,
					      entry_id,
					      i_id,
					      flags,
					      &obj_type,
					      &unk_object);
	}
	MAPIFreeBuffer(entry_id);
	MAPIFreeBuffer(i_id);

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}
	if (S_OK != hr) {
		BRUTUS_LOG_ERR("BRUTUS_IMAPISession_i::OpenEntry() failed");
		BRUTUS_EXIT;
	}

	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		if (object_type_mapi_to_brutus(obj_type, lpulObjType)) {
			if (!create_brutus_object(obj_type, unk_object, poa_.in(), obj.out(), mapi_session_)) {
				if (unk_object)
					unk_object->Release();
				BRUTUS_LOG_BUG("Could not create brutus object");
				br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
				BRUTUS_EXIT;
			}
		} else {
			if (!create_brutus_object(lpInterface, unk_object, poa_, obj.out(), mapi_session_)) {
				if (unk_object)
					unk_object->Release();
				BRUTUS_LOG_BUG("Could not create brutus object");
				br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
				BRUTUS_EXIT;
			}
		}
	}
	lppUnk = obj._retn();

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::OpenEntry()");
	return br;
}


::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::CompareEntryIDs(const ::BRUTUS::ENTRYID &lpEntryID1,
				       const ::BRUTUS::ENTRYID &lpEntryID2,
				       ::BRUTUS::BDEFINE ulFlags,
				       ::CORBA::Boolean_out lpulResult)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::CompareEntryIDs()");

	ENTRYID *entry_id_1;
	ENTRYID *entry_id_2;

	unsigned long result = 0;
	unsigned long flags = native_flags(ulFlags);

	unsigned long entry_id_1_size;
	if (!entryid_brutus_to_mapi(&lpEntryID1, 0, entry_id_1_size, entry_id_1)) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	unsigned long entry_id_2_size;
	if (!entryid_brutus_to_mapi(&lpEntryID2, 0, entry_id_2_size, entry_id_2)) {
		MAPIFreeBuffer(entry_id_1);
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->CompareEntryIDs(entry_id_1_size,
						    entry_id_1,
						    entry_id_2_size,
						    entry_id_2,
						    flags,
						    &result);
	}
	MAPIFreeBuffer(entry_id_1);
	MAPIFreeBuffer(entry_id_2);

	if (result == TRUE)
		lpulResult = (::CORBA::Boolean)1;
	else
		lpulResult = (::CORBA::Boolean)0;

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::CompareEntryIDs()");
	return br;
}


::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::Advise(const ::BRUTUS::ENTRYID &lpEntryID,
			      ::BRUTUS::BDEFINE ulEventMask,
			      ::BRUTUS::IMAPIAdviseSink_ptr lpAdviseSink,
			      ::CORBA::ULong_out lpulConnection)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::Advise()");

	unsigned long event_mask = native_eventmask(ulEventMask);

	lpulConnection = (::CORBA::ULong)0;

	HRESULT hr = S_OK;
	::BRUTUS::BRESULT br;
	if (::CORBA::is_nil(lpAdviseSink)) {
		BRUTUS_LOG_BUG("lpAdviseSink is NIL");
		br = ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
		BRUTUS_EXIT;
	}

	ENTRYID *entry_id;
	unsigned long entry_id_size;
	if (!entryid_brutus_to_mapi(&lpEntryID, 0, entry_id_size, entry_id)) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	CMAPIAdviseSink *sink;
	try {
		sink = new CMAPIAdviseSink(lpAdviseSink, mapi_session_, poa_.in());
	}
	catch (std::bad_alloc &) {
		MAPIFreeBuffer(entry_id);
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		unsigned long adv_con; // the compiler complains otherwise..
		hr = mapi_session_->Advise(entry_id_size,
					   entry_id,
					   event_mask,
					   sink,
					   &adv_con);

		lpulConnection = (::CORBA::ULong)adv_con; // see above..
	}
	MAPIFreeBuffer(entry_id);
	sink->Release(); // MAPI::UnAdvise will call Release()

	if (S_OK == hr)
		advise_sinks_.AddSink(lpulConnection);

	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::Advise()");
	return br;
}


::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::Unadvise(::CORBA::ULong ulConnection)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::Unadvise()");

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->Unadvise(ulConnection);
	}
	advise_sinks_.RemoveSink(ulConnection);

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::Unadvise()");
	return br;
}


::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::QueryDefaultMessageOpt(const char * lpszAdrType,
					      ::BRUTUS::BDEFINE ulFlags,
					      ::BRUTUS::seq_SPropValue_out lppOptions)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::QueryDefaultMessageOpt()");

	::BRUTUS::seq_SPropValue_var out_values;
	try {
		out_values = new ::BRUTUS::seq_SPropValue;
	}
	catch (std::bad_alloc &) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}
	out_values->length(0);

	unsigned long count = 0;
	LPSPropValue values = NULL;
	unsigned long flags = native_flags(ulFlags);

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->QueryDefaultMessageOpt((char*)lpszAdrType,
							   flags,
							   &count,
							   &values);
	}

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

	if (count && (S_OK == hr))
		spropvalue_array_mapi_to_brutus(count, values, out_values, mapi_session_, true, poa_);
	else if (values)
		MAPIFreeBuffer(values);

	lppOptions = out_values._retn();

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::QueryDefaultMessageOpt()");
	return br;
}



::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::EnumAdrTypes(::BRUTUS::BDEFINE ulFlags,
				    ::BRUTUS::seq_string_out lpppszAdrTypes)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::EnumAdrTypes()");

	::BRUTUS::seq_string_var out_adr_types;
	try {
		out_adr_types = new ::BRUTUS::seq_string;
	}
	catch (std::bad_alloc &) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}
	out_adr_types->length(0);

	unsigned long count = 0;
	unsigned long flags = native_flags(ulFlags);
	LPTSTR *adr_types = NULL;

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->EnumAdrTypes(flags,
						 &count,
						 &adr_types);
	}

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		MAPIFreeBuffer(adr_types);
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

	if (count && (S_OK == hr)) {
		out_adr_types->length(count);
		for (::CORBA::ULong i = 0; i < count; i++)
			out_adr_types[i] = ::CORBA::string_dup(adr_types[i]);
	}
	MAPIFreeBuffer(adr_types);
	lpppszAdrTypes = out_adr_types._retn();

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::EnumAdrTypes()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::QueryIdentity(::BRUTUS::ENTRYID_out lppEntryID)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::QueryIdentity()");

	unsigned long count = 0;
	ENTRYID *entry_id = NULL;

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->QueryIdentity(&count,
						  &entry_id);
	}

	::BRUTUS::ENTRYID_var out_entry_id;
	if (!entryid_mapi_to_brutus(count, entry_id, out_entry_id.out(), true)) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}
	lppEntryID = out_entry_id._retn();

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::QueryIdentity()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::SetDefaultStore(::BRUTUS::BDEFINE ulFlags,
				       const ::BRUTUS::ENTRYID &lpEntryID)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::SetDefaultStore()");

	ENTRYID *entry_id = NULL;
	unsigned long entry_id_size;
	if (!entryid_brutus_to_mapi(&lpEntryID, 0, entry_id_size, entry_id)) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	unsigned long flags = native_message_store_flags(ulFlags);

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->SetDefaultStore(flags, entry_id_size, entry_id);
	}
	MAPIFreeBuffer(entry_id);

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::SetDefaultStore()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::AdminServices(::BRUTUS::BDEFINE ulFlags,
				     ::BRUTUS::IMsgServiceAdmin_out lppServiceAdmin)

{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::AdminServices()");

	lppServiceAdmin = ::BRUTUS::IMsgServiceAdmin::_nil();

	LPSERVICEADMIN mapi_service_admin = NULL;
	unsigned long flags = (unsigned long)ulFlags;

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->AdminServices(flags,
						  &mapi_service_admin);
	}

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

	if (S_OK == hr ) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lppServiceAdmin = create_object<BRUTUS_IMsgServiceAdmin_i, ::BRUTUS::IMsgServiceAdmin, LPSERVICEADMIN>
			(mapi_service_admin, poa_.in(), mapi_session_);
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::AdminServices()");
	return br;
}

void
BRUTUS_IMAPISession_i::SetCodePage(::CORBA::ULong codepage)
{
	ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
	local_code_page = (unsigned long)codepage;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::QueryInterface(const char *iid,
				      ::BRUTUS::IUnknown_out ppvObject)
{
	ppvObject = ::BRUTUS::IUnknown::_nil();

	HRESULT hr = S_OK;
	::BRUTUS::BRESULT br;
	void *object = NULL;

	GUID mapi_iid;
	if (!guid_brutus_to_mapi_no_alloc(iid, &mapi_iid)) {
		BRUTUS_LOG_BUG("Could not convert ::BRUTUS::GUID into MAPI GUID");
		br = ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
		BRUTUS_EXIT;
	}

	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr =  mapi_session_->QueryInterface(mapi_iid, &object);
	}

	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

	if (S_OK == hr) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		if (!create_brutus_object(iid, (LPUNKNOWN)object, poa_, ppvObject, mapi_session_)) {
			BRUTUS_LOG_BUG("Could not create brutus object.");
			((LPUNKNOWN)object)->Release();
			br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
			BRUTUS_EXIT;
		}
	}

exit:
	return br;
}

void
BRUTUS_IMAPISession_i::Destroy(::CORBA::ULong InstanceID)
{
	ACE_Write_Guard<ACE_RW_Mutex> check_guard(life_check_mutex_);

	this->remove_life_check(InstanceID);
	refcount_--;
	if (0 < refcount_)
		goto exit;

	// stop dead client supervisor thread
   	if (CLIENT_DEAD_HANDLE)
   		SetEvent(CLIENT_DEAD_HANDLE);

	//
	// Should I invoke HrDispatchNotifications(0) here to fire off
	// all queued notifications?
	//

	// shut down the ORB down before doing anything else
	try {
		orb_->shutdown(false);
	}
	catch (...) {
	}

exit:
	return;
}



////////////////////////////////////////////////////////////
//                                                        //
// The following functions are Brutus specific management //
// functions. They are *not* part of IMAPISession proper. //
//                                                        //
////////////////////////////////////////////////////////////

::CORBA::ULong
BRUTUS_IMAPISession_i::addLifeline(::BRUTUS::BrutusCheck_ptr LifeLine)
{
	ACE_Write_Guard<ACE_RW_Mutex> guard(life_check_mutex_);

	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::addLifeline()");

	refcount_++;
	life_line_counter_++;
	life_lines_.push_back(new LifeCheck(LifeLine, life_line_counter_));

	{
		char msg[128] = {0};
		sprintf_s(msg, sizeof(msg), "Adding lifeline %d. refcount = %d", life_line_counter_, refcount_);
		BRUTUS_LOG_INF(msg);
	}

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::addLifeline()");

	return life_line_counter_;
}

void
BRUTUS_IMAPISession_i::ping(void)
{
	BRUTUS_LOG_INF("BRUTUS_IMAPISession_i::ping()");
}

void
BRUTUS_IMAPISession_i::checkLifelines(void)
{
	ACE_Write_Guard<ACE_RW_Mutex> guard(life_check_mutex_);

	unsigned long n = 0;
	std::vector<::CORBA::ULong> dead_ones;
	std::vector<LifeCheck*>::iterator lit = life_lines_.begin();

	for (n = 0; n < life_lines_.size(); n++, lit++) {
		try {
			life_lines_.at(n)->life_line->ping();
		}
		catch (const ::CORBA::Exception&) {
			dead_ones.push_back(life_lines_.at(n)->id);
		}
		catch (...) {
			dead_ones.push_back(life_lines_.at(n)->id);
		}
	}
	if (0 == dead_ones.size())
		return;

	for (n = 0; n < dead_ones.size(); n++) {
		this->remove_life_check(dead_ones[n]);
		refcount_--;
	}
	if (0 < refcount_)
		return;

	// stop dead client supervisor thread
    	if (CLIENT_DEAD_HANDLE)
    		SetEvent(CLIENT_DEAD_HANDLE);

	//
	// Should I invoke HrDispatchNotifications(0) here to fire off
	// all queued notifications?
	//

	// shut the ORB down before doing anything else
	try {
		orb_->shutdown(false);
	}
	catch (...) {
	}

	// if the ORB shutdown doesn't get it then this will
	try {
		shutdown_();
	}
	catch (...) {
	}

	return;
}


///////////////////////////////////////////////////////////
//                                                       //
// The following functions are generic helper functions  //
// typically found in the Exchange SDK. They are *not*   //
// a part of IMAPISession proper.                        //
//                                                       //
///////////////////////////////////////////////////////////

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::CreateIProp(::BRUTUS::IPropData_out lppPropData)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::CreateIProp()");

	lppPropData = ::BRUTUS::IPropData::_nil();
	LPPROPDATA prop_data = NULL;

	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = ::CreateIProp(&IID_IMAPIPropData,
				   MAPIAllocateBuffer,
				   MAPIAllocateMore,
				   MAPIFreeBuffer,
				   0,
				   &prop_data);
	}
	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

	if (S_OK == hr) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lppPropData = create_object<BRUTUS_IPropData_i, ::BRUTUS::IPropData, LPPROPDATA>
			(prop_data, poa_.in(), mapi_session_);
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::CreateIProp()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::OpenTnefStreamEx(::BRUTUS::IStream_ptr lpStreamName,
					const char * lpszStreamName,
					::BRUTUS::BDEFINE ulFlags,
					::BRUTUS::IMessage_ptr lpMessage,
					::CORBA::Short wKeyVal,
					::BRUTUS::IAddrBook_ptr lpAdressBook,
					::BRUTUS::ITnef_out lppTNEF)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::OpenTnefStreamEx()");

	lppTNEF = ::BRUTUS::ITnef::_nil();
	::CORBA::ULongLong p = (::CORBA::ULongLong)NULL;
	LPADRBOOK addr_book = NULL;
	LPMESSAGE message = NULL;

	CStream *brutus_stream;
	try {
		brutus_stream = new CStream(lpStreamName);
	}
	catch (...) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	::BRUTUS::BDEFINE brutus_flags = ulFlags;
	ULONG flags = 0;
	if (::BRUTUS::BRUTUS_TNEF_DECODE == brutus_flags) { // BRUTUS_TNEF_DECODE == 0 (zero)
		flags = TNEF_DECODE; // TNEF_DECODE == 0 (zero)
	} else {
		if (brutus_flags & ::BRUTUS::BRUTUS_TNEF_BEST_DATA) {
			flags |= TNEF_BEST_DATA;
			FLAGS_OFF(::BRUTUS::BDEFINE, brutus_flags, ::BRUTUS::BRUTUS_TNEF_BEST_DATA);
		}
		if (brutus_flags & ::BRUTUS::BRUTUS_TNEF_COMPATIBILITY) {
			flags |= TNEF_COMPATIBILITY;
			FLAGS_OFF(::BRUTUS::BDEFINE, brutus_flags, ::BRUTUS::BRUTUS_TNEF_COMPATIBILITY);
		}
		if (brutus_flags & ::BRUTUS::BRUTUS_TNEF_ENCODE) {
			flags |= TNEF_ENCODE;
			FLAGS_OFF(::BRUTUS::BDEFINE, brutus_flags, ::BRUTUS::BRUTUS_TNEF_ENCODE);
		}
		if (brutus_flags & ::BRUTUS::BRUTUS_TNEF_PURE) {
			flags |= TNEF_PURE;
			FLAGS_OFF(::BRUTUS::BDEFINE, brutus_flags, ::BRUTUS::BRUTUS_TNEF_PURE);
		}
		if (brutus_flags) {
			char msg[128] = {0};
			sprintf_s(msg, sizeof(msg), "Unknown flag(s) in BRUTUS_IMAPISession_i::OpenTnefStreamEx() : %X", brutus_flags);
			BRUTUS_LOG_BUG(msg);
		}
	}

	HRESULT hr = S_OK;
	::BRUTUS::BRESULT br;
	if (!::CORBA::is_nil(lpMessage)) {
		try {
			br = lpMessage->GetLocalPointer(p);
		}
		catch (...) {
			BRUTUS_LOG_ERR("Could not retrive local pointer");
			brutus_stream->Release();
			br = ::BRUTUS::BRUTUS_EXCEPTION_FROM_CLIENT;
			BRUTUS_EXIT;
		}
		if (::BRUTUS::BRUTUS_S_OK != br) {
			BRUTUS_LOG_ERR("Could not retrive local pointer");
			brutus_stream->Release();
			br = ::BRUTUS::BRUTUS_UNKNOWN_ERROR;
			BRUTUS_EXIT;
		}
	}
	message = (LPMESSAGE)p;
	if (!valid_mapi_interface_pointer<IMessage>(message)) {
		br = ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
		message = NULL;
		BRUTUS_EXIT;
	}

	p = (::CORBA::ULongLong)NULL;

	if (!::CORBA::is_nil(lpAdressBook)) {
		try {
			br = lpAdressBook->GetLocalPointer(p);
		}
		catch (...) {
			BRUTUS_LOG_ERR("Could not retrive local pointer");
			brutus_stream->Release();
			message->Release();
			br = ::BRUTUS::BRUTUS_EXCEPTION_FROM_CLIENT;
			BRUTUS_EXIT;
		}
		if (::BRUTUS::BRUTUS_S_OK != br) {
			BRUTUS_LOG_ERR("Could not retrive local pointer");
			brutus_stream->Release();
			message->Release();
			br = ::BRUTUS::BRUTUS_UNKNOWN_ERROR;
			BRUTUS_EXIT;
		}
	}
	addr_book = (LPADRBOOK)p;
	if (!valid_mapi_interface_pointer<IAddrBook>(addr_book)) {
		br = ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
		addr_book = NULL;
		BRUTUS_EXIT;
	}
	p = (::CORBA::ULongLong)NULL;

	LPITNEF tnef;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = ::OpenTnefStreamEx(0,
					brutus_stream,
					(char*)lpszStreamName,
					flags,
					message,
					wKeyVal,
					addr_book,
					&tnef);
	}
	brutus_stream->Release();
	message->Release();
	addr_book->Release();

	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

	if (S_OK == hr) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lppTNEF = create_object<BRUTUS_ITnef_i, ::BRUTUS::ITnef, LPITNEF>
			(tnef, poa_.in(), mapi_session_);
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::OpenTnefStreamEx()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::MAPIAdminProfiles(::BRUTUS::BDEFINE ulFlags,
					 ::BRUTUS::IProfAdmin_out ProfAdmin)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::MAPIAdminProfiles()");

	ProfAdmin = ::BRUTUS::IProfAdmin::_nil();

	// Get an IProfAdmin interface.
	LPPROFADMIN lpProfAdmin = NULL;
	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = ::MAPIAdminProfiles(0, &lpProfAdmin);
	}

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}
	if (S_OK == hr) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		ProfAdmin = create_object<BRUTUS_IProfAdmin_i, ::BRUTUS::IProfAdmin, LPPROFADMIN>
			(lpProfAdmin, poa_.in(), mapi_session_);
	}

exit:
	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::MAPIAdminProfiles()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::GetDefaultMsgStore(::BRUTUS::BDEFINE ulFlags,
					  ::BRUTUS::IMsgStore_out lpMDB)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::GetDefaultMsgStore()");

	lpMDB = ::BRUTUS::IMsgStore::_nil();

	ULONG flags = 0;
	ULONG cRows = 0;
	LPSRowSet lpRows = NULL;
	LPENTRYID entry_id = NULL;
	ULONG entry_id_size = 0;
	ULONG i;
	LPMDB msg_store = NULL;

	// Columns to return from the table
	SizedSPropTagArray(2, prop_tags) = {2, {PR_DEFAULT_STORE, PR_ENTRYID} };

	// Get list of available message stores
	HRESULT hr;
	LPMAPITABLE mapi_table = NULL;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->GetMsgStoresTable(0, &mapi_table);
	}
	if (S_OK != hr)
		BRUTUS_EXIT;

	// Get row count
	hr = mapi_table->GetRowCount(0, &cRows);
	if (S_OK != hr)
		BRUTUS_EXIT;
	if (!cRows) {
		hr = MAPI_E_NOT_FOUND;
		BRUTUS_EXIT;
	}

	// Select columns to return from the table
	hr = mapi_table->SetColumns((LPSPropTagArray)&prop_tags, 0);
	if (S_OK != hr)
		BRUTUS_EXIT;

	// Go to the beginning of the recipient table for the envelope
	hr = mapi_table->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
	if (S_OK != hr)
		BRUTUS_EXIT;

	// Read all the rows of the table
	hr = mapi_table->QueryRows(cRows, 0, &lpRows);
	if ((S_OK == hr) && (lpRows != NULL) && (lpRows->cRows == 0)) {
		FreeProws(lpRows);
		hr = MAPI_E_NOT_FOUND;
		BRUTUS_EXIT;
	}
	mapi_table->Release();
	mapi_table = NULL;

	for (i = 0; i < cRows; i++) {
		// check PR_DEFAULT_STORE boolean
		if (lpRows && (TRUE == lpRows->aRow[i].lpProps[0].Value.b)) {
			entry_id = (LPENTRYID)lpRows->aRow[i].lpProps[1].Value.bin.lpb;
			entry_id_size = lpRows->aRow[i].lpProps[1].Value.bin.cb;
			break;
		}
	}

	flags = native_flags(ulFlags);
	flags |= MDB_NO_DIALOG;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->OpenMsgStore(0,
						 entry_id_size,
						 entry_id,
						 NULL,
						 flags,
						 &msg_store);
	}
	if ((S_OK == hr) || (MAPI_W_ERRORS_RETURNED == hr)) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lpMDB = create_object<BRUTUS_IMsgStore_i, ::BRUTUS::IMsgStore, LPMDB>
			(msg_store, poa_.in(), mapi_session_);
	}

exit:
	if (mapi_table)
		mapi_table->Release();

	if (lpRows)
		FreeProws(lpRows);

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
	}

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::GetDefaultMsgStore()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::GetPublicMsgStore(::BRUTUS::BDEFINE ulFlags,
					 ::BRUTUS::IMsgStore_out lpMDB)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::GetPublicMsgStore()");

	lpMDB = ::BRUTUS::IMsgStore::_nil();

	ULONG flags = 0;
	ULONG cRows = 0;
	LPSRowSet lpRows = NULL;
	LPENTRYID entry_id = NULL;
	ULONG entry_id_size = 0;
	ULONG i;
	LPMDB msg_store = NULL;

	// Columns to return from the table
	SizedSPropTagArray(2, prop_tags) = {2, {PR_MDB_PROVIDER, PR_ENTRYID} };

	// Get list of available message stores
	HRESULT hr;
	LPMAPITABLE mapi_table = NULL;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->GetMsgStoresTable(0, &mapi_table);
	}
	if (S_OK != hr)
		BRUTUS_EXIT;

	// Get row count
	hr = mapi_table->GetRowCount(0, &cRows);
	if (S_OK != hr)
		BRUTUS_EXIT;
	if (!cRows) {
		hr = MAPI_E_NOT_FOUND;
		BRUTUS_EXIT;
	}

	// Select columns to return from the table
	hr = mapi_table->SetColumns((LPSPropTagArray)&prop_tags, 0);
	if (S_OK != hr)
		BRUTUS_EXIT;

	// Go to the beginning of the recipient table for the envelope
	hr = mapi_table->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
	if (S_OK != hr)
		BRUTUS_EXIT;

	// Read all the rows of the table
	hr = mapi_table->QueryRows(cRows, 0, &lpRows);
	if (!lpRows || ((S_OK == hr) && (lpRows != NULL) && (lpRows->cRows == 0))) {
		if (lpRows)
			FreeProws(lpRows);
		hr = MAPI_E_NOT_FOUND;
		BRUTUS_EXIT;
	}
	mapi_table->Release();
	mapi_table = NULL;

	for (i = 0; i < cRows; i++) {
		if (!memcmp(lpRows->aRow[i].lpProps[0].Value.bin.lpb, pbExchangeProviderPublicGuid, sizeof(MAPIUID))) {
			entry_id = (LPENTRYID)lpRows->aRow[i].lpProps[1].Value.bin.lpb;
			entry_id_size = lpRows->aRow[i].lpProps[1].Value.bin.cb;
			break;
		}
	}

	flags = native_flags(ulFlags);
	flags |= MDB_NO_DIALOG;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->OpenMsgStore(0,
						 entry_id_size,
						 entry_id,
						 NULL,
						 flags,
						 &msg_store);
	}
	if ((S_OK == hr) || (MAPI_W_ERRORS_RETURNED == hr)) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lpMDB = create_object<BRUTUS_IMsgStore_i, ::BRUTUS::IMsgStore, LPMDB>
			(msg_store, poa_.in(), mapi_session_);
	}

exit:
	if (mapi_table)
		mapi_table->Release();

	if (lpRows)
		FreeProws(lpRows);

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
	}

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::GetPublicMsgStore()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::OpenStoreFromGuid(const char *lpGUID,
					 ::BRUTUS::BDEFINE ulFlags,
					 ::BRUTUS::IMsgStore_out lpMDB)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::OpenStoreFromGuid()");

	lpMDB = ::BRUTUS::IMsgStore::_nil();

	HRESULT hr = NOERROR;
	ULONG flags = 0;
	LPMAPITABLE mapi_table = NULL;
	LPMDB mapi_store = NULL;
	LPSRowSet lpRows = NULL;
	BYTE mapi_lpbyte[sizeof(GUID)];

	SPropTagArray aptEntryID = {1, {PR_ENTRYID} };
	SPropValue SProp = {PR_MDB_PROVIDER, 0L, {0} };

	SRestriction SRestrict;
	SRestrict.rt = RES_PROPERTY;
	SRestrict.res.resProperty.relop = RELOP_EQ;
	SRestrict.res.resProperty.ulPropTag = PR_MDB_PROVIDER;
	SRestrict.res.resProperty.lpProp = &SProp;

	guid_brutus_to_lpbyte_no_alloc(lpGUID, mapi_lpbyte);

	// Get table of message stores
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->GetMsgStoresTable(0, &mapi_table);
	}
	if (S_OK != hr)
		BRUTUS_EXIT;

	// Restrict the table to the appropriate Exchange store
	SProp.Value.bin.cb  = sizeof(GUID);
	SProp.Value.bin.lpb = mapi_lpbyte;

	hr = HrQueryAllRows(mapi_table, &aptEntryID, &SRestrict, NULL, 0, &lpRows);
	if (S_OK != hr)
		BRUTUS_EXIT;

	if (!lpRows->cRows) {
		hr = MAPI_E_NOT_FOUND;
		BRUTUS_EXIT;
	}
	if ((lpRows->aRow->cValues != 1) || (lpRows->aRow->lpProps[0].ulPropTag != PR_ENTRYID)) {
		hr = E_FAIL;
		BRUTUS_EXIT;
	}

	// Open the message store
	flags = native_flags(ulFlags);
	flags |= MDB_NO_DIALOG;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->OpenMsgStore(0,
						 lpRows->aRow->lpProps[0].Value.bin.cb,
						 (LPENTRYID)lpRows->aRow->lpProps[0].Value.bin.lpb,
						 NULL,
						 flags,
						 &mapi_store);
	}
	if ((S_OK == hr) || (MAPI_W_ERRORS_RETURNED == hr)) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lpMDB = create_object<BRUTUS_IMsgStore_i, ::BRUTUS::IMsgStore, LPMDB>
			(mapi_store, poa_.in(), mapi_session_);
	} else
		BRUTUS_EXIT;


exit:
	if (mapi_table)
		mapi_table->Release();

	if (lpRows)
		FreeProws(lpRows);

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
	}

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::OpenStoreFromGuid()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::MailboxLogon(::BRUTUS::IMsgStore_ptr lpMDB,
				    const char * lpszMsgStoreDN,
				    const char * lpszMailboxDN,
				    ::BRUTUS::BDEFINE ulCreateFlags,
				    ::BRUTUS::BDEFINE ulOpenFlags,
				    ::BRUTUS::IMsgStore_out lppMailboxMDB)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::MailboxLogon()");

	lppMailboxMDB = ::BRUTUS::IMsgStore::_nil();

	HRESULT hr = S_OK;
	ULONG flags = 0;
	ULONG mapi_entry_id_count = 0;
	ENTRYID *mapi_entry_id = NULL;
	LPMDB input_message_store = NULL;
	LPMDB mailbox_store = NULL;
	LPEXCHANGEMANAGESTORE mapi_exchange_manage_store = NULL;
	::CORBA::ULongLong p = (::CORBA::ULongLong)NULL;

	// sanity checks
	if (::CORBA::is_nil(lpMDB) || !strlen(lpszMsgStoreDN)) {
		hr = MAPI_E_INVALID_PARAMETER;
		BRUTUS_EXIT;
	}

	::BRUTUS::BRESULT br;
	if (!::CORBA::is_nil(lpMDB))
		try {
			br = lpMDB->GetLocalPointer(p);
		}
		catch (...) {
			BRUTUS_LOG_ERR("Could not retrive local pointer");
			br = ::BRUTUS::BRUTUS_EXCEPTION_FROM_CLIENT;
			BRUTUS_EXIT;
		}
		if (::BRUTUS::BRUTUS_S_OK != br) {
			BRUTUS_LOG_ERR("Could not retrive local pointer");
			br = ::BRUTUS::BRUTUS_UNKNOWN_ERROR;
			BRUTUS_EXIT;
		}
	input_message_store = (LPMDB)p;
	if (!valid_mapi_interface_pointer<IMsgStore>(input_message_store)) {
		br = ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
		input_message_store = NULL;
		BRUTUS_EXIT;
	}

	hr = input_message_store->QueryInterface(IID_IExchangeManageStore,
						 (LPVOID*) &mapi_exchange_manage_store);
	if (S_OK != hr)
		BRUTUS_EXIT;

	flags = native_flags(ulCreateFlags);
	hr = mapi_exchange_manage_store->CreateStoreEntryID((char*)lpszMsgStoreDN,
							    (char*)lpszMailboxDN,
							    flags,
							    &mapi_entry_id_count,
							    &mapi_entry_id);
	if (!mapi_entry_id || (S_OK != hr))
		BRUTUS_EXIT;

	flags = native_flags(ulOpenFlags);
	flags |= MDB_NO_DIALOG;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->OpenMsgStore(0,
						 mapi_entry_id_count,
						 mapi_entry_id,
						 NULL,
						 flags,
						 &mailbox_store);
	}
	if ((S_OK == hr) || (MAPI_W_ERRORS_RETURNED == hr)) {
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		lppMailboxMDB = create_object<BRUTUS_IMsgStore_i, ::BRUTUS::IMsgStore, LPMDB>
			(mailbox_store, poa_.in(), mapi_session_);
	} else if (MAPI_E_FAILONEPROVIDER == hr) { // required behavior by MSDN (http://support.microsoft.com/?kbid=260141)
		hr = MAPI_E_CALL_FAILED;
		BRUTUS_EXIT;
	} else
		BRUTUS_EXIT;

exit:
	if (mapi_entry_id)
		MAPIFreeBuffer(mapi_entry_id);

	if (mapi_exchange_manage_store)
		mapi_exchange_manage_store->Release();

	if (input_message_store)
		input_message_store->Release();

	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
	}

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::MailboxLogon()");
	return br;
}

::HRESULT
BRUTUS_IMAPISession_i::get_outlook_folder_entryid(::BRUTUS::OUTLOOK_FOLDER Which,
						  LPMDB msg_store,
						  ULONG FAR *lpcbEntryID,
						  LPENTRYID FAR *lppEntryID)
{
	BRUTUS_LOG_INF("Entering get_outlook_folder_entryid()");

	HRESULT hr;
	ULONG prop_tag = 0;
	ULONG obj_type;
	LPUNKNOWN unk = NULL;
	LPMAPIFOLDER root_folder = NULL;
	LPSPropValue pv = NULL;
	char *explicit_class = NULL;

	*lpcbEntryID = 0;
	*lppEntryID = NULL;

	// create property tag
	switch (Which) {
	case ::BRUTUS::OUTLOOK_INBOX :
		break;
	case ::BRUTUS::OUTLOOK_FAVORITES :    // on all message stores
		prop_tag = PR_IPM_FAVORITES_ENTRYID;
		break;
	case ::BRUTUS::OUTLOOK_ROOT_FOLDER :  // on all message stores
		prop_tag = PR_IPM_SUBTREE_ENTRYID;
		break;
	case ::BRUTUS::OUTLOOK_OUTBOX :       // on private message store
		prop_tag = PR_IPM_OUTLOOK_OUTBOX;
		break;
	case ::BRUTUS::OUTLOOK_WASTEBASKET :  // on private message store
		prop_tag = PR_IPM_OUTLOOK_WASTEBASKET;
		break;
	case ::BRUTUS::OUTLOOK_SENTMAIL :     // on private message store
		prop_tag = PR_IPM_OUTLOOK_SENTMAIL;
		break;
	case ::BRUTUS::OUTLOOK_VIEWS :        // on private message store
		prop_tag = PR_IPM_OUTLOOK_VIEWS;
		break;
	case ::BRUTUS::OUTLOOK_COMMON_VIEWS : // on private message store
		prop_tag = PR_IPM_OUTLOOK_COMMON_VIEWS;
		break;
	case ::BRUTUS::OUTLOOK_FINDER :       // on private message store
		prop_tag = PR_IPM_OUTLOOK_FINDER;
		break;
	case ::BRUTUS::OUTLOOK_JUNK :         // on root folder or INBOX in private message store
		prop_tag = PR_ADDITIONAL_REN_ENTRYIDS;
		break;
	case ::BRUTUS::OUTLOOK_CALENDAR :     // on root folder in private message store
		prop_tag = PR_IPM_OUTLOOK_CALENDAR;
		break;
	case ::BRUTUS::OUTLOOK_CONTACTS :     // on root folder in private message store
		prop_tag = PR_IPM_OUTLOOK_CONTACTS;
		break;
	case ::BRUTUS::OUTLOOK_JOURNAL :      // on root folder in private message store
		prop_tag = PR_IPM_OUTLOOK_JOURNAL;
		break;
	case ::BRUTUS::OUTLOOK_NOTES :        // on root folder in private message store
		prop_tag = PR_IPM_OUTLOOK_NOTES;
		break;
	case ::BRUTUS::OUTLOOK_TASKS :        // on root folder in private message store
		prop_tag = PR_IPM_OUTLOOK_TASKS;
		break;
	case ::BRUTUS::OUTLOOK_REMINDERS :    // on root folder in private message store
		prop_tag = PR_IPM_OUTLOOK_REMINDERS;
		break;
	case ::BRUTUS::OUTLOOK_DRAFTS :       // on root folder in private message store
		prop_tag = PR_IPM_OUTLOOK_DRAFTS;
		break;
	default :
		BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
		return MAPI_E_INVALID_PARAMETER;
	}

	// open outlook folder
	switch (Which) {
	case ::BRUTUS::OUTLOOK_INBOX :
	{
		hr = msg_store->GetReceiveFolder("IPM.Note",
						 0,
						 lpcbEntryID,
						 lppEntryID,
						 &explicit_class);
		MAPIFreeBuffer(explicit_class);
		if (S_OK != hr) {
			BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
			return hr;
		}

		BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
		return hr;
	}
	break;
	case ::BRUTUS::OUTLOOK_FAVORITES :
	case ::BRUTUS::OUTLOOK_ROOT_FOLDER :
	case ::BRUTUS::OUTLOOK_OUTBOX :
	case ::BRUTUS::OUTLOOK_WASTEBASKET :
	case ::BRUTUS::OUTLOOK_SENTMAIL :
	case ::BRUTUS::OUTLOOK_VIEWS :
	case ::BRUTUS::OUTLOOK_COMMON_VIEWS :
	case ::BRUTUS::OUTLOOK_FINDER :
	{
		hr = HrGetOneProp(msg_store, prop_tag, &pv);
		if (S_OK != hr) {
			BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
			return hr;
		}

		*lpcbEntryID = pv->Value.bin.cb;
		hr = MAPIAllocateBuffer(*lpcbEntryID, (void**)lppEntryID);
		if (S_OK != hr) {
			MAPIFreeBuffer(pv);
			BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
			return hr;
		}
		memcpy((void*)*lppEntryID, pv->Value.bin.lpb, *lpcbEntryID);
		MAPIFreeBuffer(pv);

		BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
		return S_OK;
	}
	break;
	case ::BRUTUS::OUTLOOK_JUNK :
	case ::BRUTUS::OUTLOOK_CALENDAR :
	case ::BRUTUS::OUTLOOK_CONTACTS :
	case ::BRUTUS::OUTLOOK_JOURNAL :
	case ::BRUTUS::OUTLOOK_NOTES :
	case ::BRUTUS::OUTLOOK_TASKS :
	case ::BRUTUS::OUTLOOK_REMINDERS :
	case ::BRUTUS::OUTLOOK_DRAFTS :
	{
		hr = msg_store->OpenEntry(0, 0, NULL, MAPI_BEST_ACCESS, &obj_type, &unk);
		if (S_OK != hr) {
			BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
			return hr;
		}

		root_folder = (LPMAPIFOLDER)unk;
		hr = HrGetOneProp(root_folder, prop_tag, &pv);
		unk->Release();
		if (S_OK != hr) {
			BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
			return hr;
		}

		if (::BRUTUS::OUTLOOK_JUNK == Which) {
			*lpcbEntryID = pv->Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX].cb;
		} else {
			*lpcbEntryID = pv->Value.bin.cb;
		}
		hr = MAPIAllocateBuffer(*lpcbEntryID, (void**)lppEntryID);
		if (S_OK != hr) {
			MAPIFreeBuffer(pv);
			BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
			return hr;
		}

		if (::BRUTUS::OUTLOOK_JUNK == Which) {
			memcpy((void*)*lppEntryID, pv->Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX].lpb, *lpcbEntryID);
		} else {
			memcpy((void*)*lppEntryID, pv->Value.bin.lpb, *lpcbEntryID);
		}
		MAPIFreeBuffer(pv);

		BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
		return S_OK;
	}
	break;
	default :
		BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
		return E_FAIL;
	}

	BRUTUS_LOG_INF("Leaving get_outlook_folder_entryid()");
	return E_FAIL;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::GetOutlookFolderENTRYID(::BRUTUS::OUTLOOK_FOLDER Which,
					       ::BRUTUS::IMsgStore_ptr lpMDB,
					       ::BRUTUS::ENTRYID_out lppEntryID)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::GetOutlookFolderENTRYID()");

	HRESULT hr;
	::BRUTUS::BRESULT br;
	LPUNKNOWN unk = NULL;
	LPMAPIFOLDER outlook_folder = NULL;
	LPMDB msg_store = NULL;
	::CORBA::ULongLong p = (::CORBA::ULongLong)NULL;
	unsigned long entry_id_size = 0;
	ENTRYID *entry_id = NULL;
	::BRUTUS::ENTRYID_var out_entry_id;

	try {
		out_entry_id = new ::BRUTUS::ENTRYID;
	}
	catch (std::bad_alloc &) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);

	// get message store
	if (::CORBA::is_nil(lpMDB)) {
		hr = get_default_message_store(mapi_session_, &msg_store);
		if ((S_OK != hr) && (MAPI_W_ERRORS_RETURNED != hr))
			BRUTUS_EXIT;
	} else {
		try {
			br = lpMDB->GetLocalPointer(p);
		}
		catch (...) {
			BRUTUS_LOG_ERR("Could not retrive local pointer");
			lppEntryID = out_entry_id._retn();
			return ::BRUTUS::BRUTUS_EXCEPTION_FROM_CLIENT;
		}
		if (::BRUTUS::BRUTUS_S_OK != br) {
			BRUTUS_LOG_ERR("Could not retrive local pointer");
			lppEntryID = out_entry_id._retn();
			return ::BRUTUS::BRUTUS_UNKNOWN_ERROR;
		}
		msg_store = (LPMDB)p;
		if (!valid_mapi_interface_pointer<IMsgStore>(msg_store)) {
			lppEntryID = out_entry_id._retn();
			return ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
		}
	}

	hr = get_outlook_folder_entryid(Which, msg_store, &entry_id_size, &entry_id);
	if (S_OK != hr)
		BRUTUS_EXIT;

	if (!entryid_mapi_to_brutus(entry_id_size, entry_id, out_entry_id.out(), true)) {
		br = ::BRUTUS::BRUTUS_UNKNOWN_ERROR;
		goto exit_no_br_conv;
	}
exit:
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
	}

exit_no_br_conv:

	lppEntryID = out_entry_id._retn();

	if (msg_store)
		msg_store->Release();

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::GetOutlookFolderENTRYID()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::GetOutlookFolder(::BRUTUS::OUTLOOK_FOLDER Which,
					::BRUTUS::IMsgStore_ptr lpMDB,
					::BRUTUS::IMAPIFolder_out Folder)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::GetOutlookFolder()");

	// initiate out value asap
	Folder = ::BRUTUS::IMAPIFolder::_nil();

	HRESULT hr;
	::BRUTUS::BRESULT br;
	ULONG obj_type;
	LPUNKNOWN unk = NULL;
	LPMAPIFOLDER outlook_folder = NULL;
	LPMDB msg_store = NULL;
	::CORBA::ULongLong p = (::CORBA::ULongLong)NULL;
	unsigned long entry_id_size = 0;
	ENTRYID *entry_id = NULL;

	ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);

	// get message store
	if (::CORBA::is_nil(lpMDB)) {
		hr = get_default_message_store(mapi_session_, &msg_store);
		if ((S_OK != hr) && (MAPI_W_ERRORS_RETURNED != hr))
			BRUTUS_EXIT;
	} else {
		try {
			br = lpMDB->GetLocalPointer(p);
		}
		catch (...) {
			BRUTUS_LOG_ERR("Could not retrive local pointer");
			return ::BRUTUS::BRUTUS_EXCEPTION_FROM_CLIENT;
		}
		if (::BRUTUS::BRUTUS_S_OK != br) {
			BRUTUS_LOG_ERR("Could not retrive local pointer");
			return ::BRUTUS::BRUTUS_UNKNOWN_ERROR;
		}
		msg_store = (LPMDB)p;
		if (!valid_mapi_interface_pointer<IMsgStore>(msg_store))
			return ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER;
	}

	hr = get_outlook_folder_entryid(Which, msg_store, &entry_id_size, &entry_id);
	if (S_OK != hr)
		BRUTUS_EXIT;

	hr = mapi_session_->OpenEntry(entry_id_size, entry_id, NULL, MAPI_BEST_ACCESS, &obj_type, &unk);
	if (S_OK != hr)
		BRUTUS_EXIT;
	outlook_folder = (LPMAPIFOLDER)unk;

	// convert to Brutus object
	Folder = create_object<BRUTUS_IMAPIFolder_i, ::BRUTUS::IMAPIFolder, LPMAPIFOLDER>
		(outlook_folder, poa_.in(), mapi_session_);
exit:
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
	}

	MAPIFreeBuffer(entry_id);
	if (msg_store)
		msg_store->Release();

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::GetOutlookFolder()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::DispatchNotifications(::CORBA::ULong Flags)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::DispatchNotifications()");

	HRESULT hr;
	{ // No multithread protection!
		hr = HrDispatchNotifications((unsigned long)Flags);
	}

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
		BRUTUS_EXIT;
	}

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::DispatchNotifications()");
exit:
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::QueryProps(const ::BRUTUS::ENTRYID & Eid,
				  const ::BRUTUS::SPropTagArray & PropTagArray,
				  ::BRUTUS::seq_SPropValue_out PropValueArray)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::QueryProps()");

	ENTRYID *entry_id = NULL;
	unsigned long entry_id_size;
	if (!entryid_brutus_to_mapi(&Eid, 0, entry_id_size, entry_id)) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	::BRUTUS::seq_SPropValue_var brutus_props;
	try {
		brutus_props = new ::BRUTUS::seq_SPropValue;
	}
	catch (std::bad_alloc &) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}
	brutus_props->length(0);

	LPMAPIPROP prop_object = NULL;
	unsigned long obj_type;
	HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->OpenEntry(entry_id_size,
					      entry_id,
					      &IID_IMAPIProp,
					      0, // only read access is needed
					      &obj_type,
					      (LPUNKNOWN*)&prop_object);
	}
	MAPIFreeBuffer(entry_id);

	if (S_OK != hr) {
		BRUTUS_LOG_ERR("IMAPISession::OpenEntry() failed");
		BRUTUS_EXIT;
	}

	SPropTagArray *tags = NULL;
	if (!proptag_array_brutus_to_mapi(&PropTagArray, 0, tags)) {
		BRUTUS_LOG_ERR("No memory");
		prop_object->Release();
		throw ::CORBA::NO_MEMORY();
	}

	SPropValue *props = NULL;
	unsigned long count = 0;
	hr = prop_object->GetProps(tags, 0, &count, &props);
	MAPIFreeBuffer(tags);
	prop_object->Release();
	prop_object = NULL;

	if ((MAPI_W_ERRORS_RETURNED == hr) || (S_OK == hr))
		spropvalue_array_mapi_to_brutus(count, props, brutus_props, mapi_session_, true, poa_);
	else
		MAPIFreeBuffer(props);

exit:
	PropValueArray = brutus_props._retn();

	if (prop_object)
		prop_object->Release();

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
	}

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::QueryProps()");
	return br;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::QueryMessage(const ::BRUTUS::ENTRYID & Eid,
				    const ::BRUTUS::SPropTagArray & ObjPropTagArray,
				    const ::BRUTUS::SPropTagArray & AdditionalObjPropTagArray,
				    const ::BRUTUS::SPropTagArray & RecpPropTagArray,
				    ::BRUTUS::seq_SPropValue_out ObjPropValueArray,
				    ::BRUTUS::seq_SPropValue_out AdditionalObjPropValueArray,
				    ::BRUTUS::SRowSet_out RecpRows)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::QueryMessage()");

	::ENTRYID *entry_id = NULL;
	unsigned long entry_id_size;
	if (!entryid_brutus_to_mapi(&Eid, 0, entry_id_size, entry_id)) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	// initiate out values
	::BRUTUS::seq_SPropValue_var brutus_obj_props;
	try {
		brutus_obj_props = new ::BRUTUS::seq_SPropValue;
	}
	catch (std::bad_alloc &) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	brutus_obj_props->length(0);
	::BRUTUS::seq_SPropValue_var brutus_additional_obj_props;
	try {
		brutus_additional_obj_props = new ::BRUTUS::seq_SPropValue;
	}
	catch (std::bad_alloc &) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	brutus_additional_obj_props->length(0);
	::BRUTUS::SRowSet_var brutus_recp_rows;
	try {
		brutus_recp_rows = new ::BRUTUS::SRowSet;
	}
	catch (std::bad_alloc &) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}
	brutus_recp_rows->length(0);

	// early declarations
	LPMAPITABLE mapi_table = NULL;
	LPSRowSet mapi_rowset = NULL;
	SPropValue *props = NULL;
	unsigned long count = 0;

	// open message object
	LPMESSAGE msg_object = NULL;
	unsigned long obj_type;
	::HRESULT hr;
	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = mapi_session_->OpenEntry(entry_id_size,
					      entry_id,
					      &IID_IMessage,
					      0, // only read access is needed
					      &obj_type,
					      (LPUNKNOWN*)&msg_object);
	}
	MAPIFreeBuffer(entry_id);
	if (S_OK != hr) {
		BRUTUS_LOG_ERR("IMAPISession::OpenEntry() failed");
		BRUTUS_EXIT;
	}

	/*
	 * RecipientTable
	 */
	SPropTagArray *tags = NULL;
	if (!proptag_array_brutus_to_mapi(&RecpPropTagArray, 0, tags)) {
		BRUTUS_LOG_ERR("No memory");
		msg_object->Release();
		throw ::CORBA::NO_MEMORY();
	}

	hr = msg_object->GetRecipientTable(0, &mapi_table);
	if (S_OK != hr) {
		BRUTUS_LOG_ERR("IMessage::GetRecipientTable() failed");
		BRUTUS_EXIT;
	}
	hr = HrQueryAllRows(mapi_table,
			    tags,
			    NULL,
			    NULL,
			    0,
			    &mapi_rowset);
	mapi_table->Release();
	mapi_table = NULL;
	MAPIFreeBuffer(tags);
	if (S_OK != hr) {
		BRUTUS_LOG_ERR("HrQueryAllRows() failed");
		BRUTUS_EXIT;
	}

	if (!srow_set_mapi_to_brutus(mapi_rowset, brutus_recp_rows, mapi_session_, true, poa_)) {
		mapi_rowset = NULL;
		BRUTUS_LOG_BUG("Conversion error");
		BRUTUS_EXIT;
	}
	mapi_rowset = NULL;

	/*
	 * Additional object properties
	 */
	if (AdditionalObjPropTagArray.length()) {
		if (!proptag_array_brutus_to_mapi(&AdditionalObjPropTagArray, 0, tags)) {
			BRUTUS_LOG_ERR("No memory");
			msg_object->Release();
			throw ::CORBA::NO_MEMORY();
		}

		hr = msg_object->GetProps(tags, 0, &count, &props);
		MAPIFreeBuffer(tags);
		if ((MAPI_W_ERRORS_RETURNED == hr) || (S_OK == hr)) {
			if (!spropvalue_array_mapi_to_brutus(count, props, brutus_additional_obj_props, mapi_session_, true, poa_)) {
				BRUTUS_LOG_BUG("Conversion error");
				BRUTUS_EXIT;
			}
		} else {
			MAPIFreeBuffer(props);
			BRUTUS_LOG_ERR("IMessage::GetProps() failed");
			BRUTUS_EXIT;
		}
	}

	/*
	 * Object properties
	 */
	if (!proptag_array_brutus_to_mapi(&ObjPropTagArray, 0, tags)) {
		BRUTUS_LOG_ERR("No memory");
		msg_object->Release();
		throw ::CORBA::NO_MEMORY();
	}

	hr = msg_object->GetProps(tags, 0, &count, &props);
	MAPIFreeBuffer(tags);
	if ((MAPI_W_ERRORS_RETURNED == hr) || (S_OK == hr)) {
		if (!spropvalue_array_mapi_to_brutus(count, props, brutus_obj_props, mapi_session_, true, poa_))
			BRUTUS_LOG_BUG("Conversion error");
	} else {
		MAPIFreeBuffer(props);
		BRUTUS_LOG_ERR("IMessage::GetProps() failed");
	}

exit:
	ObjPropValueArray = brutus_obj_props._retn();
	AdditionalObjPropValueArray = brutus_additional_obj_props._retn();
	RecpRows = brutus_recp_rows._retn();
        if (mapi_rowset)
		MAPIFreeBuffer(mapi_rowset);
	if (mapi_table)
		mapi_table->Release();
	if (msg_object)
		msg_object->Release();

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
	}

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::QueryMessage()");
	return br;
}

::CORBA::Boolean
BRUTUS_IMAPISession_i::GetServerTime(const char *server,
				     ::BRUTUS::TIME_OF_DAY_INFO_out tod)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::GetServerTime()");

//	LPTSTR server_name = NULL;
	::CORBA::Boolean retv = false;
	TIME_OF_DAY_INFO *win32_tod = NULL;

//	if (strlen(server))
//		server_name = (char*)server;

//	LPWSTR w_server_name = ascii_to_unicode(NULL, server_name);

	//
	// NetRemoteTOD() has a bad habit of timing out or just plain hanging
	// indefinitely. We can't have that...
	//
	// if (NERR_Success == NetRemoteTOD(w_server_name, (LPBYTE*) &win32_tod))
	//	retv = true;
	if (NERR_Success == NetRemoteTOD(NULL, (LPBYTE*) &win32_tod))
		retv = true;

	if (retv) {
		if (win32_tod) {
			tod.tod_elapsedt = win32_tod->tod_elapsedt;
			tod.tod_msecs = win32_tod->tod_msecs ;
			tod.tod_hours = win32_tod->tod_hours;
			tod.tod_mins = win32_tod->tod_mins ;
			tod.tod_secs = win32_tod->tod_secs;
			tod.tod_hunds = win32_tod->tod_hunds;
			tod.tod_timezone = win32_tod->tod_timezone;
			tod.tod_tinterval = win32_tod->tod_tinterval;
			tod.tod_day = win32_tod->tod_day;
			tod.tod_month = win32_tod->tod_month;
			tod.tod_year = win32_tod->tod_year;
			tod.tod_weekday = win32_tod->tod_weekday;
		} else
			retv = false;
	}

//	MAPIFreeBuffer(w_server_name);

	if (win32_tod)
		NetApiBufferFree(win32_tod);

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::GetServerTime()");
	return retv;
}


::CORBA::Boolean
BRUTUS_IMAPISession_i::LookupAccountName(const char *lpSystemName,
					 const char *lpAccountName,
					 ::BRUTUS::seq_octet_out Sid,
					 ::CORBA::String_out ReferencedDomainName,
					 ::BRUTUS::SID_NAME_USE_out peUse)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::LookupAccountName()");

	::CORBA::Boolean retv = false;

	// initiate out values ASAP
	peUse = ::BRUTUS::BRUTUS_SidTypeUnknown;
	::CORBA::String_var out_ref_dn = (const char *)"";
	::BRUTUS::seq_octet_var brutus_sid;
	try {
		brutus_sid = new ::BRUTUS::seq_octet;
	}
	catch (std::bad_alloc &) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}
	brutus_sid->length(0);

	DWORD cbSID = 0;
	DWORD cbRefDN = 0;
	SID_NAME_USE mapi_peUse;
	char *system_name = strlen(lpSystemName) ? (char*)lpSystemName : NULL;
	char *account_name = strlen(lpAccountName) ? (char*)lpAccountName : NULL;
	::LookupAccountName(system_name,
			    account_name,
			    NULL,
			    &cbSID,
			    NULL,
			    &cbRefDN,
			    &mapi_peUse);

	PSID mapi_sid = malloc(cbSID);
	if (!mapi_sid) {
		BRUTUS_LOG_ERR("No memory");
		throw ::CORBA::NO_MEMORY();
	}

	char *RefDN = (char*)malloc(sizeof(TCHAR)*cbRefDN);
	if (!::LookupAccountName(system_name,
				 account_name,
				 mapi_sid,
				 &cbSID,
				 RefDN,
				 &cbRefDN,
				 &mapi_peUse)) {
		retv = false;

		DWORD err = ::GetLastError();
		char msg[512] = {0};
		LPVOID msg_buf;

		::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
				NULL,
				err,
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
				(LPTSTR) &msg_buf,
				0,
				NULL );
		((char*)msg_buf)[strlen((char*)msg_buf) - 2] = '\0';

		sprintf_s(msg, sizeof(msg), "LookupAccountName(%s/%s) failed - GetLastError() returned: 0x%X (%s)", system_name, account_name, err, (char*)msg_buf);
		BRUTUS_LOG_ERR(msg);
		LocalFree(msg_buf);

		goto out;
	} else
		retv = true;

	// copy SID
	unsigned long n = 0;
	brutus_sid->length(cbSID);
	for (n = 0; n < cbSID; n++)
		brutus_sid[n] = (::CORBA::Octet)((LPBYTE*)mapi_sid)[n];
	free(mapi_sid);

	// copy RefDN
	out_ref_dn = ::CORBA::string_dup(RefDN);
	free(RefDN);

	switch (mapi_peUse) {
	case SidTypeUser :
		peUse = ::BRUTUS::BRUTUS_SidTypeUser;
		break;
	case SidTypeGroup :
		peUse = ::BRUTUS::BRUTUS_SidTypeGroup;
		break;
	case SidTypeDomain :
		peUse = ::BRUTUS::BRUTUS_SidTypeDomain;
		break;
	case SidTypeAlias :
		peUse = ::BRUTUS::BRUTUS_SidTypeAlias;
		break;
	case SidTypeWellKnownGroup :
		peUse = ::BRUTUS::BRUTUS_SidTypeWellKnownGroup;
		break;
	case SidTypeDeletedAccount :
		peUse = ::BRUTUS::BRUTUS_SidTypeDeletedAccount;
		break;
	case SidTypeInvalid :
		peUse = ::BRUTUS::BRUTUS_SidTypeInvalid;
		break;
	case SidTypeUnknown :
		peUse = ::BRUTUS::BRUTUS_SidTypeUnknown;
		break;
	case SidTypeComputer :
		peUse = ::BRUTUS::BRUTUS_SidTypeComputer;
		break;
	default :
	{
		char msg[128] = {0};
		sprintf_s(msg, sizeof(msg), "Unknown SID_NAME_USE from Windows : %d", mapi_peUse);
		BRUTUS_LOG_BUG(msg);
		break;
	}
	}
out:
	Sid = brutus_sid._retn();
	ReferencedDomainName = out_ref_dn._retn();

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::LookupAccountName()");
	return retv;
}

static ::HRESULT
create_imessage_by_name(LPMAPIFOLDER parent,
			const LPTSTR message_class,
			const LPTSTR subject,
			LPMESSAGE *message,
			::ULONG *entryid_count,
			LPENTRYID *entryid)
{
	BRUTUS_LOG_INF("Entering create_imessage_by_name()");

	::HRESULT hr = E_FAIL;
	SPropValue pv;
	LPSPropValue lpprop = NULL;

	*message = NULL;
	*entryid_count = 0;
	*entryid = NULL;

	hr = parent->CreateMessage(NULL,
				   0,
				   message);
	if (S_OK != hr)
		return hr;

	hr = (*message)->SaveChanges(KEEP_OPEN_READWRITE);
	if (S_OK != hr) {
		(*message)->Release();
		(*message) = NULL;
		return hr;
	}

	if (message_class) {
		pv.ulPropTag = PR_MESSAGE_CLASS;
		pv.Value.lpszA = message_class;
		hr = (*message)->SetProps(1, &pv, NULL);
		if (S_OK != hr) {
			(*message)->Release();
			(*message) = NULL;
			return hr;
		}
	}

	if (subject) {
		pv.ulPropTag = PR_SUBJECT;
		pv.Value.lpszA = subject;
		hr = (*message)->SetProps(1, &pv, NULL);
		if (S_OK != hr) {
			(*message)->Release();
			(*message) = NULL;
			return hr;
		}
	}

	hr = (*message)->SaveChanges(KEEP_OPEN_READWRITE);
	if (S_OK != hr) {
		(*message)->Release();
		(*message) = NULL;
		return hr;
	}

	hr = HrGetOneProp((LPMAPIPROP)(*message), PR_ENTRYID, &lpprop);
	if (S_OK != hr) {
		(*message)->Release();
		(*message) = NULL;
		return hr;
	}

	*entryid_count = lpprop->Value.bin.cb;
	hr = MAPIAllocateBuffer(lpprop->Value.bin.cb, (void**)entryid);
	if (S_OK != hr) {
		MAPIFreeBuffer(lpprop);
		(*message)->Release();
		(*message) = NULL;
		return hr;
	}
	memcpy((void*)*entryid, lpprop->Value.bin.lpb, lpprop->Value.bin.cb);
	*entryid_count = lpprop->Value.bin.cb;
	MAPIFreeBuffer(lpprop);

	hr = parent->SaveChanges(KEEP_OPEN_READWRITE);
	if (S_OK != hr) {
		(*message)->Release();
		(*message) = NULL;
		return hr;
	}

	BRUTUS_LOG_INF("Leaving create_imessage_by_name()");
	return hr;
}

static ::HRESULT
create_subfolder_by_name(LPMAPIFOLDER parent,
			 const LPTSTR child_name,
			 const LPTSTR container_class,
			 const ULONG folder_type,
			 LPMAPIFOLDER *child,
			 ::ULONG *entryid_count,
			 LPENTRYID *entryid)
{
	BRUTUS_LOG_INF("Entering create_subfolder_by_name()");

	::HRESULT hr = E_FAIL;
	SPropValue pv;
	LPSPropValue lpprop = NULL;

	*child = NULL;
	*entryid_count = 0;
	*entryid = NULL;

	hr = parent->CreateFolder(folder_type,
				  child_name,
				  NULL,
				  NULL,
				  OPEN_IF_EXISTS,
				  child);
	if (S_OK != hr)
		return hr;

	hr = (*child)->SaveChanges(KEEP_OPEN_READWRITE);
	if (S_OK != hr) {
		(*child)->Release();
		(*child) = NULL;
		return hr;
	}

	if (container_class) {
		pv.ulPropTag = PR_CONTAINER_CLASS;
		pv.Value.lpszA = container_class;
		hr = (*child)->SetProps(1, &pv, NULL);
		if (S_OK != hr) {
			(*child)->Release();
			(*child) = NULL;
			return hr;
		}
	}

	hr = (*child)->SaveChanges(KEEP_OPEN_READWRITE);
	if (S_OK != hr) {
		(*child)->Release();
		(*child) = NULL;
		return hr;
	}

	hr = HrGetOneProp((LPMAPIPROP)(*child), PR_ENTRYID, &lpprop);
	if (S_OK != hr) {
		(*child)->Release();
		(*child) = NULL;
		return hr;
	}

	*entryid_count = lpprop->Value.bin.cb;
	hr = MAPIAllocateBuffer(lpprop->Value.bin.cb, (void**)entryid);
	if (S_OK != hr) {
		MAPIFreeBuffer(lpprop);
		(*child)->Release();
		(*child) = NULL;
		return hr;
	}
	memcpy((void*)*entryid, lpprop->Value.bin.lpb, lpprop->Value.bin.cb);
	*entryid_count = lpprop->Value.bin.cb;
	MAPIFreeBuffer(lpprop);

	hr = parent->SaveChanges(KEEP_OPEN_READWRITE);
	if (S_OK != hr) {
		(*child)->Release();
		(*child) = NULL;
		return hr;
	}

	BRUTUS_LOG_INF("Leaving create_subfolder_by_name()");
	return hr;
}

static ::HRESULT
init_mailbox(LPMAPISESSION mapi_session)
{
	BRUTUS_LOG_INF("Entering init_mailbox()");

	::HRESULT hr = E_FAIL;
	::HRESULT hhr = E_FAIL;
	ULONG obj_type = 0;
	LPMDB msg_store = NULL;
	LPMAPIFOLDER root_folder = NULL;
	LPMAPIFOLDER top_folder = NULL; // "Top of Information Store"
	LPMAPIFOLDER child_folder = NULL;
	LPMAPIFOLDER inbox_folder = NULL;
	LPMAPIFOLDER finder_folder = NULL;
	SPropValue pv;
	ULONG entryid_count = 0;
	ENTRYID *entryid = NULL;
	SRowSet *row_set = NULL;

	// get personal message store
	hr = get_default_message_store(mapi_session, &msg_store);
	if ((S_OK != hr) && (MAPI_W_ERRORS_RETURNED != hr))
		goto exit;

	// open root folder
	hr = msg_store->OpenEntry(0, 0, NULL, MAPI_BEST_ACCESS, &obj_type, (LPUNKNOWN*)&root_folder);
	if (S_OK != hr)
		goto exit;

	/*
	 * Create folders and properties
	 */

	do { // root->Shortcuts (Favorites) - eid on message store
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(msg_store, PR_IPM_FAVORITES_ENTRYID, &lpv);
		if ((S_OK == hr) && (lpv->Value.bin.cb)) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(root_folder,
					      "Shortcuts",
					      NULL,
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_FAVORITES_ENTRYID;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = msg_store->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = msg_store->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // root->top_folder (Top of Information Store) - eid on message store
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(msg_store, PR_IPM_SUBTREE_ENTRYID, &lpv);
		if ((S_OK == hr) && (lpv->Value.bin.cb)) { // already present
			// open top folder
			hr = msg_store->OpenEntry(lpv->Value.bin.cb,
						  (LPENTRYID)lpv->Value.bin.lpb,
						  NULL,
						  MAPI_BEST_ACCESS,
						  &obj_type,
						  (LPUNKNOWN*)&top_folder);
			if (S_OK != hr)
				goto exit;

			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(root_folder,
					      "Top of Information Store",
					      NULL,
					      FOLDER_GENERIC,
					      &top_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_SUBTREE_ENTRYID;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = msg_store->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = msg_store->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;
	} while (false);

	do { // top_folder->Outbox - eid on message store
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(msg_store, PR_IPM_OUTLOOK_OUTBOX, &lpv);
		if ((S_OK == hr) && (lpv->Value.bin.cb)) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(top_folder,
					      "Outbox",
					      NULL,
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_OUTBOX;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = msg_store->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = msg_store->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // top_folder->Deleted Items - eid on message store
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(msg_store, PR_IPM_OUTLOOK_WASTEBASKET, &lpv);
		if ((S_OK == hr) && (lpv->Value.bin.cb)) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(top_folder,
					      "Deleted Items",
					      NULL,
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_WASTEBASKET;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = msg_store->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = msg_store->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // top_folder->Sent Items - eid on message store
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(msg_store, PR_IPM_OUTLOOK_SENTMAIL, &lpv);
		if ((S_OK == hr) && (lpv->Value.bin.cb)) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(top_folder,
					      "Sent Items",
					      NULL,
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_SENTMAIL;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = msg_store->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = msg_store->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // root_folder->Views - eid on message store
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(msg_store, PR_IPM_OUTLOOK_VIEWS, &lpv);
		if ((S_OK == hr) && (lpv->Value.bin.cb)) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(root_folder,
					      "Views",
					      NULL,
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_VIEWS;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = msg_store->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = msg_store->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // root_folder->Common Views - eid on message store
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(msg_store, PR_IPM_OUTLOOK_COMMON_VIEWS, &lpv);
		if ((S_OK == hr) && (lpv->Value.bin.cb)) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(root_folder,
					      "Common Views",
					      NULL,
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_COMMON_VIEWS;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = msg_store->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = msg_store->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // root_folder->Finder - eid on message store
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(msg_store, PR_IPM_OUTLOOK_FINDER, &lpv);
		if ((S_OK == hr) && (lpv->Value.bin.cb)) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(root_folder,
					      "Finder",
					      NULL,
					      FOLDER_GENERIC,
					      &finder_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_FINDER;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = msg_store->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = msg_store->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;
	} while (false);

	do {// root_folder->Finder->MS-OLK-AllMailItems - Search folder
		// TODO: check for presence
		if (!finder_folder)
			break;

		hr = create_subfolder_by_name(finder_folder,
					      "MS-OLK-AllMailItems",
					      "IPF.Note",
					      FOLDER_SEARCH,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		MAPIFreeBuffer(entryid);
		entryid = NULL;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // top_folder->Inbox - ReceiveFolder
		char *explicit_class = NULL;

		hr = msg_store->GetReceiveFolder("IPM.Note",
						 0,
						 &entryid_count,
						 &entryid,
						 &explicit_class);
		MAPIFreeBuffer(explicit_class);
		if ((S_OK == hr) && entryid_count) {
			hr = msg_store->OpenEntry(entryid_count,
						  entryid,
						  NULL,
						  MAPI_BEST_ACCESS,
						  &obj_type,
						  (LPUNKNOWN*)&inbox_folder);
			MAPIFreeBuffer(entryid);
			entryid = NULL;
			break;
		}

		hr = create_subfolder_by_name(top_folder,
					      "Inbox",
					      NULL,
					      FOLDER_GENERIC,
					      &inbox_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		hr = msg_store->SetReceiveFolder("IPM.Note",
						 0,
						 entryid_count,
						 entryid);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = msg_store->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;
	} while (false);

	do { // top_folder->Junk E-mail - eid on root folder and Inbox
		ULONG n;
		LPSPropValue lpprop = NULL;
		SPropValue new_pv;

		hr = HrGetOneProp(root_folder, PR_ADDITIONAL_REN_ENTRYIDS, &lpprop);
		if ((S_OK == hr)
		    && (lpprop->Value.MVbin.cValues >= ::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX + 1)
		    && lpprop->Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX].cb) { // already present
			MAPIFreeBuffer(lpprop);
			break;
		}
		if ((S_OK != hr) && (MAPI_E_NOT_FOUND != hr))
			goto exit;

		hhr = create_subfolder_by_name(top_folder,
					       "Junk E-mail",
					       "IPF.Note",
					       FOLDER_GENERIC,
					       &child_folder,
					       &entryid_count,
					       &entryid);
		if (S_OK != hhr) {
			MAPIFreeBuffer(lpprop);
			goto exit;
		}

		/*
		 * Get and set on root folder
		 */

		// initialize new SPropValue
		new_pv.ulPropTag = PR_ADDITIONAL_REN_ENTRYIDS;

		if (MAPI_E_NOT_FOUND == hr) {
			lpprop = NULL;

			new_pv.Value.MVbin.cValues = ::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX + 1;
			hr = MAPIAllocateBuffer(new_pv.Value.MVbin.cValues * sizeof(SBinary), (void**)&new_pv.Value.MVbin.lpbin);
			if (S_OK != hr)
				goto exit;

			// initialize array
			for (n = 0; n < new_pv.Value.MVbin.cValues; n++) {
				new_pv.Value.MVbin.lpbin[n].cb = 0;
				new_pv.Value.MVbin.lpbin[n].lpb = NULL;
			}
		} else {
			// allocate new SPropValue data array
			if (::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX + 1 > lpprop->Value.MVbin.cValues) {
				new_pv.Value.MVbin.cValues = ::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX + 1;
			} else {
				new_pv.Value.MVbin.cValues = lpprop->Value.MVbin.cValues;
			}
			hr = MAPIAllocateBuffer(new_pv.Value.MVbin.cValues * sizeof(SBinary), (void**)&new_pv.Value.MVbin.lpbin);
			if (S_OK != hr) {
				MAPIFreeBuffer(lpprop);
				goto exit;
			}

			// copy old values
			for (n = 0; n < lpprop->Value.MVbin.cValues; n++) {
				new_pv.Value.MVbin.lpbin[n].cb = lpprop->Value.MVbin.lpbin[n].cb;
				new_pv.Value.MVbin.lpbin[n].lpb = lpprop->Value.MVbin.lpbin[n].lpb;
			}
			for (n = lpprop->Value.MVbin.cValues; n < new_pv.Value.MVbin.cValues; n++) {
				new_pv.Value.MVbin.lpbin[n].cb = 0;
				new_pv.Value.MVbin.lpbin[n].lpb = NULL;
			}
		}
		// copy junk entryid
		new_pv.Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX].cb = entryid_count;
		new_pv.Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX].lpb = (LPBYTE)entryid;

		// set property on root folder
		hr = root_folder->SetProps(1, &new_pv, NULL);
		if (lpprop) {
			MAPIFreeBuffer(lpprop);
			lpprop = NULL;
		}
		MAPIFreeBuffer(new_pv.Value.MVbin.lpbin);
		if (S_OK != hr) {
			MAPIFreeBuffer(entryid);
			entryid = NULL;
			goto exit;
		}
		hr = root_folder->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		/*
		 * Get and set on inbox folder
		 */

		// get old value
		new_pv.Value.MVbin.lpbin = NULL;
		hr = HrGetOneProp(inbox_folder, PR_ADDITIONAL_REN_ENTRYIDS, &lpprop);
		if ((S_OK != hr) && (MAPI_E_NOT_FOUND != hr))
			goto exit;

		if (MAPI_E_NOT_FOUND == hr) {
			lpprop = NULL;

			new_pv.Value.MVbin.cValues = ::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX + 1;
			hr = MAPIAllocateBuffer(new_pv.Value.MVbin.cValues * sizeof(SBinary), (void**)&new_pv.Value.MVbin.lpbin);
			if (S_OK != hr)
				goto exit;

			// initialize array
			for (n = 0; n < new_pv.Value.MVbin.cValues; n++) {
				new_pv.Value.MVbin.lpbin[n].cb = 0;
				new_pv.Value.MVbin.lpbin[n].lpb = NULL;
			}
		} else {
			// allocate new SPropValue data array
			if (::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX + 1 > lpprop->Value.MVbin.cValues)
				new_pv.Value.MVbin.cValues = ::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX + 1;
			else
				new_pv.Value.MVbin.cValues = lpprop->Value.MVbin.cValues;
			hr = MAPIAllocateBuffer(new_pv.Value.MVbin.cValues * sizeof(SBinary), (void**)&new_pv.Value.MVbin.lpbin);
			if (S_OK != hr) {
				MAPIFreeBuffer(lpprop);
				goto exit;
			}

			// copy old values
			for (n = 0; n < lpprop->Value.MVbin.cValues; n++) {
				new_pv.Value.MVbin.lpbin[n].cb = lpprop->Value.MVbin.lpbin[n].cb;
				new_pv.Value.MVbin.lpbin[n].lpb = lpprop->Value.MVbin.lpbin[n].lpb;
			}
			for (n = lpprop->Value.MVbin.cValues; n < new_pv.Value.MVbin.cValues; n++) {
				new_pv.Value.MVbin.lpbin[n].cb = 0;
				new_pv.Value.MVbin.lpbin[n].lpb = NULL;
			}
		}
		// copy junk entryid
		new_pv.Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX].cb = entryid_count;
		new_pv.Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_ADDITIONAL_REN_ENTRYIDS_JUNK_INDEX].lpb = (LPBYTE)entryid;

		// set property on inbox folder
		hr = inbox_folder->SetProps(1, &new_pv, NULL);
		if (lpprop)
			MAPIFreeBuffer(lpprop);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		MAPIFreeBuffer(new_pv.Value.MVbin.lpbin);
		if (S_OK != hr)
			goto exit;

		hr = inbox_folder->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // "root_folder->Freebusy Data" and LocalFreebusy contained IMessage - eids on root folder
		ULONG n;
		SPropValue new_pv;
		LPSPropValue lpprop = NULL;
		LPMESSAGE message = NULL;
		ULONG msg_entryid_count = 0;
		ENTRYID *msg_entryid = NULL;

		hr = HrGetOneProp(root_folder, PR_FREEBUSY_ENTRYIDS, &lpprop);
		if ((S_OK == hr)
		    && (lpprop->Value.MVbin.cValues >= ::BRUTUS::BRUTUS_PR_FREEBUSY_ENTRYIDS_LOCAL_FOLDER_INDEX + 1)
		    && lpprop->Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_FREEBUSY_ENTRYIDS_LOCAL_FOLDER_INDEX].cb) { // assuming already present with contained message
			MAPIFreeBuffer(lpprop);
			break;
		}
		if ((S_OK != hr) && (MAPI_E_NOT_FOUND != hr))
			goto exit;

		hhr = create_subfolder_by_name(root_folder,
					       "Freebusy Data",
					       NULL,
					       FOLDER_GENERIC,
					       &child_folder,
					       &entryid_count,
					       &entryid);
		if (S_OK != hhr) {
			MAPIFreeBuffer(lpprop);
			goto exit;
		}

		/*
		 * Get and set on root folder
		 */

		// initialize new SPropValue
		new_pv.ulPropTag = PR_FREEBUSY_ENTRYIDS;

		if (MAPI_E_NOT_FOUND == hr) {
			lpprop = NULL;

			new_pv.Value.MVbin.cValues = ::BRUTUS::BRUTUS_PR_FREEBUSY_ENTRYIDS_LOCAL_FOLDER_INDEX + 1;
			hr = MAPIAllocateBuffer(new_pv.Value.MVbin.cValues * sizeof(SBinary), (void**)&new_pv.Value.MVbin.lpbin);
			if (S_OK != hr)
				goto exit;

			// initialize array
			for (n = 0; n < new_pv.Value.MVbin.cValues; n++) {
				new_pv.Value.MVbin.lpbin[n].cb = 0;
				new_pv.Value.MVbin.lpbin[n].lpb = NULL;
			}
		} else {
			// allocate new SPropValue data array
			if (::BRUTUS::BRUTUS_PR_FREEBUSY_ENTRYIDS_LOCAL_FOLDER_INDEX + 1 > lpprop->Value.MVbin.cValues)
				new_pv.Value.MVbin.cValues = ::BRUTUS::BRUTUS_PR_FREEBUSY_ENTRYIDS_LOCAL_FOLDER_INDEX + 1;
			else
				new_pv.Value.MVbin.cValues = lpprop->Value.MVbin.cValues;
			hr = MAPIAllocateBuffer(new_pv.Value.MVbin.cValues * sizeof(SBinary), (void**)&new_pv.Value.MVbin.lpbin);
			if (S_OK != hr) {
				MAPIFreeBuffer(lpprop);
				goto exit;
			}

			// copy old values
			for (n = 0; n < lpprop->Value.MVbin.cValues; n++) {
				new_pv.Value.MVbin.lpbin[n].cb = lpprop->Value.MVbin.lpbin[n].cb;
				new_pv.Value.MVbin.lpbin[n].lpb = lpprop->Value.MVbin.lpbin[n].lpb;
			}
			for (n = lpprop->Value.MVbin.cValues; n < new_pv.Value.MVbin.cValues; n++) {
				new_pv.Value.MVbin.lpbin[n].cb = 0;
				new_pv.Value.MVbin.lpbin[n].lpb = NULL;
			}
		}

		// copy Freebusy entryid
		new_pv.Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_FREEBUSY_ENTRYIDS_LOCAL_FOLDER_INDEX].cb = entryid_count;
		new_pv.Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_FREEBUSY_ENTRYIDS_LOCAL_FOLDER_INDEX].lpb = (LPBYTE)entryid;

		/*
		 * Create root->Freebusy Data/LocalFreebusy" IMessage before setting property
		 */

		hr = create_imessage_by_name(child_folder,
					     "IPM.Microsoft.ScheduleData.FreeBusy",
					     "LocalFreebusy",
					     &message,
					     &msg_entryid_count,
					     &msg_entryid);
		if (message) {
			message->SaveChanges(0);
			message->Release();
		}
		if (S_OK != hr) {
			MAPIFreeBuffer(lpprop);
			goto exit;
		}

		// now copy LocalFreebusy entryid
		new_pv.Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_FREEBUSY_ENTRYIDS_LOCAL_IMESSAGE_INDEX].cb = msg_entryid_count;
		new_pv.Value.MVbin.lpbin[::BRUTUS::BRUTUS_PR_FREEBUSY_ENTRYIDS_LOCAL_IMESSAGE_INDEX].lpb = (LPBYTE)msg_entryid;

		// set property on root folder
		hr = root_folder->SetProps(1, &new_pv, NULL);
		if (lpprop) {
			MAPIFreeBuffer(lpprop);
			lpprop = NULL;
		}
		MAPIFreeBuffer(new_pv.Value.MVbin.lpbin);
		MAPIFreeBuffer(msg_entryid);
		if (S_OK != hr) {
			MAPIFreeBuffer(entryid);
			entryid = NULL;
			goto exit;
		}
		hr = root_folder->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // top_folder->Calendar - eid on root folder
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(root_folder, PR_IPM_OUTLOOK_CALENDAR, &lpv);
		if ((S_OK == hr) && lpv && lpv->Value.bin.cb) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(top_folder,
					      "Calendar",
					      "IPF.Appointment",
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_CALENDAR;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = root_folder->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = root_folder->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // top_folder->Contacts - eid on root folder
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(root_folder, PR_IPM_OUTLOOK_CONTACTS, &lpv);
		if ((S_OK == hr) && lpv && lpv->Value.bin.cb) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(top_folder,
					      "Contacts",
					      "IPF.Contact",
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_CONTACTS;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = root_folder->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = root_folder->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // top_folder->Journal - eid on root folder
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(root_folder, PR_IPM_OUTLOOK_JOURNAL, &lpv);
		if ((S_OK == hr) && lpv && lpv->Value.bin.cb) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(top_folder,
					      "Journal",
					      "IPF.Journal",
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_JOURNAL;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = root_folder->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = root_folder->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // top_folder->Notes - eid on root folder
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(root_folder, PR_IPM_OUTLOOK_NOTES, &lpv);
		if ((S_OK == hr) && lpv && lpv->Value.bin.cb) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(top_folder,
					      "Notes",
					      "IPF.StickyNote",
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_NOTES;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = root_folder->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = root_folder->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // top_folder->Tasks - eid on root folder
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(root_folder, PR_IPM_OUTLOOK_TASKS, &lpv);
		if ((S_OK == hr) && lpv && lpv->Value.bin.cb) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(top_folder,
					      "Tasks",
					      "IPF.Task",
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_TASKS;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = root_folder->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = root_folder->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // root_folder->Reminders - eid on root folder
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(root_folder, PR_IPM_OUTLOOK_REMINDERS, &lpv);
		if ((S_OK == hr) && lpv && lpv->Value.bin.cb) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(root_folder,
					      "Reminders",
					      "Outlook.Reminder",
					      FOLDER_SEARCH,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_REMINDERS;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = root_folder->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = root_folder->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

	do { // top_folder->Drafts - eid on root folder
		LPSPropValue lpv = NULL;

		hr = HrGetOneProp(root_folder, PR_IPM_OUTLOOK_DRAFTS, &lpv);
		if ((S_OK == hr) && lpv && lpv->Value.bin.cb) { // already present
			MAPIFreeBuffer(lpv);
			break;
		}
		MAPIFreeBuffer(lpv);

		hr = create_subfolder_by_name(top_folder,
					      "Drafts",
					      "IPF.Note",
					      FOLDER_GENERIC,
					      &child_folder,
					      &entryid_count,
					      &entryid);
		if (S_OK != hr)
			goto exit;

		pv.ulPropTag = PR_IPM_OUTLOOK_DRAFTS;
		pv.Value.bin.cb = entryid_count;
		pv.Value.bin.lpb = (LPBYTE)entryid;
		hr = root_folder->SetProps(1, &pv, NULL);
		MAPIFreeBuffer(entryid);
		entryid = NULL;
		if (S_OK != hr)
			goto exit;

		hr = root_folder->SaveChanges(KEEP_OPEN_READWRITE);
		if (S_OK != hr)
			goto exit;

		child_folder->SaveChanges(0);
		child_folder->Release();
		child_folder = NULL;
	} while (false);

exit:
	if (entryid)
		MAPIFreeBuffer(entryid);

	if (child_folder) {
		child_folder->SaveChanges(0);
		child_folder->Release();
	}

	if (inbox_folder) {
		inbox_folder->SaveChanges(0);
		inbox_folder->Release();
	}

	if (finder_folder) {
		finder_folder->SaveChanges(0);
		finder_folder->Release();
	}

	if (top_folder) {
		top_folder->SaveChanges(0);
		top_folder->Release();
	}

	if (root_folder) {
		root_folder->SaveChanges(0);
		root_folder->Release();
	}

	if (msg_store) {
		msg_store->SaveChanges(0);
		msg_store->Release();
	}

	BRUTUS_LOG_INF("Leaving init_mailbox()");
	return hr;
}

::BRUTUS::BRESULT
BRUTUS_IMAPISession_i::InitMailbox(void)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::init_mailbox()");

	::HRESULT hr = E_FAIL;

	{
		ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);
		hr = init_mailbox(mapi_session_);
	}

	::BRUTUS::BRESULT br;
	if (!hresult_to_bresult(hr, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		br = ::BRUTUS::BRUTUS_INTERNAL_ERROR;
	}

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::InitMailbox()");
	return br;
}

::CORBA::Boolean
BRUTUS_IMAPISession_i::GetServerVersion(::BRUTUS::SERVER_VERSION_out Version)
{
	BRUTUS_LOG_INF("Entering BRUTUS_IMAPISession_i::GetServerVersion()");

	::CORBA::Boolean retv = false;
	try {
		::HRESULT hr = E_FAIL;
		ULONG obj_type = 0;
		LPMDB msg_store = NULL;
		LPMAPIFOLDER root_folder = NULL;
		LPSPropValue lpprop = NULL;
		::BRUTUS::SERVER_VERSION_var ver;

		try {
			ver = new ::BRUTUS::SERVER_VERSION;
		}
		catch (std::bad_alloc &) {
			BRUTUS_LOG_ERR("No memory");
			throw ::CORBA::NO_MEMORY();
		}
		ver->MajorVersion = 0x0000;
		ver->MinorVersion = 0x0000;
		ver->Build = 0x0000;
		ver->MinorBuild = 0x0000;

		{
			ACE_Write_Guard<ACE_RW_Mutex> guard(mutex_);

			// get personal message store
			hr = get_default_message_store(mapi_session_, &msg_store);
			if ((S_OK != hr) && (MAPI_W_ERRORS_RETURNED != hr))
				goto exit;
		}

		// open root folder
		hr = msg_store->OpenEntry(0, 0, NULL, MAPI_BEST_ACCESS, &obj_type, (LPUNKNOWN*)&root_folder);
		if (S_OK != hr)
			goto exit;

		hr = HrGetOneProp(root_folder, PR_REPLICA_VERSION, &lpprop);
		if (S_OK != hr)
			goto exit;

		retv = large_int_mapi_to_brutus_server_version(&(lpprop->Value.li), ver.out());
	exit:
		Version = ver._retn();

		if (root_folder)
			root_folder->Release();

		if (msg_store)
			msg_store->Release();

		if (lpprop)
			MAPIFreeBuffer(lpprop);
	}
	catch (std::bad_alloc &) {
		BRUTUS_LOG_ERR("No memory");
		retv = false;
	}
	catch (const ::CORBA::Exception &e) {
		BRUTUS_LOG_CRITICAL(e._info().c_str());
		retv = false;
	}
	catch (...) {
		BRUTUS_LOG_CRITICAL("Unknown exception caught");
		retv = false;
	}

	BRUTUS_LOG_INF("Leaving BRUTUS_IMAPISession_i::GetServerVersion()");
	return retv;
}
