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.

2966 lines
85 KiB

  1. //
  2. // asyncctx.cpp -- This file contains the class implementation for:
  3. // CAsyncLookupContext
  4. //
  5. // Created:
  6. // Mar 4, 1997 -- Milan Shah (milans)
  7. //
  8. // Changes:
  9. //
  10. #include "precomp.h"
  11. #include "simparray.cpp"
  12. DWORD CBatchLdapConnection::m_nMaxSearchBlockSize = 0;
  13. DWORD CBatchLdapConnection::m_nMaxPendingSearches = 0;
  14. DWORD CBatchLdapConnection::m_nMaxConnectionRetries = 0;
  15. //+----------------------------------------------------------------------------
  16. //
  17. // Function: CBatchLdapConnection::InitializeFromRegistry
  18. //
  19. // Synopsis: Static function that looks at registry to determine maximum
  20. // number of queries that will be compressed into a single query.
  21. // If the registry key does not exist or there is any other
  22. // problem reading the key, the value defaults to
  23. // MAX_SEARCH_BLOCK_SIZE
  24. //
  25. // Arguments: None
  26. //
  27. // Returns: Nothing.
  28. //
  29. //-----------------------------------------------------------------------------
  30. VOID CBatchLdapConnection::InitializeFromRegistry()
  31. {
  32. HKEY hkey;
  33. DWORD dwErr, dwType, dwValue, cbValue;
  34. dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, MAX_SEARCH_BLOCK_SIZE_KEY, &hkey);
  35. if (dwErr == ERROR_SUCCESS) {
  36. cbValue = sizeof(dwValue);
  37. dwErr = RegQueryValueEx(
  38. hkey,
  39. MAX_SEARCH_BLOCK_SIZE_VALUE,
  40. NULL,
  41. &dwType,
  42. (LPBYTE) &dwValue,
  43. &cbValue);
  44. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD &&
  45. dwValue > 0 && dwValue < MAX_SEARCH_BLOCK_SIZE) {
  46. InterlockedExchange((PLONG) &m_nMaxSearchBlockSize, (LONG)dwValue);
  47. }
  48. cbValue = sizeof(dwValue);
  49. dwErr = RegQueryValueEx(
  50. hkey,
  51. MAX_PENDING_SEARCHES_VALUE,
  52. NULL,
  53. &dwType,
  54. (LPBYTE) &dwValue,
  55. &cbValue);
  56. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD &&
  57. dwValue > 0) {
  58. InterlockedExchange((PLONG) &m_nMaxPendingSearches, (LONG)dwValue);
  59. }
  60. cbValue = sizeof(dwValue);
  61. dwErr = RegQueryValueEx(
  62. hkey,
  63. MAX_CONNECTION_RETRIES_VALUE,
  64. NULL,
  65. &dwType,
  66. (LPBYTE) &dwValue,
  67. &cbValue);
  68. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD &&
  69. dwValue > 0) {
  70. InterlockedExchange((PLONG) &m_nMaxConnectionRetries, (LONG)dwValue);
  71. }
  72. RegCloseKey( hkey );
  73. }
  74. if(m_nMaxSearchBlockSize == 0)
  75. m_nMaxSearchBlockSize = MAX_SEARCH_BLOCK_SIZE;
  76. if(m_nMaxPendingSearches == 0)
  77. m_nMaxPendingSearches = MAX_PENDING_SEARCHES;
  78. if(m_nMaxPendingSearches < m_nMaxSearchBlockSize)
  79. m_nMaxPendingSearches = m_nMaxSearchBlockSize;
  80. if(m_nMaxConnectionRetries == 0)
  81. m_nMaxConnectionRetries = MAX_CONNECTION_RETRIES;
  82. }
  83. //+------------------------------------------------------------
  84. //
  85. // Function: CSearchRequestBlock::operator new
  86. //
  87. // Synopsis: Allocate enough memory for this and the specified number
  88. // of SEARCH_REQUEST structurers
  89. //
  90. // Arguments:
  91. // size: Normal size of object
  92. // dwNumRequests: Number of props desired in this object
  93. //
  94. // Returns: ptr to allocated memory or NULL
  95. //
  96. // History:
  97. // jstamerj 1999/03/10 16:15:43: Created
  98. //
  99. //-------------------------------------------------------------
  100. void * CSearchRequestBlock::operator new(
  101. size_t size,
  102. DWORD dwNumRequests)
  103. {
  104. DWORD dwSize;
  105. void *pmem;
  106. CSearchRequestBlock *pBlock;
  107. //
  108. // Calcualte size in bytes required
  109. //
  110. dwSize = size +
  111. (dwNumRequests*sizeof(SEARCH_REQUEST)) +
  112. (dwNumRequests*sizeof(ICategorizerItem *));
  113. pmem = new BYTE[dwSize];
  114. if(pmem) {
  115. pBlock = (CSearchRequestBlock *)pmem;
  116. pBlock->m_dwSignature = SIGNATURE_CSEARCHREQUESTBLOCK;
  117. pBlock->m_cBlockSize = dwNumRequests;
  118. pBlock->m_prgSearchRequests = (PSEARCH_REQUEST)
  119. ((PBYTE)pmem + size);
  120. pBlock->m_rgpICatItems = (ICategorizerItem **)
  121. ((PBYTE)pmem + size +
  122. (dwNumRequests*sizeof(SEARCH_REQUEST)));
  123. _ASSERT( (DWORD) ((PBYTE)pBlock->m_rgpICatItems +
  124. (dwNumRequests*sizeof(ICategorizerItem *)) -
  125. (PBYTE)pmem)
  126. == dwSize);
  127. }
  128. return pmem;
  129. }
  130. //+------------------------------------------------------------
  131. //
  132. // Function: CSearchRequestBlock::~CSearchRequestBlock
  133. //
  134. // Synopsis: Release everything we have references to
  135. //
  136. // Arguments: NONE
  137. //
  138. // Returns: NOTHING
  139. //
  140. // History:
  141. // jstamerj 1999/03/11 18:45:59: Created
  142. //
  143. //-------------------------------------------------------------
  144. CSearchRequestBlock::~CSearchRequestBlock()
  145. {
  146. DWORD dwCount;
  147. //
  148. // Release all CCatAddrs
  149. //
  150. for(dwCount = 0;
  151. dwCount < DwNumBlockRequests();
  152. dwCount++) {
  153. PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]);
  154. preq->pCCatAddr->Release();
  155. }
  156. //
  157. // Release all the attr interfaces
  158. //
  159. for(dwCount = 0;
  160. dwCount < m_csaItemAttr.Size();
  161. dwCount++) {
  162. ((ICategorizerItemAttributes **)
  163. m_csaItemAttr)[dwCount]->Release();
  164. }
  165. if(m_pISMTPServer)
  166. m_pISMTPServer->Release();
  167. if(m_pISMTPServerEx)
  168. m_pISMTPServerEx->Release();
  169. if(m_pICatParams)
  170. m_pICatParams->Release();
  171. if(m_pszSearchFilter)
  172. delete m_pszSearchFilter;
  173. if(m_pConn)
  174. m_pConn->Release();
  175. _ASSERT(m_dwSignature == SIGNATURE_CSEARCHREQUESTBLOCK);
  176. m_dwSignature = SIGNATURE_CSEARCHREQUESTBLOCK_INVALID;
  177. }
  178. //+------------------------------------------------------------
  179. //
  180. // Function: CSearchRequestBlock::InsertSearchRequest
  181. //
  182. // Synopsis: Inserts a search request in this block. When the block
  183. // is full, dispatch the block to LDAP before returning
  184. //
  185. // Arguments:
  186. // pISMTPServer: ISMTPServer to use for triggering events
  187. // pICatParams: ICategorizerParameters to use
  188. // pCCatAddr: Address item for the search
  189. // fnSearchCompletion: Async Completion routine
  190. // ctxSearchCompletion: Context to pass to the async completion routine
  191. // pszSearchFilter: Search filter to use
  192. // pszDistinguishingAttribute: The distinguishing attribute for matching
  193. // pszDistinguishingAttributeValue: above attribute's distinguishing value
  194. //
  195. // Returns: NOTHING
  196. //
  197. // History:
  198. // jstamerj 1999/03/11 13:12:20: Created.
  199. //
  200. //-------------------------------------------------------------
  201. VOID CSearchRequestBlock::InsertSearchRequest(
  202. ISMTPServer *pISMTPServer,
  203. ICategorizerParameters *pICatParams,
  204. CCatAddr *pCCatAddr,
  205. LPSEARCHCOMPLETION fnSearchCompletion,
  206. CStoreListResolveContext *pslrc,
  207. LPSTR pszSearchFilter,
  208. LPSTR pszDistinguishingAttribute,
  209. LPSTR pszDistinguishingAttributeValue)
  210. {
  211. PSEARCH_REQUEST preq;
  212. DWORD dwIndex;
  213. HRESULT hr = S_OK;
  214. CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::InsertSearchRequest");
  215. //
  216. // Unset any existing HRSTATUS -- the status will be set again in
  217. // the search completion
  218. //
  219. _VERIFY(SUCCEEDED(
  220. pCCatAddr->UnSetPropId(
  221. ICATEGORIZERITEM_HRSTATUS)));
  222. m_pConn->IncrementPendingSearches();
  223. preq = GetNextSearchRequest(&dwIndex);
  224. _ASSERT(preq);
  225. pCCatAddr->AddRef();
  226. preq->pCCatAddr = pCCatAddr;
  227. preq->fnSearchCompletion = fnSearchCompletion;
  228. preq->pslrc = pslrc;
  229. preq->pszSearchFilter = pszSearchFilter;
  230. preq->pszDistinguishingAttribute = pszDistinguishingAttribute;
  231. preq->pszDistinguishingAttributeValue = pszDistinguishingAttributeValue;
  232. m_rgpICatItems[dwIndex] = pCCatAddr;
  233. if(dwIndex == 0) {
  234. //
  235. // Use the first insertion's ISMTPServer
  236. //
  237. _ASSERT(m_pISMTPServer == NULL);
  238. m_pISMTPServer = pISMTPServer;
  239. if(m_pISMTPServer) {
  240. m_pISMTPServer->AddRef();
  241. hr = m_pISMTPServer->QueryInterface(
  242. IID_ISMTPServerEx,
  243. (LPVOID *) &m_pISMTPServerEx);
  244. if(FAILED(hr))
  245. {
  246. m_pISMTPServerEx = NULL;;
  247. }
  248. else
  249. {
  250. m_CICatQueries.SetISMTPServerEx(
  251. m_pISMTPServerEx);
  252. m_CICatAsyncContext.SetISMTPServerEx(
  253. m_pISMTPServerEx);
  254. }
  255. }
  256. _ASSERT(m_pICatParams == NULL);
  257. m_pICatParams = pICatParams;
  258. m_pICatParams->AddRef();
  259. }
  260. //
  261. // Now dispatch this block if we are the last request to finish
  262. //
  263. if( (DWORD) (InterlockedIncrement((PLONG)&m_cBlockRequestsReadyForDispatch)) == m_cBlockSize)
  264. DispatchBlock();
  265. CatFunctLeaveEx((LPARAM)this);
  266. }
  267. //+------------------------------------------------------------
  268. //
  269. // Function: CSearchRequestBlock::DispatchBlock
  270. //
  271. // Synopsis: Send the LDAP query for this search request block
  272. //
  273. // Arguments: NONE
  274. //
  275. // Returns: NOTHING
  276. //
  277. // History:
  278. // jstamerj 1999/03/11 15:00:44: Created.
  279. // haozhang 2001/11/30 Fix for 193848
  280. //-------------------------------------------------------------
  281. VOID CSearchRequestBlock::DispatchBlock()
  282. {
  283. HRESULT hr = S_OK;
  284. CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::DispatchBlock");
  285. m_pConn->RemoveSearchRequestBlockFromList(this);
  286. //
  287. // If the block is empty, we will delete it and bail out.
  288. // We will AV down the road otherwise.
  289. // This is an unintended result of fix of 193848.
  290. //
  291. if ( 0 == DwNumBlockRequests()) {
  292. DebugTrace((LPARAM)this, "DispatchBlock bailing out because the block is empty");
  293. delete this;
  294. goto CLEANUP;
  295. }
  296. //
  297. // Build up the query string
  298. //
  299. hr = HrTriggerBuildQueries();
  300. ERROR_CLEANUP_LOG("HrTriggerBuildQueryies");
  301. //
  302. // Send the query
  303. //
  304. hr = HrTriggerSendQuery();
  305. ERROR_CLEANUP_LOG("HrTriggerSendQuery");
  306. CLEANUP:
  307. if(FAILED(hr)) {
  308. CompleteBlockWithError(hr);
  309. delete this;
  310. }
  311. //
  312. // this may be deleted, but that's okay; we're just tracing a user
  313. // value
  314. //
  315. CatFunctLeaveEx((LPARAM)this);
  316. }
  317. //+------------------------------------------------------------
  318. //
  319. // Function: CSearchRequestBlock::HrTriggerBuildQueries
  320. //
  321. // Synopsis: Trigger the BuildQueries event
  322. //
  323. // Arguments:
  324. // pCICatQueries: CICategorizerQueriesIMP object to use
  325. //
  326. // Returns:
  327. // S_OK: Success
  328. // error from dispatcher
  329. //
  330. // History:
  331. // jstamerj 1999/03/11 19:03:29: Created.
  332. //
  333. //-------------------------------------------------------------
  334. HRESULT CSearchRequestBlock::HrTriggerBuildQueries()
  335. {
  336. HRESULT hr = S_OK;
  337. EVENTPARAMS_CATBUILDQUERIES Params;
  338. CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::HrTriggerBuildQueries");
  339. Params.pICatParams = m_pICatParams;
  340. Params.dwcAddresses = DwNumBlockRequests();
  341. Params.rgpICatItems = m_rgpICatItems;
  342. Params.pICatQueries = &m_CICatQueries;
  343. Params.pfnDefault = HrBuildQueriesDefault;
  344. Params.pblk = this;
  345. if(m_pISMTPServer) {
  346. hr = m_pISMTPServer->TriggerServerEvent(
  347. SMTP_MAILTRANSPORT_CATEGORIZE_BUILDQUERIES_EVENT,
  348. &Params);
  349. if(FAILED(hr) && (hr != E_NOTIMPL)) {
  350. ERROR_LOG("m_pISMTPServer->TriggerServerEvent(buildquery)");
  351. }
  352. } else {
  353. hr = E_NOTIMPL;
  354. }
  355. if(hr == E_NOTIMPL) {
  356. //
  357. // Events are disabled
  358. //
  359. hr = HrBuildQueriesDefault(
  360. S_OK,
  361. &Params);
  362. if(FAILED(hr)) {
  363. ERROR_LOG("HrBuildQueriesDefault");
  364. }
  365. }
  366. //
  367. // Make sure somebody really set the query string
  368. //
  369. if(SUCCEEDED(hr) &&
  370. (m_pszSearchFilter == NULL)) {
  371. hr = E_FAIL;
  372. ERROR_LOG("--no filter--");
  373. }
  374. DebugTrace((LPARAM)this, "returning hr %08lx",hr);
  375. CatFunctLeaveEx((LPARAM)this);
  376. return hr;
  377. }
  378. //+------------------------------------------------------------
  379. //
  380. // Function: CSearchRequestBlock::HrBuildQueriesDefault
  381. //
  382. // Synopsis: Default implementation of the build queries sink
  383. //
  384. // Arguments:
  385. // hrStatus: Status of events so far
  386. // pContext: Event params context
  387. //
  388. // Returns:
  389. // S_OK: Success
  390. //
  391. // History:
  392. // jstamerj 1999/03/11 19:42:53: Created.
  393. //
  394. //-------------------------------------------------------------
  395. HRESULT CSearchRequestBlock::HrBuildQueriesDefault(
  396. HRESULT HrStatus,
  397. PVOID pContext)
  398. {
  399. HRESULT hr = S_OK;
  400. PEVENTPARAMS_CATBUILDQUERIES pParams;
  401. DWORD cReqs, cOrTerms, idx, idxSecondToLastTerm, idxLastTerm;
  402. DWORD cbSearchFilter, rgcbSearchFilters[MAX_SEARCH_BLOCK_SIZE];
  403. LPSTR pszSearchFilterNew;
  404. CSearchRequestBlock *pblk;
  405. pParams = (PEVENTPARAMS_CATBUILDQUERIES)pContext;
  406. _ASSERT(pParams);
  407. pblk = (CSearchRequestBlock *)pParams->pblk;
  408. _ASSERT(pblk);
  409. CatFunctEnterEx((LPARAM)pblk, "CSearchRequestBlock::HrBuildQueriesDefault");
  410. cReqs = pblk->DwNumBlockRequests();
  411. _ASSERT( cReqs > 0 );
  412. cOrTerms = cReqs - 1;
  413. //
  414. // Figure out the size of the composite search filter
  415. //
  416. cbSearchFilter = 0;
  417. for (idx = 0; idx < cReqs; idx++) {
  418. rgcbSearchFilters[idx] =
  419. strlen(pblk->m_prgSearchRequests[idx].pszSearchFilter);
  420. cbSearchFilter += rgcbSearchFilters[idx];
  421. }
  422. cbSearchFilter += cOrTerms * (sizeof( "(| )" ) - 1);
  423. cbSearchFilter++; // Terminating NULL.
  424. pszSearchFilterNew = new CHAR [cbSearchFilter];
  425. if (pszSearchFilterNew != NULL) {
  426. idxLastTerm = cReqs - 1;
  427. idxSecondToLastTerm = idxLastTerm - 1;
  428. //
  429. // We special case the cReqs == 1
  430. //
  431. if (cReqs == 1) {
  432. strcpy(
  433. pszSearchFilterNew,
  434. pblk->m_prgSearchRequests[0].pszSearchFilter);
  435. } else {
  436. //
  437. // The loop below builds up the block filter all the way up to the
  438. // last term. For each term, it adds a "(| " to start a new OR
  439. // term, then adds the OR term itself, then puts a space after the
  440. // OR term. Also, it puts a matching ")" at the end of the
  441. // search filter string being built up.
  442. //
  443. LPSTR szNextItem = &pszSearchFilterNew[0];
  444. LPSTR szTerminatingParens =
  445. &pszSearchFilterNew[cbSearchFilter - 1 - (cReqs-1)];
  446. pszSearchFilterNew[cbSearchFilter - 1] = 0;
  447. for (idx = 0; idx <= idxSecondToLastTerm; idx++) {
  448. strcpy( szNextItem, "(| " );
  449. szNextItem += sizeof( "(| " ) - 1;
  450. strcpy(
  451. szNextItem,
  452. pblk->m_prgSearchRequests[idx].pszSearchFilter);
  453. szNextItem += rgcbSearchFilters[idx];
  454. *szNextItem++ = ' ';
  455. *szTerminatingParens++ = ')';
  456. }
  457. //
  458. // Now, all that remains is to add in the last OR term
  459. //
  460. CopyMemory(
  461. szNextItem,
  462. pblk->m_prgSearchRequests[idxLastTerm].pszSearchFilter,
  463. rgcbSearchFilters[idxLastTerm]);
  464. }
  465. _ASSERT( ((DWORD) lstrlen(pszSearchFilterNew)) < cbSearchFilter );
  466. //
  467. // Save our generated filter string in ICategorizerQueries
  468. //
  469. hr = pblk->m_CICatQueries.SetQueryStringNoAlloc(pszSearchFilterNew);
  470. // There's no good reason for that to fail...
  471. _ASSERT(SUCCEEDED(hr));
  472. } else {
  473. hr = E_OUTOFMEMORY;
  474. ERROR_LOG_STATIC(
  475. "new CHAR[]",
  476. pblk,
  477. pblk->GetISMTPServerEx());
  478. }
  479. DebugTrace((LPARAM)pblk, "returning hr %08lx", hr);
  480. CatFunctLeaveEx((LPARAM)pblk);
  481. return hr;
  482. }
  483. //+------------------------------------------------------------
  484. //
  485. // Function: CSearchRequestBlock::HrTriggerSendQuery
  486. //
  487. // Synopsis: Trigger the SendQuery event
  488. //
  489. // Arguments:
  490. //
  491. // Returns:
  492. // S_OK: Success
  493. //
  494. // History:
  495. // jstamerj 1999/03/11 20:18:02: Created.
  496. //
  497. //-------------------------------------------------------------
  498. HRESULT CSearchRequestBlock::HrTriggerSendQuery()
  499. {
  500. HRESULT hr = S_OK;
  501. EVENTPARAMS_CATSENDQUERY Params;
  502. CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::HrTriggerSendQuery");
  503. Params.pICatParams = m_pICatParams;
  504. Params.pICatQueries = &m_CICatQueries;
  505. Params.pICatAsyncContext = &m_CICatAsyncContext;
  506. Params.pIMailTransportNotify = NULL; // These should be set in CStoreParams
  507. Params.pvNotifyContext = NULL;
  508. Params.hrResolutionStatus = S_OK;
  509. Params.pblk = this;
  510. Params.pfnDefault = HrSendQueryDefault;
  511. Params.pfnCompletion = HrSendQueryCompletion;
  512. if(m_pISMTPServer) {
  513. hr = m_pISMTPServer->TriggerServerEvent(
  514. SMTP_MAILTRANSPORT_CATEGORIZE_SENDQUERY_EVENT,
  515. &Params);
  516. if(FAILED(hr) && (hr != E_NOTIMPL)) {
  517. ERROR_LOG("m_pISMTPServer->TriggerServerEvent(sendquery)");
  518. }
  519. } else {
  520. hr = E_NOTIMPL;
  521. }
  522. if(hr == E_NOTIMPL) {
  523. //
  524. // Events are disabled
  525. // Heap allocation is required
  526. //
  527. PEVENTPARAMS_CATSENDQUERY pParams;
  528. pParams = new EVENTPARAMS_CATSENDQUERY;
  529. if(pParams == NULL) {
  530. hr = E_OUTOFMEMORY;
  531. ERROR_LOG("new EVENTPARAMS_CATSENDQUERY");
  532. } else {
  533. CopyMemory(pParams, &Params, sizeof(EVENTPARAMS_CATSENDQUERY));
  534. HrSendQueryDefault(
  535. S_OK,
  536. pParams);
  537. hr = S_OK;
  538. }
  539. }
  540. DebugTrace((LPARAM)this, "returning %08lx", (hr == MAILTRANSPORT_S_PENDING) ? S_OK : hr);
  541. CatFunctLeaveEx((LPARAM)this);
  542. return (hr == MAILTRANSPORT_S_PENDING) ? S_OK : hr;
  543. } // CSearchRequestBlock::HrTriggerSendQuery
  544. //+------------------------------------------------------------
  545. //
  546. // Function: CSearchRequestBlock::HrSendQueryDefault
  547. //
  548. // Synopsis: The default sink function for the SendQuery event
  549. //
  550. // Arguments:
  551. // hrStatus: status of the event so far
  552. // pContext: Event params context
  553. //
  554. // Returns:
  555. // S_OK: Success
  556. //
  557. // History:
  558. // jstamerj 1999/03/16 11:46:24: Created.
  559. //
  560. //-------------------------------------------------------------
  561. HRESULT CSearchRequestBlock::HrSendQueryDefault(
  562. HRESULT HrStatus,
  563. PVOID pContext)
  564. {
  565. HRESULT hr = S_OK;
  566. PEVENTPARAMS_CATSENDQUERY pParams;
  567. CSearchRequestBlock *pBlock;
  568. LPWSTR *rgpszAttributes = NULL;
  569. ICategorizerParametersEx *pIPhatParams = NULL;
  570. ICategorizerRequestedAttributes *pIRequestedAttributes = NULL;
  571. pParams = (PEVENTPARAMS_CATSENDQUERY) pContext;
  572. _ASSERT(pParams);
  573. pBlock = (CSearchRequestBlock *) pParams->pblk;
  574. _ASSERT(pBlock);
  575. CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::HrSendQueryDefault");
  576. hr = pParams->pICatParams->QueryInterface(
  577. IID_ICategorizerParametersEx,
  578. (LPVOID *)&pIPhatParams);
  579. if(FAILED(hr)) {
  580. ERROR_LOG_STATIC(
  581. "pParams->pICatParams->QueryInterface(IID_ICategorizerParametersEx",
  582. pBlock,
  583. pBlock->GetISMTPServerEx());
  584. pIPhatParams = NULL;
  585. goto CLEANUP;
  586. }
  587. hr = pIPhatParams->GetRequestedAttributes(
  588. &pIRequestedAttributes);
  589. ERROR_CLEANUP_LOG_STATIC(
  590. "pIPhatParams->GetRequestedAttributes",
  591. pBlock,
  592. pBlock->GetISMTPServerEx());
  593. hr = pIRequestedAttributes->GetAllAttributesW(
  594. &rgpszAttributes);
  595. ERROR_CLEANUP_LOG_STATIC(
  596. "pIRequestedAttributes->GetAllAttributesW",
  597. pBlock,
  598. pBlock->GetISMTPServerEx());
  599. hr = pBlock->m_pConn->AsyncSearch(
  600. pBlock->m_pConn->GetNamingContextW(),
  601. LDAP_SCOPE_SUBTREE,
  602. pBlock->m_pszSearchFilter,
  603. (LPCWSTR *)rgpszAttributes,
  604. 0, // Do not do a paged search
  605. LDAPCompletion,
  606. pParams);
  607. ERROR_CLEANUP_LOG_STATIC(
  608. "pBlock->m_pConn->AsyncSearch",
  609. pBlock,
  610. pBlock->GetISMTPServerEx());
  611. CLEANUP:
  612. if(FAILED(hr)) {
  613. ErrorTrace((LPARAM)pBlock, "HrSendQueryDefault failing hr %08lx", hr);
  614. //
  615. // Call the completion routine directly with the error
  616. //
  617. hr = pParams->pICatAsyncContext->CompleteQuery(
  618. pParams, // Query context
  619. hr, // Status
  620. 0, // dwcResults
  621. NULL, // rgpItemAttributes,
  622. TRUE); // fFinalCompletion
  623. //
  624. // CompleteQuery should not fail
  625. //
  626. _ASSERT(SUCCEEDED(hr));
  627. }
  628. if(pIRequestedAttributes)
  629. pIRequestedAttributes->Release();
  630. if(pIPhatParams)
  631. pIPhatParams->Release();
  632. CatFunctLeaveEx((LPARAM)pBlock);
  633. return MAILTRANSPORT_S_PENDING;
  634. } // CSearchRequestBlock::HrSendQueryDefault
  635. //+------------------------------------------------------------
  636. //
  637. // Function: CSearchRequestBlock::LDAPCompletion
  638. //
  639. // Synopsis: Wrapper for the default processing completion of SendQuery
  640. //
  641. // Arguments: [ctx] -- Opaque pointer to EVENTPARAMS_SENDQUERY being
  642. // completed
  643. // [dwNumReults] -- The number of objects found
  644. // [rgpICatItemAttributes] -- An array of
  645. // ICategorizerItemAttributes; one per object found
  646. // [hrStatus] -- The error code if the search request failed
  647. // fFinalCompletion:
  648. // FALSE: This is a completion for
  649. // pending results; there will be another completion
  650. // called with more results
  651. // TRUE: This is the final completion call
  652. //
  653. //
  654. // Returns: Nothing
  655. //
  656. // History:
  657. // jstamerj 1999/03/16 12:23:54: Created
  658. //
  659. //-------------------------------------------------------------
  660. VOID CSearchRequestBlock::LDAPCompletion(
  661. LPVOID ctx,
  662. DWORD dwNumResults,
  663. ICategorizerItemAttributes **rgpICatItemAttributes,
  664. HRESULT hrStatus,
  665. BOOL fFinalCompletion)
  666. {
  667. HRESULT hr;
  668. PEVENTPARAMS_CATSENDQUERY pParams;
  669. CSearchRequestBlock *pBlock;
  670. pParams = (PEVENTPARAMS_CATSENDQUERY) ctx;
  671. _ASSERT(pParams);
  672. pBlock = (CSearchRequestBlock *) pParams->pblk;
  673. _ASSERT(pBlock);
  674. CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::LDAPCompletion");
  675. if(FAILED(hrStatus))
  676. {
  677. //
  678. // Log async completion failure
  679. //
  680. hr = hrStatus;
  681. ERROR_LOG_STATIC(
  682. "async",
  683. pBlock,
  684. pBlock->GetISMTPServerEx());
  685. }
  686. //
  687. // Call the normal sink completion routine
  688. //
  689. hr = pParams->pICatAsyncContext->CompleteQuery(
  690. pParams, // Query Context
  691. hrStatus, // Status
  692. dwNumResults, // dwcResults
  693. rgpICatItemAttributes, // rgpItemAttributes
  694. fFinalCompletion); // Is this the final completion for the query?
  695. _ASSERT(SUCCEEDED(hr));
  696. CatFunctLeaveEx((LPARAM)pBlock);
  697. }
  698. //+------------------------------------------------------------
  699. //
  700. // Function: CSearchRequestBlock::HrSendQueryCompletion
  701. //
  702. // Synopsis: The completion routine for the SendQuery event
  703. //
  704. // Arguments:
  705. // hrStatus: status of the event so far
  706. // pContext: Event params context
  707. //
  708. // Returns:
  709. // S_OK: Success
  710. //
  711. // History:
  712. // jstamerj 1999/03/16 12:52:22: Created.
  713. //
  714. //-------------------------------------------------------------
  715. HRESULT CSearchRequestBlock::HrSendQueryCompletion(
  716. HRESULT HrStatus,
  717. PVOID pContext)
  718. {
  719. HRESULT hr = S_OK;
  720. PEVENTPARAMS_CATSENDQUERY pParams;
  721. CSearchRequestBlock *pBlock;
  722. pParams = (PEVENTPARAMS_CATSENDQUERY) pContext;
  723. _ASSERT(pParams);
  724. pBlock = (CSearchRequestBlock *) pParams->pblk;
  725. _ASSERT(pBlock);
  726. CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::HrSendQueryCompletion");
  727. //
  728. // Log async failure
  729. //
  730. if(FAILED(HrStatus))
  731. {
  732. hr = HrStatus;
  733. ERROR_LOG_STATIC(
  734. "async",
  735. pBlock,
  736. pBlock->GetISMTPServerEx());
  737. }
  738. pBlock->CompleteSearchBlock(
  739. pParams->hrResolutionStatus);
  740. if(pBlock->m_pISMTPServer == NULL) {
  741. //
  742. // Events are disabled
  743. // We must free the eventparams
  744. //
  745. delete pParams;
  746. }
  747. //
  748. // The purpose of this block is complete. Today is a good day to
  749. // die!
  750. // -- Lt. Commander Worf
  751. //
  752. delete pBlock;
  753. CatFunctLeaveEx((LPARAM)pBlock);
  754. return S_OK;
  755. } // HrSendQueryCompletion
  756. //+------------------------------------------------------------
  757. //
  758. // Function: CSearchRequestBlock::CompleteSearchBlock
  759. //
  760. // Synopsis: Completion routine when the SendQuery event is done
  761. //
  762. // Arguments:
  763. // hrStatus: Resolution status
  764. //
  765. // Returns: NOTHING
  766. //
  767. // History:
  768. // jstamerj 1999/03/16 13:36:33: Created.
  769. //
  770. //-------------------------------------------------------------
  771. VOID CSearchRequestBlock::CompleteSearchBlock(
  772. HRESULT hrStatus)
  773. {
  774. HRESULT hr = S_OK;
  775. HRESULT hrFetch, hrResult;
  776. DWORD dwCount;
  777. CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::CompleteSearchBlock");
  778. hr = HrTriggerSortQueryResult(hrStatus);
  779. ERROR_CLEANUP_LOG("HrTriggerSortQueryResult");
  780. //
  781. // Check every ICategorizerItem
  782. // If any one of them does not have an hrStatus set, set it to
  783. // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
  784. //
  785. for(dwCount = 0;
  786. dwCount < DwNumBlockRequests();
  787. dwCount++) {
  788. hrFetch = m_rgpICatItems[dwCount]->GetHRESULT(
  789. ICATEGORIZERITEM_HRSTATUS,
  790. &hrResult);
  791. if(FAILED(hrFetch)) {
  792. _ASSERT(hrFetch == CAT_E_PROPNOTFOUND);
  793. _VERIFY(SUCCEEDED(
  794. m_rgpICatItems[dwCount]->PutHRESULT(
  795. ICATEGORIZERITEM_HRSTATUS,
  796. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))));
  797. }
  798. }
  799. CLEANUP:
  800. if(FAILED(hr)) {
  801. ErrorTrace((LPARAM)this, "Failing block hr %08lx", hr);
  802. PutBlockHRESULT(hr);
  803. }
  804. //
  805. // Call all the individual completion routines
  806. //
  807. CallCompletions();
  808. CatFunctLeaveEx((LPARAM)this);
  809. } // CSearchRequestBlock::CompleteSearchBlock
  810. //+------------------------------------------------------------
  811. //
  812. // Function: CSearchRequestBlock::PutBlockHRESULT
  813. //
  814. // Synopsis: Set the status of every ICatItem in the block to some hr
  815. //
  816. // Arguments:
  817. // hr: Status to set
  818. //
  819. // Returns: NOTHING
  820. //
  821. // History:
  822. // jstamerj 1999/03/16 14:03:30: Created.
  823. //
  824. //-------------------------------------------------------------
  825. VOID CSearchRequestBlock::PutBlockHRESULT(
  826. HRESULT hr)
  827. {
  828. DWORD dwCount;
  829. CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::PutBlockHRESULT");
  830. DebugTrace((LPARAM)this, "hr = %08lx", hr);
  831. for(dwCount = 0;
  832. dwCount < DwNumBlockRequests();
  833. dwCount++) {
  834. PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]);
  835. //
  836. // Set the error status
  837. //
  838. _VERIFY(SUCCEEDED(preq->pCCatAddr->PutHRESULT(
  839. ICATEGORIZERITEM_HRSTATUS,
  840. hr)));
  841. }
  842. CatFunctLeaveEx((LPARAM)this);
  843. } // CSearchRequestBlock::PutBlockHRESULT
  844. //+------------------------------------------------------------
  845. //
  846. // Function: CSearchRequestBlock::CallCompletions
  847. //
  848. // Synopsis: Call the completion routine of every item in the block
  849. //
  850. // Arguments: NONE
  851. //
  852. // Returns: NOTHING
  853. //
  854. // History:
  855. // jstamerj 1999/03/16 14:05:50: Created.
  856. // dlongley 2001/10/23: Modified.
  857. //
  858. //-------------------------------------------------------------
  859. VOID CSearchRequestBlock::CallCompletions()
  860. {
  861. DWORD dwCount;
  862. CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::CallCompletions");
  863. //
  864. // Get an Insertion context before calling completions so that
  865. // newly inserted searches will be batched
  866. //
  867. for(dwCount = 0;
  868. dwCount < DwNumBlockRequests();
  869. dwCount++) {
  870. PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]);
  871. preq->pslrc->AddRef();
  872. preq->pslrc->GetInsertionContext();
  873. preq->fnSearchCompletion(
  874. preq->pCCatAddr,
  875. preq->pslrc,
  876. m_pConn);
  877. }
  878. m_pConn->DecrementPendingSearches(
  879. DwNumBlockRequests());
  880. for(dwCount = 0;
  881. dwCount < DwNumBlockRequests();
  882. dwCount++) {
  883. PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]);
  884. preq->pslrc->ReleaseInsertionContext();
  885. preq->pslrc->Release();
  886. }
  887. CatFunctLeaveEx((LPARAM)this);
  888. } // CSearchRequestBlock::CallCompletions
  889. //+------------------------------------------------------------
  890. //
  891. // Function: CSearchRequestBlock::HrTriggerSortQueryResult
  892. //
  893. // Synopsis: Trigger the SortQueryResult event
  894. //
  895. // Arguments:
  896. // hrStatus: Status of Resolution
  897. //
  898. // Returns:
  899. // S_OK: Success
  900. // error from the dispatcher
  901. //
  902. // History:
  903. // jstamerj 1999/03/16 14:09:12: Created.
  904. //
  905. //-------------------------------------------------------------
  906. HRESULT CSearchRequestBlock::HrTriggerSortQueryResult(
  907. HRESULT hrStatus)
  908. {
  909. HRESULT hr = S_OK;
  910. EVENTPARAMS_CATSORTQUERYRESULT Params;
  911. CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::HrTriggerSortQueryResult");
  912. Params.pICatParams = m_pICatParams;
  913. Params.hrResolutionStatus = hrStatus;
  914. Params.dwcAddresses = DwNumBlockRequests();
  915. Params.rgpICatItems = m_rgpICatItems;
  916. Params.dwcResults = m_csaItemAttr.Size();
  917. Params.rgpICatItemAttributes = m_csaItemAttr;
  918. Params.pfnDefault = HrSortQueryResultDefault;
  919. Params.pblk = this;
  920. if(m_pISMTPServer) {
  921. hr = m_pISMTPServer->TriggerServerEvent(
  922. SMTP_MAILTRANSPORT_CATEGORIZE_SORTQUERYRESULT_EVENT,
  923. &Params);
  924. if(FAILED(hr) && (hr != E_NOTIMPL))
  925. {
  926. ERROR_LOG("m_pISMTPServer->TriggerServerEvent");
  927. }
  928. } else {
  929. hr = E_NOTIMPL;
  930. }
  931. if(hr == E_NOTIMPL) {
  932. //
  933. // Events are disabled, call default processing
  934. //
  935. HrSortQueryResultDefault(
  936. S_OK,
  937. &Params);
  938. hr = S_OK;
  939. }
  940. DebugTrace((LPARAM)this, "returning %08lx", hr);
  941. CatFunctLeaveEx((LPARAM)this);
  942. return hr;
  943. } // CSearchRequestBlock::HrTriggerSortQueryResult
  944. //+------------------------------------------------------------
  945. //
  946. // Function: CSearchRequestBlock::HrSortQueryResultDefault
  947. //
  948. // Synopsis: Default sink for SortQueryResult -- match the objects found
  949. // with the objects requested
  950. //
  951. // Arguments:
  952. // hrStatus: Status of events
  953. // pContext: Params context for this event
  954. //
  955. // Returns:
  956. // S_OK: Success
  957. //
  958. // History:
  959. // jstamerj 1999/03/16 14:17:49: Created.
  960. //
  961. //-------------------------------------------------------------
  962. HRESULT CSearchRequestBlock::HrSortQueryResultDefault(
  963. HRESULT hrStatus,
  964. PVOID pContext)
  965. {
  966. HRESULT hr = S_OK;
  967. PEVENTPARAMS_CATSORTQUERYRESULT pParams;
  968. CSearchRequestBlock *pBlock;
  969. DWORD dwAttrIndex, dwReqIndex;
  970. ATTRIBUTE_ENUMERATOR enumerator;
  971. pParams = (PEVENTPARAMS_CATSORTQUERYRESULT) pContext;
  972. _ASSERT(pParams);
  973. pBlock = (CSearchRequestBlock *) pParams->pblk;
  974. _ASSERT(pBlock);
  975. CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::HrSortQueryResultDefault");
  976. DebugTrace((LPARAM)pBlock, "hrResolutionStatus %08lx, dwcResults %08lx",
  977. pParams->hrResolutionStatus, pParams->dwcResults);
  978. if(FAILED(pParams->hrResolutionStatus)) {
  979. //
  980. // Fail the entire block
  981. //
  982. pBlock->PutBlockHRESULT(pParams->hrResolutionStatus);
  983. goto CLEANUP;
  984. }
  985. //
  986. // Resolution succeeded
  987. // If dwcResults is not zero, then rgpICatItemAttrs can NOT be null
  988. //
  989. _ASSERT((pParams->dwcResults == 0) ||
  990. (pParams->rgpICatItemAttributes != NULL));
  991. //
  992. // Loop through every rgpICatItemAttrs. For each
  993. // ICategorizerItemAttributes, looking for a matching SEARCH_REQUEST
  994. //
  995. for(dwAttrIndex = 0; dwAttrIndex < pParams->dwcResults; dwAttrIndex++) {
  996. ICategorizerItemAttributes *pICatItemAttr = NULL;
  997. ICategorizerUTF8Attributes *pIUTF8 = NULL;
  998. pICatItemAttr = pParams->rgpICatItemAttributes[dwAttrIndex];
  999. LPCSTR pszLastDistinguishingAttribute = NULL;
  1000. BOOL fEnumerating = FALSE;
  1001. hr = pICatItemAttr->QueryInterface(
  1002. IID_ICategorizerUTF8Attributes,
  1003. (LPVOID *) &pIUTF8);
  1004. ERROR_CLEANUP_LOG_STATIC(
  1005. "pICatItemAttr->QueryInterface",
  1006. pBlock,
  1007. pBlock->GetISMTPServerEx());
  1008. for(dwReqIndex = 0; dwReqIndex < pBlock->DwNumBlockRequests();
  1009. dwReqIndex++) {
  1010. PSEARCH_REQUEST preq = &(pBlock->m_prgSearchRequests[dwReqIndex]);
  1011. //#ifdef DEBUG
  1012. // WCHAR wszPreqDistinguishingAttributeValue[20];
  1013. //#else
  1014. WCHAR wszPreqDistinguishingAttributeValue[CAT_MAX_INTERNAL_FULL_EMAIL];
  1015. //#endif
  1016. LPWSTR pwszPreqDistinguishingAttributeValue = wszPreqDistinguishingAttributeValue;
  1017. DWORD cPreqDistinguishingAttributeValue;
  1018. DWORD rc;
  1019. //
  1020. // If we don't have a distinguishing attribute and
  1021. // distinguishing attribute value for this search
  1022. // request, we've no hope of matching it up
  1023. //
  1024. if((preq->pszDistinguishingAttribute == NULL) ||
  1025. (preq->pszDistinguishingAttributeValue == NULL))
  1026. continue;
  1027. // convert pszDistinguishingAttributeValue to unicode
  1028. cPreqDistinguishingAttributeValue =
  1029. MultiByteToWideChar(CP_UTF8,
  1030. 0,
  1031. preq->pszDistinguishingAttributeValue,
  1032. -1,
  1033. pwszPreqDistinguishingAttributeValue,
  1034. 0);
  1035. if (cPreqDistinguishingAttributeValue >
  1036. (sizeof(wszPreqDistinguishingAttributeValue) / sizeof(WCHAR)) )
  1037. {
  1038. pwszPreqDistinguishingAttributeValue =
  1039. new WCHAR[cPreqDistinguishingAttributeValue + 1];
  1040. if (pwszPreqDistinguishingAttributeValue == NULL) {
  1041. hr = E_OUTOFMEMORY;
  1042. ERROR_LOG_STATIC(
  1043. "new WCHAR[]",
  1044. pBlock,
  1045. pBlock->GetISMTPServerEx());
  1046. continue;
  1047. }
  1048. }
  1049. rc = MultiByteToWideChar(CP_UTF8,
  1050. 0,
  1051. preq->pszDistinguishingAttributeValue,
  1052. -1,
  1053. pwszPreqDistinguishingAttributeValue,
  1054. cPreqDistinguishingAttributeValue);
  1055. if (rc == 0) {
  1056. hr = HRESULT_FROM_WIN32(GetLastError());
  1057. ERROR_LOG_STATIC(
  1058. "MultiByteToWideChar",
  1059. pBlock,
  1060. pBlock->GetISMTPServerEx());
  1061. continue;
  1062. }
  1063. //
  1064. // Start an attribute value enumeration if necessary
  1065. //
  1066. if((pszLastDistinguishingAttribute == NULL) ||
  1067. (lstrcmpi(pszLastDistinguishingAttribute,
  1068. preq->pszDistinguishingAttribute) != 0)) {
  1069. if(fEnumerating) {
  1070. pIUTF8->EndUTF8AttributeEnumeration(&enumerator);
  1071. }
  1072. hr = pIUTF8->BeginUTF8AttributeEnumeration(
  1073. preq->pszDistinguishingAttribute,
  1074. &enumerator);
  1075. fEnumerating = SUCCEEDED(hr);
  1076. pszLastDistinguishingAttribute = preq->pszDistinguishingAttribute;
  1077. } else {
  1078. //
  1079. // else just rewind our current enumeration
  1080. //
  1081. if(fEnumerating)
  1082. _VERIFY(SUCCEEDED(pIUTF8->RewindUTF8AttributeEnumeration(
  1083. &enumerator)));
  1084. }
  1085. //
  1086. // If we can't enumerate through the distinguishing
  1087. // attribute, there's no hope in matching up requests
  1088. //
  1089. if(!fEnumerating)
  1090. continue;
  1091. //
  1092. // See if the distinguishing attribute value matches
  1093. //
  1094. LPSTR pszDistinguishingAttributeValue;
  1095. hr = pIUTF8->GetNextUTF8AttributeValue(
  1096. &enumerator,
  1097. &pszDistinguishingAttributeValue);
  1098. while(SUCCEEDED(hr)) {
  1099. hr = wcsutf8cmpi(pwszPreqDistinguishingAttributeValue,
  1100. pszDistinguishingAttributeValue);
  1101. if (SUCCEEDED(hr)) {
  1102. if(hr == S_OK) {
  1103. DebugTrace((LPARAM)pBlock, "Matched dwAttrIndex %d with dwReqIndex %d", dwAttrIndex, dwReqIndex);
  1104. pBlock->MatchItem(
  1105. preq->pCCatAddr,
  1106. pICatItemAttr);
  1107. }
  1108. hr = pIUTF8->GetNextUTF8AttributeValue(
  1109. &enumerator,
  1110. &pszDistinguishingAttributeValue);
  1111. } else {
  1112. ERROR_LOG_STATIC(
  1113. "wcsutf8cmpi",
  1114. pBlock,
  1115. pBlock->GetISMTPServerEx());
  1116. }
  1117. }
  1118. if (pwszPreqDistinguishingAttributeValue != wszPreqDistinguishingAttributeValue) {
  1119. delete[] pwszPreqDistinguishingAttributeValue;
  1120. }
  1121. }
  1122. //
  1123. // End any last enumeration going on
  1124. //
  1125. if(fEnumerating)
  1126. pIUTF8->EndUTF8AttributeEnumeration(&enumerator);
  1127. fEnumerating = FALSE;
  1128. if(pIUTF8) {
  1129. pIUTF8->Release();
  1130. pIUTF8 = NULL;
  1131. }
  1132. }
  1133. CLEANUP:
  1134. CatFunctLeaveEx((LPARAM)pBlock);
  1135. return S_OK;
  1136. } // CSearchRequestBlock::HrSortQueryResultDefault
  1137. //+------------------------------------------------------------
  1138. //
  1139. // Function: CSearchRequestBlock::MatchItem
  1140. //
  1141. // Synopsis: Match a particular ICategorizerItem to a particular ICategorizerItemAttributes
  1142. // If already matched with an ICategorizerItemAttributes with an
  1143. // identical ID then set item status to CAT_E_MULTIPLE_MATCHES
  1144. // If already matched with an ICategorizerItemAttributes with a
  1145. // different ID then attempt aggregation
  1146. ////
  1147. // Arguments:
  1148. // pICatItem: an ICategorizerItem
  1149. // pICatItemAttr: the matching attribute interface for pICatItem
  1150. //
  1151. // Returns: NOTHING
  1152. //
  1153. // History:
  1154. // jstamerj 1999/03/16 14:36:45: Created.
  1155. //
  1156. //-------------------------------------------------------------
  1157. VOID CSearchRequestBlock::MatchItem(
  1158. ICategorizerItem *pICatItem,
  1159. ICategorizerItemAttributes *pICatItemAttr)
  1160. {
  1161. HRESULT hr = S_OK;
  1162. ICategorizerItemAttributes *pICatItemAttr_Current = NULL;
  1163. CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::MatchItem");
  1164. _ASSERT(pICatItem);
  1165. _ASSERT(pICatItemAttr);
  1166. //
  1167. // Check to see if this item already has
  1168. // ICategorizerItemAttributes set
  1169. //
  1170. hr = pICatItem->GetICategorizerItemAttributes(
  1171. ICATEGORIZERITEM_ICATEGORIZERITEMATTRIBUTES,
  1172. &pICatItemAttr_Current);
  1173. if(SUCCEEDED(hr)) {
  1174. //
  1175. // This guy is already matched. Is the duplicate from the
  1176. // same resolver sink?
  1177. //
  1178. GUID GOriginal, GNew;
  1179. GOriginal = pICatItemAttr_Current->GetTransportSinkID();
  1180. GNew = pICatItemAttr->GetTransportSinkID();
  1181. if(GOriginal == GNew) {
  1182. //
  1183. // Two matches from the same resolver sink indicates that
  1184. // there are multiple matches for this object. This is an
  1185. // error.
  1186. //
  1187. //
  1188. // This guy is already matched -- the distinguishing attribute
  1189. // really wasn't distinguishing. Set error hrstatus.
  1190. //
  1191. LogAmbiguousEvent(pICatItem);
  1192. _VERIFY(SUCCEEDED(
  1193. pICatItem->PutHRESULT(
  1194. ICATEGORIZERITEM_HRSTATUS,
  1195. CAT_E_MULTIPLE_MATCHES)));
  1196. } else {
  1197. //
  1198. // We have multiple matches from different resolver
  1199. // sinks. Let's try to aggregate the new
  1200. // ICategorizerItemAttributes
  1201. //
  1202. hr = pICatItemAttr_Current->AggregateAttributes(
  1203. pICatItemAttr);
  1204. if(FAILED(hr) && (hr != E_NOTIMPL)) {
  1205. //
  1206. // Fail categorization for this item
  1207. //
  1208. ERROR_LOG("pICatItemAttr_Current->AggregateAttributes");
  1209. _VERIFY(SUCCEEDED(
  1210. pICatItem->PutHRESULT(
  1211. ICATEGORIZERITEM_HRSTATUS,
  1212. hr)));
  1213. }
  1214. }
  1215. } else {
  1216. //
  1217. // Normal case -- set the ICategorizerItemAttribute property
  1218. // of ICategorizerItem
  1219. //
  1220. _VERIFY(SUCCEEDED(
  1221. pICatItem->PutICategorizerItemAttributes(
  1222. ICATEGORIZERITEM_ICATEGORIZERITEMATTRIBUTES,
  1223. pICatItemAttr)));
  1224. //
  1225. // Set hrStatus of this guy to success
  1226. //
  1227. _VERIFY(SUCCEEDED(
  1228. pICatItem->PutHRESULT(
  1229. ICATEGORIZERITEM_HRSTATUS,
  1230. S_OK)));
  1231. }
  1232. if(pICatItemAttr_Current)
  1233. pICatItemAttr_Current->Release();
  1234. CatFunctLeaveEx((LPARAM)this);
  1235. } // CSearchRequestBlock::MatchItem
  1236. //+------------------------------------------------------------
  1237. //
  1238. // Function: CBatchLdapConnection::HrInsertSearchRequest
  1239. //
  1240. // Synopsis: Insert a search request
  1241. //
  1242. // Arguments:
  1243. // pISMTPServer: ISMTPServer interface to use for triggering events
  1244. // pCCatAddr: Address item for the search
  1245. // fnSearchCompletion: Async Completion routine
  1246. // ctxSearchCompletion: Context to pass to the async completion routine
  1247. // pszSearchFilter: Search filter to use
  1248. // pszDistinguishingAttribute: The distinguishing attribute for matching
  1249. // pszDistinguishingAttributeValue: above attribute's distinguishing value
  1250. //
  1251. // Returns:
  1252. // S_OK: Success
  1253. //
  1254. // History:
  1255. // jstamerj 1999/03/08 19:41:37: Created.
  1256. //
  1257. //-------------------------------------------------------------
  1258. HRESULT CBatchLdapConnection::HrInsertSearchRequest(
  1259. ISMTPServer *pISMTPServer,
  1260. ICategorizerParameters *pICatParams,
  1261. CCatAddr *pCCatAddr,
  1262. LPSEARCHCOMPLETION fnSearchCompletion,
  1263. CStoreListResolveContext *pslrc,
  1264. LPSTR pszSearchFilter,
  1265. LPSTR pszDistinguishingAttribute,
  1266. LPSTR pszDistinguishingAttributeValue)
  1267. {
  1268. HRESULT hr = S_OK;
  1269. CSearchRequestBlock *pBlock;
  1270. CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::HrInsertSearchRequest");
  1271. _ASSERT(m_cInsertionContext);
  1272. _ASSERT(pCCatAddr);
  1273. _ASSERT(fnSearchCompletion);
  1274. _ASSERT(pszSearchFilter);
  1275. _ASSERT(pszDistinguishingAttribute);
  1276. _ASSERT(pszDistinguishingAttributeValue);
  1277. pBlock = GetSearchRequestBlock();
  1278. if(pBlock == NULL) {
  1279. ErrorTrace((LPARAM)this, "out of memory getting a search block");
  1280. hr = E_OUTOFMEMORY;
  1281. ERROR_LOG_ADDR(pCCatAddr, "GetSearchRequestBlock");
  1282. goto CLEANUP;
  1283. }
  1284. pBlock->InsertSearchRequest(
  1285. pISMTPServer,
  1286. pICatParams,
  1287. pCCatAddr,
  1288. fnSearchCompletion,
  1289. pslrc,
  1290. pszSearchFilter,
  1291. pszDistinguishingAttribute,
  1292. pszDistinguishingAttributeValue);
  1293. CLEANUP:
  1294. DebugTrace((LPARAM)this, "Returning hr %08lx", hr);
  1295. CatFunctLeaveEx((LPARAM)this);
  1296. return hr;
  1297. }
  1298. //+------------------------------------------------------------
  1299. //
  1300. // Function: CBatchLdapConnection::GetSearchRequestBlock
  1301. //
  1302. // Synopsis: Gets the next available search block with room
  1303. //
  1304. // Arguments: NONE
  1305. //
  1306. // Returns:
  1307. // NULL: Out of memory
  1308. // else, a search block object
  1309. //
  1310. // History:
  1311. // jstamerj 1999/03/08 19:41:37: Created.
  1312. // haozhang 2001/11/25 updated for 193848
  1313. //
  1314. //-------------------------------------------------------------
  1315. CSearchRequestBlock * CBatchLdapConnection::GetSearchRequestBlock()
  1316. {
  1317. HRESULT hr = E_FAIL;
  1318. PLIST_ENTRY ple;
  1319. CSearchRequestBlock *pBlock = NULL;
  1320. //
  1321. // Updated for fix of 193848
  1322. // We do two passes. In first one, we will go through the list
  1323. // and reserve a slot if available(then return). If we don't,
  1324. // we will created a new block and proceed with a second pass. In
  1325. // second pass, we will first insert the block to the list, then
  1326. // go through the list again to reserve a slot in the first
  1327. // avaiable block. The fix differs from previous version in that
  1328. // we will not simply reserve a slot in the new block we just
  1329. // created. Instead, we will go through the list again in case
  1330. // existing block still has room. Therefore, we avoided the
  1331. // core problem in which we reserve a slot on new block even
  1332. // though there is room in existing block.
  1333. //
  1334. AcquireSpinLock(&m_spinlock);
  1335. //
  1336. // See if there is an insertion block with available slots
  1337. //
  1338. for(ple = m_listhead.Flink;
  1339. (ple != &m_listhead) && (FAILED(hr));
  1340. ple = ple->Flink) {
  1341. pBlock = CONTAINING_RECORD(ple, CSearchRequestBlock, m_listentry);
  1342. hr = pBlock->ReserveSlot();
  1343. }
  1344. ReleaseSpinLock(&m_spinlock);
  1345. if(SUCCEEDED(hr))
  1346. return pBlock;
  1347. //
  1348. // Create a new block
  1349. //
  1350. pBlock = new (m_nMaxSearchBlockSize) CSearchRequestBlock(this);
  1351. if(pBlock) {
  1352. AcquireSpinLock(&m_spinlock);
  1353. InsertTailList(&m_listhead, &(pBlock->m_listentry));
  1354. //
  1355. // Again,see if there is an insertion block with available slots
  1356. //
  1357. for(ple = m_listhead.Flink;
  1358. (ple != &m_listhead) && (FAILED(hr));
  1359. ple = ple->Flink) {
  1360. pBlock = CONTAINING_RECORD(ple, CSearchRequestBlock, m_listentry);
  1361. hr = pBlock->ReserveSlot();
  1362. }
  1363. ReleaseSpinLock(&m_spinlock);
  1364. _ASSERT(SUCCEEDED(hr));
  1365. }
  1366. return pBlock;
  1367. }
  1368. //+------------------------------------------------------------
  1369. //
  1370. // Function: CSearchRequestBlock::LogAmbiguousEvent
  1371. //
  1372. // Synopsis: Eventlogs an ambiguous address error
  1373. //
  1374. // Arguments:
  1375. // pItem: ICatItem with ambig address
  1376. //
  1377. // Returns: Nothing
  1378. //
  1379. // History:
  1380. // jstamerj 2001/12/13 00:03:16: Created.
  1381. //
  1382. //-------------------------------------------------------------
  1383. VOID CSearchRequestBlock::LogAmbiguousEvent(
  1384. IN ICategorizerItem *pItem)
  1385. {
  1386. HRESULT hr = S_OK;
  1387. LPCSTR rgSubStrings[2];
  1388. CHAR szAddress[CAT_MAX_INTERNAL_FULL_EMAIL];
  1389. CHAR szAddressType[CAT_MAX_ADDRESS_TYPE_STRING];
  1390. CatFunctEnter("CIMstRecipListAddr::LogNDREvent");
  1391. //
  1392. // Get the address
  1393. //
  1394. hr = HrGetAddressStringFromICatItem(
  1395. pItem,
  1396. sizeof(szAddressType) / sizeof(szAddressType[0]),
  1397. szAddressType,
  1398. sizeof(szAddress) / sizeof(szAddress[0]),
  1399. szAddress);
  1400. if(FAILED(hr))
  1401. {
  1402. //
  1403. // Still log an event, but use "unknown" for address type/string
  1404. //
  1405. lstrcpyn(szAddressType, "unknown",
  1406. sizeof(szAddressType) / sizeof(szAddressType[0]));
  1407. lstrcpyn(szAddress, "unknown",
  1408. sizeof(szAddress) / sizeof(szAddress[0]));
  1409. hr = S_OK;
  1410. }
  1411. rgSubStrings[0] = szAddressType;
  1412. rgSubStrings[1] = szAddress;
  1413. //
  1414. // Can we log an event?
  1415. //
  1416. if(GetISMTPServerEx() == NULL)
  1417. {
  1418. FatalTrace((LPARAM)0, "Unable to log ambiguous address event; NULL pISMTPServerEx");
  1419. for(DWORD dwIdx = 0; dwIdx < 2; dwIdx++)
  1420. {
  1421. if( rgSubStrings[dwIdx] != NULL )
  1422. {
  1423. FatalTrace((LPARAM)0, "Event String %d: %s",
  1424. dwIdx, rgSubStrings[dwIdx]);
  1425. }
  1426. }
  1427. }
  1428. else
  1429. {
  1430. CatLogEvent(
  1431. GetISMTPServerEx(),
  1432. CAT_EVENT_AMBIGUOUS_ADDRESS,
  1433. 2,
  1434. rgSubStrings,
  1435. S_OK,
  1436. szAddress,
  1437. LOGEVENT_FLAG_PERIODIC,
  1438. LOGEVENT_LEVEL_MINIMUM);
  1439. }
  1440. }
  1441. //+------------------------------------------------------------
  1442. //
  1443. // Function: CBatchLdapConnection::DispatchBlocks
  1444. //
  1445. // Synopsis: Dispatch all the blocks in a list
  1446. //
  1447. // Arguments:
  1448. // plisthead: List to dispatch
  1449. //
  1450. // Returns: NOTHING
  1451. //
  1452. // History:
  1453. // jstamerj 1999/03/11 15:16:36: Created.
  1454. //
  1455. //-------------------------------------------------------------
  1456. VOID CBatchLdapConnection::DispatchBlocks(
  1457. PLIST_ENTRY plisthead)
  1458. {
  1459. PLIST_ENTRY ple, ple_next;
  1460. CSearchRequestBlock *pBlock;
  1461. for(ple = plisthead->Flink;
  1462. ple != plisthead;
  1463. ple = ple_next) {
  1464. ple_next = ple->Flink;
  1465. pBlock = CONTAINING_RECORD(ple, CSearchRequestBlock,
  1466. m_listentry);
  1467. pBlock->DispatchBlock();
  1468. }
  1469. }
  1470. //+------------------------------------------------------------
  1471. //
  1472. // Function: CStoreListResolveContext::CStoreListResolveContext
  1473. //
  1474. // Synopsis: Construct a CStoreListResolveContext object
  1475. //
  1476. // Arguments: NONE
  1477. //
  1478. // Returns: NOTHING
  1479. //
  1480. // History:
  1481. // jstamerj 1999/03/22 12:16:08: Created.
  1482. //
  1483. //-------------------------------------------------------------
  1484. CStoreListResolveContext::CStoreListResolveContext(
  1485. CEmailIDLdapStore<CCatAddr> *pStore)
  1486. {
  1487. CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::CStoreListResolveContext");
  1488. m_cRefs = 1;
  1489. m_dwSignature = SIGNATURE_CSTORELISTRESOLVECONTEXT;
  1490. m_pConn = NULL;
  1491. m_fCanceled = FALSE;
  1492. m_dwcRetries = 0;
  1493. m_dwcCompletedLookups = 0;
  1494. InitializeCriticalSectionAndSpinCount(&m_cs, 2000);
  1495. m_pISMTPServer = NULL;
  1496. m_pISMTPServerEx = NULL;
  1497. m_pICatParams = NULL;
  1498. m_dwcInsertionContext = 0;
  1499. m_pStore = pStore;
  1500. CatFunctLeaveEx((LPARAM)this);
  1501. } // CStoreListResolveContext::CStoreListResolveContext
  1502. //+------------------------------------------------------------
  1503. //
  1504. // Function: CStoreListResolveContext::~CStoreListResolveContext
  1505. //
  1506. // Synopsis: Destruct a list resolve context
  1507. //
  1508. // Arguments: NONE
  1509. //
  1510. // Returns: NOTHING
  1511. //
  1512. // History:
  1513. // jstamerj 1999/03/22 12:18:01: Created.
  1514. //
  1515. //-------------------------------------------------------------
  1516. CStoreListResolveContext::~CStoreListResolveContext()
  1517. {
  1518. CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::~CStoreListResolveContext");
  1519. _ASSERT(m_dwSignature == SIGNATURE_CSTORELISTRESOLVECONTEXT);
  1520. m_dwSignature = SIGNATURE_CSTORELISTRESOLVECONTEXT_INVALID;
  1521. if(m_pConn)
  1522. m_pConn->Release();
  1523. if(m_pISMTPServer)
  1524. m_pISMTPServer->Release();
  1525. if(m_pISMTPServerEx)
  1526. m_pISMTPServerEx->Release();
  1527. if(m_pICatParams)
  1528. m_pICatParams->Release();
  1529. DeleteCriticalSection(&m_cs);
  1530. CatFunctLeaveEx((LPARAM)this);
  1531. } // CStoreListResolveContext::~CStoreListResolveContext
  1532. //+------------------------------------------------------------
  1533. //
  1534. // Function: CStoreListResolveContext::HrInitialize
  1535. //
  1536. // Synopsis: Initailize this object so that it is ready to handle lookups
  1537. //
  1538. // Arguments:
  1539. // pISMTPServer: ISMTPServer interface to use for triggering events
  1540. // pICatParams: ICatParams interface to use
  1541. //
  1542. // Note: All of these string buffers must remain valid for the
  1543. // lifetime of this object!
  1544. // pszAccount: LDAP account to use for binding
  1545. // pszPassword: LDAP password to use
  1546. // pszNamingContext: Naming context to use for searches
  1547. // pszHost: LDAP Host to connect to
  1548. // dwPort: LDAP TCP port to use
  1549. // bt: Method of LDAP bind to use
  1550. //
  1551. // Returns:
  1552. // S_OK: Success
  1553. // error from LdapConnectionCache
  1554. //
  1555. // History:
  1556. // jstamerj 1999/03/22 12:20:31: Created.
  1557. //
  1558. //-------------------------------------------------------------
  1559. HRESULT CStoreListResolveContext::HrInitialize(
  1560. ISMTPServer *pISMTPServer,
  1561. ICategorizerParameters *pICatParams)
  1562. {
  1563. HRESULT hr = S_OK;
  1564. CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::HrInitialize");
  1565. _ASSERT(m_pISMTPServer == NULL);
  1566. _ASSERT(m_pICatParams == NULL);
  1567. _ASSERT(pICatParams != NULL);
  1568. if(pISMTPServer) {
  1569. m_pISMTPServer = pISMTPServer;
  1570. m_pISMTPServer->AddRef();
  1571. hr = m_pISMTPServer->QueryInterface(
  1572. IID_ISMTPServerEx,
  1573. (LPVOID *) &m_pISMTPServerEx);
  1574. if(FAILED(hr)) {
  1575. //
  1576. // Deal with error
  1577. //
  1578. m_pISMTPServerEx = NULL;
  1579. hr = S_OK;
  1580. }
  1581. }
  1582. if(pICatParams) {
  1583. m_pICatParams = pICatParams;
  1584. m_pICatParams->AddRef();
  1585. }
  1586. hr = m_pStore->HrGetConnection(
  1587. &m_pConn);
  1588. if(FAILED(hr)) {
  1589. ERROR_LOG("m_pStore->HrGetConnection");
  1590. m_pConn = NULL;
  1591. }
  1592. DebugTrace((LPARAM)this, "returning %08lx", hr);
  1593. CatFunctLeaveEx((LPARAM)this);
  1594. return hr;
  1595. } // CStoreListResolveContext::HrInitialize
  1596. //+------------------------------------------------------------
  1597. //
  1598. // Function: CStoreListResolveContext::HrLookupEntryAsync
  1599. //
  1600. // Synopsis: Dispatch an async LDAP lookup
  1601. //
  1602. // Arguments:
  1603. // pCCatAddr: Address object to lookup
  1604. //
  1605. // Returns:
  1606. // S_OK: Success
  1607. // error from LdapConn
  1608. //
  1609. // History:
  1610. // jstamerj 1999/03/22 12:28:52: Created.
  1611. //
  1612. //-------------------------------------------------------------
  1613. HRESULT CStoreListResolveContext::HrLookupEntryAsync(
  1614. CCatAddr *pCCatAddr)
  1615. {
  1616. HRESULT hr = S_OK;
  1617. LPSTR pszSearchFilter = NULL;
  1618. LPSTR pszDistinguishingAttribute = NULL;
  1619. LPSTR pszDistinguishingAttributeValue = NULL;
  1620. BOOL fTryAgain;
  1621. CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::HrLookupEntryAsync");
  1622. //
  1623. // Addref the CCatAddr here, release after completion
  1624. //
  1625. pCCatAddr->AddRef();
  1626. hr = pCCatAddr->HrTriggerBuildQuery();
  1627. ERROR_CLEANUP_LOG_ADDR(pCCatAddr, "pCCatAddr->HrTriggerBuildQuery");
  1628. //
  1629. // Fetch the distinguishing attribute and distinguishing attribute
  1630. // value from pCCatAddr
  1631. //
  1632. pCCatAddr->GetStringAPtr(
  1633. ICATEGORIZERITEM_LDAPQUERYSTRING,
  1634. &pszSearchFilter);
  1635. pCCatAddr->GetStringAPtr(
  1636. ICATEGORIZERITEM_DISTINGUISHINGATTRIBUTE,
  1637. &pszDistinguishingAttribute);
  1638. pCCatAddr->GetStringAPtr(
  1639. ICATEGORIZERITEM_DISTINGUISHINGATTRIBUTEVALUE,
  1640. &pszDistinguishingAttributeValue);
  1641. //
  1642. // Check to see if anyone set a search filter
  1643. //
  1644. if(pszSearchFilter == NULL) {
  1645. HRESULT hrStatus;
  1646. //
  1647. // If the status is unset, set it to CAT_E_NO_FILTER
  1648. //
  1649. hr = pCCatAddr->GetHRESULT(
  1650. ICATEGORIZERITEM_HRSTATUS,
  1651. &hrStatus);
  1652. if(FAILED(hr)) {
  1653. ErrorTrace((LPARAM)this, "No search filter set");
  1654. ERROR_LOG_ADDR(pCCatAddr, "pCCatAddr->GetHRESULT(hrstatus) -- no filter");
  1655. _VERIFY(SUCCEEDED(pCCatAddr->PutHRESULT(
  1656. ICATEGORIZERITEM_HRSTATUS,
  1657. CAT_E_NO_FILTER)));
  1658. }
  1659. DebugTrace((LPARAM)this, "BuildQuery did not build a search filter");
  1660. //
  1661. // Call the completion directly
  1662. //
  1663. pCCatAddr->LookupCompletion();
  1664. pCCatAddr->Release();
  1665. hr = S_OK;
  1666. goto CLEANUP;
  1667. }
  1668. if((pszDistinguishingAttribute == NULL) ||
  1669. (pszDistinguishingAttributeValue == NULL)) {
  1670. ErrorTrace((LPARAM)this, "Distinguishing attribute not set");
  1671. ERROR_LOG_ADDR(pCCatAddr, "--no distinguishing attribute--");
  1672. hr = E_INVALIDARG;
  1673. goto CLEANUP;
  1674. }
  1675. do {
  1676. fTryAgain = FALSE;
  1677. CBatchLdapConnection *pConn;
  1678. pConn = GetConnection();
  1679. //
  1680. // Insert the search request into the CBatchLdapConnection
  1681. // object. We will use the email address as the distinguishing
  1682. // attribute
  1683. //
  1684. if(pConn == NULL) {
  1685. hr = CAT_E_DBCONNECTION;
  1686. ERROR_LOG_ADDR(pCCatAddr, "GetConnection");
  1687. } else {
  1688. pConn->GetInsertionContext();
  1689. hr = pConn->HrInsertSearchRequest(
  1690. m_pISMTPServer,
  1691. m_pICatParams,
  1692. pCCatAddr,
  1693. CStoreListResolveContext::AsyncLookupCompletion,
  1694. this,
  1695. pszSearchFilter,
  1696. pszDistinguishingAttribute,
  1697. pszDistinguishingAttributeValue);
  1698. if(FAILED(hr)) {
  1699. ERROR_LOG_ADDR(pCCatAddr, "pConn->HrInsertSearchRequest");
  1700. }
  1701. pConn->ReleaseInsertionContext();
  1702. }
  1703. //
  1704. // If the above fails with CAT_E_TRANX_FAILED, it may be due
  1705. // to a stale connection. Attempt to reconnect.
  1706. //
  1707. if((hr == CAT_E_TRANX_FAILED) || (hr == CAT_E_DBCONNECTION)) {
  1708. HRESULT hrTryAgain = S_OK;
  1709. hrTryAgain = HrInvalidateConnectionAndRetrieveNewConnection(pConn);
  1710. fTryAgain = SUCCEEDED(hrTryAgain);
  1711. if(FAILED(hrTryAgain)) {
  1712. //
  1713. // Declare a new local called hr here because the
  1714. // ERROR_LOG macro uses it
  1715. //
  1716. HRESULT hr = hrTryAgain;
  1717. ERROR_LOG_ADDR(pCCatAddr, "HrInvalidateConnectionAndRetrieveNewConnection");
  1718. }
  1719. }
  1720. if(pConn != NULL)
  1721. pConn->Release();
  1722. } while(fTryAgain);
  1723. CLEANUP:
  1724. if(FAILED(hr)) {
  1725. ErrorTrace((LPARAM)this, "failing hr %08lx", hr);
  1726. pCCatAddr->Release();
  1727. }
  1728. CatFunctLeaveEx((LPARAM)this);
  1729. return hr;
  1730. } // CStoreListResolveContext::HrLookupEntryAsync
  1731. //+------------------------------------------------------------
  1732. //
  1733. // Function: CStoreListResolveContext::Cancel
  1734. //
  1735. // Synopsis: Cancels pending lookups
  1736. //
  1737. // Arguments: NONE
  1738. //
  1739. // Returns:
  1740. // S_OK: Success
  1741. //
  1742. // History:
  1743. // jstamerj 1999/03/22 12:45:21: Created.
  1744. //
  1745. //-------------------------------------------------------------
  1746. VOID CStoreListResolveContext::Cancel()
  1747. {
  1748. CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::Cancel");
  1749. EnterCriticalSection(&m_cs);
  1750. m_fCanceled = TRUE;
  1751. m_pConn->CancelAllSearches();
  1752. LeaveCriticalSection(&m_cs);
  1753. CatFunctLeaveEx((LPARAM)this);
  1754. } // CStoreListResolveContext::HrCancel
  1755. //+------------------------------------------------------------
  1756. //
  1757. // Function: CStoreListResolveContext::AsyncLookupCompletion
  1758. //
  1759. // Synopsis: Handle completion of a CCatAddr from CSearchRequestBlock
  1760. //
  1761. // Arguments:
  1762. // pCCatAddr: the item being completed
  1763. // pConn: Connection object used to do the search
  1764. //
  1765. // Returns: NOTHING
  1766. //
  1767. // History:
  1768. // jstamerj 1999/03/22 14:37:09: Created.
  1769. // dlongley 2001/10/23: Modified.
  1770. //
  1771. //-------------------------------------------------------------
  1772. VOID CStoreListResolveContext::AsyncLookupCompletion(
  1773. CCatAddr *pCCatAddr,
  1774. CStoreListResolveContext *pslrc,
  1775. CBatchLdapConnection *pConn)
  1776. {
  1777. HRESULT hr = S_OK;
  1778. HRESULT hrStatus;
  1779. CSingleSearchReinsertionRequest *pCInsertionRequest = NULL;
  1780. CatFunctEnterEx((LPARAM)pslrc,
  1781. "CStoreListResolveContext::AsyncLookupCompletion");
  1782. _ASSERT(pCCatAddr);
  1783. hr = pCCatAddr->GetHRESULT(
  1784. ICATEGORIZERITEM_HRSTATUS,
  1785. &hrStatus);
  1786. _ASSERT(SUCCEEDED(hr));
  1787. if( SUCCEEDED(hrStatus) )
  1788. InterlockedIncrement((LPLONG) &(pslrc->m_dwcCompletedLookups));
  1789. if( (hrStatus == CAT_E_DBCONNECTION) &&
  1790. SUCCEEDED(pslrc->HrInvalidateConnectionAndRetrieveNewConnection(pConn))) {
  1791. //
  1792. // Retry the search with the new connection
  1793. //
  1794. pCInsertionRequest = new CSingleSearchReinsertionRequest(
  1795. pslrc,
  1796. pCCatAddr);
  1797. if(!pCInsertionRequest) {
  1798. hr = E_OUTOFMEMORY;
  1799. ERROR_LOG_ADDR_STATIC(
  1800. pCCatAddr,
  1801. "new CSingleSearchReinsertionRequest",
  1802. pslrc,
  1803. pslrc->GetISMTPServerEx());
  1804. pCCatAddr->LookupCompletion();
  1805. } else {
  1806. hr = pslrc->HrInsertInsertionRequest(pCInsertionRequest);
  1807. if(FAILED(hr))
  1808. {
  1809. ERROR_LOG_ADDR_STATIC(
  1810. pCCatAddr,
  1811. "pslrc->HrInsertInsertionRequest",
  1812. pslrc,
  1813. pslrc->GetISMTPServerEx());
  1814. }
  1815. //
  1816. // The insertion request destructor should call the lookup
  1817. // completion
  1818. //
  1819. pCInsertionRequest->Release();
  1820. }
  1821. } else {
  1822. pCCatAddr->LookupCompletion();
  1823. }
  1824. pCCatAddr->Release(); // Release reference count addref'd in LookupEntryAsync
  1825. CatFunctLeaveEx((LPARAM)pslrc);
  1826. } // CStoreListResolveContext::AsyncLookupCompletion
  1827. //+------------------------------------------------------------
  1828. //
  1829. // Function: CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection
  1830. //
  1831. // Synopsis: Invalidate our current connection and get a new connection
  1832. //
  1833. // Arguments:
  1834. // pConn: The old LDAP connection
  1835. // fCountAsRetry: Whether or not to increment the retry counter. We don't want to
  1836. // increment the retry counter in the case of a failed insertion request
  1837. // insertion, because that means that
  1838. //
  1839. // Returns:
  1840. // S_OK: Success
  1841. // CAT_E_MAX_RETRIES: Too many retries already
  1842. // or error from ldapconn
  1843. //
  1844. // History:
  1845. // jstamerj 1999/03/22 14:50:07: Created.
  1846. //
  1847. //-------------------------------------------------------------
  1848. HRESULT CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection(
  1849. CBatchLdapConnection *pConn,
  1850. BOOL fIncrementRetryCount)
  1851. {
  1852. HRESULT hr = S_OK;
  1853. CCfgConnection *pNewConn = NULL;
  1854. CCfgConnection *pOldConn = NULL;
  1855. DWORD dwCount;
  1856. DWORD dwcInsertionContext;
  1857. DWORD dwcCompletedLookups;
  1858. DWORD dwcRetries;
  1859. CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection");
  1860. DebugTrace((LPARAM)this, "pConn: %08lx", pConn);
  1861. EnterCriticalSection(&m_cs);
  1862. DebugTrace((LPARAM)this, "m_pConn: %08lx", (CBatchLdapConnection *)m_pConn);
  1863. if(pConn != m_pConn) {
  1864. DebugTrace((LPARAM)this, "Connection already invalidated");
  1865. //
  1866. // We have already invalidated this connection
  1867. //
  1868. LeaveCriticalSection(&m_cs);
  1869. hr = S_OK;
  1870. goto CLEANUP;
  1871. }
  1872. DebugTrace((LPARAM)this, "Invalidating conn %08lx",
  1873. (CBatchLdapConnection *)m_pConn);
  1874. pOldConn = m_pConn;
  1875. pOldConn->Invalidate();
  1876. dwcCompletedLookups = (DWORD) InterlockedExchange((LPLONG) &m_dwcCompletedLookups, 0);
  1877. if( fIncrementRetryCount ) {
  1878. if( dwcCompletedLookups > 0 ) {
  1879. InterlockedExchange((LPLONG) &m_dwcRetries, 0);
  1880. dwcRetries = 0;
  1881. } else {
  1882. dwcRetries = (DWORD) InterlockedIncrement((LPLONG) &m_dwcRetries);
  1883. }
  1884. } else {
  1885. dwcRetries = 0;
  1886. }
  1887. if( dwcRetries > CBatchLdapConnection::m_nMaxConnectionRetries ) {
  1888. LogSLRCFailure(CBatchLdapConnection::m_nMaxConnectionRetries, pOldConn->GetHostName());
  1889. ErrorTrace((LPARAM)this, "Over max retry limit");
  1890. LeaveCriticalSection(&m_cs);
  1891. pOldConn->CancelAllSearches();
  1892. hr = CAT_E_MAX_RETRIES;
  1893. goto CLEANUP;
  1894. } else {
  1895. hr = m_pStore->HrGetConnection(
  1896. &pNewConn);
  1897. if(FAILED(hr)) {
  1898. LeaveCriticalSection(&m_cs);
  1899. ERROR_LOG("m_pStore->HrGetConnection");
  1900. pOldConn->CancelAllSearches();
  1901. goto CLEANUP;
  1902. }
  1903. LogSLRCFailover(dwcRetries, pOldConn->GetHostName(), pNewConn->GetHostName());
  1904. DebugTrace((LPARAM)this, "pNewConn: %08lx", pNewConn);
  1905. //
  1906. // Switch-a-roo
  1907. //
  1908. m_pConn = pNewConn;
  1909. DebugTrace((LPARAM)this, "m_dwcInsertionContext: %08lx",
  1910. m_dwcInsertionContext);
  1911. //
  1912. // Get insertion contexts on the new connection
  1913. //
  1914. dwcInsertionContext = m_dwcInsertionContext;
  1915. for(dwCount = 0;
  1916. dwCount < dwcInsertionContext;
  1917. dwCount++) {
  1918. pNewConn->GetInsertionContext();
  1919. }
  1920. LeaveCriticalSection(&m_cs);
  1921. pOldConn->CancelAllSearches();
  1922. //
  1923. // Release insertion contexts on the old connection
  1924. //
  1925. for(dwCount = 0;
  1926. dwCount < dwcInsertionContext;
  1927. dwCount++) {
  1928. pOldConn->ReleaseInsertionContext();
  1929. }
  1930. pOldConn->Release();
  1931. }
  1932. CLEANUP:
  1933. DebugTrace((LPARAM)this, "returning %08lx", hr);
  1934. CatFunctLeaveEx((LPARAM)this);
  1935. return hr;
  1936. } // CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection
  1937. //+------------------------------------------------------------
  1938. //
  1939. // Function: CBatchLdapConnection::HrInsertInsertionRequest
  1940. //
  1941. // Synopsis: Queues an insertion request
  1942. //
  1943. // Arguments: pCInsertionRequest: the insertion context to queue up
  1944. //
  1945. // Returns:
  1946. // S_OK: Success
  1947. //
  1948. // History:
  1949. // jstamerj 1999/03/24 16:51:10: Created.
  1950. //
  1951. //-------------------------------------------------------------
  1952. HRESULT CBatchLdapConnection::HrInsertInsertionRequest(
  1953. CInsertionRequest *pCInsertionRequest)
  1954. {
  1955. HRESULT hr = S_OK;
  1956. CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::HrInsertInsertionRequest");
  1957. //
  1958. // Add this thing to the queue and then call
  1959. // DecrementPendingSearches to dispatch available requests
  1960. //
  1961. pCInsertionRequest->AddRef();
  1962. if ( pCInsertionRequest->IsBatchable() )
  1963. GetInsertionContext();
  1964. AcquireSpinLock(&m_spinlock_insertionrequests);
  1965. if( IsValid() ) {
  1966. InsertTailList(&m_listhead_insertionrequests,
  1967. &(pCInsertionRequest->m_listentry_insertionrequest));
  1968. } else {
  1969. hr = CAT_E_DBCONNECTION;
  1970. }
  1971. ReleaseSpinLock(&m_spinlock_insertionrequests);
  1972. if(hr == CAT_E_DBCONNECTION) {
  1973. ERROR_LOG("IsValid");
  1974. }
  1975. if( hr == S_OK ) {
  1976. DecrementPendingSearches(0); // Decrement zero searches
  1977. } else {
  1978. if ( pCInsertionRequest->IsBatchable() )
  1979. ReleaseInsertionContext();
  1980. pCInsertionRequest->Release();
  1981. }
  1982. CatFunctLeaveEx((LPARAM)this);
  1983. return hr;
  1984. } // CBatchLdapConnection::HrInsertInsertionRequest
  1985. //+------------------------------------------------------------
  1986. //
  1987. // Function: CBatchLdapConnection::DecrementPendingSearches
  1988. //
  1989. // Synopsis: Decrement the pending LDAP search count and issue
  1990. // searches if we are below MAX_PENDING_SEARCHES and items
  1991. // are left in the InsertionRequestQueue
  1992. //
  1993. // Arguments:
  1994. // dwcSearches: Amount to decrement by
  1995. //
  1996. // Returns: NOTHING
  1997. //
  1998. // History:
  1999. // jstamerj 1999/03/24 17:09:38: Created.
  2000. //
  2001. //-------------------------------------------------------------
  2002. VOID CBatchLdapConnection::DecrementPendingSearches(
  2003. DWORD dwcSearches)
  2004. {
  2005. HRESULT hr;
  2006. DWORD dwcSearchesToDecrement = dwcSearches;
  2007. DWORD dwcSearchesReserved;
  2008. CInsertionRequest *pCInsertionRequest = NULL;
  2009. BOOL fLoop = TRUE;
  2010. CANCELNOTIFY cn;
  2011. BOOL fDispatchBlocks = FALSE;
  2012. DWORD dwMinimumRequiredSearches = 1;
  2013. CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::DecrementPendingSearches");
  2014. //
  2015. // The module that calls us (CStoreListResolve) has a reference to
  2016. // us (obviously). However, it may release us when a search
  2017. // fails, for example inside of
  2018. // pCInsertionRequest->HrInsertSearches(). Since we need to
  2019. // continue to access member data in this situation, AddRef() here
  2020. // and Release() at the end of this function.
  2021. //
  2022. AddRef();
  2023. //
  2024. // Decrement the count first
  2025. //
  2026. AcquireSpinLock(&m_spinlock_insertionrequests);
  2027. m_dwcPendingSearches -= dwcSearchesToDecrement;
  2028. if (m_fDPS_Was_Here) {
  2029. fLoop = FALSE;
  2030. } else {
  2031. m_fDPS_Was_Here = TRUE;
  2032. }
  2033. ReleaseSpinLock(&m_spinlock_insertionrequests);
  2034. //
  2035. // Now dispatch any insertion requests we can dispatch
  2036. //
  2037. while(fLoop) {
  2038. pCInsertionRequest = NULL;
  2039. AcquireSpinLock(&m_spinlock_insertionrequests);
  2040. if( IsValid() &&
  2041. (m_dwcPendingSearches < m_nMaxPendingSearches) &&
  2042. (!IsListEmpty(&m_listhead_insertionrequests)) ) {
  2043. dwcSearchesReserved = m_nMaxPendingSearches - m_dwcPendingSearches;
  2044. pCInsertionRequest = CONTAINING_RECORD(
  2045. m_listhead_insertionrequests.Flink,
  2046. CInsertionRequest,
  2047. m_listentry_insertionrequest);
  2048. _ASSERT(pCInsertionRequest);
  2049. dwMinimumRequiredSearches = pCInsertionRequest->GetMinimumRequiredSearches();
  2050. _ASSERT(dwMinimumRequiredSearches > 0);
  2051. if(dwMinimumRequiredSearches > m_nMaxPendingSearches) {
  2052. dwMinimumRequiredSearches = m_nMaxPendingSearches;
  2053. }
  2054. if(m_dwcPendingSearches + dwMinimumRequiredSearches > m_nMaxPendingSearches) {
  2055. pCInsertionRequest = NULL;
  2056. fDispatchBlocks = TRUE;
  2057. } else {
  2058. RemoveEntryList(m_listhead_insertionrequests.Flink);
  2059. //
  2060. // Insert a cancel-Notify structure so that we know if we
  2061. // should cancel this insertion request (ie. not reinsert)
  2062. //
  2063. cn.hrCancel = S_OK;
  2064. InsertTailList(&m_listhead_cancelnotifies, &(cn.le));
  2065. }
  2066. }
  2067. if(!pCInsertionRequest) {
  2068. //
  2069. // There are no requests or no room to insert
  2070. // requests...Break out of the loop
  2071. //
  2072. fLoop = FALSE;
  2073. m_fDPS_Was_Here = FALSE;
  2074. }
  2075. ReleaseSpinLock(&m_spinlock_insertionrequests);
  2076. if(pCInsertionRequest) {
  2077. //
  2078. // Dispatch up to dwcSearchesReserved searches
  2079. //
  2080. hr = pCInsertionRequest->HrInsertSearches(dwcSearchesReserved);
  2081. if(FAILED(hr)) {
  2082. if(FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS))) {
  2083. ERROR_LOG("pCInsertionRequest->HrInsertSearches");
  2084. }
  2085. pCInsertionRequest->NotifyDeQueue(hr);
  2086. if ( pCInsertionRequest->IsBatchable() )
  2087. ReleaseInsertionContext();
  2088. pCInsertionRequest->Release();
  2089. AcquireSpinLock(&m_spinlock_insertionrequests);
  2090. //
  2091. // Remove the cancel notify
  2092. //
  2093. RemoveEntryList(&(cn.le));
  2094. ReleaseSpinLock(&m_spinlock_insertionrequests);
  2095. } else {
  2096. //
  2097. // There is more work to be done in this block; insert it
  2098. // back into the queue
  2099. //
  2100. AcquireSpinLock(&m_spinlock_insertionrequests);
  2101. //
  2102. // Remove the cancel notify
  2103. //
  2104. RemoveEntryList(&(cn.le));
  2105. //
  2106. // If we are NOT cancelling, then insert back into the queue
  2107. //
  2108. if(cn.hrCancel == S_OK) {
  2109. InsertHeadList(&m_listhead_insertionrequests,
  2110. &(pCInsertionRequest->m_listentry_insertionrequest));
  2111. }
  2112. ReleaseSpinLock(&m_spinlock_insertionrequests);
  2113. //
  2114. // If we are cancelling, then release this insertion request
  2115. //
  2116. if(cn.hrCancel != S_OK) {
  2117. pCInsertionRequest->NotifyDeQueue(cn.hrCancel);
  2118. if ( pCInsertionRequest->IsBatchable() )
  2119. ReleaseInsertionContext();
  2120. pCInsertionRequest->Release();
  2121. }
  2122. }
  2123. }
  2124. }
  2125. if(fDispatchBlocks) {
  2126. //
  2127. // X5:197905. We call DispatchBlocks now to avoid a deadlock where
  2128. // there is a partially filled batch and there are batchable insertion
  2129. // requests in the queue that prevent it from being dispatched, but
  2130. // the next insertion request in the queue is not batchable and
  2131. // requires a minimum number of searches that is greater than the max
  2132. // pending will allow, given that some of the available searches are
  2133. // (dormantly) consumed by the partially filled batch.
  2134. //
  2135. LIST_ENTRY listhead_dispatch;
  2136. AcquireSpinLock(&m_spinlock);
  2137. //
  2138. // Remove all blocks from the insertion list and put them in the dispatch list
  2139. //
  2140. if(IsListEmpty(&m_listhead)) {
  2141. //
  2142. // No blocks
  2143. //
  2144. ReleaseSpinLock(&m_spinlock);
  2145. } else {
  2146. InsertTailList(&m_listhead, &listhead_dispatch);
  2147. RemoveEntryList(&m_listhead);
  2148. InitializeListHead(&m_listhead);
  2149. ReleaseSpinLock(&m_spinlock);
  2150. //
  2151. // Dispatch all the blocks
  2152. //
  2153. DispatchBlocks(&listhead_dispatch);
  2154. }
  2155. }
  2156. Release();
  2157. CatFunctLeaveEx((LPARAM)this);
  2158. } // CBatchLdapConnection::DecrementPendingSearches
  2159. //+------------------------------------------------------------
  2160. //
  2161. // Function: CBatchLdapConnection::CancelAllSearches
  2162. //
  2163. // Synopsis: Cancels all outstanding searches
  2164. //
  2165. // Arguments:
  2166. // hr: optinal reason for cancelling the searches
  2167. //
  2168. // Returns: NOTHING
  2169. //
  2170. // History:
  2171. // jstamerj 1999/03/25 11:44:30: Created.
  2172. //
  2173. //-------------------------------------------------------------
  2174. VOID CBatchLdapConnection::CancelAllSearches(
  2175. HRESULT hr)
  2176. {
  2177. LIST_ENTRY listhead;
  2178. PLIST_ENTRY ple;
  2179. CInsertionRequest *pCInsertionRequest;
  2180. CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::CancelAllSearches");
  2181. _ASSERT(hr != S_OK);
  2182. AcquireSpinLock(&m_spinlock_insertionrequests);
  2183. //
  2184. // Grab the list
  2185. //
  2186. if(!IsListEmpty(&m_listhead_insertionrequests)) {
  2187. CopyMemory(&listhead, &m_listhead_insertionrequests, sizeof(LIST_ENTRY));
  2188. listhead.Flink->Blink = &listhead;
  2189. listhead.Blink->Flink = &listhead;
  2190. InitializeListHead(&m_listhead_insertionrequests);
  2191. } else {
  2192. InitializeListHead(&listhead);
  2193. }
  2194. //
  2195. // Traverse the cancel notify list and set each hresult
  2196. //
  2197. for(ple = m_listhead_cancelnotifies.Flink;
  2198. ple != &m_listhead_cancelnotifies;
  2199. ple = ple->Flink) {
  2200. PCANCELNOTIFY pcn;
  2201. pcn = CONTAINING_RECORD(ple, CANCELNOTIFY, le);
  2202. pcn->hrCancel = hr;
  2203. }
  2204. ReleaseSpinLock(&m_spinlock_insertionrequests);
  2205. CCachedLdapConnection::CancelAllSearches(hr);
  2206. for(ple = listhead.Flink;
  2207. ple != &listhead;
  2208. ple = listhead.Flink) {
  2209. pCInsertionRequest = CONTAINING_RECORD(
  2210. ple,
  2211. CInsertionRequest,
  2212. m_listentry_insertionrequest);
  2213. RemoveEntryList(&(pCInsertionRequest->m_listentry_insertionrequest));
  2214. pCInsertionRequest->NotifyDeQueue(hr);
  2215. if (pCInsertionRequest->IsBatchable() )
  2216. ReleaseInsertionContext();
  2217. pCInsertionRequest->Release();
  2218. }
  2219. CatFunctLeaveEx((LPARAM)this);
  2220. } // CBatchLdapConnection::CancelAllSearches
  2221. //+------------------------------------------------------------
  2222. //
  2223. // Function: CStoreListResolveContext::GetConnection
  2224. //
  2225. // Synopsis: AddRef/return the current connection
  2226. //
  2227. // Arguments: NONE
  2228. //
  2229. // Returns: Connection pointer
  2230. //
  2231. // History:
  2232. // jstamerj 1999/06/21 12:14:50: Created.
  2233. //
  2234. //-------------------------------------------------------------
  2235. CCfgConnection * CStoreListResolveContext::GetConnection()
  2236. {
  2237. CCfgConnection *ret;
  2238. EnterCriticalSection(&m_cs);
  2239. ret = m_pConn;
  2240. if(ret)
  2241. ret->AddRef();
  2242. LeaveCriticalSection(&m_cs);
  2243. return ret;
  2244. } // CStoreListResolveContext::GetConnection
  2245. //+------------------------------------------------------------
  2246. //
  2247. // Function: CStoreListResolveContext::GetInsertionContext
  2248. //
  2249. // Synopsis:
  2250. //
  2251. // Arguments:
  2252. //
  2253. // Returns:
  2254. // S_OK: Success
  2255. //
  2256. // History:
  2257. // jstamerj 1999/06/21 12:16:38: Created.
  2258. //
  2259. //-------------------------------------------------------------
  2260. VOID CStoreListResolveContext::GetInsertionContext()
  2261. {
  2262. EnterCriticalSection(&m_cs);
  2263. InterlockedIncrement((PLONG) &m_dwcInsertionContext);
  2264. m_pConn->GetInsertionContext();
  2265. LeaveCriticalSection(&m_cs);
  2266. } // CStoreListResolveContext::GetInsertionContext
  2267. //+------------------------------------------------------------
  2268. //
  2269. // Function: CStoreListResolveContext::ReleaseInsertionContext
  2270. //
  2271. // Synopsis:
  2272. //
  2273. // Arguments:
  2274. //
  2275. // Returns:
  2276. // S_OK: Success
  2277. //
  2278. // History:
  2279. // jstamerj 1999/06/21 12:16:48: Created.
  2280. //
  2281. //-------------------------------------------------------------
  2282. VOID CStoreListResolveContext::ReleaseInsertionContext()
  2283. {
  2284. EnterCriticalSection(&m_cs);
  2285. InterlockedDecrement((PLONG) &m_dwcInsertionContext);
  2286. m_pConn->ReleaseInsertionContext();
  2287. LeaveCriticalSection(&m_cs);
  2288. } // CStoreListResolveContext::ReleaseInsertionContext
  2289. //+------------------------------------------------------------
  2290. //
  2291. // Function: CStoreListResolveContext::HrInsertInsertionRequest
  2292. //
  2293. // Synopsis:
  2294. //
  2295. // Arguments:
  2296. //
  2297. // Returns:
  2298. // S_OK: Success
  2299. //
  2300. // History:
  2301. // jstamerj 1999/06/21 12:20:19: Created.
  2302. //
  2303. //-------------------------------------------------------------
  2304. HRESULT CStoreListResolveContext::HrInsertInsertionRequest(
  2305. CInsertionRequest *pCInsertionRequest)
  2306. {
  2307. HRESULT hr = S_OK;
  2308. BOOL fTryAgain;
  2309. CatFunctEnterEx((LPARAM)this,
  2310. "CStoreListResolveContext::HrInsertInsertionRequest");
  2311. do {
  2312. fTryAgain = FALSE;
  2313. CBatchLdapConnection *pConn;
  2314. pConn = GetConnection();
  2315. //
  2316. // Insert the search request into the CBatchLdapConnection
  2317. // object. We will use the email address as the distinguishing
  2318. // attribute
  2319. //
  2320. if( pConn == NULL ) {
  2321. hr = CAT_E_DBCONNECTION;
  2322. if(FAILED(hr)) {
  2323. ERROR_LOG("GetConnection");
  2324. }
  2325. } else {
  2326. hr = m_pConn->HrInsertInsertionRequest(pCInsertionRequest);
  2327. if(FAILED(hr)) {
  2328. ERROR_LOG("m_pConn->HrInsertInsertionRequest");
  2329. }
  2330. }
  2331. //
  2332. // Attempt to reconnect.
  2333. //
  2334. if( hr == CAT_E_DBCONNECTION ) {
  2335. HRESULT hrTryAgain = S_OK;
  2336. hrTryAgain =
  2337. HrInvalidateConnectionAndRetrieveNewConnection(pConn, FALSE);
  2338. fTryAgain = SUCCEEDED(hrTryAgain);
  2339. if(FAILED(hrTryAgain)) {
  2340. //
  2341. // Declare a new local called hr here because the
  2342. // ERROR_LOG macro uses it
  2343. //
  2344. HRESULT hr = hrTryAgain;
  2345. ERROR_LOG("HrInvalidateConnectionAndRetrieveNewConnection");
  2346. }
  2347. }
  2348. if(pConn != NULL)
  2349. pConn->Release();
  2350. } while(fTryAgain);
  2351. CatFunctLeaveEx((LPARAM)this);
  2352. return hr;
  2353. } // CStoreListResolveContext::HrInsertInsertionRequest
  2354. //+------------------------------------------------------------
  2355. //
  2356. // Function: CStoreListResolveContext::LogSLRCFailure
  2357. //
  2358. // Synopsis: Log a failure for the SLRC (over max retry limit)
  2359. //
  2360. // Arguments:
  2361. // dwcRetries: Number of times we've retried
  2362. // pszHost: The last host that failed
  2363. //
  2364. // Returns: nothing
  2365. //
  2366. // History:
  2367. // jstamerj 2001/12/13 00:24:07: Created.
  2368. //
  2369. //-------------------------------------------------------------
  2370. VOID CStoreListResolveContext::LogSLRCFailure(
  2371. IN DWORD dwcRetries,
  2372. IN LPSTR pszHost)
  2373. {
  2374. LPCSTR rgSubStrings[2];
  2375. CHAR szRetries[32];
  2376. _snprintf(szRetries, sizeof(szRetries), "%d", dwcRetries);
  2377. rgSubStrings[0] = szRetries;
  2378. rgSubStrings[1] = pszHost;
  2379. CatLogEvent(
  2380. GetISMTPServerEx(),
  2381. CAT_EVENT_SLRC_FAILURE,
  2382. 2,
  2383. rgSubStrings,
  2384. S_OK,
  2385. pszHost,
  2386. LOGEVENT_FLAG_ALWAYS,
  2387. LOGEVENT_LEVEL_FIELD_ENGINEERING);
  2388. }
  2389. //+------------------------------------------------------------
  2390. //
  2391. // Function: CStoreListResolveContext::LogSLRCFailover
  2392. //
  2393. // Synopsis: Log a failover event
  2394. //
  2395. // Arguments:
  2396. // dwcRetries: Number of retires so far
  2397. // pszOldHost: Old LDAP host
  2398. // pszNewHost: New LDAP host
  2399. //
  2400. // Returns: nothing
  2401. //
  2402. // History:
  2403. // jstamerj 2001/12/13 00:24:18: Created.
  2404. //
  2405. //-------------------------------------------------------------
  2406. VOID CStoreListResolveContext::LogSLRCFailover(
  2407. IN DWORD dwcRetries,
  2408. IN LPSTR pszOldHost,
  2409. IN LPSTR pszNewHost)
  2410. {
  2411. LPCSTR rgSubStrings[3];
  2412. CHAR szRetries[32];
  2413. _snprintf(szRetries, sizeof(szRetries), "%d", dwcRetries);
  2414. rgSubStrings[0] = pszOldHost;
  2415. rgSubStrings[1] = pszNewHost;
  2416. rgSubStrings[2] = szRetries;
  2417. CatLogEvent(
  2418. GetISMTPServerEx(),
  2419. CAT_EVENT_SLRC_FAILOVER,
  2420. 3,
  2421. rgSubStrings,
  2422. S_OK,
  2423. pszOldHost,
  2424. LOGEVENT_FLAG_ALWAYS,
  2425. LOGEVENT_LEVEL_FIELD_ENGINEERING);
  2426. }
  2427. //+------------------------------------------------------------
  2428. //
  2429. // Function: CSingleSearchReinsertionRequest::HrInsertSearches
  2430. //
  2431. // Synopsis: reinsert a request for a single search
  2432. //
  2433. // Arguments:
  2434. // dwcSearches: Number of searches we may insert
  2435. //
  2436. // Returns:
  2437. // S_OK: Success
  2438. // HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)
  2439. //
  2440. // History:
  2441. // dlongley 2001/10/22: Created.
  2442. //
  2443. //-------------------------------------------------------------
  2444. HRESULT CSingleSearchReinsertionRequest::HrInsertSearches(
  2445. DWORD dwcSearches)
  2446. {
  2447. HRESULT hr = S_OK;
  2448. CatFunctEnterEx((LPARAM)this, "CSingleSearchReinsertionRequest::HrInsertSearches");
  2449. if( (m_dwcSearches == 0) && (dwcSearches > 0) ) {
  2450. hr = m_pslrc->HrLookupEntryAsync(m_pCCatAddr);
  2451. if(FAILED(hr)) {
  2452. ERROR_LOG_ADDR(m_pCCatAddr, "m_pslrc->HrLookupEntryAsync");
  2453. m_hr = hr;
  2454. } else {
  2455. m_dwcSearches = 1;
  2456. }
  2457. }
  2458. if(SUCCEEDED(hr))
  2459. hr = (m_dwcSearches == 1 ? HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) : S_OK);
  2460. DebugTrace((LPARAM)this, "returning %08lx", hr);
  2461. CatFunctLeaveEx((LPARAM)this);
  2462. return hr;
  2463. } // CSingleSearchReinsertionRequest::HrInsertSearches
  2464. //+------------------------------------------------------------
  2465. //
  2466. // Function: CSingleSearchReinsertionRequest::NotifyDeQueue
  2467. //
  2468. // Synopsis: Callback to notify us that our request is being removed
  2469. // from the store's queue
  2470. //
  2471. // Arguments: NONE
  2472. //
  2473. // Returns: NOTHING
  2474. //
  2475. // History:
  2476. // dlongley 2001/10/22: Created.
  2477. //
  2478. //-------------------------------------------------------------
  2479. VOID CSingleSearchReinsertionRequest::NotifyDeQueue(
  2480. HRESULT hrReason)
  2481. {
  2482. HRESULT hr;
  2483. CatFunctEnterEx((LPARAM)this, "CSingleSearchReinsertionRequest::NotifyDeQueue");
  2484. //
  2485. // If we still have things left to resolve, reinsert this
  2486. // insertion request
  2487. //
  2488. hr = hrReason;
  2489. if( SUCCEEDED(m_hr) && (m_dwcSearches == 0) && !(m_pslrc->Canceled()) ) {
  2490. if( (hr == CAT_E_DBCONNECTION) ||
  2491. (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) ) {
  2492. hr = m_pslrc->HrInsertInsertionRequest(this);
  2493. if(FAILED(hr)) {
  2494. ERROR_LOG_ADDR(m_pCCatAddr, "m_pslrc->HrInsertInsertionRequest");
  2495. }
  2496. }
  2497. }
  2498. CatFunctLeaveEx((LPARAM)this);
  2499. } // CSingleSearchReinsertionRequest::NotifyDeQueue