Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

930 lines
26 KiB

#include "pch.hxx"
#include "store.h"
#include "instance.h"
#include "storutil.h"
#include <conman.h>
#include <syncop.h>
#include <shared.h>
#include "enumsync.h"
#include "playback.h"
#include "sync.h"
COfflineSync *g_pSync = NULL;
//--------------------------------------------------------------------------
// COfflineSync::COfflineSync
//--------------------------------------------------------------------------
COfflineSync::COfflineSync(void)
{
m_cRef = 1;
m_pDB = NULL;
}
//--------------------------------------------------------------------------
// CFolderSync::~CFolderSync
//--------------------------------------------------------------------------
COfflineSync::~COfflineSync(void)
{
if (m_pDB != NULL)
m_pDB->Release();
}
//--------------------------------------------------------------------------
// CFolderSync::QueryInterface
//--------------------------------------------------------------------------
STDMETHODIMP COfflineSync::QueryInterface(REFIID riid, LPVOID *ppv)
{
if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
{
*ppv = NULL;
return(E_NOINTERFACE);
}
// AddRef It
((IUnknown *)*ppv)->AddRef();
return(S_OK);
}
//--------------------------------------------------------------------------
// COfflineSync::AddRef
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) COfflineSync::AddRef(void)
{
return InterlockedIncrement(&m_cRef);
}
//--------------------------------------------------------------------------
// COfflineSync::Release
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) COfflineSync::Release(void)
{
LONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
delete this;
return (ULONG)cRef;
}
HRESULT COfflineSync::_SetMessageFlags(IMessageFolder *pFolder, FOLDERID idServer, FOLDERID idFolder, MESSAGEID idMessage, MESSAGEFLAGS dwFlags, LPADJUSTFLAGS pFlags)
{
MESSAGEFLAGS dwAdd, dwRemove;
SYNCOPINFO info;
MESSAGEIDLIST list;
HRESULT hr;
Assert(pFolder != NULL);
Assert(pFlags != NULL);
Assert(0 != pFlags->dwAdd || 0 != pFlags->dwRemove);
// if no new flags are being added or only unset flags are being removed,
// we don't need to do anything
if ((dwFlags | pFlags->dwAdd) == dwFlags &&
(dwFlags & pFlags->dwRemove) == 0)
return(S_OK);
hr = _FindExistingOperation(idServer, idFolder, idMessage,
SYNC_CREATE_MSG | SYNC_SETPROP_MSG, SYNC_COPY_MSG | SYNC_MOVE_MSG, &info);
if (FAILED(hr))
return(hr);
if (hr == S_OK)
{
if (info.tyOperation == SYNC_CREATE_MSG)
{
// this message has been created offline and will be uploaded to the
// server, so we can just set the flags in the message and they will
// get uploaded with the message
}
else
{
dwAdd = pFlags->dwAdd;
dwRemove = pFlags->dwRemove;
dwFlags = info.dwAdd & dwRemove;
if (dwFlags != 0)
{
FLAGCLEAR(info.dwAdd, dwFlags);
FLAGCLEAR(dwRemove, dwFlags);
}
dwFlags = info.dwRemove & dwAdd;
if (dwFlags != 0)
{
FLAGCLEAR(info.dwRemove, dwFlags);
FLAGCLEAR(dwAdd, dwFlags);
}
FLAGSET(info.dwAdd, dwAdd);
FLAGSET(info.dwRemove, dwRemove);
if (info.dwAdd == 0 && info.dwRemove == 0 && info.tyOperation == SYNC_SETPROP_MSG)
{
// no flags are being changed so we can get rid of this operation
hr = m_pDB->DeleteRecord(&info);
}
else
{
hr = m_pDB->UpdateRecord(&info);
}
}
m_pDB->FreeRecord(&info);
if (FAILED(hr))
return(hr);
}
else
{
// no create or set prop operations exist for this message yet,
// so create a new one
ZeroMemory(&info, sizeof(SYNCOPINFO));
hr = m_pDB->GenerateId((LPDWORD)&info.idOperation);
if (FAILED(hr))
return(hr);
info.idServer = idServer;
info.idFolder = idFolder;
info.idMessage = idMessage;
info.tyOperation = SYNC_SETPROP_MSG;
// info.dwFlags
info.dwAdd = (~dwFlags & pFlags->dwAdd);
info.dwRemove = (dwFlags & pFlags->dwRemove);
hr = m_pDB->InsertRecord(&info);
if (FAILED(hr))
return(hr);
}
list.cAllocated = 0;
list.cMsgs = 1;
list.prgidMsg = &idMessage;
hr = pFolder->SetMessageFlags(&list, pFlags, NULL, NULL);
return(hr);
}
HRESULT COfflineSync::SetMessageFlags(IMessageFolder *pFolder, LPMESSAGEIDLIST pList, LPADJUSTFLAGS pFlags)
{
DWORD i;
FOLDERID idFolder, idServer;
MESSAGEINFO Message;
HRESULT hr;
HROWSET hRowset = NULL;
Assert(pFolder != NULL);
Assert(pFlags != NULL);
Assert(0 != pFlags->dwAdd || 0 != pFlags->dwRemove);
hr = pFolder->GetFolderId(&idFolder);
if (FAILED(hr))
return(hr);
hr = GetFolderServerId(idFolder, &idServer);
if (FAILED(hr))
return(hr);
if (NULL == pList)
{
hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset);
if (FAILED(hr))
return(hr);
}
for (i = 0; ; i++)
{
if (pList != NULL)
{
if (i >= pList->cMsgs)
break;
Message.idMessage = pList->prgidMsg[i];
hr = pFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Message, NULL);
if (FAILED(hr))
break;
else if (hr != DB_S_FOUND)
continue;
}
else
{
hr = pFolder->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL);
if (S_FALSE == hr)
{
hr = S_OK;
break;
}
else if (FAILED(hr))
{
break;
}
}
hr = _SetMessageFlags(pFolder, idServer, idFolder, Message.idMessage, Message.dwFlags, pFlags);
pFolder->FreeRecord(&Message);
if (FAILED(hr))
break;
}
if (hRowset != NULL)
pFolder->CloseRowset(&hRowset);
return(hr);
}
HRESULT COfflineSync::DeleteMessages(IMessageFolder *pFolder, DELETEMESSAGEFLAGS dwFlags, LPMESSAGEIDLIST pList)
{
DWORD i;
ADJUSTFLAGS afFlags;
BOOL fNoOp, fImap;
FOLDERINFO Server;
FOLDERID idFolder, idServer;
MESSAGEID idMessage;
SYNCOPINFO info;
MESSAGEIDLIST list;
MESSAGEINFO Message;
HRESULT hr;
HROWSET hRowset = NULL;
// TODO: what about trashcan deletes????
Assert(pFolder != NULL);
hr = pFolder->GetFolderId(&idFolder);
if (FAILED(hr))
return(hr);
hr = GetFolderServer(idFolder, &Server);
if (FAILED(hr))
return(hr);
idServer = Server.idFolder;
fImap = (Server.tyFolder == FOLDER_IMAP);
g_pStore->FreeRecord(&Server);
if (fImap)
{
if (!!(dwFlags & DELETE_MESSAGE_UNDELETE))
{
afFlags.dwAdd = 0;
afFlags.dwRemove = ARF_ENDANGERED;
}
else
{
afFlags.dwAdd = ARF_ENDANGERED;
afFlags.dwRemove = 0;
}
return(SetMessageFlags(pFolder, pList, &afFlags));
}
Assert(0 == (dwFlags & DELETE_MESSAGE_UNDELETE));
if (NULL == pList)
{
hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset);
if (FAILED(hr))
return(hr);
}
list.cAllocated = 0;
list.cMsgs = 1;
list.prgidMsg = &idMessage;
afFlags.dwAdd = ARF_DELETED_OFFLINE;
afFlags.dwRemove = 0;
for (i = 0; ; i++)
{
if (pList != NULL)
{
if (i >= pList->cMsgs)
break;
idMessage = pList->prgidMsg[i];
}
else
{
hr = pFolder->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL);
if (S_FALSE == hr)
{
hr = S_OK;
break;
}
else if (FAILED(hr))
{
break;
}
idMessage = Message.idMessage;
pFolder->FreeRecord(&Message);
}
hr = _FindExistingOperation(idServer, idFolder, idMessage,
SYNC_CREATE_MSG | SYNC_SETPROP_MSG, SYNC_COPY_MSG | SYNC_MOVE_MSG, &info);
if (FAILED(hr))
break;
if (hr == S_OK)
{
fNoOp = TRUE;
if (info.tyOperation == SYNC_CREATE_MSG || info.tyOperation == SYNC_COPY_MSG)
{
// we don't need to do this create or copy anymore because the message is being
// deleted. we don't need to do the delete either because the message
// has never existed on the server
hr = m_pDB->DeleteRecord(&info);
}
else if (info.tyOperation == SYNC_SETPROP_MSG)
{
// if it is a set prop operation, we don't need to do it anymore because the message
// is just getting deleted anyway
fNoOp = FALSE;
hr = m_pDB->DeleteRecord(&info);
}
else
{
Assert(info.tyOperation == SYNC_MOVE_MSG);
// convert it to a delete operation which is the same as moving it then deleting it
info.idFolderDest = 0;
info.idMessageDest = 0;
info.tyOperation = SYNC_DELETE_MSG;
info.dwAdd = 0;
info.dwRemove = 0;
info.dwFlags = dwFlags;
hr = m_pDB->UpdateRecord(&info);
}
m_pDB->FreeRecord(&info);
if (FAILED(hr))
{
break;
}
else if (fNoOp)
{
hr = pFolder->DeleteMessages(dwFlags, &list, NULL, NULL);
if (FAILED(hr))
break;
continue;
}
}
// create the delete operation
ZeroMemory(&info, sizeof(SYNCOPINFO));
hr = m_pDB->GenerateId((LPDWORD)&info.idOperation);
if (FAILED(hr))
break;
info.idServer = idServer;
info.idFolder = idFolder;
info.idMessage = idMessage;
info.tyOperation = SYNC_DELETE_MSG;
info.dwFlags = dwFlags;
// info.dwAdd
// info.dwRemove
hr = m_pDB->InsertRecord(&info);
if (FAILED(hr))
break;
hr = pFolder->SetMessageFlags(&list, &afFlags, NULL, NULL);
if (FAILED(hr))
break;
}
if (hRowset != NULL)
m_pDB->CloseRowset(&hRowset);
return(hr);
}
HRESULT COfflineSync::CreateMessage(IMessageFolder *pFolder,
LPMESSAGEID pidMessage,
SAVEMESSAGEFLAGS dwOptions,
MESSAGEFLAGS dwFlags,
IStream *pStream,
IMimeMessage *pMessage)
{
MESSAGEID idMessage;
HRESULT hr;
SYNCOPINFO info;
FOLDERID idFolder, idServer;
Assert(pFolder != NULL);
Assert(pMessage != NULL);
Assert(!!(dwOptions & SAVE_MESSAGE_GENID));
hr = pFolder->GetFolderId(&idFolder);
if (FAILED(hr))
return(hr);
hr = GetFolderServerId(idFolder, &idServer);
if (FAILED(hr))
return(hr);
ZeroMemory(&info, sizeof(SYNCOPINFO));
hr = m_pDB->GenerateId((LPDWORD)&info.idOperation);
if (FAILED(hr))
return(hr);
hr = pFolder->SaveMessage(&idMessage, SAVE_MESSAGE_GENID, dwFlags, pStream, pMessage, NULL);
if (FAILED(hr))
return(hr);
info.idServer = idServer;
info.idFolder = idFolder;
info.idMessage = idMessage;
info.tyOperation = SYNC_CREATE_MSG;
info.dwFlags = dwOptions;
// info.dwAdd
// info.dwRemove
hr = m_pDB->InsertRecord(&info);
return(hr);
}
HRESULT COfflineSync::CopyMessages(IMessageFolder *pFolder, IMessageFolder *pFolderDest, COPYMESSAGEFLAGS dwCopyFlags, LPMESSAGEIDLIST pList, LPADJUSTFLAGS pFlags)
{
DWORD i;
BOOL fMove, fImap, fCopyToMove;
FOLDERINFO Server;
MESSAGEFLAGS dwFlags;
ADJUSTFLAGS afFlags;
FOLDERID idFolder, idServer, idFolderDest;
MESSAGEID idMessage;
SYNCOPINFO info, infoT;
MESSAGEIDLIST list;
HRESULT hr;
IMimeMessage *pMsg;
HROWSET hRowset = NULL;
MESSAGEINFO Message = { 0 };
Assert(pFolder != NULL);
Assert(pFolderDest != NULL);
hr = pFolder->GetFolderId(&idFolder);
if (FAILED(hr))
return(hr);
hr = pFolderDest->GetFolderId(&idFolderDest);
if (FAILED(hr))
return(hr);
hr = GetFolderServer(idFolder, &Server);
if (FAILED(hr))
return(hr);
idServer = Server.idFolder;
fImap = (Server.tyFolder == FOLDER_IMAP);
g_pStore->FreeRecord(&Server);
#ifdef DEBUG
FOLDERID idServerDest;
Assert(SUCCEEDED(GetFolderServerId(idFolderDest, &idServerDest)));
Assert(SUCCEEDED(hr));
Assert(idServer == idServerDest);
#endif // DEBUG
if (NULL == pList)
{
hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset);
if (FAILED(hr))
return(hr);
}
fMove = !!(dwCopyFlags & COPY_MESSAGE_MOVE);
if (fMove)
{
list.cAllocated = 0;
list.cMsgs = 1;
list.prgidMsg = &idMessage;
if (fImap)
{
afFlags.dwAdd = ARF_ENDANGERED;
afFlags.dwRemove = 0;
}
else
{
afFlags.dwAdd = ARF_DELETED_OFFLINE;
afFlags.dwRemove = 0;
}
}
for (i = 0; ; i++)
{
if (pList != NULL)
{
if (i >= pList->cMsgs)
break;
Message.idMessage = pList->prgidMsg[i];
hr = pFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Message, NULL);
if (FAILED(hr))
break;
else if (hr != DB_S_FOUND)
continue;
}
else
{
hr = pFolder->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL);
if (S_FALSE == hr)
{
hr = S_OK;
break;
}
else if (FAILED(hr))
{
break;
}
}
idMessage = Message.idMessage;
dwFlags = Message.dwFlags;
if (pFlags != NULL)
{
if (pFlags->dwRemove != 0)
Message.dwFlags &= ~pFlags->dwRemove;
if (pFlags->dwAdd != 0)
Message.dwFlags |= pFlags->dwAdd;
}
pMsg = NULL;
hr = pFolder->OpenMessage(idMessage, NOFLAGS, &pMsg, NULL);
if (hr == STORE_E_NOBODY)
{
// just create the header in the destination folder
Assert(pMsg == NULL);
hr = pFolderDest->GenerateId((LPDWORD)&Message.idMessage);
if (SUCCEEDED(hr))
hr = pFolderDest->InsertRecord(&Message);
}
else if (SUCCEEDED(hr))
{
// create the whole message in the destination folder
Assert(pMsg != NULL);
hr = pFolderDest->SaveMessage(&Message.idMessage, SAVE_MESSAGE_GENID, Message.dwFlags, 0, pMsg, NULL);
pMsg->Release();
}
else
{
Assert(pMsg == NULL);
}
if (FAILED(hr))
break;
hr = _FindExistingOperation(idServer, idFolder, idMessage,
SYNC_CREATE_MSG, SYNC_COPY_MSG | SYNC_MOVE_MSG, &info);
if (FAILED(hr))
break;
if (hr == S_OK)
{
if (fMove)
{
// delete source msg because we're moving a msg which doesn't exist on the server
// and then move the previous operation to the destination folder
hr = pFolder->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &list, NULL, NULL);
if (SUCCEEDED(hr))
{
if (info.tyOperation == SYNC_CREATE_MSG)
{
info.idFolder = idFolderDest;
info.idMessage = Message.idMessage;
}
else
{
info.idFolderDest = idFolderDest;
info.idMessageDest = Message.idMessage;
}
hr = m_pDB->UpdateRecord(&info);
// foo
}
}
else
{
if (info.tyOperation == SYNC_CREATE_MSG)
{
// we can't copy this message because it doesn't exist on the server,
// so we'll add another create operation for the destination message
ZeroMemory(&infoT, sizeof(SYNCOPINFO));
hr = m_pDB->GenerateId((LPDWORD)&infoT.idOperation);
if (SUCCEEDED(hr))
{
infoT.idServer = idServer;
infoT.idFolder = idFolderDest;
infoT.idMessage = Message.idMessage;
infoT.tyOperation = SYNC_CREATE_MSG;
// infoT.dwFlags
// info.dwAdd
// info.dwRemove
hr = m_pDB->InsertRecord(&infoT);
}
}
else if (info.tyOperation == SYNC_COPY_MSG)
{
fCopyToMove = FALSE;
// if there is an earlier operation that will result in the source msg
// being deleted, then we'll find that and remove it (delete) or change
// it (move), and then we'll do a move instead of a copy
hr = _FindExistingOperation(info.idServer, info.idFolder, info.idMessage,
SYNC_DELETE_MSG | SYNC_MOVE_MSG, 0, &infoT);
if (hr == S_OK)
{
if (infoT.tyOperation == SYNC_DELETE_MSG)
{
hr = m_pDB->DeleteRecord(&infoT);
}
else
{
Assert(infoT.tyOperation == SYNC_MOVE_MSG);
infoT.tyOperation = SYNC_COPY_MSG;
hr = m_pDB->UpdateRecord(&infoT);
}
fCopyToMove = TRUE;
m_pDB->FreeRecord(&infoT);
}
if (SUCCEEDED(hr))
{
hr = m_pDB->GenerateId((LPDWORD)&info.idOperation);
if (SUCCEEDED(hr))
{
info.idFolderDest = idFolderDest;
info.idMessageDest = Message.idMessage;
if (fCopyToMove)
info.tyOperation = SYNC_MOVE_MSG;
hr = m_pDB->InsertRecord(&info);
}
}
}
else
{
Assert(info.tyOperation == SYNC_MOVE_MSG);
// instead of doing a move then a copy which wouldn't work so good,
// we'll have the current copy become a move and the earlier move will become a copy
infoT = info;
hr = m_pDB->GenerateId((LPDWORD)&infoT.idOperation);
if (SUCCEEDED(hr))
{
infoT.idFolderDest = idFolderDest;
infoT.idMessageDest = Message.idMessage;
hr = m_pDB->InsertRecord(&infoT);
if (SUCCEEDED(hr))
{
info.tyOperation = SYNC_COPY_MSG;
hr = m_pDB->UpdateRecord(&info);
}
}
}
}
m_pDB->FreeRecord(&info);
if (FAILED(hr))
{
break;
}
else
{
pFolder->FreeRecord(&Message);
continue;
}
}
ZeroMemory(&info, sizeof(SYNCOPINFO));
hr = m_pDB->GenerateId((LPDWORD)&info.idOperation);
if (FAILED(hr))
break;
info.idServer = idServer;
info.idFolder = idFolder;
info.idMessage = idMessage;
info.tyOperation = (fMove && !fImap) ? SYNC_MOVE_MSG : SYNC_COPY_MSG;
// info.dwFlags
if (pFlags != NULL)
{
info.dwAdd = (~dwFlags & pFlags->dwAdd);
info.dwRemove = (dwFlags & pFlags->dwRemove);
}
info.idFolderDest = idFolderDest;
info.idMessageDest = Message.idMessage;
hr = m_pDB->InsertRecord(&info);
// TODO: if this fails, we should probably blow away the new msg we just created...
if (FAILED(hr))
break;
if (fMove)
{
if (fImap)
{
// put this msg in the endangered species list
hr = _SetMessageFlags(pFolder, idServer, idFolder, idMessage, dwFlags, &afFlags);
if (FAILED(hr))
break;
}
else
{
// hide this msg because it is now deleted
pFolder->SetMessageFlags(&list, &afFlags, NULL, NULL);
}
}
pFolder->FreeRecord(&Message);
}
pFolder->FreeRecord(&Message);
if (hRowset != NULL)
pFolder->CloseRowset(&hRowset);
return(hr);
}
HRESULT COfflineSync::Initialize()
{
HRESULT hr;
BOOL fReset;
TABLEINDEX Index;
CHAR szDirectory[MAX_PATH];
CHAR szFilePath[MAX_PATH];
SYNCOPUSERDATA UserData={0};
Assert(g_pStore != NULL);
hr = g_pStore->GetDirectory(szDirectory, ARRAYSIZE(szDirectory));
if (FAILED(hr))
return(hr);
hr = MakeFilePath(szDirectory, c_szOfflineFile, c_szEmpty, szFilePath, ARRAYSIZE(szFilePath));
if (FAILED(hr))
return(hr);
hr = g_pDBSession->OpenDatabase(szFilePath, NOFLAGS, &g_SyncOpTableSchema, NULL, &m_pDB);
if (FAILED(hr))
return(hr);
fReset = FALSE;
// Create the idServer / idFolder Index
if (FAILED(m_pDB->GetIndexInfo(IINDEX_ALL, NULL, &Index)))
fReset = TRUE;
// If still noreset, see of indexes are the same
else if (S_FALSE == CompareTableIndexes(&Index, &g_OpFolderIdIndex))
fReset = TRUE;
// Change the Index
if (fReset)
{
// Create the idParent / FolderName Index
hr = m_pDB->ModifyIndex(IINDEX_ALL, NULL, &g_OpFolderIdIndex);
if (FAILED(hr))
return(hr);
}
hr = m_pDB->GetUserData(&UserData, sizeof(SYNCOPUSERDATA));
if (SUCCEEDED(hr))
{
if (!UserData.fInitialized)
{
UserData.fInitialized = TRUE;
hr = m_pDB->SetUserData(&UserData, sizeof(SYNCOPUSERDATA));
}
}
return(hr);
}
HRESULT COfflineSync::DoPlayback(HWND hwnd, FOLDERID *pId, DWORD cId, FOLDERID idFolderSel)
{
HRESULT hr;
DWORD cOps;
COfflinePlayback *pPlayback;
Assert(pId != NULL);
Assert(cId > 0);
hr = m_pDB->GetRecordCount(IINDEX_PRIMARY, &cOps);
if (SUCCEEDED(hr) && cOps > 0)
{
pPlayback = new COfflinePlayback;
if (pPlayback == NULL)
return(E_OUTOFMEMORY);
hr = pPlayback->DoPlayback(hwnd, m_pDB, pId, cId, idFolderSel);
pPlayback->Release();
}
return(hr);
}
HRESULT COfflineSync::_FindExistingOperation(FOLDERID idServer, FOLDERID idFolder, MESSAGEID idMessage,
DWORD dwFlagsSrc, DWORD dwFlagsDest, LPSYNCOPINFO pInfo)
{
ROWORDINAL iRow;
HRESULT hr;
HROWSET hRowset = NULL;
Assert(pInfo != NULL);
Assert(dwFlagsSrc != 0 || dwFlagsDest != 0);
ZeroMemory(pInfo, sizeof(SYNCOPINFO));
pInfo->idServer = idServer;
hr = m_pDB->FindRecord(IINDEX_ALL, 1, pInfo, &iRow);
if (hr != DB_S_FOUND)
return(S_FALSE);
m_pDB->FreeRecord(pInfo);
hr = m_pDB->CreateRowset(IINDEX_ALL, NOFLAGS, &hRowset);
if (FAILED(hr))
return(hr);
hr = m_pDB->SeekRowset(hRowset, SEEK_ROWSET_BEGIN, iRow - 1, NULL);
if (SUCCEEDED(hr))
{
while (TRUE)
{
hr = m_pDB->QueryRowset(hRowset, 1, (LPVOID *)pInfo, NULL);
if (S_FALSE == hr)
{
break;
}
else if (FAILED(hr))
{
break;
}
if (pInfo->idServer != idServer)
{
hr = S_FALSE;
m_pDB->FreeRecord(pInfo);
break;
}
if (dwFlagsSrc != 0)
{
if (pInfo->idFolder == idFolder && pInfo->idMessage == idMessage)
{
if (!!(dwFlagsSrc & pInfo->tyOperation))
break;
}
}
if (dwFlagsDest != 0)
{
if (pInfo->idFolderDest == idFolder && pInfo->idMessageDest == idMessage)
{
if (!!(dwFlagsDest & pInfo->tyOperation))
break;
}
}
m_pDB->FreeRecord(pInfo);
}
}
m_pDB->CloseRowset(&hRowset);
return(hr);
}