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.
2966 lines
85 KiB
2966 lines
85 KiB
//
|
|
// asyncctx.cpp -- This file contains the class implementation for:
|
|
// CAsyncLookupContext
|
|
//
|
|
// Created:
|
|
// Mar 4, 1997 -- Milan Shah (milans)
|
|
//
|
|
// Changes:
|
|
//
|
|
|
|
#include "precomp.h"
|
|
#include "simparray.cpp"
|
|
|
|
DWORD CBatchLdapConnection::m_nMaxSearchBlockSize = 0;
|
|
DWORD CBatchLdapConnection::m_nMaxPendingSearches = 0;
|
|
DWORD CBatchLdapConnection::m_nMaxConnectionRetries = 0;
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CBatchLdapConnection::InitializeFromRegistry
|
|
//
|
|
// Synopsis: Static function that looks at registry to determine maximum
|
|
// number of queries that will be compressed into a single query.
|
|
// If the registry key does not exist or there is any other
|
|
// problem reading the key, the value defaults to
|
|
// MAX_SEARCH_BLOCK_SIZE
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nothing.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID CBatchLdapConnection::InitializeFromRegistry()
|
|
{
|
|
HKEY hkey;
|
|
DWORD dwErr, dwType, dwValue, cbValue;
|
|
|
|
dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, MAX_SEARCH_BLOCK_SIZE_KEY, &hkey);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
cbValue = sizeof(dwValue);
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
MAX_SEARCH_BLOCK_SIZE_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD &&
|
|
dwValue > 0 && dwValue < MAX_SEARCH_BLOCK_SIZE) {
|
|
|
|
InterlockedExchange((PLONG) &m_nMaxSearchBlockSize, (LONG)dwValue);
|
|
}
|
|
|
|
cbValue = sizeof(dwValue);
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
MAX_PENDING_SEARCHES_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD &&
|
|
dwValue > 0) {
|
|
|
|
InterlockedExchange((PLONG) &m_nMaxPendingSearches, (LONG)dwValue);
|
|
}
|
|
|
|
cbValue = sizeof(dwValue);
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
MAX_CONNECTION_RETRIES_VALUE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwValue,
|
|
&cbValue);
|
|
|
|
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD &&
|
|
dwValue > 0) {
|
|
|
|
InterlockedExchange((PLONG) &m_nMaxConnectionRetries, (LONG)dwValue);
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
if(m_nMaxSearchBlockSize == 0)
|
|
m_nMaxSearchBlockSize = MAX_SEARCH_BLOCK_SIZE;
|
|
if(m_nMaxPendingSearches == 0)
|
|
m_nMaxPendingSearches = MAX_PENDING_SEARCHES;
|
|
if(m_nMaxPendingSearches < m_nMaxSearchBlockSize)
|
|
m_nMaxPendingSearches = m_nMaxSearchBlockSize;
|
|
if(m_nMaxConnectionRetries == 0)
|
|
m_nMaxConnectionRetries = MAX_CONNECTION_RETRIES;
|
|
}
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::operator new
|
|
//
|
|
// Synopsis: Allocate enough memory for this and the specified number
|
|
// of SEARCH_REQUEST structurers
|
|
//
|
|
// Arguments:
|
|
// size: Normal size of object
|
|
// dwNumRequests: Number of props desired in this object
|
|
//
|
|
// Returns: ptr to allocated memory or NULL
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/10 16:15:43: Created
|
|
//
|
|
//-------------------------------------------------------------
|
|
void * CSearchRequestBlock::operator new(
|
|
size_t size,
|
|
DWORD dwNumRequests)
|
|
{
|
|
DWORD dwSize;
|
|
void *pmem;
|
|
CSearchRequestBlock *pBlock;
|
|
|
|
//
|
|
// Calcualte size in bytes required
|
|
//
|
|
dwSize = size +
|
|
(dwNumRequests*sizeof(SEARCH_REQUEST)) +
|
|
(dwNumRequests*sizeof(ICategorizerItem *));
|
|
|
|
pmem = new BYTE[dwSize];
|
|
|
|
if(pmem) {
|
|
|
|
pBlock = (CSearchRequestBlock *)pmem;
|
|
pBlock->m_dwSignature = SIGNATURE_CSEARCHREQUESTBLOCK;
|
|
pBlock->m_cBlockSize = dwNumRequests;
|
|
|
|
pBlock->m_prgSearchRequests = (PSEARCH_REQUEST)
|
|
((PBYTE)pmem + size);
|
|
|
|
pBlock->m_rgpICatItems = (ICategorizerItem **)
|
|
((PBYTE)pmem + size +
|
|
(dwNumRequests*sizeof(SEARCH_REQUEST)));
|
|
|
|
_ASSERT( (DWORD) ((PBYTE)pBlock->m_rgpICatItems +
|
|
(dwNumRequests*sizeof(ICategorizerItem *)) -
|
|
(PBYTE)pmem)
|
|
== dwSize);
|
|
|
|
}
|
|
return pmem;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::~CSearchRequestBlock
|
|
//
|
|
// Synopsis: Release everything we have references to
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/11 18:45:59: Created
|
|
//
|
|
//-------------------------------------------------------------
|
|
CSearchRequestBlock::~CSearchRequestBlock()
|
|
{
|
|
DWORD dwCount;
|
|
//
|
|
// Release all CCatAddrs
|
|
//
|
|
for(dwCount = 0;
|
|
dwCount < DwNumBlockRequests();
|
|
dwCount++) {
|
|
|
|
PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]);
|
|
|
|
preq->pCCatAddr->Release();
|
|
}
|
|
//
|
|
// Release all the attr interfaces
|
|
//
|
|
for(dwCount = 0;
|
|
dwCount < m_csaItemAttr.Size();
|
|
dwCount++) {
|
|
|
|
((ICategorizerItemAttributes **)
|
|
m_csaItemAttr)[dwCount]->Release();
|
|
}
|
|
|
|
if(m_pISMTPServer)
|
|
m_pISMTPServer->Release();
|
|
|
|
if(m_pISMTPServerEx)
|
|
m_pISMTPServerEx->Release();
|
|
|
|
if(m_pICatParams)
|
|
m_pICatParams->Release();
|
|
|
|
if(m_pszSearchFilter)
|
|
delete m_pszSearchFilter;
|
|
|
|
if(m_pConn)
|
|
m_pConn->Release();
|
|
|
|
_ASSERT(m_dwSignature == SIGNATURE_CSEARCHREQUESTBLOCK);
|
|
m_dwSignature = SIGNATURE_CSEARCHREQUESTBLOCK_INVALID;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::InsertSearchRequest
|
|
//
|
|
// Synopsis: Inserts a search request in this block. When the block
|
|
// is full, dispatch the block to LDAP before returning
|
|
//
|
|
// Arguments:
|
|
// pISMTPServer: ISMTPServer to use for triggering events
|
|
// pICatParams: ICategorizerParameters to use
|
|
// pCCatAddr: Address item for the search
|
|
// fnSearchCompletion: Async Completion routine
|
|
// ctxSearchCompletion: Context to pass to the async completion routine
|
|
// pszSearchFilter: Search filter to use
|
|
// pszDistinguishingAttribute: The distinguishing attribute for matching
|
|
// pszDistinguishingAttributeValue: above attribute's distinguishing value
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/11 13:12:20: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CSearchRequestBlock::InsertSearchRequest(
|
|
ISMTPServer *pISMTPServer,
|
|
ICategorizerParameters *pICatParams,
|
|
CCatAddr *pCCatAddr,
|
|
LPSEARCHCOMPLETION fnSearchCompletion,
|
|
CStoreListResolveContext *pslrc,
|
|
LPSTR pszSearchFilter,
|
|
LPSTR pszDistinguishingAttribute,
|
|
LPSTR pszDistinguishingAttributeValue)
|
|
{
|
|
PSEARCH_REQUEST preq;
|
|
DWORD dwIndex;
|
|
HRESULT hr = S_OK;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::InsertSearchRequest");
|
|
//
|
|
// Unset any existing HRSTATUS -- the status will be set again in
|
|
// the search completion
|
|
//
|
|
_VERIFY(SUCCEEDED(
|
|
pCCatAddr->UnSetPropId(
|
|
ICATEGORIZERITEM_HRSTATUS)));
|
|
|
|
m_pConn->IncrementPendingSearches();
|
|
|
|
preq = GetNextSearchRequest(&dwIndex);
|
|
|
|
_ASSERT(preq);
|
|
|
|
pCCatAddr->AddRef();
|
|
preq->pCCatAddr = pCCatAddr;
|
|
preq->fnSearchCompletion = fnSearchCompletion;
|
|
preq->pslrc = pslrc;
|
|
preq->pszSearchFilter = pszSearchFilter;
|
|
preq->pszDistinguishingAttribute = pszDistinguishingAttribute;
|
|
preq->pszDistinguishingAttributeValue = pszDistinguishingAttributeValue;
|
|
|
|
m_rgpICatItems[dwIndex] = pCCatAddr;
|
|
|
|
if(dwIndex == 0) {
|
|
//
|
|
// Use the first insertion's ISMTPServer
|
|
//
|
|
_ASSERT(m_pISMTPServer == NULL);
|
|
m_pISMTPServer = pISMTPServer;
|
|
|
|
if(m_pISMTPServer) {
|
|
m_pISMTPServer->AddRef();
|
|
|
|
hr = m_pISMTPServer->QueryInterface(
|
|
IID_ISMTPServerEx,
|
|
(LPVOID *) &m_pISMTPServerEx);
|
|
if(FAILED(hr))
|
|
{
|
|
m_pISMTPServerEx = NULL;;
|
|
}
|
|
else
|
|
{
|
|
m_CICatQueries.SetISMTPServerEx(
|
|
m_pISMTPServerEx);
|
|
m_CICatAsyncContext.SetISMTPServerEx(
|
|
m_pISMTPServerEx);
|
|
}
|
|
}
|
|
|
|
_ASSERT(m_pICatParams == NULL);
|
|
m_pICatParams = pICatParams;
|
|
m_pICatParams->AddRef();
|
|
}
|
|
|
|
//
|
|
// Now dispatch this block if we are the last request to finish
|
|
//
|
|
if( (DWORD) (InterlockedIncrement((PLONG)&m_cBlockRequestsReadyForDispatch)) == m_cBlockSize)
|
|
DispatchBlock();
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::DispatchBlock
|
|
//
|
|
// Synopsis: Send the LDAP query for this search request block
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/11 15:00:44: Created.
|
|
// haozhang 2001/11/30 Fix for 193848
|
|
//-------------------------------------------------------------
|
|
VOID CSearchRequestBlock::DispatchBlock()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::DispatchBlock");
|
|
|
|
m_pConn->RemoveSearchRequestBlockFromList(this);
|
|
|
|
//
|
|
// If the block is empty, we will delete it and bail out.
|
|
// We will AV down the road otherwise.
|
|
// This is an unintended result of fix of 193848.
|
|
//
|
|
if ( 0 == DwNumBlockRequests()) {
|
|
DebugTrace((LPARAM)this, "DispatchBlock bailing out because the block is empty");
|
|
delete this;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//
|
|
// Build up the query string
|
|
//
|
|
hr = HrTriggerBuildQueries();
|
|
ERROR_CLEANUP_LOG("HrTriggerBuildQueryies");
|
|
//
|
|
// Send the query
|
|
//
|
|
hr = HrTriggerSendQuery();
|
|
ERROR_CLEANUP_LOG("HrTriggerSendQuery");
|
|
|
|
CLEANUP:
|
|
if(FAILED(hr)) {
|
|
CompleteBlockWithError(hr);
|
|
delete this;
|
|
}
|
|
//
|
|
// this may be deleted, but that's okay; we're just tracing a user
|
|
// value
|
|
//
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::HrTriggerBuildQueries
|
|
//
|
|
// Synopsis: Trigger the BuildQueries event
|
|
//
|
|
// Arguments:
|
|
// pCICatQueries: CICategorizerQueriesIMP object to use
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// error from dispatcher
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/11 19:03:29: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CSearchRequestBlock::HrTriggerBuildQueries()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
EVENTPARAMS_CATBUILDQUERIES Params;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::HrTriggerBuildQueries");
|
|
|
|
Params.pICatParams = m_pICatParams;
|
|
Params.dwcAddresses = DwNumBlockRequests();
|
|
Params.rgpICatItems = m_rgpICatItems;
|
|
Params.pICatQueries = &m_CICatQueries;
|
|
Params.pfnDefault = HrBuildQueriesDefault;
|
|
Params.pblk = this;
|
|
|
|
if(m_pISMTPServer) {
|
|
|
|
hr = m_pISMTPServer->TriggerServerEvent(
|
|
SMTP_MAILTRANSPORT_CATEGORIZE_BUILDQUERIES_EVENT,
|
|
&Params);
|
|
if(FAILED(hr) && (hr != E_NOTIMPL)) {
|
|
ERROR_LOG("m_pISMTPServer->TriggerServerEvent(buildquery)");
|
|
}
|
|
|
|
} else {
|
|
hr = E_NOTIMPL;
|
|
}
|
|
|
|
if(hr == E_NOTIMPL) {
|
|
//
|
|
// Events are disabled
|
|
//
|
|
hr = HrBuildQueriesDefault(
|
|
S_OK,
|
|
&Params);
|
|
if(FAILED(hr)) {
|
|
ERROR_LOG("HrBuildQueriesDefault");
|
|
}
|
|
}
|
|
//
|
|
// Make sure somebody really set the query string
|
|
//
|
|
if(SUCCEEDED(hr) &&
|
|
(m_pszSearchFilter == NULL)) {
|
|
|
|
hr = E_FAIL;
|
|
ERROR_LOG("--no filter--");
|
|
}
|
|
|
|
|
|
DebugTrace((LPARAM)this, "returning hr %08lx",hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::HrBuildQueriesDefault
|
|
//
|
|
// Synopsis: Default implementation of the build queries sink
|
|
//
|
|
// Arguments:
|
|
// hrStatus: Status of events so far
|
|
// pContext: Event params context
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/11 19:42:53: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CSearchRequestBlock::HrBuildQueriesDefault(
|
|
HRESULT HrStatus,
|
|
PVOID pContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PEVENTPARAMS_CATBUILDQUERIES pParams;
|
|
DWORD cReqs, cOrTerms, idx, idxSecondToLastTerm, idxLastTerm;
|
|
DWORD cbSearchFilter, rgcbSearchFilters[MAX_SEARCH_BLOCK_SIZE];
|
|
LPSTR pszSearchFilterNew;
|
|
CSearchRequestBlock *pblk;
|
|
|
|
pParams = (PEVENTPARAMS_CATBUILDQUERIES)pContext;
|
|
_ASSERT(pParams);
|
|
pblk = (CSearchRequestBlock *)pParams->pblk;
|
|
_ASSERT(pblk);
|
|
|
|
CatFunctEnterEx((LPARAM)pblk, "CSearchRequestBlock::HrBuildQueriesDefault");
|
|
|
|
cReqs = pblk->DwNumBlockRequests();
|
|
_ASSERT( cReqs > 0 );
|
|
|
|
cOrTerms = cReqs - 1;
|
|
//
|
|
// Figure out the size of the composite search filter
|
|
//
|
|
cbSearchFilter = 0;
|
|
|
|
for (idx = 0; idx < cReqs; idx++) {
|
|
|
|
rgcbSearchFilters[idx] =
|
|
strlen(pblk->m_prgSearchRequests[idx].pszSearchFilter);
|
|
|
|
cbSearchFilter += rgcbSearchFilters[idx];
|
|
}
|
|
|
|
cbSearchFilter += cOrTerms * (sizeof( "(| )" ) - 1);
|
|
cbSearchFilter++; // Terminating NULL.
|
|
|
|
pszSearchFilterNew = new CHAR [cbSearchFilter];
|
|
|
|
if (pszSearchFilterNew != NULL) {
|
|
|
|
idxLastTerm = cReqs - 1;
|
|
idxSecondToLastTerm = idxLastTerm - 1;
|
|
//
|
|
// We special case the cReqs == 1
|
|
//
|
|
if (cReqs == 1) {
|
|
|
|
strcpy(
|
|
pszSearchFilterNew,
|
|
pblk->m_prgSearchRequests[0].pszSearchFilter);
|
|
|
|
} else {
|
|
//
|
|
// The loop below builds up the block filter all the way up to the
|
|
// last term. For each term, it adds a "(| " to start a new OR
|
|
// term, then adds the OR term itself, then puts a space after the
|
|
// OR term. Also, it puts a matching ")" at the end of the
|
|
// search filter string being built up.
|
|
//
|
|
LPSTR szNextItem = &pszSearchFilterNew[0];
|
|
LPSTR szTerminatingParens =
|
|
&pszSearchFilterNew[cbSearchFilter - 1 - (cReqs-1)];
|
|
|
|
pszSearchFilterNew[cbSearchFilter - 1] = 0;
|
|
|
|
for (idx = 0; idx <= idxSecondToLastTerm; idx++) {
|
|
|
|
strcpy( szNextItem, "(| " );
|
|
szNextItem += sizeof( "(| " ) - 1;
|
|
|
|
strcpy(
|
|
szNextItem,
|
|
pblk->m_prgSearchRequests[idx].pszSearchFilter);
|
|
szNextItem += rgcbSearchFilters[idx];
|
|
*szNextItem++ = ' ';
|
|
*szTerminatingParens++ = ')';
|
|
}
|
|
|
|
//
|
|
// Now, all that remains is to add in the last OR term
|
|
//
|
|
CopyMemory(
|
|
szNextItem,
|
|
pblk->m_prgSearchRequests[idxLastTerm].pszSearchFilter,
|
|
rgcbSearchFilters[idxLastTerm]);
|
|
|
|
}
|
|
|
|
_ASSERT( ((DWORD) lstrlen(pszSearchFilterNew)) < cbSearchFilter );
|
|
|
|
//
|
|
// Save our generated filter string in ICategorizerQueries
|
|
//
|
|
hr = pblk->m_CICatQueries.SetQueryStringNoAlloc(pszSearchFilterNew);
|
|
|
|
// There's no good reason for that to fail...
|
|
_ASSERT(SUCCEEDED(hr));
|
|
|
|
} else {
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
ERROR_LOG_STATIC(
|
|
"new CHAR[]",
|
|
pblk,
|
|
pblk->GetISMTPServerEx());
|
|
}
|
|
|
|
DebugTrace((LPARAM)pblk, "returning hr %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)pblk);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::HrTriggerSendQuery
|
|
//
|
|
// Synopsis: Trigger the SendQuery event
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/11 20:18:02: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CSearchRequestBlock::HrTriggerSendQuery()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
EVENTPARAMS_CATSENDQUERY Params;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::HrTriggerSendQuery");
|
|
|
|
Params.pICatParams = m_pICatParams;
|
|
Params.pICatQueries = &m_CICatQueries;
|
|
Params.pICatAsyncContext = &m_CICatAsyncContext;
|
|
Params.pIMailTransportNotify = NULL; // These should be set in CStoreParams
|
|
Params.pvNotifyContext = NULL;
|
|
Params.hrResolutionStatus = S_OK;
|
|
Params.pblk = this;
|
|
Params.pfnDefault = HrSendQueryDefault;
|
|
Params.pfnCompletion = HrSendQueryCompletion;
|
|
|
|
if(m_pISMTPServer) {
|
|
|
|
hr = m_pISMTPServer->TriggerServerEvent(
|
|
SMTP_MAILTRANSPORT_CATEGORIZE_SENDQUERY_EVENT,
|
|
&Params);
|
|
if(FAILED(hr) && (hr != E_NOTIMPL)) {
|
|
ERROR_LOG("m_pISMTPServer->TriggerServerEvent(sendquery)");
|
|
}
|
|
|
|
} else {
|
|
hr = E_NOTIMPL;
|
|
}
|
|
if(hr == E_NOTIMPL) {
|
|
//
|
|
// Events are disabled
|
|
// Heap allocation is required
|
|
//
|
|
PEVENTPARAMS_CATSENDQUERY pParams;
|
|
pParams = new EVENTPARAMS_CATSENDQUERY;
|
|
if(pParams == NULL) {
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
ERROR_LOG("new EVENTPARAMS_CATSENDQUERY");
|
|
|
|
} else {
|
|
CopyMemory(pParams, &Params, sizeof(EVENTPARAMS_CATSENDQUERY));
|
|
HrSendQueryDefault(
|
|
S_OK,
|
|
pParams);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", (hr == MAILTRANSPORT_S_PENDING) ? S_OK : hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return (hr == MAILTRANSPORT_S_PENDING) ? S_OK : hr;
|
|
} // CSearchRequestBlock::HrTriggerSendQuery
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::HrSendQueryDefault
|
|
//
|
|
// Synopsis: The default sink function for the SendQuery event
|
|
//
|
|
// Arguments:
|
|
// hrStatus: status of the event so far
|
|
// pContext: Event params context
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/16 11:46:24: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CSearchRequestBlock::HrSendQueryDefault(
|
|
HRESULT HrStatus,
|
|
PVOID pContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PEVENTPARAMS_CATSENDQUERY pParams;
|
|
CSearchRequestBlock *pBlock;
|
|
LPWSTR *rgpszAttributes = NULL;
|
|
ICategorizerParametersEx *pIPhatParams = NULL;
|
|
ICategorizerRequestedAttributes *pIRequestedAttributes = NULL;
|
|
|
|
pParams = (PEVENTPARAMS_CATSENDQUERY) pContext;
|
|
_ASSERT(pParams);
|
|
|
|
pBlock = (CSearchRequestBlock *) pParams->pblk;
|
|
_ASSERT(pBlock);
|
|
CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::HrSendQueryDefault");
|
|
hr = pParams->pICatParams->QueryInterface(
|
|
IID_ICategorizerParametersEx,
|
|
(LPVOID *)&pIPhatParams);
|
|
|
|
if(FAILED(hr)) {
|
|
ERROR_LOG_STATIC(
|
|
"pParams->pICatParams->QueryInterface(IID_ICategorizerParametersEx",
|
|
pBlock,
|
|
pBlock->GetISMTPServerEx());
|
|
pIPhatParams = NULL;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
hr = pIPhatParams->GetRequestedAttributes(
|
|
&pIRequestedAttributes);
|
|
ERROR_CLEANUP_LOG_STATIC(
|
|
"pIPhatParams->GetRequestedAttributes",
|
|
pBlock,
|
|
pBlock->GetISMTPServerEx());
|
|
|
|
hr = pIRequestedAttributes->GetAllAttributesW(
|
|
&rgpszAttributes);
|
|
ERROR_CLEANUP_LOG_STATIC(
|
|
"pIRequestedAttributes->GetAllAttributesW",
|
|
pBlock,
|
|
pBlock->GetISMTPServerEx());
|
|
|
|
hr = pBlock->m_pConn->AsyncSearch(
|
|
pBlock->m_pConn->GetNamingContextW(),
|
|
LDAP_SCOPE_SUBTREE,
|
|
pBlock->m_pszSearchFilter,
|
|
(LPCWSTR *)rgpszAttributes,
|
|
0, // Do not do a paged search
|
|
LDAPCompletion,
|
|
pParams);
|
|
ERROR_CLEANUP_LOG_STATIC(
|
|
"pBlock->m_pConn->AsyncSearch",
|
|
pBlock,
|
|
pBlock->GetISMTPServerEx());
|
|
|
|
CLEANUP:
|
|
if(FAILED(hr)) {
|
|
|
|
ErrorTrace((LPARAM)pBlock, "HrSendQueryDefault failing hr %08lx", hr);
|
|
//
|
|
// Call the completion routine directly with the error
|
|
//
|
|
hr = pParams->pICatAsyncContext->CompleteQuery(
|
|
pParams, // Query context
|
|
hr, // Status
|
|
0, // dwcResults
|
|
NULL, // rgpItemAttributes,
|
|
TRUE); // fFinalCompletion
|
|
//
|
|
// CompleteQuery should not fail
|
|
//
|
|
_ASSERT(SUCCEEDED(hr));
|
|
}
|
|
if(pIRequestedAttributes)
|
|
pIRequestedAttributes->Release();
|
|
if(pIPhatParams)
|
|
pIPhatParams->Release();
|
|
|
|
CatFunctLeaveEx((LPARAM)pBlock);
|
|
return MAILTRANSPORT_S_PENDING;
|
|
} // CSearchRequestBlock::HrSendQueryDefault
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::LDAPCompletion
|
|
//
|
|
// Synopsis: Wrapper for the default processing completion of SendQuery
|
|
//
|
|
// Arguments: [ctx] -- Opaque pointer to EVENTPARAMS_SENDQUERY being
|
|
// completed
|
|
// [dwNumReults] -- The number of objects found
|
|
// [rgpICatItemAttributes] -- An array of
|
|
// ICategorizerItemAttributes; one per object found
|
|
// [hrStatus] -- The error code if the search request failed
|
|
// fFinalCompletion:
|
|
// FALSE: This is a completion for
|
|
// pending results; there will be another completion
|
|
// called with more results
|
|
// TRUE: This is the final completion call
|
|
//
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/16 12:23:54: Created
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CSearchRequestBlock::LDAPCompletion(
|
|
LPVOID ctx,
|
|
DWORD dwNumResults,
|
|
ICategorizerItemAttributes **rgpICatItemAttributes,
|
|
HRESULT hrStatus,
|
|
BOOL fFinalCompletion)
|
|
{
|
|
HRESULT hr;
|
|
PEVENTPARAMS_CATSENDQUERY pParams;
|
|
CSearchRequestBlock *pBlock;
|
|
|
|
pParams = (PEVENTPARAMS_CATSENDQUERY) ctx;
|
|
_ASSERT(pParams);
|
|
|
|
pBlock = (CSearchRequestBlock *) pParams->pblk;
|
|
_ASSERT(pBlock);
|
|
|
|
CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::LDAPCompletion");
|
|
|
|
if(FAILED(hrStatus))
|
|
{
|
|
//
|
|
// Log async completion failure
|
|
//
|
|
hr = hrStatus;
|
|
ERROR_LOG_STATIC(
|
|
"async",
|
|
pBlock,
|
|
pBlock->GetISMTPServerEx());
|
|
}
|
|
|
|
//
|
|
// Call the normal sink completion routine
|
|
//
|
|
hr = pParams->pICatAsyncContext->CompleteQuery(
|
|
pParams, // Query Context
|
|
hrStatus, // Status
|
|
dwNumResults, // dwcResults
|
|
rgpICatItemAttributes, // rgpItemAttributes
|
|
fFinalCompletion); // Is this the final completion for the query?
|
|
|
|
_ASSERT(SUCCEEDED(hr));
|
|
|
|
CatFunctLeaveEx((LPARAM)pBlock);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::HrSendQueryCompletion
|
|
//
|
|
// Synopsis: The completion routine for the SendQuery event
|
|
//
|
|
// Arguments:
|
|
// hrStatus: status of the event so far
|
|
// pContext: Event params context
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/16 12:52:22: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CSearchRequestBlock::HrSendQueryCompletion(
|
|
HRESULT HrStatus,
|
|
PVOID pContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PEVENTPARAMS_CATSENDQUERY pParams;
|
|
CSearchRequestBlock *pBlock;
|
|
|
|
pParams = (PEVENTPARAMS_CATSENDQUERY) pContext;
|
|
_ASSERT(pParams);
|
|
|
|
pBlock = (CSearchRequestBlock *) pParams->pblk;
|
|
_ASSERT(pBlock);
|
|
|
|
CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::HrSendQueryCompletion");
|
|
|
|
//
|
|
// Log async failure
|
|
//
|
|
if(FAILED(HrStatus))
|
|
{
|
|
hr = HrStatus;
|
|
ERROR_LOG_STATIC(
|
|
"async",
|
|
pBlock,
|
|
pBlock->GetISMTPServerEx());
|
|
}
|
|
|
|
pBlock->CompleteSearchBlock(
|
|
pParams->hrResolutionStatus);
|
|
|
|
if(pBlock->m_pISMTPServer == NULL) {
|
|
//
|
|
// Events are disabled
|
|
// We must free the eventparams
|
|
//
|
|
delete pParams;
|
|
}
|
|
//
|
|
// The purpose of this block is complete. Today is a good day to
|
|
// die!
|
|
// -- Lt. Commander Worf
|
|
//
|
|
delete pBlock;
|
|
|
|
CatFunctLeaveEx((LPARAM)pBlock);
|
|
return S_OK;
|
|
} // HrSendQueryCompletion
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::CompleteSearchBlock
|
|
//
|
|
// Synopsis: Completion routine when the SendQuery event is done
|
|
//
|
|
// Arguments:
|
|
// hrStatus: Resolution status
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/16 13:36:33: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CSearchRequestBlock::CompleteSearchBlock(
|
|
HRESULT hrStatus)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrFetch, hrResult;
|
|
DWORD dwCount;
|
|
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::CompleteSearchBlock");
|
|
|
|
hr = HrTriggerSortQueryResult(hrStatus);
|
|
ERROR_CLEANUP_LOG("HrTriggerSortQueryResult");
|
|
//
|
|
// Check every ICategorizerItem
|
|
// If any one of them does not have an hrStatus set, set it to
|
|
// HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
|
|
//
|
|
for(dwCount = 0;
|
|
dwCount < DwNumBlockRequests();
|
|
dwCount++) {
|
|
|
|
hrFetch = m_rgpICatItems[dwCount]->GetHRESULT(
|
|
ICATEGORIZERITEM_HRSTATUS,
|
|
&hrResult);
|
|
|
|
if(FAILED(hrFetch)) {
|
|
_ASSERT(hrFetch == CAT_E_PROPNOTFOUND);
|
|
_VERIFY(SUCCEEDED(
|
|
m_rgpICatItems[dwCount]->PutHRESULT(
|
|
ICATEGORIZERITEM_HRSTATUS,
|
|
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))));
|
|
}
|
|
}
|
|
|
|
CLEANUP:
|
|
if(FAILED(hr)) {
|
|
|
|
ErrorTrace((LPARAM)this, "Failing block hr %08lx", hr);
|
|
PutBlockHRESULT(hr);
|
|
}
|
|
//
|
|
// Call all the individual completion routines
|
|
//
|
|
CallCompletions();
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CSearchRequestBlock::CompleteSearchBlock
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::PutBlockHRESULT
|
|
//
|
|
// Synopsis: Set the status of every ICatItem in the block to some hr
|
|
//
|
|
// Arguments:
|
|
// hr: Status to set
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/16 14:03:30: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CSearchRequestBlock::PutBlockHRESULT(
|
|
HRESULT hr)
|
|
{
|
|
DWORD dwCount;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::PutBlockHRESULT");
|
|
DebugTrace((LPARAM)this, "hr = %08lx", hr);
|
|
|
|
for(dwCount = 0;
|
|
dwCount < DwNumBlockRequests();
|
|
dwCount++) {
|
|
|
|
PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]);
|
|
//
|
|
// Set the error status
|
|
//
|
|
_VERIFY(SUCCEEDED(preq->pCCatAddr->PutHRESULT(
|
|
ICATEGORIZERITEM_HRSTATUS,
|
|
hr)));
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CSearchRequestBlock::PutBlockHRESULT
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::CallCompletions
|
|
//
|
|
// Synopsis: Call the completion routine of every item in the block
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/16 14:05:50: Created.
|
|
// dlongley 2001/10/23: Modified.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CSearchRequestBlock::CallCompletions()
|
|
{
|
|
DWORD dwCount;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::CallCompletions");
|
|
|
|
//
|
|
// Get an Insertion context before calling completions so that
|
|
// newly inserted searches will be batched
|
|
//
|
|
for(dwCount = 0;
|
|
dwCount < DwNumBlockRequests();
|
|
dwCount++) {
|
|
|
|
PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]);
|
|
|
|
preq->pslrc->AddRef();
|
|
preq->pslrc->GetInsertionContext();
|
|
|
|
preq->fnSearchCompletion(
|
|
preq->pCCatAddr,
|
|
preq->pslrc,
|
|
m_pConn);
|
|
}
|
|
|
|
m_pConn->DecrementPendingSearches(
|
|
DwNumBlockRequests());
|
|
|
|
for(dwCount = 0;
|
|
dwCount < DwNumBlockRequests();
|
|
dwCount++) {
|
|
|
|
PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]);
|
|
|
|
preq->pslrc->ReleaseInsertionContext();
|
|
preq->pslrc->Release();
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CSearchRequestBlock::CallCompletions
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::HrTriggerSortQueryResult
|
|
//
|
|
// Synopsis: Trigger the SortQueryResult event
|
|
//
|
|
// Arguments:
|
|
// hrStatus: Status of Resolution
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// error from the dispatcher
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/16 14:09:12: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CSearchRequestBlock::HrTriggerSortQueryResult(
|
|
HRESULT hrStatus)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
EVENTPARAMS_CATSORTQUERYRESULT Params;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::HrTriggerSortQueryResult");
|
|
|
|
Params.pICatParams = m_pICatParams;
|
|
Params.hrResolutionStatus = hrStatus;
|
|
Params.dwcAddresses = DwNumBlockRequests();
|
|
Params.rgpICatItems = m_rgpICatItems;
|
|
Params.dwcResults = m_csaItemAttr.Size();
|
|
Params.rgpICatItemAttributes = m_csaItemAttr;
|
|
Params.pfnDefault = HrSortQueryResultDefault;
|
|
Params.pblk = this;
|
|
|
|
if(m_pISMTPServer) {
|
|
|
|
hr = m_pISMTPServer->TriggerServerEvent(
|
|
SMTP_MAILTRANSPORT_CATEGORIZE_SORTQUERYRESULT_EVENT,
|
|
&Params);
|
|
if(FAILED(hr) && (hr != E_NOTIMPL))
|
|
{
|
|
ERROR_LOG("m_pISMTPServer->TriggerServerEvent");
|
|
}
|
|
} else {
|
|
hr = E_NOTIMPL;
|
|
}
|
|
if(hr == E_NOTIMPL) {
|
|
//
|
|
// Events are disabled, call default processing
|
|
//
|
|
HrSortQueryResultDefault(
|
|
S_OK,
|
|
&Params);
|
|
hr = S_OK;
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CSearchRequestBlock::HrTriggerSortQueryResult
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::HrSortQueryResultDefault
|
|
//
|
|
// Synopsis: Default sink for SortQueryResult -- match the objects found
|
|
// with the objects requested
|
|
//
|
|
// Arguments:
|
|
// hrStatus: Status of events
|
|
// pContext: Params context for this event
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/16 14:17:49: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CSearchRequestBlock::HrSortQueryResultDefault(
|
|
HRESULT hrStatus,
|
|
PVOID pContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PEVENTPARAMS_CATSORTQUERYRESULT pParams;
|
|
CSearchRequestBlock *pBlock;
|
|
DWORD dwAttrIndex, dwReqIndex;
|
|
ATTRIBUTE_ENUMERATOR enumerator;
|
|
|
|
pParams = (PEVENTPARAMS_CATSORTQUERYRESULT) pContext;
|
|
_ASSERT(pParams);
|
|
|
|
pBlock = (CSearchRequestBlock *) pParams->pblk;
|
|
_ASSERT(pBlock);
|
|
|
|
CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::HrSortQueryResultDefault");
|
|
DebugTrace((LPARAM)pBlock, "hrResolutionStatus %08lx, dwcResults %08lx",
|
|
pParams->hrResolutionStatus, pParams->dwcResults);
|
|
|
|
if(FAILED(pParams->hrResolutionStatus)) {
|
|
//
|
|
// Fail the entire block
|
|
//
|
|
pBlock->PutBlockHRESULT(pParams->hrResolutionStatus);
|
|
goto CLEANUP;
|
|
}
|
|
//
|
|
// Resolution succeeded
|
|
// If dwcResults is not zero, then rgpICatItemAttrs can NOT be null
|
|
//
|
|
_ASSERT((pParams->dwcResults == 0) ||
|
|
(pParams->rgpICatItemAttributes != NULL));
|
|
|
|
//
|
|
// Loop through every rgpICatItemAttrs. For each
|
|
// ICategorizerItemAttributes, looking for a matching SEARCH_REQUEST
|
|
//
|
|
for(dwAttrIndex = 0; dwAttrIndex < pParams->dwcResults; dwAttrIndex++) {
|
|
ICategorizerItemAttributes *pICatItemAttr = NULL;
|
|
ICategorizerUTF8Attributes *pIUTF8 = NULL;
|
|
|
|
pICatItemAttr = pParams->rgpICatItemAttributes[dwAttrIndex];
|
|
LPCSTR pszLastDistinguishingAttribute = NULL;
|
|
BOOL fEnumerating = FALSE;
|
|
|
|
hr = pICatItemAttr->QueryInterface(
|
|
IID_ICategorizerUTF8Attributes,
|
|
(LPVOID *) &pIUTF8);
|
|
ERROR_CLEANUP_LOG_STATIC(
|
|
"pICatItemAttr->QueryInterface",
|
|
pBlock,
|
|
pBlock->GetISMTPServerEx());
|
|
|
|
for(dwReqIndex = 0; dwReqIndex < pBlock->DwNumBlockRequests();
|
|
dwReqIndex++) {
|
|
PSEARCH_REQUEST preq = &(pBlock->m_prgSearchRequests[dwReqIndex]);
|
|
//#ifdef DEBUG
|
|
// WCHAR wszPreqDistinguishingAttributeValue[20];
|
|
//#else
|
|
WCHAR wszPreqDistinguishingAttributeValue[CAT_MAX_INTERNAL_FULL_EMAIL];
|
|
//#endif
|
|
LPWSTR pwszPreqDistinguishingAttributeValue = wszPreqDistinguishingAttributeValue;
|
|
DWORD cPreqDistinguishingAttributeValue;
|
|
DWORD rc;
|
|
|
|
//
|
|
// If we don't have a distinguishing attribute and
|
|
// distinguishing attribute value for this search
|
|
// request, we've no hope of matching it up
|
|
//
|
|
if((preq->pszDistinguishingAttribute == NULL) ||
|
|
(preq->pszDistinguishingAttributeValue == NULL))
|
|
continue;
|
|
|
|
// convert pszDistinguishingAttributeValue to unicode
|
|
cPreqDistinguishingAttributeValue =
|
|
MultiByteToWideChar(CP_UTF8,
|
|
0,
|
|
preq->pszDistinguishingAttributeValue,
|
|
-1,
|
|
pwszPreqDistinguishingAttributeValue,
|
|
0);
|
|
if (cPreqDistinguishingAttributeValue >
|
|
(sizeof(wszPreqDistinguishingAttributeValue) / sizeof(WCHAR)) )
|
|
{
|
|
pwszPreqDistinguishingAttributeValue =
|
|
new WCHAR[cPreqDistinguishingAttributeValue + 1];
|
|
if (pwszPreqDistinguishingAttributeValue == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
ERROR_LOG_STATIC(
|
|
"new WCHAR[]",
|
|
pBlock,
|
|
pBlock->GetISMTPServerEx());
|
|
continue;
|
|
}
|
|
}
|
|
rc = MultiByteToWideChar(CP_UTF8,
|
|
0,
|
|
preq->pszDistinguishingAttributeValue,
|
|
-1,
|
|
pwszPreqDistinguishingAttributeValue,
|
|
cPreqDistinguishingAttributeValue);
|
|
if (rc == 0) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
ERROR_LOG_STATIC(
|
|
"MultiByteToWideChar",
|
|
pBlock,
|
|
pBlock->GetISMTPServerEx());
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Start an attribute value enumeration if necessary
|
|
//
|
|
if((pszLastDistinguishingAttribute == NULL) ||
|
|
(lstrcmpi(pszLastDistinguishingAttribute,
|
|
preq->pszDistinguishingAttribute) != 0)) {
|
|
if(fEnumerating) {
|
|
pIUTF8->EndUTF8AttributeEnumeration(&enumerator);
|
|
}
|
|
hr = pIUTF8->BeginUTF8AttributeEnumeration(
|
|
preq->pszDistinguishingAttribute,
|
|
&enumerator);
|
|
fEnumerating = SUCCEEDED(hr);
|
|
pszLastDistinguishingAttribute = preq->pszDistinguishingAttribute;
|
|
} else {
|
|
//
|
|
// else just rewind our current enumeration
|
|
//
|
|
if(fEnumerating)
|
|
_VERIFY(SUCCEEDED(pIUTF8->RewindUTF8AttributeEnumeration(
|
|
&enumerator)));
|
|
}
|
|
//
|
|
// If we can't enumerate through the distinguishing
|
|
// attribute, there's no hope in matching up requests
|
|
//
|
|
if(!fEnumerating)
|
|
continue;
|
|
|
|
//
|
|
// See if the distinguishing attribute value matches
|
|
//
|
|
LPSTR pszDistinguishingAttributeValue;
|
|
hr = pIUTF8->GetNextUTF8AttributeValue(
|
|
&enumerator,
|
|
&pszDistinguishingAttributeValue);
|
|
while(SUCCEEDED(hr)) {
|
|
hr = wcsutf8cmpi(pwszPreqDistinguishingAttributeValue,
|
|
pszDistinguishingAttributeValue);
|
|
if (SUCCEEDED(hr)) {
|
|
if(hr == S_OK) {
|
|
DebugTrace((LPARAM)pBlock, "Matched dwAttrIndex %d with dwReqIndex %d", dwAttrIndex, dwReqIndex);
|
|
pBlock->MatchItem(
|
|
preq->pCCatAddr,
|
|
pICatItemAttr);
|
|
}
|
|
hr = pIUTF8->GetNextUTF8AttributeValue(
|
|
&enumerator,
|
|
&pszDistinguishingAttributeValue);
|
|
} else {
|
|
ERROR_LOG_STATIC(
|
|
"wcsutf8cmpi",
|
|
pBlock,
|
|
pBlock->GetISMTPServerEx());
|
|
}
|
|
}
|
|
|
|
if (pwszPreqDistinguishingAttributeValue != wszPreqDistinguishingAttributeValue) {
|
|
delete[] pwszPreqDistinguishingAttributeValue;
|
|
}
|
|
}
|
|
//
|
|
// End any last enumeration going on
|
|
//
|
|
if(fEnumerating)
|
|
pIUTF8->EndUTF8AttributeEnumeration(&enumerator);
|
|
fEnumerating = FALSE;
|
|
if(pIUTF8) {
|
|
pIUTF8->Release();
|
|
pIUTF8 = NULL;
|
|
}
|
|
}
|
|
|
|
CLEANUP:
|
|
CatFunctLeaveEx((LPARAM)pBlock);
|
|
return S_OK;
|
|
} // CSearchRequestBlock::HrSortQueryResultDefault
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::MatchItem
|
|
//
|
|
// Synopsis: Match a particular ICategorizerItem to a particular ICategorizerItemAttributes
|
|
// If already matched with an ICategorizerItemAttributes with an
|
|
// identical ID then set item status to CAT_E_MULTIPLE_MATCHES
|
|
// If already matched with an ICategorizerItemAttributes with a
|
|
// different ID then attempt aggregation
|
|
////
|
|
// Arguments:
|
|
// pICatItem: an ICategorizerItem
|
|
// pICatItemAttr: the matching attribute interface for pICatItem
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/16 14:36:45: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CSearchRequestBlock::MatchItem(
|
|
ICategorizerItem *pICatItem,
|
|
ICategorizerItemAttributes *pICatItemAttr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ICategorizerItemAttributes *pICatItemAttr_Current = NULL;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::MatchItem");
|
|
|
|
_ASSERT(pICatItem);
|
|
_ASSERT(pICatItemAttr);
|
|
//
|
|
// Check to see if this item already has
|
|
// ICategorizerItemAttributes set
|
|
//
|
|
hr = pICatItem->GetICategorizerItemAttributes(
|
|
ICATEGORIZERITEM_ICATEGORIZERITEMATTRIBUTES,
|
|
&pICatItemAttr_Current);
|
|
if(SUCCEEDED(hr)) {
|
|
//
|
|
// This guy is already matched. Is the duplicate from the
|
|
// same resolver sink?
|
|
//
|
|
GUID GOriginal, GNew;
|
|
GOriginal = pICatItemAttr_Current->GetTransportSinkID();
|
|
GNew = pICatItemAttr->GetTransportSinkID();
|
|
|
|
if(GOriginal == GNew) {
|
|
//
|
|
// Two matches from the same resolver sink indicates that
|
|
// there are multiple matches for this object. This is an
|
|
// error.
|
|
//
|
|
|
|
//
|
|
// This guy is already matched -- the distinguishing attribute
|
|
// really wasn't distinguishing. Set error hrstatus.
|
|
//
|
|
LogAmbiguousEvent(pICatItem);
|
|
|
|
_VERIFY(SUCCEEDED(
|
|
pICatItem->PutHRESULT(
|
|
ICATEGORIZERITEM_HRSTATUS,
|
|
CAT_E_MULTIPLE_MATCHES)));
|
|
} else {
|
|
|
|
//
|
|
// We have multiple matches from different resolver
|
|
// sinks. Let's try to aggregate the new
|
|
// ICategorizerItemAttributes
|
|
//
|
|
|
|
hr = pICatItemAttr_Current->AggregateAttributes(
|
|
pICatItemAttr);
|
|
|
|
if(FAILED(hr) && (hr != E_NOTIMPL)) {
|
|
//
|
|
// Fail categorization for this item
|
|
//
|
|
ERROR_LOG("pICatItemAttr_Current->AggregateAttributes");
|
|
_VERIFY(SUCCEEDED(
|
|
pICatItem->PutHRESULT(
|
|
ICATEGORIZERITEM_HRSTATUS,
|
|
hr)));
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Normal case -- set the ICategorizerItemAttribute property
|
|
// of ICategorizerItem
|
|
//
|
|
_VERIFY(SUCCEEDED(
|
|
pICatItem->PutICategorizerItemAttributes(
|
|
ICATEGORIZERITEM_ICATEGORIZERITEMATTRIBUTES,
|
|
pICatItemAttr)));
|
|
//
|
|
// Set hrStatus of this guy to success
|
|
//
|
|
_VERIFY(SUCCEEDED(
|
|
pICatItem->PutHRESULT(
|
|
ICATEGORIZERITEM_HRSTATUS,
|
|
S_OK)));
|
|
}
|
|
|
|
if(pICatItemAttr_Current)
|
|
pICatItemAttr_Current->Release();
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CSearchRequestBlock::MatchItem
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CBatchLdapConnection::HrInsertSearchRequest
|
|
//
|
|
// Synopsis: Insert a search request
|
|
//
|
|
// Arguments:
|
|
// pISMTPServer: ISMTPServer interface to use for triggering events
|
|
// pCCatAddr: Address item for the search
|
|
// fnSearchCompletion: Async Completion routine
|
|
// ctxSearchCompletion: Context to pass to the async completion routine
|
|
// pszSearchFilter: Search filter to use
|
|
// pszDistinguishingAttribute: The distinguishing attribute for matching
|
|
// pszDistinguishingAttributeValue: above attribute's distinguishing value
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/08 19:41:37: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CBatchLdapConnection::HrInsertSearchRequest(
|
|
ISMTPServer *pISMTPServer,
|
|
ICategorizerParameters *pICatParams,
|
|
CCatAddr *pCCatAddr,
|
|
LPSEARCHCOMPLETION fnSearchCompletion,
|
|
CStoreListResolveContext *pslrc,
|
|
LPSTR pszSearchFilter,
|
|
LPSTR pszDistinguishingAttribute,
|
|
LPSTR pszDistinguishingAttributeValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CSearchRequestBlock *pBlock;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::HrInsertSearchRequest");
|
|
|
|
_ASSERT(m_cInsertionContext);
|
|
_ASSERT(pCCatAddr);
|
|
_ASSERT(fnSearchCompletion);
|
|
_ASSERT(pszSearchFilter);
|
|
_ASSERT(pszDistinguishingAttribute);
|
|
_ASSERT(pszDistinguishingAttributeValue);
|
|
|
|
pBlock = GetSearchRequestBlock();
|
|
|
|
if(pBlock == NULL) {
|
|
|
|
ErrorTrace((LPARAM)this, "out of memory getting a search block");
|
|
hr = E_OUTOFMEMORY;
|
|
ERROR_LOG_ADDR(pCCatAddr, "GetSearchRequestBlock");
|
|
goto CLEANUP;
|
|
}
|
|
|
|
pBlock->InsertSearchRequest(
|
|
pISMTPServer,
|
|
pICatParams,
|
|
pCCatAddr,
|
|
fnSearchCompletion,
|
|
pslrc,
|
|
pszSearchFilter,
|
|
pszDistinguishingAttribute,
|
|
pszDistinguishingAttributeValue);
|
|
|
|
CLEANUP:
|
|
DebugTrace((LPARAM)this, "Returning hr %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CBatchLdapConnection::GetSearchRequestBlock
|
|
//
|
|
// Synopsis: Gets the next available search block with room
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns:
|
|
// NULL: Out of memory
|
|
// else, a search block object
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/08 19:41:37: Created.
|
|
// haozhang 2001/11/25 updated for 193848
|
|
//
|
|
//-------------------------------------------------------------
|
|
CSearchRequestBlock * CBatchLdapConnection::GetSearchRequestBlock()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
PLIST_ENTRY ple;
|
|
CSearchRequestBlock *pBlock = NULL;
|
|
|
|
//
|
|
// Updated for fix of 193848
|
|
// We do two passes. In first one, we will go through the list
|
|
// and reserve a slot if available(then return). If we don't,
|
|
// we will created a new block and proceed with a second pass. In
|
|
// second pass, we will first insert the block to the list, then
|
|
// go through the list again to reserve a slot in the first
|
|
// avaiable block. The fix differs from previous version in that
|
|
// we will not simply reserve a slot in the new block we just
|
|
// created. Instead, we will go through the list again in case
|
|
// existing block still has room. Therefore, we avoided the
|
|
// core problem in which we reserve a slot on new block even
|
|
// though there is room in existing block.
|
|
//
|
|
|
|
AcquireSpinLock(&m_spinlock);
|
|
//
|
|
// See if there is an insertion block with available slots
|
|
//
|
|
for(ple = m_listhead.Flink;
|
|
(ple != &m_listhead) && (FAILED(hr));
|
|
ple = ple->Flink) {
|
|
|
|
pBlock = CONTAINING_RECORD(ple, CSearchRequestBlock, m_listentry);
|
|
|
|
hr = pBlock->ReserveSlot();
|
|
}
|
|
|
|
ReleaseSpinLock(&m_spinlock);
|
|
|
|
if(SUCCEEDED(hr))
|
|
return pBlock;
|
|
|
|
//
|
|
// Create a new block
|
|
//
|
|
pBlock = new (m_nMaxSearchBlockSize) CSearchRequestBlock(this);
|
|
if(pBlock) {
|
|
|
|
AcquireSpinLock(&m_spinlock);
|
|
|
|
InsertTailList(&m_listhead, &(pBlock->m_listentry));
|
|
|
|
//
|
|
// Again,see if there is an insertion block with available slots
|
|
//
|
|
for(ple = m_listhead.Flink;
|
|
(ple != &m_listhead) && (FAILED(hr));
|
|
ple = ple->Flink) {
|
|
|
|
pBlock = CONTAINING_RECORD(ple, CSearchRequestBlock, m_listentry);
|
|
|
|
hr = pBlock->ReserveSlot();
|
|
}
|
|
ReleaseSpinLock(&m_spinlock);
|
|
|
|
_ASSERT(SUCCEEDED(hr));
|
|
}
|
|
return pBlock;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSearchRequestBlock::LogAmbiguousEvent
|
|
//
|
|
// Synopsis: Eventlogs an ambiguous address error
|
|
//
|
|
// Arguments:
|
|
// pItem: ICatItem with ambig address
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History:
|
|
// jstamerj 2001/12/13 00:03:16: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CSearchRequestBlock::LogAmbiguousEvent(
|
|
IN ICategorizerItem *pItem)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPCSTR rgSubStrings[2];
|
|
CHAR szAddress[CAT_MAX_INTERNAL_FULL_EMAIL];
|
|
CHAR szAddressType[CAT_MAX_ADDRESS_TYPE_STRING];
|
|
|
|
CatFunctEnter("CIMstRecipListAddr::LogNDREvent");
|
|
|
|
//
|
|
// Get the address
|
|
//
|
|
hr = HrGetAddressStringFromICatItem(
|
|
pItem,
|
|
sizeof(szAddressType) / sizeof(szAddressType[0]),
|
|
szAddressType,
|
|
sizeof(szAddress) / sizeof(szAddress[0]),
|
|
szAddress);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
//
|
|
// Still log an event, but use "unknown" for address type/string
|
|
//
|
|
lstrcpyn(szAddressType, "unknown",
|
|
sizeof(szAddressType) / sizeof(szAddressType[0]));
|
|
lstrcpyn(szAddress, "unknown",
|
|
sizeof(szAddress) / sizeof(szAddress[0]));
|
|
hr = S_OK;
|
|
}
|
|
|
|
rgSubStrings[0] = szAddressType;
|
|
rgSubStrings[1] = szAddress;
|
|
|
|
//
|
|
// Can we log an event?
|
|
//
|
|
if(GetISMTPServerEx() == NULL)
|
|
{
|
|
FatalTrace((LPARAM)0, "Unable to log ambiguous address event; NULL pISMTPServerEx");
|
|
for(DWORD dwIdx = 0; dwIdx < 2; dwIdx++)
|
|
{
|
|
if( rgSubStrings[dwIdx] != NULL )
|
|
{
|
|
FatalTrace((LPARAM)0, "Event String %d: %s",
|
|
dwIdx, rgSubStrings[dwIdx]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CatLogEvent(
|
|
GetISMTPServerEx(),
|
|
CAT_EVENT_AMBIGUOUS_ADDRESS,
|
|
2,
|
|
rgSubStrings,
|
|
S_OK,
|
|
szAddress,
|
|
LOGEVENT_FLAG_PERIODIC,
|
|
LOGEVENT_LEVEL_MINIMUM);
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CBatchLdapConnection::DispatchBlocks
|
|
//
|
|
// Synopsis: Dispatch all the blocks in a list
|
|
//
|
|
// Arguments:
|
|
// plisthead: List to dispatch
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/11 15:16:36: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CBatchLdapConnection::DispatchBlocks(
|
|
PLIST_ENTRY plisthead)
|
|
{
|
|
PLIST_ENTRY ple, ple_next;
|
|
CSearchRequestBlock *pBlock;
|
|
|
|
for(ple = plisthead->Flink;
|
|
ple != plisthead;
|
|
ple = ple_next) {
|
|
|
|
ple_next = ple->Flink;
|
|
|
|
pBlock = CONTAINING_RECORD(ple, CSearchRequestBlock,
|
|
m_listentry);
|
|
|
|
pBlock->DispatchBlock();
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::CStoreListResolveContext
|
|
//
|
|
// Synopsis: Construct a CStoreListResolveContext object
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/22 12:16:08: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CStoreListResolveContext::CStoreListResolveContext(
|
|
CEmailIDLdapStore<CCatAddr> *pStore)
|
|
{
|
|
CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::CStoreListResolveContext");
|
|
|
|
m_cRefs = 1;
|
|
m_dwSignature = SIGNATURE_CSTORELISTRESOLVECONTEXT;
|
|
m_pConn = NULL;
|
|
m_fCanceled = FALSE;
|
|
m_dwcRetries = 0;
|
|
m_dwcCompletedLookups = 0;
|
|
InitializeCriticalSectionAndSpinCount(&m_cs, 2000);
|
|
m_pISMTPServer = NULL;
|
|
m_pISMTPServerEx = NULL;
|
|
m_pICatParams = NULL;
|
|
m_dwcInsertionContext = 0;
|
|
m_pStore = pStore;
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CStoreListResolveContext::CStoreListResolveContext
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::~CStoreListResolveContext
|
|
//
|
|
// Synopsis: Destruct a list resolve context
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/22 12:18:01: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CStoreListResolveContext::~CStoreListResolveContext()
|
|
{
|
|
CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::~CStoreListResolveContext");
|
|
|
|
_ASSERT(m_dwSignature == SIGNATURE_CSTORELISTRESOLVECONTEXT);
|
|
m_dwSignature = SIGNATURE_CSTORELISTRESOLVECONTEXT_INVALID;
|
|
|
|
if(m_pConn)
|
|
m_pConn->Release();
|
|
|
|
if(m_pISMTPServer)
|
|
m_pISMTPServer->Release();
|
|
|
|
if(m_pISMTPServerEx)
|
|
m_pISMTPServerEx->Release();
|
|
|
|
if(m_pICatParams)
|
|
m_pICatParams->Release();
|
|
|
|
DeleteCriticalSection(&m_cs);
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CStoreListResolveContext::~CStoreListResolveContext
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::HrInitialize
|
|
//
|
|
// Synopsis: Initailize this object so that it is ready to handle lookups
|
|
//
|
|
// Arguments:
|
|
// pISMTPServer: ISMTPServer interface to use for triggering events
|
|
// pICatParams: ICatParams interface to use
|
|
//
|
|
// Note: All of these string buffers must remain valid for the
|
|
// lifetime of this object!
|
|
// pszAccount: LDAP account to use for binding
|
|
// pszPassword: LDAP password to use
|
|
// pszNamingContext: Naming context to use for searches
|
|
// pszHost: LDAP Host to connect to
|
|
// dwPort: LDAP TCP port to use
|
|
// bt: Method of LDAP bind to use
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// error from LdapConnectionCache
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/22 12:20:31: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CStoreListResolveContext::HrInitialize(
|
|
ISMTPServer *pISMTPServer,
|
|
ICategorizerParameters *pICatParams)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::HrInitialize");
|
|
|
|
_ASSERT(m_pISMTPServer == NULL);
|
|
_ASSERT(m_pICatParams == NULL);
|
|
_ASSERT(pICatParams != NULL);
|
|
|
|
if(pISMTPServer) {
|
|
m_pISMTPServer = pISMTPServer;
|
|
m_pISMTPServer->AddRef();
|
|
|
|
hr = m_pISMTPServer->QueryInterface(
|
|
IID_ISMTPServerEx,
|
|
(LPVOID *) &m_pISMTPServerEx);
|
|
if(FAILED(hr)) {
|
|
//
|
|
// Deal with error
|
|
//
|
|
m_pISMTPServerEx = NULL;
|
|
hr = S_OK;
|
|
}
|
|
|
|
}
|
|
if(pICatParams) {
|
|
m_pICatParams = pICatParams;
|
|
m_pICatParams->AddRef();
|
|
}
|
|
|
|
hr = m_pStore->HrGetConnection(
|
|
&m_pConn);
|
|
|
|
if(FAILED(hr)) {
|
|
ERROR_LOG("m_pStore->HrGetConnection");
|
|
m_pConn = NULL;
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CStoreListResolveContext::HrInitialize
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::HrLookupEntryAsync
|
|
//
|
|
// Synopsis: Dispatch an async LDAP lookup
|
|
//
|
|
// Arguments:
|
|
// pCCatAddr: Address object to lookup
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// error from LdapConn
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/22 12:28:52: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CStoreListResolveContext::HrLookupEntryAsync(
|
|
CCatAddr *pCCatAddr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPSTR pszSearchFilter = NULL;
|
|
LPSTR pszDistinguishingAttribute = NULL;
|
|
LPSTR pszDistinguishingAttributeValue = NULL;
|
|
BOOL fTryAgain;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::HrLookupEntryAsync");
|
|
|
|
//
|
|
// Addref the CCatAddr here, release after completion
|
|
//
|
|
pCCatAddr->AddRef();
|
|
|
|
hr = pCCatAddr->HrTriggerBuildQuery();
|
|
ERROR_CLEANUP_LOG_ADDR(pCCatAddr, "pCCatAddr->HrTriggerBuildQuery");
|
|
|
|
//
|
|
// Fetch the distinguishing attribute and distinguishing attribute
|
|
// value from pCCatAddr
|
|
//
|
|
pCCatAddr->GetStringAPtr(
|
|
ICATEGORIZERITEM_LDAPQUERYSTRING,
|
|
&pszSearchFilter);
|
|
pCCatAddr->GetStringAPtr(
|
|
ICATEGORIZERITEM_DISTINGUISHINGATTRIBUTE,
|
|
&pszDistinguishingAttribute);
|
|
pCCatAddr->GetStringAPtr(
|
|
ICATEGORIZERITEM_DISTINGUISHINGATTRIBUTEVALUE,
|
|
&pszDistinguishingAttributeValue);
|
|
|
|
//
|
|
// Check to see if anyone set a search filter
|
|
//
|
|
if(pszSearchFilter == NULL) {
|
|
|
|
HRESULT hrStatus;
|
|
//
|
|
// If the status is unset, set it to CAT_E_NO_FILTER
|
|
//
|
|
hr = pCCatAddr->GetHRESULT(
|
|
ICATEGORIZERITEM_HRSTATUS,
|
|
&hrStatus);
|
|
|
|
if(FAILED(hr)) {
|
|
ErrorTrace((LPARAM)this, "No search filter set");
|
|
ERROR_LOG_ADDR(pCCatAddr, "pCCatAddr->GetHRESULT(hrstatus) -- no filter");
|
|
|
|
_VERIFY(SUCCEEDED(pCCatAddr->PutHRESULT(
|
|
ICATEGORIZERITEM_HRSTATUS,
|
|
CAT_E_NO_FILTER)));
|
|
}
|
|
DebugTrace((LPARAM)this, "BuildQuery did not build a search filter");
|
|
//
|
|
// Call the completion directly
|
|
//
|
|
pCCatAddr->LookupCompletion();
|
|
pCCatAddr->Release();
|
|
hr = S_OK;
|
|
goto CLEANUP;
|
|
}
|
|
if((pszDistinguishingAttribute == NULL) ||
|
|
(pszDistinguishingAttributeValue == NULL)) {
|
|
ErrorTrace((LPARAM)this, "Distinguishing attribute not set");
|
|
ERROR_LOG_ADDR(pCCatAddr, "--no distinguishing attribute--");
|
|
hr = E_INVALIDARG;
|
|
goto CLEANUP;
|
|
}
|
|
do {
|
|
|
|
fTryAgain = FALSE;
|
|
CBatchLdapConnection *pConn;
|
|
|
|
pConn = GetConnection();
|
|
|
|
//
|
|
// Insert the search request into the CBatchLdapConnection
|
|
// object. We will use the email address as the distinguishing
|
|
// attribute
|
|
//
|
|
if(pConn == NULL) {
|
|
|
|
hr = CAT_E_DBCONNECTION;
|
|
ERROR_LOG_ADDR(pCCatAddr, "GetConnection");
|
|
|
|
} else {
|
|
|
|
pConn->GetInsertionContext();
|
|
|
|
hr = pConn->HrInsertSearchRequest(
|
|
m_pISMTPServer,
|
|
m_pICatParams,
|
|
pCCatAddr,
|
|
CStoreListResolveContext::AsyncLookupCompletion,
|
|
this,
|
|
pszSearchFilter,
|
|
pszDistinguishingAttribute,
|
|
pszDistinguishingAttributeValue);
|
|
|
|
if(FAILED(hr)) {
|
|
ERROR_LOG_ADDR(pCCatAddr, "pConn->HrInsertSearchRequest");
|
|
}
|
|
|
|
pConn->ReleaseInsertionContext();
|
|
|
|
}
|
|
//
|
|
// If the above fails with CAT_E_TRANX_FAILED, it may be due
|
|
// to a stale connection. Attempt to reconnect.
|
|
//
|
|
if((hr == CAT_E_TRANX_FAILED) || (hr == CAT_E_DBCONNECTION)) {
|
|
|
|
HRESULT hrTryAgain = S_OK;
|
|
|
|
hrTryAgain = HrInvalidateConnectionAndRetrieveNewConnection(pConn);
|
|
fTryAgain = SUCCEEDED(hrTryAgain);
|
|
|
|
if(FAILED(hrTryAgain)) {
|
|
//
|
|
// Declare a new local called hr here because the
|
|
// ERROR_LOG macro uses it
|
|
//
|
|
HRESULT hr = hrTryAgain;
|
|
ERROR_LOG_ADDR(pCCatAddr, "HrInvalidateConnectionAndRetrieveNewConnection");
|
|
}
|
|
}
|
|
if(pConn != NULL)
|
|
pConn->Release();
|
|
|
|
} while(fTryAgain);
|
|
|
|
CLEANUP:
|
|
if(FAILED(hr)) {
|
|
|
|
ErrorTrace((LPARAM)this, "failing hr %08lx", hr);
|
|
pCCatAddr->Release();
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CStoreListResolveContext::HrLookupEntryAsync
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::Cancel
|
|
//
|
|
// Synopsis: Cancels pending lookups
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/22 12:45:21: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CStoreListResolveContext::Cancel()
|
|
{
|
|
CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::Cancel");
|
|
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
m_fCanceled = TRUE;
|
|
m_pConn->CancelAllSearches();
|
|
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CStoreListResolveContext::HrCancel
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::AsyncLookupCompletion
|
|
//
|
|
// Synopsis: Handle completion of a CCatAddr from CSearchRequestBlock
|
|
//
|
|
// Arguments:
|
|
// pCCatAddr: the item being completed
|
|
// pConn: Connection object used to do the search
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/22 14:37:09: Created.
|
|
// dlongley 2001/10/23: Modified.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CStoreListResolveContext::AsyncLookupCompletion(
|
|
CCatAddr *pCCatAddr,
|
|
CStoreListResolveContext *pslrc,
|
|
CBatchLdapConnection *pConn)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrStatus;
|
|
CSingleSearchReinsertionRequest *pCInsertionRequest = NULL;
|
|
|
|
CatFunctEnterEx((LPARAM)pslrc,
|
|
"CStoreListResolveContext::AsyncLookupCompletion");
|
|
|
|
_ASSERT(pCCatAddr);
|
|
|
|
hr = pCCatAddr->GetHRESULT(
|
|
ICATEGORIZERITEM_HRSTATUS,
|
|
&hrStatus);
|
|
_ASSERT(SUCCEEDED(hr));
|
|
|
|
if( SUCCEEDED(hrStatus) )
|
|
InterlockedIncrement((LPLONG) &(pslrc->m_dwcCompletedLookups));
|
|
|
|
if( (hrStatus == CAT_E_DBCONNECTION) &&
|
|
SUCCEEDED(pslrc->HrInvalidateConnectionAndRetrieveNewConnection(pConn))) {
|
|
//
|
|
// Retry the search with the new connection
|
|
//
|
|
pCInsertionRequest = new CSingleSearchReinsertionRequest(
|
|
pslrc,
|
|
pCCatAddr);
|
|
|
|
if(!pCInsertionRequest) {
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
ERROR_LOG_ADDR_STATIC(
|
|
pCCatAddr,
|
|
"new CSingleSearchReinsertionRequest",
|
|
pslrc,
|
|
pslrc->GetISMTPServerEx());
|
|
pCCatAddr->LookupCompletion();
|
|
|
|
} else {
|
|
|
|
hr = pslrc->HrInsertInsertionRequest(pCInsertionRequest);
|
|
if(FAILED(hr))
|
|
{
|
|
ERROR_LOG_ADDR_STATIC(
|
|
pCCatAddr,
|
|
"pslrc->HrInsertInsertionRequest",
|
|
pslrc,
|
|
pslrc->GetISMTPServerEx());
|
|
}
|
|
//
|
|
// The insertion request destructor should call the lookup
|
|
// completion
|
|
//
|
|
pCInsertionRequest->Release();
|
|
}
|
|
|
|
} else {
|
|
|
|
pCCatAddr->LookupCompletion();
|
|
}
|
|
pCCatAddr->Release(); // Release reference count addref'd in LookupEntryAsync
|
|
|
|
CatFunctLeaveEx((LPARAM)pslrc);
|
|
} // CStoreListResolveContext::AsyncLookupCompletion
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection
|
|
//
|
|
// Synopsis: Invalidate our current connection and get a new connection
|
|
//
|
|
// Arguments:
|
|
// pConn: The old LDAP connection
|
|
// fCountAsRetry: Whether or not to increment the retry counter. We don't want to
|
|
// increment the retry counter in the case of a failed insertion request
|
|
// insertion, because that means that
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// CAT_E_MAX_RETRIES: Too many retries already
|
|
// or error from ldapconn
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/22 14:50:07: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection(
|
|
CBatchLdapConnection *pConn,
|
|
BOOL fIncrementRetryCount)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CCfgConnection *pNewConn = NULL;
|
|
CCfgConnection *pOldConn = NULL;
|
|
DWORD dwCount;
|
|
DWORD dwcInsertionContext;
|
|
DWORD dwcCompletedLookups;
|
|
DWORD dwcRetries;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection");
|
|
|
|
DebugTrace((LPARAM)this, "pConn: %08lx", pConn);
|
|
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
DebugTrace((LPARAM)this, "m_pConn: %08lx", (CBatchLdapConnection *)m_pConn);
|
|
|
|
if(pConn != m_pConn) {
|
|
|
|
DebugTrace((LPARAM)this, "Connection already invalidated");
|
|
//
|
|
// We have already invalidated this connection
|
|
//
|
|
LeaveCriticalSection(&m_cs);
|
|
hr = S_OK;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
DebugTrace((LPARAM)this, "Invalidating conn %08lx",
|
|
(CBatchLdapConnection *)m_pConn);
|
|
|
|
pOldConn = m_pConn;
|
|
pOldConn->Invalidate();
|
|
|
|
dwcCompletedLookups = (DWORD) InterlockedExchange((LPLONG) &m_dwcCompletedLookups, 0);
|
|
|
|
if( fIncrementRetryCount ) {
|
|
|
|
if( dwcCompletedLookups > 0 ) {
|
|
|
|
InterlockedExchange((LPLONG) &m_dwcRetries, 0);
|
|
dwcRetries = 0;
|
|
|
|
} else {
|
|
|
|
dwcRetries = (DWORD) InterlockedIncrement((LPLONG) &m_dwcRetries);
|
|
}
|
|
|
|
} else {
|
|
|
|
dwcRetries = 0;
|
|
|
|
}
|
|
|
|
if( dwcRetries > CBatchLdapConnection::m_nMaxConnectionRetries ) {
|
|
|
|
LogSLRCFailure(CBatchLdapConnection::m_nMaxConnectionRetries, pOldConn->GetHostName());
|
|
|
|
ErrorTrace((LPARAM)this, "Over max retry limit");
|
|
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
pOldConn->CancelAllSearches();
|
|
|
|
hr = CAT_E_MAX_RETRIES;
|
|
goto CLEANUP;
|
|
|
|
} else {
|
|
|
|
hr = m_pStore->HrGetConnection(
|
|
&pNewConn);
|
|
|
|
if(FAILED(hr)) {
|
|
LeaveCriticalSection(&m_cs);
|
|
ERROR_LOG("m_pStore->HrGetConnection");
|
|
|
|
pOldConn->CancelAllSearches();
|
|
|
|
goto CLEANUP;
|
|
}
|
|
|
|
LogSLRCFailover(dwcRetries, pOldConn->GetHostName(), pNewConn->GetHostName());
|
|
|
|
DebugTrace((LPARAM)this, "pNewConn: %08lx", pNewConn);
|
|
|
|
//
|
|
// Switch-a-roo
|
|
//
|
|
m_pConn = pNewConn;
|
|
|
|
DebugTrace((LPARAM)this, "m_dwcInsertionContext: %08lx",
|
|
m_dwcInsertionContext);
|
|
//
|
|
// Get insertion contexts on the new connection
|
|
//
|
|
dwcInsertionContext = m_dwcInsertionContext;
|
|
|
|
for(dwCount = 0;
|
|
dwCount < dwcInsertionContext;
|
|
dwCount++) {
|
|
|
|
pNewConn->GetInsertionContext();
|
|
}
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
pOldConn->CancelAllSearches();
|
|
|
|
//
|
|
// Release insertion contexts on the old connection
|
|
//
|
|
for(dwCount = 0;
|
|
dwCount < dwcInsertionContext;
|
|
dwCount++) {
|
|
|
|
pOldConn->ReleaseInsertionContext();
|
|
}
|
|
|
|
pOldConn->Release();
|
|
}
|
|
CLEANUP:
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CBatchLdapConnection::HrInsertInsertionRequest
|
|
//
|
|
// Synopsis: Queues an insertion request
|
|
//
|
|
// Arguments: pCInsertionRequest: the insertion context to queue up
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/24 16:51:10: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CBatchLdapConnection::HrInsertInsertionRequest(
|
|
CInsertionRequest *pCInsertionRequest)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::HrInsertInsertionRequest");
|
|
|
|
//
|
|
// Add this thing to the queue and then call
|
|
// DecrementPendingSearches to dispatch available requests
|
|
//
|
|
pCInsertionRequest->AddRef();
|
|
|
|
if ( pCInsertionRequest->IsBatchable() )
|
|
GetInsertionContext();
|
|
|
|
AcquireSpinLock(&m_spinlock_insertionrequests);
|
|
|
|
if( IsValid() ) {
|
|
|
|
InsertTailList(&m_listhead_insertionrequests,
|
|
&(pCInsertionRequest->m_listentry_insertionrequest));
|
|
} else {
|
|
|
|
hr = CAT_E_DBCONNECTION;
|
|
}
|
|
|
|
ReleaseSpinLock(&m_spinlock_insertionrequests);
|
|
|
|
if(hr == CAT_E_DBCONNECTION) {
|
|
|
|
ERROR_LOG("IsValid");
|
|
}
|
|
|
|
if( hr == S_OK ) {
|
|
|
|
DecrementPendingSearches(0); // Decrement zero searches
|
|
} else {
|
|
|
|
if ( pCInsertionRequest->IsBatchable() )
|
|
ReleaseInsertionContext();
|
|
|
|
pCInsertionRequest->Release();
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CBatchLdapConnection::HrInsertInsertionRequest
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CBatchLdapConnection::DecrementPendingSearches
|
|
//
|
|
// Synopsis: Decrement the pending LDAP search count and issue
|
|
// searches if we are below MAX_PENDING_SEARCHES and items
|
|
// are left in the InsertionRequestQueue
|
|
//
|
|
// Arguments:
|
|
// dwcSearches: Amount to decrement by
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/24 17:09:38: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CBatchLdapConnection::DecrementPendingSearches(
|
|
DWORD dwcSearches)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwcSearchesToDecrement = dwcSearches;
|
|
DWORD dwcSearchesReserved;
|
|
CInsertionRequest *pCInsertionRequest = NULL;
|
|
BOOL fLoop = TRUE;
|
|
CANCELNOTIFY cn;
|
|
BOOL fDispatchBlocks = FALSE;
|
|
DWORD dwMinimumRequiredSearches = 1;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::DecrementPendingSearches");
|
|
|
|
//
|
|
// The module that calls us (CStoreListResolve) has a reference to
|
|
// us (obviously). However, it may release us when a search
|
|
// fails, for example inside of
|
|
// pCInsertionRequest->HrInsertSearches(). Since we need to
|
|
// continue to access member data in this situation, AddRef() here
|
|
// and Release() at the end of this function.
|
|
//
|
|
AddRef();
|
|
|
|
//
|
|
// Decrement the count first
|
|
//
|
|
AcquireSpinLock(&m_spinlock_insertionrequests);
|
|
|
|
m_dwcPendingSearches -= dwcSearchesToDecrement;
|
|
|
|
if (m_fDPS_Was_Here) {
|
|
fLoop = FALSE;
|
|
} else {
|
|
m_fDPS_Was_Here = TRUE;
|
|
}
|
|
|
|
ReleaseSpinLock(&m_spinlock_insertionrequests);
|
|
//
|
|
// Now dispatch any insertion requests we can dispatch
|
|
//
|
|
while(fLoop) {
|
|
|
|
pCInsertionRequest = NULL;
|
|
AcquireSpinLock(&m_spinlock_insertionrequests);
|
|
|
|
if( IsValid() &&
|
|
(m_dwcPendingSearches < m_nMaxPendingSearches) &&
|
|
(!IsListEmpty(&m_listhead_insertionrequests)) ) {
|
|
|
|
dwcSearchesReserved = m_nMaxPendingSearches - m_dwcPendingSearches;
|
|
|
|
pCInsertionRequest = CONTAINING_RECORD(
|
|
m_listhead_insertionrequests.Flink,
|
|
CInsertionRequest,
|
|
m_listentry_insertionrequest);
|
|
|
|
_ASSERT(pCInsertionRequest);
|
|
|
|
dwMinimumRequiredSearches = pCInsertionRequest->GetMinimumRequiredSearches();
|
|
_ASSERT(dwMinimumRequiredSearches > 0);
|
|
|
|
if(dwMinimumRequiredSearches > m_nMaxPendingSearches) {
|
|
dwMinimumRequiredSearches = m_nMaxPendingSearches;
|
|
}
|
|
|
|
if(m_dwcPendingSearches + dwMinimumRequiredSearches > m_nMaxPendingSearches) {
|
|
|
|
pCInsertionRequest = NULL;
|
|
fDispatchBlocks = TRUE;
|
|
|
|
} else {
|
|
|
|
RemoveEntryList(m_listhead_insertionrequests.Flink);
|
|
//
|
|
// Insert a cancel-Notify structure so that we know if we
|
|
// should cancel this insertion request (ie. not reinsert)
|
|
//
|
|
cn.hrCancel = S_OK;
|
|
InsertTailList(&m_listhead_cancelnotifies, &(cn.le));
|
|
}
|
|
}
|
|
|
|
if(!pCInsertionRequest) {
|
|
//
|
|
// There are no requests or no room to insert
|
|
// requests...Break out of the loop
|
|
//
|
|
fLoop = FALSE;
|
|
m_fDPS_Was_Here = FALSE;
|
|
}
|
|
|
|
ReleaseSpinLock(&m_spinlock_insertionrequests);
|
|
|
|
if(pCInsertionRequest) {
|
|
//
|
|
// Dispatch up to dwcSearchesReserved searches
|
|
//
|
|
hr = pCInsertionRequest->HrInsertSearches(dwcSearchesReserved);
|
|
|
|
if(FAILED(hr)) {
|
|
|
|
if(FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS))) {
|
|
|
|
ERROR_LOG("pCInsertionRequest->HrInsertSearches");
|
|
}
|
|
|
|
pCInsertionRequest->NotifyDeQueue(hr);
|
|
|
|
if ( pCInsertionRequest->IsBatchable() )
|
|
ReleaseInsertionContext();
|
|
|
|
pCInsertionRequest->Release();
|
|
|
|
AcquireSpinLock(&m_spinlock_insertionrequests);
|
|
//
|
|
// Remove the cancel notify
|
|
//
|
|
RemoveEntryList(&(cn.le));
|
|
ReleaseSpinLock(&m_spinlock_insertionrequests);
|
|
|
|
} else {
|
|
//
|
|
// There is more work to be done in this block; insert it
|
|
// back into the queue
|
|
//
|
|
AcquireSpinLock(&m_spinlock_insertionrequests);
|
|
//
|
|
// Remove the cancel notify
|
|
//
|
|
RemoveEntryList(&(cn.le));
|
|
|
|
//
|
|
// If we are NOT cancelling, then insert back into the queue
|
|
//
|
|
if(cn.hrCancel == S_OK) {
|
|
|
|
InsertHeadList(&m_listhead_insertionrequests,
|
|
&(pCInsertionRequest->m_listentry_insertionrequest));
|
|
}
|
|
ReleaseSpinLock(&m_spinlock_insertionrequests);
|
|
|
|
//
|
|
// If we are cancelling, then release this insertion request
|
|
//
|
|
if(cn.hrCancel != S_OK) {
|
|
pCInsertionRequest->NotifyDeQueue(cn.hrCancel);
|
|
|
|
if ( pCInsertionRequest->IsBatchable() )
|
|
ReleaseInsertionContext();
|
|
|
|
pCInsertionRequest->Release();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(fDispatchBlocks) {
|
|
//
|
|
// X5:197905. We call DispatchBlocks now to avoid a deadlock where
|
|
// there is a partially filled batch and there are batchable insertion
|
|
// requests in the queue that prevent it from being dispatched, but
|
|
// the next insertion request in the queue is not batchable and
|
|
// requires a minimum number of searches that is greater than the max
|
|
// pending will allow, given that some of the available searches are
|
|
// (dormantly) consumed by the partially filled batch.
|
|
//
|
|
LIST_ENTRY listhead_dispatch;
|
|
|
|
AcquireSpinLock(&m_spinlock);
|
|
//
|
|
// Remove all blocks from the insertion list and put them in the dispatch list
|
|
//
|
|
if(IsListEmpty(&m_listhead)) {
|
|
//
|
|
// No blocks
|
|
//
|
|
ReleaseSpinLock(&m_spinlock);
|
|
} else {
|
|
|
|
InsertTailList(&m_listhead, &listhead_dispatch);
|
|
RemoveEntryList(&m_listhead);
|
|
InitializeListHead(&m_listhead);
|
|
|
|
ReleaseSpinLock(&m_spinlock);
|
|
//
|
|
// Dispatch all the blocks
|
|
//
|
|
DispatchBlocks(&listhead_dispatch);
|
|
}
|
|
}
|
|
|
|
Release();
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CBatchLdapConnection::DecrementPendingSearches
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CBatchLdapConnection::CancelAllSearches
|
|
//
|
|
// Synopsis: Cancels all outstanding searches
|
|
//
|
|
// Arguments:
|
|
// hr: optinal reason for cancelling the searches
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// jstamerj 1999/03/25 11:44:30: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CBatchLdapConnection::CancelAllSearches(
|
|
HRESULT hr)
|
|
{
|
|
LIST_ENTRY listhead;
|
|
PLIST_ENTRY ple;
|
|
CInsertionRequest *pCInsertionRequest;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::CancelAllSearches");
|
|
|
|
_ASSERT(hr != S_OK);
|
|
|
|
AcquireSpinLock(&m_spinlock_insertionrequests);
|
|
//
|
|
// Grab the list
|
|
//
|
|
if(!IsListEmpty(&m_listhead_insertionrequests)) {
|
|
|
|
CopyMemory(&listhead, &m_listhead_insertionrequests, sizeof(LIST_ENTRY));
|
|
listhead.Flink->Blink = &listhead;
|
|
listhead.Blink->Flink = &listhead;
|
|
InitializeListHead(&m_listhead_insertionrequests);
|
|
|
|
} else {
|
|
|
|
InitializeListHead(&listhead);
|
|
}
|
|
//
|
|
// Traverse the cancel notify list and set each hresult
|
|
//
|
|
for(ple = m_listhead_cancelnotifies.Flink;
|
|
ple != &m_listhead_cancelnotifies;
|
|
ple = ple->Flink) {
|
|
|
|
PCANCELNOTIFY pcn;
|
|
pcn = CONTAINING_RECORD(ple, CANCELNOTIFY, le);
|
|
pcn->hrCancel = hr;
|
|
}
|
|
|
|
ReleaseSpinLock(&m_spinlock_insertionrequests);
|
|
|
|
CCachedLdapConnection::CancelAllSearches(hr);
|
|
|
|
for(ple = listhead.Flink;
|
|
ple != &listhead;
|
|
ple = listhead.Flink) {
|
|
|
|
pCInsertionRequest = CONTAINING_RECORD(
|
|
ple,
|
|
CInsertionRequest,
|
|
m_listentry_insertionrequest);
|
|
|
|
RemoveEntryList(&(pCInsertionRequest->m_listentry_insertionrequest));
|
|
pCInsertionRequest->NotifyDeQueue(hr);
|
|
|
|
if (pCInsertionRequest->IsBatchable() )
|
|
ReleaseInsertionContext();
|
|
|
|
pCInsertionRequest->Release();
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CBatchLdapConnection::CancelAllSearches
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::GetConnection
|
|
//
|
|
// Synopsis: AddRef/return the current connection
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: Connection pointer
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/21 12:14:50: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
CCfgConnection * CStoreListResolveContext::GetConnection()
|
|
{
|
|
CCfgConnection *ret;
|
|
EnterCriticalSection(&m_cs);
|
|
ret = m_pConn;
|
|
if(ret)
|
|
ret->AddRef();
|
|
LeaveCriticalSection(&m_cs);
|
|
return ret;
|
|
} // CStoreListResolveContext::GetConnection
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::GetInsertionContext
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/21 12:16:38: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CStoreListResolveContext::GetInsertionContext()
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
InterlockedIncrement((PLONG) &m_dwcInsertionContext);
|
|
m_pConn->GetInsertionContext();
|
|
LeaveCriticalSection(&m_cs);
|
|
} // CStoreListResolveContext::GetInsertionContext
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::ReleaseInsertionContext
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/21 12:16:48: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CStoreListResolveContext::ReleaseInsertionContext()
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
InterlockedDecrement((PLONG) &m_dwcInsertionContext);
|
|
m_pConn->ReleaseInsertionContext();
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
} // CStoreListResolveContext::ReleaseInsertionContext
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::HrInsertInsertionRequest
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
//
|
|
// History:
|
|
// jstamerj 1999/06/21 12:20:19: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CStoreListResolveContext::HrInsertInsertionRequest(
|
|
CInsertionRequest *pCInsertionRequest)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fTryAgain;
|
|
CatFunctEnterEx((LPARAM)this,
|
|
"CStoreListResolveContext::HrInsertInsertionRequest");
|
|
|
|
do {
|
|
|
|
fTryAgain = FALSE;
|
|
CBatchLdapConnection *pConn;
|
|
|
|
pConn = GetConnection();
|
|
|
|
//
|
|
// Insert the search request into the CBatchLdapConnection
|
|
// object. We will use the email address as the distinguishing
|
|
// attribute
|
|
//
|
|
if( pConn == NULL ) {
|
|
|
|
hr = CAT_E_DBCONNECTION;
|
|
if(FAILED(hr)) {
|
|
ERROR_LOG("GetConnection");
|
|
}
|
|
|
|
} else {
|
|
|
|
hr = m_pConn->HrInsertInsertionRequest(pCInsertionRequest);
|
|
if(FAILED(hr)) {
|
|
ERROR_LOG("m_pConn->HrInsertInsertionRequest");
|
|
}
|
|
}
|
|
//
|
|
// Attempt to reconnect.
|
|
//
|
|
if( hr == CAT_E_DBCONNECTION ) {
|
|
|
|
HRESULT hrTryAgain = S_OK;
|
|
|
|
hrTryAgain =
|
|
HrInvalidateConnectionAndRetrieveNewConnection(pConn, FALSE);
|
|
fTryAgain = SUCCEEDED(hrTryAgain);
|
|
|
|
if(FAILED(hrTryAgain)) {
|
|
//
|
|
// Declare a new local called hr here because the
|
|
// ERROR_LOG macro uses it
|
|
//
|
|
HRESULT hr = hrTryAgain;
|
|
ERROR_LOG("HrInvalidateConnectionAndRetrieveNewConnection");
|
|
}
|
|
}
|
|
|
|
if(pConn != NULL)
|
|
pConn->Release();
|
|
|
|
} while(fTryAgain);
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
return hr;
|
|
} // CStoreListResolveContext::HrInsertInsertionRequest
|
|
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::LogSLRCFailure
|
|
//
|
|
// Synopsis: Log a failure for the SLRC (over max retry limit)
|
|
//
|
|
// Arguments:
|
|
// dwcRetries: Number of times we've retried
|
|
// pszHost: The last host that failed
|
|
//
|
|
// Returns: nothing
|
|
//
|
|
// History:
|
|
// jstamerj 2001/12/13 00:24:07: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CStoreListResolveContext::LogSLRCFailure(
|
|
IN DWORD dwcRetries,
|
|
IN LPSTR pszHost)
|
|
{
|
|
LPCSTR rgSubStrings[2];
|
|
CHAR szRetries[32];
|
|
|
|
_snprintf(szRetries, sizeof(szRetries), "%d", dwcRetries);
|
|
|
|
rgSubStrings[0] = szRetries;
|
|
rgSubStrings[1] = pszHost;
|
|
|
|
CatLogEvent(
|
|
GetISMTPServerEx(),
|
|
CAT_EVENT_SLRC_FAILURE,
|
|
2,
|
|
rgSubStrings,
|
|
S_OK,
|
|
pszHost,
|
|
LOGEVENT_FLAG_ALWAYS,
|
|
LOGEVENT_LEVEL_FIELD_ENGINEERING);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CStoreListResolveContext::LogSLRCFailover
|
|
//
|
|
// Synopsis: Log a failover event
|
|
//
|
|
// Arguments:
|
|
// dwcRetries: Number of retires so far
|
|
// pszOldHost: Old LDAP host
|
|
// pszNewHost: New LDAP host
|
|
//
|
|
// Returns: nothing
|
|
//
|
|
// History:
|
|
// jstamerj 2001/12/13 00:24:18: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CStoreListResolveContext::LogSLRCFailover(
|
|
IN DWORD dwcRetries,
|
|
IN LPSTR pszOldHost,
|
|
IN LPSTR pszNewHost)
|
|
{
|
|
LPCSTR rgSubStrings[3];
|
|
CHAR szRetries[32];
|
|
|
|
_snprintf(szRetries, sizeof(szRetries), "%d", dwcRetries);
|
|
|
|
rgSubStrings[0] = pszOldHost;
|
|
rgSubStrings[1] = pszNewHost;
|
|
rgSubStrings[2] = szRetries;
|
|
|
|
CatLogEvent(
|
|
GetISMTPServerEx(),
|
|
CAT_EVENT_SLRC_FAILOVER,
|
|
3,
|
|
rgSubStrings,
|
|
S_OK,
|
|
pszOldHost,
|
|
LOGEVENT_FLAG_ALWAYS,
|
|
LOGEVENT_LEVEL_FIELD_ENGINEERING);
|
|
}
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSingleSearchReinsertionRequest::HrInsertSearches
|
|
//
|
|
// Synopsis: reinsert a request for a single search
|
|
//
|
|
// Arguments:
|
|
// dwcSearches: Number of searches we may insert
|
|
//
|
|
// Returns:
|
|
// S_OK: Success
|
|
// HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)
|
|
//
|
|
// History:
|
|
// dlongley 2001/10/22: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
HRESULT CSingleSearchReinsertionRequest::HrInsertSearches(
|
|
DWORD dwcSearches)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CatFunctEnterEx((LPARAM)this, "CSingleSearchReinsertionRequest::HrInsertSearches");
|
|
|
|
if( (m_dwcSearches == 0) && (dwcSearches > 0) ) {
|
|
|
|
hr = m_pslrc->HrLookupEntryAsync(m_pCCatAddr);
|
|
|
|
if(FAILED(hr)) {
|
|
ERROR_LOG_ADDR(m_pCCatAddr, "m_pslrc->HrLookupEntryAsync");
|
|
m_hr = hr;
|
|
} else {
|
|
m_dwcSearches = 1;
|
|
}
|
|
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
hr = (m_dwcSearches == 1 ? HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) : S_OK);
|
|
|
|
DebugTrace((LPARAM)this, "returning %08lx", hr);
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
|
|
return hr;
|
|
} // CSingleSearchReinsertionRequest::HrInsertSearches
|
|
|
|
|
|
//+------------------------------------------------------------
|
|
//
|
|
// Function: CSingleSearchReinsertionRequest::NotifyDeQueue
|
|
//
|
|
// Synopsis: Callback to notify us that our request is being removed
|
|
// from the store's queue
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: NOTHING
|
|
//
|
|
// History:
|
|
// dlongley 2001/10/22: Created.
|
|
//
|
|
//-------------------------------------------------------------
|
|
VOID CSingleSearchReinsertionRequest::NotifyDeQueue(
|
|
HRESULT hrReason)
|
|
{
|
|
HRESULT hr;
|
|
CatFunctEnterEx((LPARAM)this, "CSingleSearchReinsertionRequest::NotifyDeQueue");
|
|
//
|
|
// If we still have things left to resolve, reinsert this
|
|
// insertion request
|
|
//
|
|
hr = hrReason;
|
|
if( SUCCEEDED(m_hr) && (m_dwcSearches == 0) && !(m_pslrc->Canceled()) ) {
|
|
|
|
if( (hr == CAT_E_DBCONNECTION) ||
|
|
(hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) ) {
|
|
|
|
hr = m_pslrc->HrInsertInsertionRequest(this);
|
|
if(FAILED(hr)) {
|
|
ERROR_LOG_ADDR(m_pCCatAddr, "m_pslrc->HrInsertInsertionRequest");
|
|
}
|
|
}
|
|
}
|
|
|
|
CatFunctLeaveEx((LPARAM)this);
|
|
} // CSingleSearchReinsertionRequest::NotifyDeQueue
|