// --gwobjcls.cpp-------------------------------------------------------------
//
// Class source file for the GWCLEAN class object.
//
// Copyright (C) Microsoft Corporation 1986-1996, All Rights Reserved
//
// ----------------------------------------------------------------------------
#include "edk.h"
#include "mspst.h"
#include "gwstring.h"
#include "gwobjcls.h"
#include "gwevents.h"// compiled from gwevents.mc
#include "gwobjcls.chk"
// external function declarations
extern VOID DisplayUserMsg(// RETURNS: VOID
IN UINT uResID,// resource string identifier
...);// additional arguments
extern inline VOID INTERNAL_ERROR(
IN LPCTSTR str,
IN const HRESULT hr);
//$--CGWClean::CGWClean----------------------------------------
//
// DESCRIPTION: constructor for CGWClean
//
// INPUT: none
//
// RETURNS: nothing
//
// -------------------------------------------------------------
CGWClean::CGWClean() // returns nothing
{
DEBUGPRIVATE("CGWClean::CGWClean()\n");
// Initialize data members.
m_fNewPST = FALSE;
m_fNoMessages = FALSE;
m_lpProfileName = NULL;
m_lpPSTName = NULL;
m_lpFolderName = NULL;
m_lpBeforeDateTime = NULL;
m_lpTempProfilePW = NULL;
m_lpTempProfName = NULL;
m_lpSessGW = NULL;
m_lpSessNew = NULL;
m_lpMDBGateway = NULL;
m_lpMDBNew = NULL;
m_lpFolderFrom = NULL;
m_lpFolderTo = NULL;
}
//$--CGWClean::~CGWClean-----------------------------------------------------
//
// DESCRIPTION: CGWClean Destructor
//
// ---------------------------------------------------------------------------
CGWClean::~CGWClean()
{
HRESULT hr = NOERROR;
DEBUGPRIVATE("CGWClean::~CGWClean()\n");
if ( m_lpMDBGateway )
{
// Set the PR_TRANSFER_ENABLED property so that message
// transfer activity resumes on the gateway.
hr = HrMAPISetPropBoolean(
m_lpMDBGateway, // MAPI object pointer
PR_TRANSFER_ENABLED, // property tag
TRUE); // boolean value
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPISetPropBoolean()"), hr);
}
}
// clean up after PST creation. (Removes temporary profile)
if ( m_fNewPST )
{
(VOID)HrCleanupPSTGlobals(m_lpTempProfName);
// If there were no messages to move, delete the
// PST created.
if ( m_fNoMessages )
{
(VOID)DeleteFile(m_lpPSTName);
}
}
// Free MAPI buffers
MAPIFREEBUFFER(m_lpTempProfilePW);
MAPIFREEBUFFER(m_lpTempProfName);
// Release MAPI store and folder objects
ULRELEASE(m_lpMDBGateway);
ULRELEASE(m_lpMDBNew);
ULRELEASE(m_lpFolderFrom);
ULRELEASE(m_lpFolderTo);
// Logoff any MAPI sessions to which we are logged on.
if ( m_lpSessGW )
{
(VOID)m_lpSessGW->Logoff(0, 0, 0);
}
if ( m_lpSessNew )
{
(VOID)m_lpSessNew->Logoff(0, 0, 0);
}
// Release MAPI session objects if they have not already been released.
ULRELEASE(m_lpSessGW);
ULRELEASE(m_lpSessNew);
// Delete m_lpBeforeDateTime buffer.
if ( m_lpBeforeDateTime )
{
delete m_lpBeforeDateTime;
}
} // end CGWClean::~CGWClean();
//$--CGWClean::HrInitialize-------------------------------------------------------
//
// DESCRIPTION: CGWClean initializer. Creates profile,
// establishes sessions, opens default stores,
// opens from and to folders.
//
// INPUT: lpProfileName -- gateway profile name
// lpPSTName -- new PST name
// lpFolder -- gateway folder name
// lpBeforeDate -- date/time before which to move messages
//
// RETURNS: HRESULT -- NOERROR if successful,
// E_INVALIDARG if bad input,
// E_OUTOFMEMORY if memory problems,
// E_FAIL otherwise
//
// ---------------------------------------------------------------------------
HRESULT CGWClean::HrInitialize(
IN LPTSTR lpProfileName, // gateway profile name
IN LPTSTR lpPSTName, // New PST name
IN LPTSTR lpFolderName, // gateway folder name
IN LPFILETIME lpBeforeTime) // date/time before which to move messages
{
HRESULT hr = NOERROR;
ULONG cbEid = 0; // number of bytes in entry identifier
TCHAR szErrorCode[16] = {0};
// Special MAPI buffer base class which frees itself
// when it goes out of scope.
LPENTRYID lpEid = NULL; // entry identifier pointer
// MAPI session flags
const ULONG ulFlags = MAPI_EXPLICIT_PROFILE |
MAPI_NEW_SESSION |
MAPI_NO_MAIL;
// new PST PR_DISPLAY_NAME value
const LPTSTR lpszDisplayName = TEXT("Mailbox - GWCLEAN");
// Separator in folder name.
const TCHAR cSeparator = TEXT('\\');
// message database store flags
const ULONG ulMDBflags = MDB_NO_DIALOG | MDB_WRITE;
DEBUGPRIVATE("CGWClean::HrInitialize()\n");
hr = CHK_CGWClean_HrInitialize(lpProfileName,
lpPSTName, lpFolderName, lpBeforeTime);
if ( FAILED(hr) )
{
RETURN(hr);
}
// Initialize class members
m_lpProfileName = lpProfileName;
m_lpPSTName = lpPSTName;
m_lpFolderName = lpFolderName;
m_lpBeforeDateTime = new FILETIME;
if( !TEST_WRITE_PTR( m_lpBeforeDateTime, sizeof(FILETIME)) )
{
EventLogMsg(
GWCLEAN_OUTOFMEMORY,
0,
0);
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}
m_lpBeforeDateTime->dwHighDateTime = lpBeforeTime->dwHighDateTime;
m_lpBeforeDateTime->dwLowDateTime = lpBeforeTime->dwLowDateTime;
// Open session to gateway.
hr = MAPILogonEx(0, // UI flags,
m_lpProfileName, // profile name
NULL, // password
ulFlags, // MAPI flags
&m_lpSessGW);
if ( FAILED(hr) )
{
EventLogMsg(
GWCLEAN_PROFILEERR,
2, m_lpProfileName, _itot( hr, szErrorCode, 16),
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Create the new PST and temporary profile.
hr = HrCreatePersonalStore(
m_lpPSTName, // fully-pathed PST name
PSTF_NO_ENCRYPTION, // type of encryption
(LPTSTR) lpszDisplayName, // PST PR_DISPLAY_NAME value
TEXT(""), // PST password
&m_lpTempProfName, // temporary profile name
&m_lpTempProfilePW); // temporary profile password
if ( FAILED(hr) )
{
EventLogMsg(
GWCLEAN_NEWPSTERR,
2, m_lpPSTName, _itot( hr, szErrorCode, 16),
0);
goto cleanup;
}
// Have created a new PST.
m_fNewPST = TRUE;
// Log onto the PST's temporary profile
hr = MAPILogonEx(0, // UI flags
m_lpTempProfName, // temporary profile name
m_lpTempProfilePW, // temporary profile password
ulFlags, // MAPI flags,
&m_lpSessNew);
if ( FAILED(hr) )
{
EventLogMsg(
GWCLEAN_PROFILEERR,
2, m_lpTempProfName, _itot( hr, szErrorCode, 16),
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Open gateway's default message store.
// Find the default MDB message store in the gateway profile.
hr = HrMAPIFindDefaultMsgStore(m_lpSessGW, // session pointer
&cbEid, // count of bytes in entry ID
&lpEid); // entry id pointer for default store
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPIFindDefaultMsgStore()"), hr);
goto cleanup;
}
// Open the gateway's default message store.
hr = m_lpSessGW->OpenMsgStore(0, // window handle
cbEid, // # of bytes in entry ID
lpEid, // pointer to entry ID
NULL, // interface ID pointer
ulMDBflags, // flags
&m_lpMDBGateway); // output ptr to store
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPISession::OpenMsgStore()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Set the PR_TRANSFER_ENABLED property so that we don't
// get any activity on the gateway.
hr = HrMAPISetPropBoolean(
m_lpMDBGateway, // MAPI object pointer
PR_TRANSFER_ENABLED, // property tag
FALSE); // boolean value
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPISetPropBoolean()"), hr);
goto cleanup;
}
// Free gateway message store entry ID buffer
MAPIFREEBUFFER(lpEid);
// Open PST temporary profile's default message store.
// Find the default MDB message store in the gateway profile
// first
hr = HrMAPIFindDefaultMsgStore(m_lpSessNew, // session pointer
&cbEid, // count of bytes in entry ID
&lpEid); // entry id pointer for default store
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPIFindDefaultMsgStore()"), hr);
goto cleanup;
}
// Open the gateway's default message store.
hr = m_lpSessNew->OpenMsgStore(0, // window handle
cbEid, // # of bytes in entry ID
lpEid, // pointer to entry ID
NULL, // interface ID pointer
ulMDBflags, // flags
&m_lpMDBNew); // output ptr to store
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPISession::OpenMsgStore()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Open desired folder in gateway.
hr = HrMAPIOpenFolderEx(
m_lpMDBGateway, // message store pointer
cSeparator, // folder path separator
m_lpFolderName, // folder path
&m_lpFolderFrom);
if ( FAILED(hr) )
{
EventLogMsg(
GWCLEAN_BADFOLDER,
3,
m_lpFolderName,
m_lpProfileName,
_itot( hr, szErrorCode, 16),
0);
goto cleanup;
}
// Create GWCLEAN folder in PST.
hr = HrCreatePSTFolder();
if ( FAILED(hr) )
{
goto cleanup;
}
// We are now ready to move messages from the open
// gateway folder to the open PST folder.
// We are done with our initialization.
cleanup:
// Free MAPI buffers
MAPIFREEBUFFER(lpEid);
RETURN(hr);
} // end CGWClean::HrInitialize()
//$--CGWClean::HrCreatePSTFolder-----------------------------------------------
//
// DESCRIPTION: Create a new folder in the new PST and
// open it.
//
// RETURNS: HRESULT -- NOERROR if successful
// E_FAIL otherwise.
//
// ---------------------------------------------------------------------------
HRESULT CGWClean::HrCreatePSTFolder() // RETURNS: HRESULT
{
HRESULT hr = NOERROR; // MAPI return code
ULONG ulObjType = 0; // object type
#ifdef USE_MAPIWRAP
// Special MAPI object base classes which release
// object when they goe out of scope.
CMAPIInterface<LPMAPIFOLDER> lpRootFolder; // PST root folder
CMAPIInterface<LPMAPIFOLDER> lpTopOfStore; // top of personal folders in PST
#else
LPMAPIFOLDER lpRootFolder = NULL; // PST root folder pointer
LPMAPIFOLDER lpTopOfStore = NULL; // top of PST personal folders
#endif
// top of store folder name for PST.
const LPTSTR lpszTopOfStoreName = TEXT("Top of Personal Folders");
// Folder to which gateway messages are copied
const LPTSTR lpszGWCLEAN = TEXT("GWCLEAN");
DEBUGPRIVATE("CGWClean::HrCreatePSTFolder()\n");
// consistency checks
ASSERT_IUNKNOWN_PTR( m_lpMDBNew, "Bad m_lpMDBNew");
// Find the new PST's root folder.
hr = m_lpMDBNew->OpenEntry(0, // # of bytes in entry ID
NULL, // ptr to entry ID
NULL, // interface ID pointer
MAPI_MODIFY | MAPI_DEFERRED_ERRORS, // flags
&ulObjType, // object type pointer
(LPUNKNOWN *) &lpRootFolder); // output ptr to folder
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMsgStore::OpenEntry()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
ASSERTERROR( ulObjType == MAPI_FOLDER, "Bad ulObjType");
// Create the new PST's Top of Personal Folders folder.
hr = lpRootFolder->CreateFolder(
FOLDER_GENERIC, // folder type
(LPTSTR) lpszTopOfStoreName, // folder name
NULL, // folder comment
NULL, // interface ID pointer
OPEN_IF_EXISTS | MAPI_DEFERRED_ERRORS, // flags
&lpTopOfStore); // new folder pointer
if ( FAILED(hr) )
{
// Check for insufficient disk space.
if ( hr == MAPI_E_NOT_ENOUGH_DISK )
{
EventLogMsg(
GWCLEAN_OUTOFDISK,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
else
{
INTERNAL_ERROR( TEXT("IMAPIFolder::CreateFolder()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}// end if creation of folder failed
// Create the new PST's GWCLEAN folder (under the Top of Personal Folders folder).
// All gateway messages will be moved into this folder
hr = lpTopOfStore->CreateFolder(
FOLDER_GENERIC, // folder type
(LPTSTR) lpszGWCLEAN, // folder name
NULL, // folder comment
NULL, // interface ID pointer
OPEN_IF_EXISTS | MAPI_DEFERRED_ERRORS, // flags
&m_lpFolderTo); // new folder pointer
if ( FAILED(hr) )
{
// Check for insufficient disk space.
if ( hr == MAPI_E_NOT_ENOUGH_DISK )
{
EventLogMsg(
GWCLEAN_OUTOFDISK,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
else
{
INTERNAL_ERROR( TEXT("IMAPIFolder::CreateFolder()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}// end if creation of folder fails
cleanup:
ULRELEASE(lpTopOfStore);
ULRELEASE(lpRootFolder);
// Base classes take care of releasing MAPI objects
// and freeing MAPI memory.
RETURN(hr);
}
//$--CGWClean::HrMoveMsgs------------------------------------------------------
//
// DESCRIPTION: Move messages from gateways MTS-OUT folder to PSTs MTS-OUT folder.
//
// RESULT: HRESULT -- NOERROR if successful,
// EDK_E_NOT_FOUND if no messages to move,
// E_FAIL otherwise.
//
// ---------------------------------------------------------------------------
HRESULT CGWClean::HrMoveMsgs() // RETURNS: HRESULT
{
HRESULT hr = NOERROR; // MAPI return code
LPMAPITABLE lpContentsTable = NULL; // contents table for gateway MTS-OUT folder
LPENTRYLIST lpEidList = NULL; // list of entry identifiers to move
LPENTRYLIST lpSearchKeyList = NULL; // list of search key identifiers for messages copied
SizedSPropTagArray(2, SPropEntryIDs); // property tag array containing only PR_ENTRY_ID and PR_SEARCH_KEY
SRestriction sRestriction = {0};// Property restriction structure
SPropValue sPropValue = {0}; // Property value structure
LPSRowSet lpMsgRows = NULL; // Row pointer corresponding to a message
ULONG ulMsgCount = 0; // count of messages moved
SYSTEMTIME sSysTime = {0}; // local system time structure
FILETIME sLocalFileTime = {0}; // local file time structure
TCHAR szDateTimeString[80] = {0};// before date time string
ULONG ulCount = 0; // loop counter
ULONG ulNumBytes = 0; // size of entry identifier
LPBYTE lpEid = NULL; // entry ID pointer for message
TCHAR szErrorCode[16] = {0}; // buffer for error code strings
DEBUGPRIVATE("CGWCLEAN::HrMoveMsgs()\n");
// Consistency checking
ASSERT_IUNKNOWN_PTR( m_lpFolderFrom, "Bad m_lpFolderFrom");
ASSERT_IUNKNOWN_PTR( m_lpFolderTo, "Bad m_lpFolderTo");
// Get the contents table for the gateway's MTS-OUT folder.
hr = m_lpFolderFrom->GetContentsTable(
MAPI_DEFERRED_ERRORS, // flags
&lpContentsTable); // Contents table pointer
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPIFolder::GetContentsTable()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
ASSERTERROR((lpContentsTable != NULL), "Bad lpContentsTable");
// Get a list of all desired message IDs from the contents table.
// First, call SetColumns to chose the PR_ENTRY_ID column and
// PR_SEARCH_KEY columns. (PR_SEARCH_KEY is the transmittable,
// unique identifier of the message.)
SPropEntryIDs.cValues = 2;
SPropEntryIDs.aulPropTag[0] = PR_ENTRYID;
SPropEntryIDs.aulPropTag[1] = PR_SEARCH_KEY;
hr = lpContentsTable->SetColumns((LPSPropTagArray) (&SPropEntryIDs), // Properties desired
0); // flags
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPITable::SetColumns()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Make a call here to Restrict to restrict the rows in the table returned
// to be those where the PR_CREATION_TIME property is less than
// the desired "before" date.
ASSERTERROR((m_lpBeforeDateTime != NULL), "Bad m_lpBeforeDateTime");
sPropValue.ulPropTag = PR_CREATION_TIME;
sPropValue.Value.ft.dwLowDateTime = m_lpBeforeDateTime->dwLowDateTime;
sPropValue.Value.ft.dwHighDateTime = m_lpBeforeDateTime->dwHighDateTime;
sRestriction.rt = RES_PROPERTY;
sRestriction.res.resProperty.relop = RELOP_LT;
sRestriction.res.resProperty.ulPropTag = PR_CREATION_TIME;
sRestriction.res.resProperty.lpProp = &sPropValue;
hr = lpContentsTable->Restrict(&sRestriction, 0);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPITable::Restrict()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Let user know that we are starting the copy.
// (Convert the FILETIME value to a string for easy
// display to the user.)
FileTimeToLocalFileTime(m_lpBeforeDateTime, &sLocalFileTime); // system file time to local file time
FileTimeToSystemTime(&sLocalFileTime, &sSysTime); // local file time to local system time
wsprintf(szDateTimeString, TEXT("%d:%d:%d.%d %d/%d/%d"), sSysTime.wHour,
sSysTime.wMinute, sSysTime.wSecond, sSysTime.wMilliseconds,
sSysTime.wMonth, sSysTime.wDay, sSysTime.wYear);
ASSERT_STRING_PTR( szDateTimeString, "Bad szDateTimeString");
DisplayUserMsg(
IDS_STARTMOVE,
szDateTimeString,
m_lpProfileName,
m_lpPSTName);
// Build a list of entry identifiers for the messages which match
// our criteria.
while ( TRUE )
{
// Free the MAPI structures (SRowSet is special!)
FREEPROWS(lpMsgRows);
// Free EDK structures.
if ( lpEidList )
{
HrMAPIDestroyEntryList(&lpEidList);
lpEidList = NULL;
}
if ( lpSearchKeyList )
{
HrMAPIDestroyEntryList(&lpSearchKeyList);
lpSearchKeyList = NULL;
}
// Retrieve the row (messages) in the table which meet our
// selection criteria in EDK_MAX_QUERY_ROWS chunks (1024 at a time).
hr = lpContentsTable->QueryRows(EDK_MAX_QUERY_ROWS, // count to return
0, // flags
&lpMsgRows); // returned row structure pointer
switch (hr)
{
case MAPI_W_POSITION_CHANGED:
// Location in table changed by somebody else.
// Warn the user.
EventLogMsg(
GWCLEAN_POSCHANGED,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
default:
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPITable::QueryRows()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
} // end switch
ASSERTERROR((lpMsgRows != NULL), "Bad lpMsgRows");
// Check to see if any messages to process.
if ( !lpMsgRows->cRows )
{
// If no messages found at all, let user know.
if ( !ulMsgCount )
{
EventLogMsg(
GWCLEAN_NOMSGS,
1,
szDateTimeString,
0);
hr = HR_LOG(EDK_E_NOT_FOUND);
// Set no messages flag
m_fNoMessages = TRUE;
goto cleanup;
}
// Otherwise, we are done!
break;
}
// Add message identifiers for messages returned to our list of
// entry IDs.
ulMsgCount += lpMsgRows->cRows; // increment message count
for ( ulCount = 0; ulCount < lpMsgRows->cRows; ulCount++ )
{
ASSERTERROR(lpMsgRows->aRow[ulCount].cValues == 2,
"Bad lpMsgRows->aRow[].cValues");
ASSERTERROR(lpMsgRows->aRow[ulCount].lpProps[0].ulPropTag == PR_ENTRYID,
"Bad lpMsgRows->aRows[].lpProps[0].ulPropTag");
ASSERTERROR(lpMsgRows->aRow[ulCount].lpProps[1].ulPropTag == PR_SEARCH_KEY,
"Bad lpMsgRows->aRows[].lpProps[1].ulPropTag");
ulNumBytes = lpMsgRows->aRow[ulCount].lpProps[0].Value.bin.cb;
lpEid = lpMsgRows->aRow[ulCount].lpProps[0].Value.bin.lpb;
// Add entry identifier to the entry ID list.
if ( !lpEidList )
{
// Create new entry identifier list.
hr = HrMAPICreateEntryList(ulNumBytes, (LPENTRYID) lpEid, &lpEidList);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPICreateEntryList()"), hr);
goto cleanup;
}
}
else
{
hr = HrMAPIAppendEntryList(ulNumBytes, (LPENTRYID) lpEid, lpEidList);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPIAppendEntryList()"), hr);
goto cleanup;
}
}
ASSERTERROR((lpEidList != NULL), "Bad lpEidList");
ulNumBytes = lpMsgRows->aRow[ulCount].lpProps[1].Value.bin.cb;
lpEid = lpMsgRows->aRow[ulCount].lpProps[1].Value.bin.lpb;
// Add seach key identifier for search key list.
if ( !lpSearchKeyList )
{
// Create new search key list.
hr = HrMAPICreateEntryList(ulNumBytes, (LPENTRYID) lpEid, &lpSearchKeyList);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPICreateEntryList()"), hr);
goto cleanup;
}
}
else
{
hr = HrMAPIAppendEntryList(ulNumBytes, (LPENTRYID) lpEid, lpSearchKeyList);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPIAppendEntryList()"), hr);
goto cleanup;
}
}
ASSERTERROR((lpSearchKeyList != NULL), "Bad lpSearchKeyList");
} // end for
ASSERTERROR((lpEidList != NULL), "Bad lpEidList"); // just in case!
ASSERTERROR((lpSearchKeyList != NULL), "Bad lpSearchKeyList");
// Copy messages from gateway MTS-OUT folder to new PST's MTS-OUT
// folder.
hr = m_lpFolderFrom->CopyMessages(lpEidList, // list of message IDs
&IID_IMAPIFolder, // interface ID of destination folder
m_lpFolderTo, // destination folder ptr
0, // window handle
0, // progress dialogue handle
MAPI_DECLINE_OK ); // flags
switch (hr)
{
case MAPI_E_DECLINE_COPY:
// Provider doesn't support CopyMessages function.
// Warn the user.
EventLogMsg(
GWCLEAN_NOCOPYMSGS,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
case MAPI_E_NOT_ENOUGH_DISK:
// insufficient disk space.
EventLogMsg(
GWCLEAN_OUTOFDISK,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
case MAPI_W_PARTIAL_COMPLETION:
// Couldn't copy all messages.
// Warn the user.
EventLogMsg(
GWCLEAN_PARTIALCOPY,
1, _itot( hr, szErrorCode, 16),
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
default:
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPIFolder::CopyMessages()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
} // end switch
// Copy the extra gateway message properties not copied via CopyMessages
// from the old messages to the new messages.
hr = HrCopyGWMessageProps(lpEidList, lpSearchKeyList);
if ( FAILED(hr) )
{
goto cleanup;
}
// Now, delete messages moved from gateway MTS-OUT folder to the
// new PST MTS-OUT folder.
// Delete copied messages from gateway's MTS-OUT folder.
hr = m_lpFolderFrom->DeleteMessages(lpEidList, // entry identifier list
0, // window handle
0, // progress dialog
0); // flags
switch (hr)
{
case MAPI_W_PARTIAL_COMPLETION:
EventLogMsg(
GWCLEAN_PARTIALDEL,
1, _itot( hr, szErrorCode, 16),
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
case MAPI_E_HAS_FOLDERS:
case MAPI_E_SUBMITTED:
EventLogMsg(
GWCLEAN_PARTIALDEL,
1, _itot( hr, szErrorCode, 16),
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
default:
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPIFolder::DeleteMessages()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
} // end switch
} // end while messages to copy
// We have done it!
// Display a successful completion message and log event.
EventLogMsg(
GWCLEAN_SUCCESS,
1, _itot( ulMsgCount, szErrorCode, 10),
0);
DisplayUserMsg(
IDS_SUCCESS,
ulMsgCount);
cleanup:
// Free EDK structures.
if ( lpEidList )
{
HrMAPIDestroyEntryList(&lpEidList);
}
if ( lpSearchKeyList )
{
HrMAPIDestroyEntryList(&lpSearchKeyList);
}
// Free MAPI structures (SRowSet is special!)
FREEPROWS(lpMsgRows);
// Release MAPI objects.
ULRELEASE(lpContentsTable);
RETURN(hr);
} // end CGWClean::MoveMsgs()
//$--CGWClean::HrCopyGWMessageProps--------------------------------------------
//
// DESCRIPTION: Copy the gateway message (envelope) properties not copied by CopyMessages
// from the gateway messages to the new PST messages.
// The additional properties copied are determined
// in HrCreateNewProps().
//
// INPUT: LPENTRYLIST -- list of entry identifiers of messages copied.
// LPENTRYLIST -- list of search key identifiers of messages copied.
//
// RETURNS: HRESULT -- NOERROR if successful,
// E_INVALIDARG if bad input,
// E_FAIL otherwise
//
// ----------------------------------------------------------------------------
HRESULT CGWClean::HrCopyGWMessageProps( // RETURNS: HRESULT
IN LPENTRYLIST lpEidList, // entry identifiers
IN LPENTRYLIST lpSearchKeyList) // search keys
{
HRESULT hr = NOERROR; // return code
LPMESSAGE lpMessage = NULL; // original message pointer (envelope)
LPMESSAGE lpNewMessage = NULL; // copied message pointer (envelope)
ULONG ulObjType = 0; // MAPI object type
LPMAPITABLE lpContentsTable = NULL; // contents table pointer for new MTS-OUT folder
SRestriction sRestriction = {0};// Property restriction structure
SPropValue sPropValue = {0}; // Property value structure
LPSRowSet lpMsgRows = NULL; // Row pointer corresponding to a message
SizedSPropTagArray(2, SPropEntryIDs); // property tag array containing only PR_ENTRY_ID and PR_SEARCH_KEY
ULONG ulLoopCounter = 0; // loop counter
ULONG ulDupEidSize = 0; // duplicate message entry ID size
LPBYTE lpDupEid = NULL; // duplicate message's search key
ULONG ulTempIndex = 0; // temporary index
BOOL bDupDone = FALSE; // Duplicate done flag
LPENTRYLIST lpDoneList = NULL; // duplicates done list
DEBUGPRIVATE("CGWClean::HrCopyGWMessageProps()\n");
hr = CHK_CGWClean_HrCopyGWMessageProps(lpEidList, lpSearchKeyList);
if ( FAILED(hr) )
{
RETURN(hr);
}
// consistency checking
ASSERT_IUNKNOWN_PTR( m_lpFolderTo, "Bad m_lpFolderTo");
ASSERT_IUNKNOWN_PTR( m_lpFolderFrom, "Bad m_lpFolderFrom");
// Get the contents table for the new MTS-OUT folder.
hr = m_lpFolderTo->GetContentsTable(0, // flags
&lpContentsTable); // Contents table pointer
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPFolder::GetContentsTable()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Call SetColumns to chose the PR_ENTRY_ID column and
// PR_SEARCH_KEY columns for the new table. (PR_SEARCH_KEY is the transmittable,
// unique identifier of the message.)
SPropEntryIDs.cValues = 2;
SPropEntryIDs.aulPropTag[0] = PR_ENTRYID;
SPropEntryIDs.aulPropTag[1] = PR_SEARCH_KEY;
hr = lpContentsTable->SetColumns((LPSPropTagArray) (&SPropEntryIDs), // Properties desired
0); // flags
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPITable::SetColumns()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Handle each message in the list
for ( ulLoopCounter = 0; ulLoopCounter < lpEidList->cValues; ulLoopCounter++ )
{
// Release the MAPI objects.
ULRELEASE(lpMessage);
// Free the MAPI structures (SRowSet is special!)
FREEPROWS(lpMsgRows);
// Print out a . for every message to be copied.
_puttchar(TEXT('.'));
// Open original message envelope.
hr = m_lpFolderFrom->OpenEntry(
lpEidList->lpbin[ulLoopCounter].cb, // # of bytes in entry ID
(LPENTRYID) (lpEidList->lpbin[ulLoopCounter].lpb),// entry ID pointer
&IID_IMessage, // interface ID pointer
0, // flags
&ulObjType, // object type
(LPUNKNOWN FAR *) &lpMessage); // output pointer to message
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPIFolder::OpenEntry()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
ASSERT_IUNKNOWN_PTR( lpMessage, "Bad lpMessage");
ASSERTERROR(ulObjType == MAPI_MESSAGE, "Bad ulObjType");
// Go about finding the corresponding new message
// Make a call to find the row in the new folder's table
// where the PR_SEARCH_KEY property is equal to the
// PR_SEARCH_KEY property of the original message.
sPropValue.ulPropTag = PR_SEARCH_KEY;
sPropValue.Value.bin.cb = lpSearchKeyList->lpbin[ulLoopCounter].cb;
sPropValue.Value.bin.lpb = lpSearchKeyList->lpbin[ulLoopCounter].lpb;
sRestriction.rt = RES_PROPERTY;
sRestriction.res.resProperty.relop = RELOP_EQ;
sRestriction.res.resProperty.ulPropTag = PR_SEARCH_KEY;
sRestriction.res.resProperty.lpProp = &sPropValue;
hr = lpContentsTable->Restrict(&sRestriction, 0);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPITable::Restrict()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Retrieve the row(s) from the new table which meet the
// selection criteria.
hr = lpContentsTable->QueryRows(lpEidList->cValues, // maximum count to return
0, // flags
&lpMsgRows); // returned row structure pointer
switch (hr)
{
case MAPI_W_POSITION_CHANGED:
// Location in table changed by somebody else.
// Warn the user.
EventLogMsg(
GWCLEAN_POSCHANGED,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
default:
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPITable::QueryRows()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
} // end switch
ASSERT_READ_PTR( lpMsgRows, sizeof(SRowSet), "Bad lpMsgRows");
ASSERTERROR( lpMsgRows->cRows,
"Bad lpMsgRows->cRows"); // should be at least one match
ASSERTERROR(lpMsgRows->aRow[0].cValues == 2,
"Bad lpMsgRows->aRow[0].cValues");
ASSERTERROR(lpMsgRows->aRow[0].lpProps[0].ulPropTag == PR_ENTRYID,
"Bad lpMsgRows->aRow[0].lpProps[0].ulPropTag");
ASSERTERROR(lpMsgRows->aRow[0].lpProps[1].ulPropTag == PR_SEARCH_KEY,
"Bad lpMsgRows->aRow[0].lpProps[1].ulPropTag");
// If this message has duplicates, see if we have already
// handled them before. If so, continue on to next message
// in list.
if ( lpMsgRows->cRows > 1 )
{
ulDupEidSize = lpMsgRows->aRow[0].lpProps[1].Value.bin.cb;
lpDupEid = lpMsgRows->aRow[0].lpProps[1].Value.bin.lpb;
// if this search key is in the done list, go to the
// next message. Otherwise, add it to the done list and
// handle its duplicates.
if ( !lpDoneList )
{
// Create done list and
// record this search key in the done list.
hr = HrMAPICreateEntryList(ulDupEidSize,
(LPENTRYID) lpDupEid,
&lpDoneList);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPICreateEntryList()"), hr);
goto cleanup;
}
}
else
{
// look for search key in done list.
for ( ulTempIndex = 0, bDupDone = FALSE;
ulTempIndex < lpDoneList->cValues; ulTempIndex++ )
{
if ( memcmp(lpDupEid, lpDoneList->lpbin[ulTempIndex].lpb, ulDupEidSize) == 0 )
{
// This duplicate has already been done.
bDupDone = TRUE;
break;
}
} // end for
// If message's duplicates already handled, continue
if ( bDupDone )
{
continue; // go do next message
}
// Otherwise, add this message's search key to the done list.
hr = HrMAPIAppendEntryList(ulDupEidSize,
(LPENTRYID) lpDupEid,
lpDoneList);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPIAppendEntryList()"), hr);
goto cleanup;
}
} // end if
} // end if message has duplicates
// Handle extra properties for message's duplicates
ULONG ulDupCount; // duplicate count
for (ulDupCount = 0; ulDupCount < lpMsgRows->cRows; ulDupCount++ )
{
// Open corresponding new message envelope.
hr = m_lpFolderTo->OpenEntry(
lpMsgRows->aRow[ulDupCount].lpProps[0].Value.bin.cb, // # of bytes in entry ID
(LPENTRYID) lpMsgRows->aRow[ulDupCount].lpProps[0].Value.bin.lpb, // entry ID pointer
&IID_IMessage, // interface ID pointer
MAPI_MODIFY | MAPI_DEFERRED_ERRORS, // flags
&ulObjType, // object type
(LPUNKNOWN FAR *) &lpNewMessage); // output pointer to message
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPIFolder::OpenEntry()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
ASSERT_IUNKNOWN_PTR( lpNewMessage, "Bad lpNewMessage");
ASSERTERROR(ulObjType == MAPI_MESSAGE, "Bad ulObjType");
// If not all properties were copied to the new message
// by IMAPIFolder::CopyMessages(),
// create those properties in the new message now.
hr = HrCreateNewProps(lpMessage, lpNewMessage);
if ( FAILED(hr) )
{
goto cleanup;
}
// Copy over the properties from the original message (envelope
// attachment) to the new message (envelope attachment).
hr = HrCopyGWAttachProps(lpMessage, lpNewMessage);
if ( FAILED(hr) )
{
goto cleanup;
}
// Save changes to new message.
hr = lpNewMessage->SaveChanges(KEEP_OPEN_READWRITE);
if ( FAILED(hr) )
{
// check for insufficient disk space
if ( hr == MAPI_E_NOT_ENOUGH_DISK )
{
EventLogMsg(
GWCLEAN_OUTOFDISK,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
else
{
INTERNAL_ERROR( TEXT("IMAPIProp::SaveChanges()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}// end if save changes failure
// Release new message MAPI object.
ULRELEASE(lpNewMessage);
} // end for all duplicates
} // end for
// We are done copying the extra gateway message properties.
cleanup:
// Release MAPI objects.
ULRELEASE(lpContentsTable);
ULRELEASE(lpMessage);
ULRELEASE(lpNewMessage);
// SRowSet is special!
FREEPROWS(lpMsgRows);
// Free done list
if ( lpDoneList )
{
HrMAPIDestroyEntryList(&lpDoneList);
}
RETURN(hr);
} // end CGWClean::CopyGWMessageProps()
//$--CGWClean::HrCopyGWMessageProps----------------------------------------------------
//
// DESCRIPTION: Recursively copy the gateway message & attachment (message)
// properties not copied by CopyMessages
// from the gateway messages to the new PST messages.
// The additional properties copied are
// determined in HrCreateNewProps().
//
// INPUT: LPMESSAGE -- Original message pointer
// LPMESSAGE -- New message pointer
//
// RESULT: HRESULT -- NOERROR if successful,
// E_INVALIDARG if bad input,
// E_FAIL otherwise
//
// ----------------------------------------------------------------------------
HRESULT CGWClean::HrCopyGWAttachProps( // RETURNS: HRESULT
IN LPMESSAGE lpParent, // original message pointer
IN LPMESSAGE lpNewParent) // new message pointer
{
HRESULT hr = NOERROR; // return code
LPMAPITABLE lpAttachTable = NULL; // Original message's attachment table
LPMAPITABLE lpNewAttachTable = NULL; // new message's attachment table
LPMESSAGE lpMessage = NULL; // Original message (envelope attachment)
LPMESSAGE lpNewMessage = NULL; // New message (envelope attachment)
ULONG ulCount = 0; // count
LPSRowSet lpRows = NULL; // old message QueryRows return
LPSRowSet lpNewRows = NULL; // new message QueryRows return
ULONG ulAttachNum = 0; // old message attachment index
ULONG ulNewAttachNum = 0; // new message attachment index
LPATTACH lpAttachment = NULL; // Original attachment
LPATTACH lpNewAttachment = NULL; // new attachment
ULONG ulLoopCounter = 0; // loop counter
LPBYTE lpSearchKey = NULL; // old search key
LPBYTE lpSearchKeyNew = NULL; // new search key
ULONG ulCountNew = 0;
BOOL bFound = FALSE; // True if find corresponding attachment
ULONG ulLoopCount2 = 0; // inner loop counter
SizedSPropTagArray(1, sPropAttachNum) = // PR_ATTACH_NUM property tag array
{
1, // number of properties
{
PR_ATTACH_NUM // property tag
}
};
DEBUGPRIVATE("CGWClean::HrCopyGWAttachProps()\n");
hr = CHK_CGWClean_HrCopyGWAttachProps(lpParent, lpNewParent);
if ( FAILED(hr) )
{
RETURN(hr);
}
// Open the message's attachments table.
hr = lpParent->GetAttachmentTable(0, &lpAttachTable);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMessage::GetAttachmentTable()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = lpNewParent->GetAttachmentTable(0, &lpNewAttachTable);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMessage::GetAttachmentTable()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
ASSERT_IUNKNOWN_PTR( lpAttachTable, "Bad lpAttachTable");
ASSERT_IUNKNOWN_PTR( lpNewAttachTable, "Bad lpNewAttachTable");
// Retrieve all the attachments for this message. This function is now
// called recursively to handle all message attachments.
hr = HrQueryAllRows(
lpAttachTable, // original attachment table
(LPSPropTagArray) &sPropAttachNum, // only want PR_ATTACH_NUM columns
NULL, // restriction pointer
NULL, // sort order set pointer
0, // maximum rows--defaults to all
&lpRows);
switch (hr)
{
case MAPI_W_POSITION_CHANGED:
// Location in table changed by somebody else.
// Warn the user.
EventLogMsg(
GWCLEAN_POSCHANGED,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
default:
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrQueryAllRows()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
} // end switch()
ASSERT_READ_PTR( lpRows, sizeof(SRowSet), "Bad lpRows");
// If there are no attachments for this message,
// we are done. Return!
if ( !(lpRows->cRows) )
{
goto cleanup;
}
// Get all the attachments for the new envelope.
hr = HrQueryAllRows(
lpNewAttachTable, // new message attachment table
(LPSPropTagArray) &sPropAttachNum, // only want PR_ATTACH_NUM columns
NULL, // restriction pointer
NULL, // sort order set pointer
0, // maximum rows--defaults to all
&lpNewRows);
switch (hr)
{
case MAPI_W_POSITION_CHANGED:
// Location in table changed by somebody else.
// Warn the user.
EventLogMsg(
GWCLEAN_POSCHANGED,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
default:
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrQueryAllRows()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
} // end switch()
ASSERT_READ_PTR( lpNewRows, sizeof(SRowSet), "Bad lpNewRows");
ASSERTERROR(lpNewRows->cRows == lpRows->cRows, "Bad lpNewRows count");
// Handle each attachment
for ( ulLoopCounter = 0; ulLoopCounter < lpRows->cRows; ulLoopCounter++ )
{
// Release MAPI objects
ULRELEASE(lpMessage);
ULRELEASE(lpAttachment);
// Get entry identifier information for attachment.
ulAttachNum = lpRows->aRow[ulLoopCounter].lpProps[0].Value.ul;
// Open the attachment specified by the entry identifier.
hr = lpParent->OpenAttach(
ulAttachNum,
0,
MAPI_DEFERRED_ERRORS, // reduces RPCs
&lpAttachment);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMessage::OpenAttach()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
ASSERT_IUNKNOWN_PTR( lpAttachment, "Bad lpAttachment");
// Try to open the attachment as a message.
hr = lpAttachment->OpenProperty(PR_ATTACH_DATA_OBJ,
&IID_IMessage, // interface identifier
0,
MAPI_DEFERRED_ERRORS, // reduces RPCs
(LPUNKNOWN FAR *) &lpMessage);
switch (hr)
{
case MAPI_E_INTERFACE_NOT_SUPPORTED:
case MAPI_E_NOT_FOUND:
// The attachment is not a message.
// Try the next attachment.
hr = HR_LOG(NOERROR); // This isn't a failure!
continue; // go to next attachment
default:
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPIProp::OpenProperty()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
} // end switch
ASSERT_IUNKNOWN_PTR( lpMessage, "Bad lpMessage");
// Find the new attachment corresponding to the old attachment.
for ( ulLoopCount2 = 0; ulLoopCount2 < lpRows->cRows; ulLoopCount2++ )
{
// Free MAPI structures
MAPIFREEBUFFER(lpSearchKey);
MAPIFREEBUFFER(lpSearchKeyNew);
// Release MAPI objects
ULRELEASE(lpNewAttachment);
ULRELEASE(lpNewMessage);
// Get entry identifier information for new message attachment.
ulNewAttachNum = lpNewRows->aRow[ulLoopCount2].lpProps[0].Value.ul;
// Open the attachment specified by the new entry identifier.
hr = lpNewParent->OpenAttach(
ulNewAttachNum,
0,
MAPI_MODIFY | MAPI_DEFERRED_ERRORS,
&lpNewAttachment);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMessage::OpenAttach()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
ASSERT_IUNKNOWN_PTR( lpNewAttachment, "Bad lpNewAttachment");
// Open the new attachment as a message
hr = lpNewAttachment->OpenProperty(PR_ATTACH_DATA_OBJ,
&IID_IMessage,
0,
MAPI_MODIFY | MAPI_DEFERRED_ERRORS,
(LPUNKNOWN FAR *) &lpNewMessage);
switch (hr)
{
case MAPI_E_INTERFACE_NOT_SUPPORTED:
case MAPI_E_NOT_FOUND:
// Not this attachment! (not an error)
hr = HR_LOG(NOERROR);
// Try the next attachment
continue;
default:
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPIProp::OpenProperty()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
} // end switch
ASSERT_IUNKNOWN_PTR( lpNewMessage, "Bad lpNewMessage");
// Compare search key of new message to search key of
// old message. If not the same, try next new attachment
// in table.
hr = HrMAPIGetPropBinary(
(LPMAPIPROP) lpNewMessage,
PR_SEARCH_KEY,
&ulCountNew,
(LPVOID FAR *) &lpSearchKeyNew);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPIGetPropBinary()"), hr);
goto cleanup;
}
hr = HrMAPIGetPropBinary(
(LPMAPIPROP) lpMessage,
PR_SEARCH_KEY,
&ulCount,
(LPVOID FAR *) &lpSearchKey);
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("HrMAPIGetPropBinary()"), hr);
goto cleanup;
}
ASSERTERROR(ulCount == ulCountNew, "Bad ulCount");
// manually compare search keys. (PR_SEARCH_KEY is comparable)
bFound = FALSE;
if ( memcmp(lpSearchKey, lpSearchKeyNew, ulCount) == 0 )
{
// Found correct new attachment.
bFound = TRUE;
break;
}
} // end for
// Make sure we found the corresponding attachment.
if ( !bFound )
{
INTERNAL_ERROR( TEXT("HrCopyGWAttachProps()"), E_FAIL);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Create and copy all properties in new attachment which aren't
// in the old attachment.
hr = HrCreateNewProps(lpMessage, lpNewMessage);
if ( FAILED(hr) )
{
goto cleanup;
}
// Call this function recursively to handle all attached messages.
hr = HrCopyGWAttachProps(lpMessage, lpNewMessage);
if ( FAILED(hr) )
{
goto cleanup;
}
// Save changes to the new message.
hr = lpNewMessage->SaveChanges(KEEP_OPEN_READWRITE);
if ( FAILED(hr) )
{
// check for insufficient disk space
if ( hr == MAPI_E_NOT_ENOUGH_DISK )
{
EventLogMsg(
GWCLEAN_OUTOFDISK,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
else
{
INTERNAL_ERROR( TEXT("IMAPIProp::SaveChanges()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}// end if save changes failure
// Save changes to the new attachment
hr = lpNewAttachment->SaveChanges(KEEP_OPEN_READWRITE);
if ( FAILED(hr) )
{
// check for insufficient disk space
if ( hr == MAPI_E_NOT_ENOUGH_DISK )
{
EventLogMsg(
GWCLEAN_OUTOFDISK,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
else
{
INTERNAL_ERROR( TEXT("IMAPIProp::SaveChanges()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
} // end for
cleanup:
// Release the MAPI objects
ULRELEASE(lpAttachTable);
ULRELEASE(lpNewAttachTable);
ULRELEASE(lpMessage);
ULRELEASE(lpNewMessage);
ULRELEASE(lpAttachment);
ULRELEASE(lpNewAttachment);
// Free MAPI structures. (SRowSet is special!)
FREEPROWS(lpRows);
FREEPROWS(lpNewRows);
MAPIFREEBUFFER(lpSearchKey);
MAPIFREEBUFFER(lpSearchKeyNew);
RETURN(hr);
} // end CGWClean::CopyGWAttachProps()
//$--CGWClean::HrCreateNewProps----------------------------------------------------
//
// DESCRIPTION: Determine which properties didn't get copied
// to the new message by CopyMessages(), and then
// create and set those properties on the new message.
//
// INPUT: LPMESSAGE -- Original message pointer
// LPMESSAGE -- New message pointer
//
// RESULT: HRESULT -- NOERROR if successful,
// E_INVALIDARG if bad input,
// E_FAIL otherwise
//
// ----------------------------------------------------------------------------
HRESULT CGWClean::HrCreateNewProps( // RETURNS: HRESULT
IN LPMESSAGE lpMessage, // source message
IN LPMESSAGE lpNewMessage) // destination message
{
const INT iMaxSize = 124; // maximum number of properties to create
HRESULT hr = NOERROR; // return code
ULONG ulCount = 0; // # props for original message
ULONG ulNewCount = 0; // # props for new message
LPSPropValue lpsPropValues = NULL; // original message properties and values
LPSPropValue lpsPropNewValues = NULL; // new message properties and values
ULONG ulLoopCount = 0; // loop counter
ULONG ulLoopCount2 = 0; // second loop counter
ULONG ulOrigProp = 0; // original message property tag
BOOL bFound = FALSE; // TRUE if property is found in new message
MAPINAMEID rgNamedMsgProps[iMaxSize] = {0}; // array of named property structures for "extra" message properties
LPMAPINAMEID lpNamedMsgProps[iMaxSize] = {0}; // array of pointers to MAPINAMEID structures
ULONG ulCreated = 0; // number of named properties created in new message
SPropValue lpsCreatedPropValues[iMaxSize] = {0}; // values of created properties
LPSPropTagArray lpsNewPropTags = NULL; // new named property tags
WCHAR lpPropNames[iMaxSize][80] = {0}; // named property array
LPCWSTR lpBaseName = L"GWMSGPROP"; // base name for named property
LPSPropProblemArray lpsPropProblems = NULL; // for SetProps call
WCHAR lpTempString[10] = {0}; // temporary string for _itow
DEBUGPRIVATE("CGWClean::HrCreateNewProps()\n");
// check input parameters
hr = CHK_CGWClean_HrCreateNewProps(lpMessage, lpNewMessage);
if ( FAILED(hr) )
{
RETURN(hr);
}
// Get all properties for the original message
hr = lpMessage->GetProps(NULL, // get all properties
0, // flags
&ulCount, // number of properties
&lpsPropValues); // property value array pointer
if ( hr == MAPI_W_ERRORS_RETURNED )
{
// May not have enough memory to get PR_BODY, PR_RTF_COMPRESSED
// and PR_ATTACH_DATA_BIN properties if they are very large.
// This is not really an error.
// CopyMessages will copy over all properties that it can.
// Then, we are only interested in copying over properties which
// exist in old object but not in the new.
hr = HR_LOG(NOERROR);
}
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPIProp::GetProps()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
ASSERT_READ_PTR( lpsPropValues, sizeof(SPropValue), "Bad lpsPropValues");
// Get all properties from the new messsage.
hr = lpNewMessage->GetProps(NULL, // get all properties
0, // flags
&ulNewCount, // number of properties
&lpsPropNewValues); // property value array pointer
if ( hr == MAPI_W_ERRORS_RETURNED )
{
// May not have enough memory to get PR_BODY, PR_RTF_COMPRESSED
// and PR_ATTACH_DATA_BIN properties if they are very large.
// This is not really an error.
// CopyMessages will copy over all properties that it can.
// Then, we are only interested in copying over properties which
// exist in old object but not in the new.
hr = HR_LOG(NOERROR);
}
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPIProp::GetProps()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
ASSERT_READ_PTR( lpsPropNewValues, sizeof(SPropValue), "Bad lpsPropNewValues");
// If the number of properties in both messages is the same,
// then we are done. Otherwise, we need to create all properties
// in the new message which are in the original message, but which
// are not currently in the new message.
if ( ulCount != ulNewCount )
{
for ( ulLoopCount = 0; ulLoopCount < ulCount; ulLoopCount++ )
{
// Get next original message property
ulOrigProp = lpsPropValues[ulLoopCount].ulPropTag;
bFound = FALSE; // initialize found flag
// Search for original property in the new message.
for ( ulLoopCount2 = 0; ulLoopCount2 < ulNewCount; ulLoopCount2++ )
{
if ( PROP_ID(lpsPropNewValues[ulLoopCount2].ulPropTag) ==
PROP_ID(ulOrigProp) )
{
// We found it. Done with this property check
bFound = TRUE;
break;
}
} // end for
// If we didn't find the property in the new message,
// create it now.
if ( !bFound )
{
// Create a named property in the new message for the
// original property in the old message
// (Set up structures here. Create when all found.)
ASSERTERROR(ulCreated < iMaxSize, "Bad ulCreated");
rgNamedMsgProps[ulCreated].lpguid = (LPGUID) &PS_PUBLIC_STRINGS;
rgNamedMsgProps[ulCreated].ulKind = MNID_STRING;
// Named property will be GWMSGPROP# where # is an integer
// starting at 0.
lstrcpyW(lpPropNames[ulCreated], lpBaseName);
lstrcatW(lpPropNames[ulCreated], _itow(ulCreated, lpTempString, 10));
rgNamedMsgProps[ulCreated].Kind.lpwstrName = lpPropNames[ulCreated];
lpNamedMsgProps[ulCreated] = &(rgNamedMsgProps[ulCreated]);
// Set up the value for the created property and the property tag type.
lpsCreatedPropValues[ulCreated].Value = lpsPropValues[ulLoopCount].Value;
lpsCreatedPropValues[ulCreated].ulPropTag = lpsPropValues[ulLoopCount].ulPropTag;
// increment count of named message properties created
ulCreated++;
} // end if not found
} // end for
// Create the needed named properties
hr = lpNewMessage->GetIDsFromNames(ulCreated, // # of names
(LPMAPINAMEID FAR *) lpNamedMsgProps,// array of names
MAPI_CREATE, // flags
&lpsNewPropTags);// address of property tags
switch ( hr )
{
case MAPI_W_ERRORS_RETURNED:
INTERNAL_ERROR( TEXT("IMAPIProp::GetIDsFromNames()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
case MAPI_E_NOT_ENOUGH_DISK:
// insufficient disk space
EventLogMsg(
GWCLEAN_OUTOFDISK,
0,
0);
hr = HR_LOG(E_FAIL);
goto cleanup;
default:
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPIProp::GetIDsFromNames()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
break;
} // end switch
// Keep the original property type, but replace the
// proptery ID with the new named property ID.
for ( ulLoopCount2 = 0; ulLoopCount2 < ulCreated; ulLoopCount2++ )
{
lpsCreatedPropValues[ulLoopCount2].ulPropTag = PROP_TAG(
PROP_TYPE(lpsCreatedPropValues[ulLoopCount2].ulPropTag),
PROP_ID(lpsNewPropTags->aulPropTag[ulLoopCount2]));
} // end for
// Set the values of the new named properties
hr = lpNewMessage->SetProps(ulCreated, // number of properties
lpsCreatedPropValues, // Property tags and values
&lpsPropProblems); // problem structure
if ( FAILED(hr) )
{
INTERNAL_ERROR( TEXT("IMAPIProp::SetProps()"), hr);
hr = HR_LOG(E_FAIL);
goto cleanup;
}
} // end if some properties not already copied over
cleanup:
// free MAPI buffers
MAPIFREEBUFFER(lpsPropValues);
MAPIFREEBUFFER(lpsPropNewValues);
MAPIFREEBUFFER(lpsNewPropTags);
MAPIFREEBUFFER(lpsPropProblems);
// Release MAPI and OLE objects
RETURN(hr);
}
/*
* EOF
*/