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.

1414 lines
37 KiB

  1. // File: ldap.cpp
  2. #include "precomp.h"
  3. #include "resource.h"
  4. #include "mapidefs.h"
  5. #include "pfnwldap.h"
  6. #include "ldap.h"
  7. #include "wab.h"
  8. #include "dirutil.h"
  9. #include "dlgcall2.h" // for WM_DISPLAY_MESSAGE
  10. #include "upropdlg.h"
  11. #define CDIRCACHE_IMAGES 3
  12. // static strings
  13. static const TCHAR s_szSearchFormat3[] = TEXT("(&(objectClass=RTPerson)(cn=%s)%s)");
  14. static const TCHAR s_szSearchFormat2[] = TEXT("(&(objectClass=RTPerson)(cn=%s)(sappid=ms-netmeeting)(sprotid=h323)%s)");
  15. static const TCHAR s_szSearchCategory[] = TEXT("(ILSA39321630=%d)");
  16. static LPCTSTR s_pszOrg = TEXT("o=Microsoft");
  17. static const TCHAR s_cszAttribShow[] = TEXT("sFlags"); // "Hide Me" (1=Show, 0=Hidden)
  18. static const TCHAR s_cszAttribEmail[] = TEXT("cn"); // Email address
  19. static const TCHAR s_cszAttribFirstName[] = TEXT("givenName"); // First Name
  20. static const TCHAR s_cszAttribLastName[] = TEXT("surName"); // Last Name
  21. static const TCHAR s_cszAttribLocation[] = TEXT("location"); // Location
  22. static const TCHAR s_cszAttribComment[] = TEXT("comment"); // Comments
  23. static const TCHAR s_cszAttribInACall[] = TEXT("ilsA26214430"); // 400 = in a call
  24. static const TCHAR s_cszAttribVersion[] = TEXT("ilsA26279966"); // 401 = version number
  25. static const TCHAR s_cszAttribAudio[] = TEXT("ilsA32833566"); // 501 = send audio
  26. static const TCHAR s_cszAttribVideo[] = TEXT("ilsA32964638"); // 503 = send video
  27. static const TCHAR s_cszAttribCategory[] = TEXT("ilsA39321630"); // 600 = category
  28. static LPCTSTR s_rgAttrNameAddr[] = {
  29. (LPTSTR) s_cszAttribShow,
  30. (LPTSTR) s_cszAttribEmail,
  31. (LPTSTR) s_cszAttribFirstName,
  32. (LPTSTR) s_cszAttribLastName,
  33. (LPTSTR) s_cszAttribLocation,
  34. (LPTSTR) s_cszAttribInACall,
  35. (LPTSTR) s_cszAttribAudio,
  36. (LPTSTR) s_cszAttribVideo,
  37. (LPTSTR) s_cszAttribComment,
  38. NULL};
  39. static LPCTSTR s_rgAttrAll[] = {
  40. (LPTSTR) s_cszAttribFirstName,
  41. (LPTSTR) s_cszAttribLastName,
  42. (LPTSTR) s_cszAttribComment,
  43. (LPTSTR) s_cszAttribAudio,
  44. (LPTSTR) s_cszAttribVideo,
  45. (LPTSTR) s_cszAttribVersion,
  46. (LPTSTR) s_cszAttribCategory,
  47. NULL};
  48. static const int _rgIdMenu[] = {
  49. IDM_DLGCALL_SPEEDDIAL,
  50. IDM_DLGCALL_WAB,
  51. -1,
  52. IDM_DLGCALL_REFRESH,
  53. IDM_DLGCALL_STOP,
  54. 0
  55. };
  56. // Local functions
  57. VOID ConvertVersionInfo(LPTSTR pszVersion, LPTSTR pszCategory);
  58. ///////////////////////////////////////////////////////////////////////
  59. CLDAP::CLDAP() :
  60. CALV(0, II_SERVER, _rgIdMenu),
  61. m_pLdap(NULL),
  62. m_ulPort(DEFAULT_LDAP_PORT),
  63. m_msgId(0),
  64. m_hThread(NULL),
  65. m_hWnd( NULL ),
  66. m_hSearchMutex( NULL ),
  67. m_fDirInProgress( FALSE ),
  68. m_cTotalEntries( 0 ),
  69. m_cEntries( 0 ),
  70. m_fHaveRefreshed( FALSE ),
  71. m_dwTickStart( 0 ),
  72. m_fIsCacheable( FALSE ),
  73. m_fNeedsRefresh( FALSE ),
  74. m_bSearchCancelled( false ),
  75. m_uniqueId( 0 )
  76. {
  77. DbgMsg(iZONE_OBJECTS, "CLDAP - Constructed(%08X)", this);
  78. HRESULT hr = WLDAP::Init();
  79. SetAvailable(S_OK == hr);
  80. m_szServer[0] = _T('\0');
  81. m_szAddress[0] = _T('\0');
  82. m_hSearchMutex = CreateMutex( NULL, false, NULL );
  83. RegEntry reUI(UI_KEY, HKEY_CURRENT_USER);
  84. m_fCacheDirectory = (0 != reUI.GetNumber(
  85. REGVAL_CACHE_DIRECTORY, DEFAULT_CACHE_DIRECTORY));
  86. m_cMinutesExpire = reUI.GetNumber(
  87. REGVAL_CACHE_DIRECTORY_EXPIRATION, DEFAULT_CACHE_DIRECTORY_EXPIRATION);
  88. }
  89. CLDAP::~CLDAP()
  90. {
  91. CloseServer();
  92. if (NULL != m_hThread)
  93. {
  94. WARNING_OUT(("CLDAP - waiting for AsyncSearch Thread to exit (start)"));
  95. WaitForSingleObject(m_hThread, 10000); // 10 seconds max
  96. WARNING_OUT(("CLDAP - waiting for AsyncSearch to exit (end)"));
  97. }
  98. if( m_hSearchMutex )
  99. {
  100. CloseHandle( m_hSearchMutex );
  101. }
  102. // Free any cached data
  103. while (!m_listDirCache.IsEmpty())
  104. {
  105. DIRCACHE * pDirCache = (DIRCACHE *) m_listDirCache.RemoveHead();
  106. ASSERT(NULL != pDirCache);
  107. FreeDirCache(pDirCache);
  108. }
  109. DbgMsg(iZONE_OBJECTS, "CLDAP - Destroyed(%08X)", this);
  110. }
  111. ///////////////////////////////////////////////////////////////////////////
  112. // CALV methods
  113. /* S H O W I T E M S */
  114. /*-------------------------------------------------------------------------
  115. %%Function: ShowItems
  116. -------------------------------------------------------------------------*/
  117. VOID CLDAP::ShowItems(HWND hwnd)
  118. {
  119. DBGENTRY(CLDAP::ShowItems);
  120. m_hWnd = hwnd;
  121. SetWindow( hwnd ); // set in base class too...
  122. CALV::ClearItems();
  123. DisplayDirectory();
  124. DBGEXIT(CLDAP::ShowItems);
  125. }
  126. /* C L E A R I T E M S */
  127. /*-------------------------------------------------------------------------
  128. %%Function: ClearItems
  129. -------------------------------------------------------------------------*/
  130. VOID CLDAP::ClearItems(void)
  131. {
  132. DBGENTRY( CLDAP::ClearItems );
  133. StopSearch();
  134. DBGEXIT( CLDAP::ClearItems );
  135. }
  136. /* virtual */
  137. RAI * CLDAP::GetAddrInfo(void)
  138. {
  139. DBGENTRY(CLDAP::GetAddrInfo);
  140. int selectedItem = CALV::GetSelection();
  141. RAI * pRai = NULL;
  142. if( selectedItem != -1 )
  143. {
  144. if( (pRai = new RAI) != NULL )
  145. {
  146. pRai->cItems = 1;
  147. pRai->rgDwStr->dw = NM_ADDR_ULS;
  148. GetSzName( pRai->szName, CCHMAX( pRai->szName ), selectedItem );
  149. TCHAR buffer[ CCHMAXSZ ];
  150. GetSzAddress( buffer, CCHMAX( buffer ),selectedItem );
  151. pRai->rgDwStr->psz = PszAlloc( buffer );
  152. }
  153. }
  154. DBGEXIT(CLDAP::GetAddrInfo);
  155. return( pRai );
  156. }
  157. /* G E T S Z A D D R E S S */
  158. /*-------------------------------------------------------------------------
  159. %%Function: GetSzAddress
  160. -------------------------------------------------------------------------*/
  161. BOOL CLDAP::GetSzAddress(LPTSTR psz, int cchMax, int iItem)
  162. {
  163. DBGENTRY(CLDAP::GetSzAddress);
  164. BOOL bRet = TRUE;
  165. int cch = lstrlen(m_szServer);
  166. if ((cch+2) < cchMax)
  167. {
  168. lstrcpy(psz, m_szServer);
  169. psz += cch;
  170. *psz++ = _T('/');
  171. cchMax -= (cch+1);
  172. bRet = CALV::GetSzData( psz, cchMax, iItem, COLUMN_INDEX_ADDRESS );
  173. }
  174. else
  175. {
  176. bRet = FALSE;
  177. }
  178. DBGEXIT(CLDAP::GetSzAddress);
  179. return bRet;
  180. }
  181. /* O N C O M M A N D */
  182. /*-------------------------------------------------------------------------
  183. %%Function: OnCommand
  184. -------------------------------------------------------------------------*/
  185. VOID CLDAP::OnCommand(WPARAM wParam, LPARAM lParam)
  186. {
  187. switch (GET_WM_COMMAND_ID(wParam, lParam))
  188. {
  189. case IDM_DLGCALL_STOP:
  190. StopSearch();
  191. break;
  192. case IDM_DLGCALL_REFRESH:
  193. if (NULL == m_hThread)
  194. {
  195. CALV::ClearItems();
  196. StartSearch();
  197. }
  198. break;
  199. case IDM_DLGCALL_WAB:
  200. CmdAddToWab();
  201. break;
  202. default:
  203. CALV::OnCommand(wParam, lParam);
  204. break;
  205. }
  206. }
  207. /* C M D P R O P E R T I E S */
  208. /*-------------------------------------------------------------------------
  209. %%Function: CmdProperties
  210. -------------------------------------------------------------------------*/
  211. VOID CLDAP::CmdProperties(void)
  212. {
  213. DBGENTRY(CLDAP::CmdProperties);
  214. DWORD dwThID;
  215. HANDLE hThread = CreateThread(NULL, 0, _sAsyncPropertyThreadFn,
  216. (LPVOID) this, 0, &dwThID);
  217. CloseHandle(hThread);
  218. DBGEXIT(CLDAP::CmdProperties);
  219. }
  220. DWORD CALLBACK CLDAP::_sAsyncPropertyThreadFn(LPVOID pv)
  221. {
  222. DBGENTRY(CLDAP::_sAsyncPropertyThreadFn);
  223. CLDAP * pThis = (CLDAP *) pv;
  224. ASSERT(NULL != pThis);
  225. pThis->ShowProperties();
  226. DBGEXIT(CLDAP::_sAsyncPropertyThreadFn);
  227. return 0;
  228. }
  229. VOID CLDAP::ShowProperties(void)
  230. {
  231. DBGENTRY(CLDAP::ShowProperties);
  232. SetBusyCursor(TRUE);
  233. LDAPUSERDATA ldapUserData;
  234. BOOL fOk = FGetUserData(&ldapUserData);
  235. SetBusyCursor(FALSE);
  236. if (!fOk)
  237. return;
  238. TCHAR szHasHardware[CCHMAXSZ];
  239. FLoadString(IDS_HARDWARE_DETECTED, szHasHardware, CCHMAX(szHasHardware));
  240. TCHAR szNoHardware[CCHMAXSZ];
  241. FLoadString(IDS_NO_HARDWARE_DETECTED, szNoHardware, CCHMAX(szNoHardware));
  242. UPROPDLGENTRY rgProp[] = {
  243. {IDS_UPROP_EMAIL, ldapUserData.szEmail},
  244. {IDS_UPROP_COMMENTS, ldapUserData.szComment},
  245. {IDS_UPROP_VIDEO, ldapUserData.fVideoSend ? szHasHardware : szNoHardware},
  246. {IDS_UPROP_AUDIO, ldapUserData.fAudioSend ? szHasHardware : szNoHardware},
  247. {IDS_UPROP_VERSION, ldapUserData.szVersion},
  248. };
  249. CUserPropertiesDlg dlgUserProp(GetHwnd(), IDI_LARGE);
  250. dlgUserProp.DoModal(rgProp, ARRAY_ELEMENTS(rgProp), ldapUserData.szName, NULL);
  251. DBGEXIT(CLDAP::ShowProperties);
  252. }
  253. /* C M D A D D T O W A B */
  254. /*-------------------------------------------------------------------------
  255. %%Function: CmdAddToWab
  256. -------------------------------------------------------------------------*/
  257. VOID CLDAP::CmdAddToWab(void)
  258. {
  259. DBGENTRY(CLDAP::CmdAddToWab);
  260. LDAPUSERDATA ldapUserData;
  261. if (!FGetUserData(&ldapUserData))
  262. return;
  263. CreateWabEntry(ldapUserData.szName, ldapUserData.szFirst, ldapUserData.szLast, ldapUserData.szEmail,
  264. NULL, NULL, ldapUserData.szComment, m_szServer);
  265. DBGEXIT(CLDAP::CmdAddToWab);
  266. }
  267. ///////////////////////////////////////////////////////////////////////////
  268. /* S E T S E R V E R */
  269. /*-------------------------------------------------------------------------
  270. %%Function: SetServer
  271. -------------------------------------------------------------------------*/
  272. VOID CLDAP::SetServer(LPCTSTR pcszServer)
  273. {
  274. DBGENTRY(CLDAP::SetServer);
  275. if ((0 != lstrcmpi(m_szServer, pcszServer)) || (DEFAULT_LDAP_PORT != m_ulPort))
  276. {
  277. CloseServer();
  278. int cch;
  279. LPCTSTR pszSeparator = _StrChr(pcszServer, _T(':'));
  280. if (NULL != pszSeparator)
  281. {
  282. cch = (pszSeparator - pcszServer) + 1;
  283. if (cch >= CCHMAX(m_szAddress))
  284. return;
  285. m_ulPort = DecimalStringToUINT(pszSeparator + 1);
  286. }
  287. else
  288. {
  289. cch = CCHMAX(m_szAddress);
  290. m_ulPort = DEFAULT_LDAP_PORT;
  291. }
  292. // save the information before changing the server name
  293. CacheServerData();
  294. lstrcpyn(m_szAddress, pcszServer, cch);
  295. lstrcpyn(m_szServer, pcszServer, CCHMAX(m_szServer));
  296. }
  297. DBGEXIT(CLDAP::SetServer);
  298. }
  299. /* D I R E C T O R Y S T A R T */
  300. /*-------------------------------------------------------------------------
  301. %%Function: DirectoryStart
  302. Initiate directory request
  303. -------------------------------------------------------------------------*/
  304. VOID CLDAP::StartSearch(void)
  305. {
  306. DBGENTRY(CLDAP::StartSearch);
  307. if (NULL == m_hThread)
  308. {
  309. DWORD dwThID;
  310. AddRef();
  311. m_bSearchCancelled = false;
  312. HANDLE hThread = CreateThread(NULL, 0, _sAsyncSearchThreadFn,
  313. (LPVOID) this, CREATE_SUSPENDED, &dwThID);
  314. if (NULL != hThread)
  315. {
  316. m_hThread = hThread;
  317. ResumeThread(hThread);
  318. }
  319. else
  320. {
  321. Release();
  322. }
  323. }
  324. DBGEXIT(CLDAP::StartSearch);
  325. }
  326. DWORD CALLBACK CLDAP::_sAsyncSearchThreadFn(LPVOID pv)
  327. {
  328. DBGENTRY(CLDAP::_sAsyncSearchThreadFn);
  329. CLDAP * pThis = (CLDAP *) pv;
  330. ASSERT(NULL != pThis);
  331. pThis->AsyncSearch();
  332. pThis->Release();
  333. DBGEXIT(CLDAP::_sAsyncSearchThreadFn);
  334. return 0;
  335. }
  336. VOID CLDAP::AsyncSearch(void)
  337. {
  338. DBGENTRY(CLDAP::AsyncSearch);
  339. HRESULT hr;
  340. WARNING_OUT(("AsyncSearch Started"));
  341. ASSERT(NULL != m_hThread);
  342. SetBusyCursor(TRUE);
  343. // We can not call EnableWindow() from this thread as it av's some of the time. This is a
  344. // known windows bug. It also doesn't really solve the problem (#4726) it was put in here
  345. // to solve anyway. We will work around this in a future build by re-architecting this so
  346. // this little helper thread doesn't mess with the ui at all. It is problematic and very
  347. // inefficient anyway.
  348. // ::EnableWindow(GetDlgItem(GetParent(GetHwnd()), IDM_DLGCALL_REFRESH), FALSE);
  349. m_fDirInProgress = TRUE;
  350. m_dwTickStart = ::GetTickCount();
  351. m_uniqueId = 0;
  352. if( SUCCEEDED( WaitWithMessageLoop( m_hSearchMutex ) ) )
  353. {
  354. if (!FAvailable())
  355. {
  356. hr = E_ACCESSDENIED;
  357. }
  358. else if (!FOpenServer())
  359. {
  360. CloseServer();
  361. hr = E_FAIL;
  362. }
  363. else
  364. {
  365. hr = DoQuery();
  366. }
  367. SetBusyCursor(FALSE); // This should be moved outside the if so it is always executed...
  368. // We can not call EnableWindow() from this thread as it av's some of the time. This is a
  369. // known windows bug. It also doesn't really solve the problem (#4726) it was put in here
  370. // to solve anyway. We will work around this in a future build by re-architecting this so
  371. // this little helper thread doesn't mess with the ui at all. It is problematic and very
  372. // inefficient anyway.
  373. // ::EnableWindow(GetDlgItem(GetParent(GetHwnd()), IDM_DLGCALL_REFRESH), TRUE);
  374. HWND hwnd = GetHwnd();
  375. if (-1 == ListView_GetNextItem(hwnd, -1, LVNI_ALL | LVNI_FOCUSED))
  376. {
  377. // No selection - set focus to the first item
  378. ListView_SetItemState(hwnd, 0, LVIS_FOCUSED, LVIS_FOCUSED);
  379. }
  380. ReleaseMutex( m_hSearchMutex );
  381. if (FAILED(hr))
  382. {
  383. PostMessage(GetParent(hwnd), WM_DISPLAY_MSG, IDS_ULSLOGON_ERROR, 0);
  384. }
  385. WARNING_OUT(("AsyncSearch Complete"));
  386. // Close the thread handle safely
  387. HANDLE hThread = m_hThread;
  388. m_hThread = NULL;
  389. CloseHandle(hThread);
  390. }
  391. if (m_fDirInProgress)
  392. {
  393. // Only cache if data took more than 2 seconds to retrieve
  394. m_fIsCacheable = ((::GetTickCount() - m_dwTickStart) > 2000);
  395. m_fDirInProgress = FALSE;
  396. }
  397. DBGEXIT(CLDAP::AsyncSearch);
  398. }
  399. ///////////////////////////////////////////////////////////////////////////
  400. /* F O P E N S E R V E R */
  401. /*-------------------------------------------------------------------------
  402. %%Function: FOpenServer
  403. Make sure the connection to the LDAP server is open
  404. -------------------------------------------------------------------------*/
  405. BOOL CLDAP::FOpenServer(void)
  406. {
  407. DBGENTRY(CLDAP::FOpenServer);
  408. BOOL bRet = TRUE;
  409. if( NULL == m_pLdap )
  410. {
  411. if( m_bSearchCancelled )
  412. {
  413. bRet = FALSE;
  414. }
  415. else
  416. {
  417. WARNING_OUT(("Opening Server [%s] Port [%d]", m_szAddress, m_ulPort));
  418. m_pLdap = WLDAP::ldap_open(m_szAddress, m_ulPort);
  419. if( (m_pLdap == NULL) && (m_ulPort == DEFAULT_LDAP_PORT) )
  420. {
  421. m_pLdap = WLDAP::ldap_open(m_szAddress, ALTERNATE_LDAP_PORT); // Automatically retry with alternate port...
  422. if( m_pLdap != NULL )
  423. {
  424. m_ulPort = ALTERNATE_LDAP_PORT;
  425. }
  426. }
  427. if(NULL != m_pLdap)
  428. {
  429. LONG lTimeOut = 30; // seconds for timeout
  430. WLDAP::ldap_set_option(m_pLdap, LDAP_OPT_TIMELIMIT, &lTimeOut);
  431. // Defaults to ILS 2
  432. ASSERT(LDAP_VERSION2 == m_pLdap->ld_version);
  433. ULONG ulRet = WLDAP::ldap_simple_bind_s(m_pLdap, NULL, NULL);
  434. WARNING_OUT(("Logon [%s] complete", m_szServer));
  435. }
  436. else
  437. {
  438. WARNING_OUT(("ldap_open err=%d", GetLastError()));
  439. return FALSE;
  440. }
  441. }
  442. }
  443. DBGEXIT(CLDAP::FOpenServer);
  444. return bRet;
  445. }
  446. /* C L O S E S E R V E R */
  447. /*-------------------------------------------------------------------------
  448. %%Function: CloseServer
  449. -------------------------------------------------------------------------*/
  450. VOID CLDAP::CloseServer(void)
  451. {
  452. DBGENTRY(CLDAP::CloseServer);
  453. if(m_pLdap)
  454. {
  455. StopSearch();
  456. if( SUCCEEDED( WaitWithMessageLoop( m_hSearchMutex ) ) )
  457. {
  458. WLDAP::ldap_unbind(m_pLdap);
  459. m_pLdap = NULL;
  460. ReleaseMutex( m_hSearchMutex );
  461. }
  462. WARNING_OUT(("Logoff [%s] complete", m_szServer));
  463. }
  464. }
  465. /* G E T N E X T A T T R I B U T E */
  466. /*-------------------------------------------------------------------------
  467. %%Function: GetNextAttribute
  468. -------------------------------------------------------------------------*/
  469. LPTSTR CLDAP::GetNextAttribute(LPCTSTR pszExpect, LPTSTR psz, int cchMax, LPTSTR pszAttrib, LDAPMessage * pEntry, BerElement * pElement)
  470. {
  471. DBGENTRY(CLDAP::GetNextAttribute);
  472. ASSERT(NULL != psz);
  473. if ((NULL == pszAttrib) || (0 != lstrcmpi(pszAttrib, pszExpect)))
  474. {
  475. *psz = _T('\0');
  476. }
  477. else
  478. {
  479. LPTSTR * rgVal = WLDAP::ldap_get_values(m_pLdap, pEntry, pszAttrib);
  480. if( rgVal[0] )
  481. {
  482. lstrcpyn(psz, rgVal[0], cchMax);
  483. }
  484. else
  485. {
  486. psz[0] = _T('\0');
  487. }
  488. WLDAP::ldap_value_free(rgVal);
  489. pszAttrib = WLDAP::ldap_next_attribute(m_pLdap, pEntry, pElement);
  490. }
  491. DBGEXIT(CLDAP::GetNextAttribute);
  492. return pszAttrib;
  493. }
  494. /* D O Q U E R Y */
  495. /*-------------------------------------------------------------------------
  496. %%Function: DoQuery
  497. -------------------------------------------------------------------------*/
  498. HRESULT CLDAP::DoQuery(void)
  499. {
  500. DBGENTRY(CLDAP::DoQuery);
  501. HRESULT hr = S_FALSE;
  502. ASSERT(FLoggedOn());
  503. TCHAR szSearch[MAX_PATH];
  504. ASSERT(CCHMAX(s_szSearchFormat3) + CCHMAX(s_szSearchCategory) < CCHMAX(szSearch));
  505. ASSERT(CCHMAX(s_szSearchFormat2) + CCHMAX(s_szSearchCategory) < CCHMAX(szSearch));
  506. if( !m_bSearchCancelled )
  507. {
  508. wsprintf(szSearch,
  509. (LDAP_VERSION2 == m_pLdap->ld_version) ? s_szSearchFormat2 : s_szSearchFormat3,
  510. (LDAP_VERSION2 == m_pLdap->ld_version) ? TEXT("%") : TEXT("*"), _T(""));
  511. ASSERT(lstrlen(szSearch) < CCHMAX(szSearch));
  512. ASSERT(0 == m_msgId); // one search at a time
  513. m_msgId = WLDAP::ldap_search(m_pLdap, (PCHAR) "objectClass=RTPerson", LDAP_SCOPE_BASE,
  514. szSearch, (PCHAR *) s_rgAttrNameAddr, 0);
  515. if( m_msgId == -1 )
  516. {
  517. m_msgId = 0;
  518. hr = E_FAIL;
  519. }
  520. else
  521. {
  522. SendMessage( m_hWnd, WM_SETREDRAW, FALSE, 0 );
  523. while( (0 != m_msgId) && (!m_bSearchCancelled) )
  524. {
  525. LDAP_TIMEVAL timeOut = {2, 0};
  526. LDAPMessage * pResult = NULL;
  527. WARNING_OUT(("DoQuery calling ldap_result"));
  528. int iResult = WLDAP::ldap_result(m_pLdap, m_msgId, 0, &timeOut, &pResult);
  529. WARNING_OUT( ("DoQuery back from ldap_result: 0x%08X", iResult) );
  530. if (0 == iResult)
  531. {
  532. SendMessage( m_hWnd, WM_SETREDRAW, TRUE, 0 );
  533. UpdateWindow( m_hWnd );
  534. SendMessage( m_hWnd, WM_SETREDRAW, FALSE, 0 );
  535. continue;
  536. }
  537. if (LDAP_RES_SEARCH_ENTRY != iResult)
  538. {
  539. // S_FALSE = abandoned
  540. // hr = (-1 == iResult) ? S_OK : S_FALSE;
  541. hr = (-1 == iResult) ? E_FAIL : S_FALSE;
  542. break;
  543. }
  544. AddEntries(pResult);
  545. WLDAP::ldap_msgfree(pResult);
  546. }
  547. SendMessage( m_hWnd, WM_SETREDRAW, TRUE, 0 );
  548. m_msgId = 0;
  549. DirComplete( TRUE );
  550. forceSort();
  551. }
  552. }
  553. DBGEXIT(CLDAP::DoQuery);
  554. return hr;
  555. }
  556. /* A D D E N T R I E S */
  557. /*-------------------------------------------------------------------------
  558. %%Function: AddEntries
  559. Add the Entries to the listbox. (Data ordered by s_rgAttrNameAddr.)
  560. -------------------------------------------------------------------------*/
  561. VOID CLDAP::AddEntries(LDAPMessage * pResult)
  562. {
  563. DBGENTRY(CLDAP::AddEntries);
  564. LDAPMessage * pEntry;
  565. BerElement * pElement;
  566. for (pEntry = WLDAP::ldap_first_entry(m_pLdap, pResult);
  567. NULL != pEntry;
  568. pEntry = WLDAP::ldap_next_entry(m_pLdap, pEntry))
  569. {
  570. LPTSTR pszAttrib = WLDAP::ldap_first_attribute(m_pLdap, pEntry, &pElement);
  571. if (NULL == pszAttrib)
  572. break;
  573. // Must have a "Show Me" attribute
  574. if (0 != lstrcmpi(pszAttrib, s_cszAttribShow))
  575. continue;
  576. LPTSTR * rgVal = WLDAP::ldap_get_values(m_pLdap, pEntry, pszAttrib);
  577. BOOL fShow = (_T('1') == *rgVal[0]);
  578. WLDAP::ldap_value_free(rgVal);
  579. if (!fShow)
  580. continue;
  581. pszAttrib = WLDAP::ldap_next_attribute(m_pLdap, pEntry, pElement);
  582. TCHAR szEmail[CCHMAXSZ_EMAIL];
  583. pszAttrib = GetNextAttribute(s_cszAttribEmail, szEmail, CCHMAX(szEmail),
  584. pszAttrib, pEntry, pElement);
  585. TCHAR szFirstName[CCHMAXSZ_FIRSTNAME];
  586. pszAttrib = GetNextAttribute(s_cszAttribFirstName, szFirstName, CCHMAX(szFirstName),
  587. pszAttrib, pEntry, pElement);
  588. TCHAR szLastName[CCHMAXSZ_LASTNAME];
  589. pszAttrib = GetNextAttribute(s_cszAttribLastName, szLastName, CCHMAX(szLastName),
  590. pszAttrib, pEntry, pElement);
  591. TCHAR szLocation[CCHMAXSZ_LASTNAME];
  592. pszAttrib = GetNextAttribute(s_cszAttribLocation, szLocation, CCHMAX(szLocation),
  593. pszAttrib, pEntry, pElement);
  594. TCHAR szTemp[4];
  595. pszAttrib = GetNextAttribute(s_cszAttribInACall, szTemp, CCHMAX(szTemp),
  596. pszAttrib, pEntry, pElement);
  597. int iInCallImage = (szTemp[0] == _T('1')) ? II_IN_A_CALL : II_COMPUTER;
  598. pszAttrib = GetNextAttribute(s_cszAttribAudio, szTemp, CCHMAX(szTemp),
  599. pszAttrib, pEntry, pElement);
  600. int iAudioImage = (szTemp[0] == _T('1')) ? II_AUDIO_CAPABLE : 0;
  601. pszAttrib = GetNextAttribute(s_cszAttribVideo, szTemp, CCHMAX(szTemp),
  602. pszAttrib, pEntry, pElement);
  603. int iVideoImage = (szTemp[0] == _T('1')) ? II_VIDEO_CAPABLE : 0;
  604. TCHAR szComment[CCHMAXSZ_COMMENT];
  605. pszAttrib = GetNextAttribute(s_cszAttribComment, szComment, CCHMAX(szComment),
  606. pszAttrib, pEntry, pElement);
  607. lvAddItem( 0, iInCallImage, iAudioImage, iVideoImage, szEmail, szFirstName, szLastName, szLocation, szComment );
  608. }
  609. DBGEXIT(CLDAP::AddEntries);
  610. }
  611. //--------------------------------------------------------------------------//
  612. // CLDAP::lvAddItem. //
  613. //--------------------------------------------------------------------------//
  614. int
  615. CLDAP::lvAddItem
  616. (
  617. int item,
  618. int iInCallImage,
  619. int iAudioImage,
  620. int iVideoImage,
  621. LPCTSTR address,
  622. LPCTSTR firstName,
  623. LPCTSTR lastName,
  624. LPCTSTR location,
  625. LPCTSTR comments
  626. ){
  627. LV_ITEM lvItem;
  628. ClearStruct( &lvItem );
  629. lvItem.mask = LVIF_PARAM;
  630. lvItem.iItem = item;
  631. lvItem.lParam = m_uniqueId++; // assign a unique lParam for this item
  632. int index = ListView_InsertItem( m_hWnd, &lvItem );
  633. if( index != -1 )
  634. {
  635. if( lastName )
  636. {
  637. ListView_SetItemText( m_hWnd, index, COLUMN_INDEX_LAST_NAME, (LPTSTR) lastName );
  638. }
  639. if( firstName )
  640. {
  641. ListView_SetItemText( m_hWnd, index, COLUMN_INDEX_FIRST_NAME, (LPTSTR) firstName );
  642. }
  643. if( iAudioImage != 0 )
  644. {
  645. lvItem.mask = LVIF_IMAGE;
  646. lvItem.iSubItem = COLUMN_INDEX_AUDIO;
  647. lvItem.iImage = iAudioImage;
  648. ListView_SetItem( m_hWnd, &lvItem );
  649. }
  650. if( iVideoImage != 0 )
  651. {
  652. lvItem.mask = LVIF_IMAGE;
  653. lvItem.iSubItem = COLUMN_INDEX_VIDEO;
  654. lvItem.iImage = iVideoImage;
  655. ListView_SetItem( m_hWnd, &lvItem );
  656. }
  657. if( address )
  658. {
  659. lvItem.mask = LVIF_IMAGE | LVIF_TEXT;
  660. lvItem.iSubItem = COLUMN_INDEX_ADDRESS;
  661. lvItem.iImage = iInCallImage;
  662. lvItem.pszText = (LPTSTR) address;
  663. lvItem.cchTextMax = lstrlen( lvItem.pszText );
  664. ListView_SetItem( m_hWnd, &lvItem );
  665. }
  666. if( location )
  667. {
  668. ListView_SetItemText( m_hWnd, index, COLUMN_INDEX_LOCATION, (LPTSTR) location );
  669. }
  670. if( comments )
  671. {
  672. ListView_SetItemText( m_hWnd, index, COLUMN_INDEX_COMMENTS, (LPTSTR) comments );
  673. }
  674. }
  675. return( index );
  676. } // End of CLDAP::lvAddItem.
  677. /* S T O P S E A R C H */
  678. /*-------------------------------------------------------------------------
  679. %%Function: StopSearch
  680. -------------------------------------------------------------------------*/
  681. VOID CLDAP::StopSearch(void)
  682. {
  683. DBGENTRY(CLDAP::StopSearch);
  684. m_bSearchCancelled = true;
  685. if (0 != m_msgId)
  686. {
  687. // Dont call ldap_abandon() from this thread as the search thread may be inside ldap_result()
  688. // at the time. For now just set m_msgId to zero and the search thread will stop when ldap_result()
  689. // returns.
  690. // ULONG uResult = WLDAP::ldap_abandon(m_pLdap, m_msgId);
  691. WARNING_OUT(("Stopping Search..."));
  692. m_msgId = 0;
  693. m_fDirInProgress = FALSE;
  694. m_fIsCacheable = FALSE;
  695. DirComplete(FALSE);
  696. }
  697. DBGEXIT(CLDAP::StopSearch);
  698. }
  699. /* F G E T U S E R D A T A */
  700. /*-------------------------------------------------------------------------
  701. %%Function: FGetUserData
  702. Get the data for a single user.
  703. -------------------------------------------------------------------------*/
  704. BOOL CLDAP::FGetUserData(LDAPUSERDATA * pLdapUserData)
  705. {
  706. DBGENTRY(CLDAP::FGetUserData);
  707. ClearStruct(pLdapUserData);
  708. if (!FLoggedOn())
  709. {
  710. DBGEXIT(CLDAP::FGetUserData);
  711. return FALSE;
  712. }
  713. int iItem = CALV::GetSelection();
  714. if (-1 == iItem)
  715. {
  716. DBGEXIT(CLDAP::FGetUserData);
  717. return FALSE;
  718. }
  719. if (!GetSzData(pLdapUserData->szEmail, CCHMAX(pLdapUserData->szEmail), iItem, COLUMN_INDEX_ADDRESS))
  720. {
  721. DBGEXIT(CLDAP::FGetUserData);
  722. return FALSE;
  723. }
  724. TCHAR szSearch[CCHMAX(s_szSearchFormat2) + CCHMAXSZ_EMAIL];
  725. wsprintf(szSearch,
  726. (LDAP_VERSION2 == m_pLdap->ld_version) ? s_szSearchFormat2 : s_szSearchFormat3,
  727. pLdapUserData->szEmail, g_cszEmpty);
  728. ASSERT(lstrlen(szSearch) < CCHMAX(szSearch));
  729. LDAPMessage * pResult = NULL;
  730. ULONG ulRet = WLDAP::ldap_search_s(m_pLdap, (LPTSTR) "objectClass=RTPerson", LDAP_SCOPE_BASE,
  731. szSearch, (PCHAR *) s_rgAttrAll, FALSE, &pResult);
  732. if (LDAP_SUCCESS != ulRet)
  733. {
  734. WLDAP::ldap_msgfree(pResult);
  735. WARNING_OUT(("ldap_search (code=%08X)", ulRet));
  736. DBGEXIT(CLDAP::FGetUserData);
  737. return FALSE;
  738. }
  739. LDAPMessage * pEntry = WLDAP::ldap_first_entry(m_pLdap, pResult);
  740. if (NULL != pEntry)
  741. {
  742. BerElement * pElement;
  743. LPTSTR pszAttrib = WLDAP::ldap_first_attribute(m_pLdap, pEntry, &pElement);
  744. // Make sure that the first attribute is s_cszAttribFirstName...
  745. if ((NULL != pszAttrib) && (0 == lstrcmpi(pszAttrib, s_cszAttribFirstName)))
  746. {
  747. LPTSTR * rgVal = WLDAP::ldap_get_values(m_pLdap, pEntry, pszAttrib);
  748. WLDAP::ldap_value_free(rgVal);
  749. // pszAttrib = WLDAP::ldap_next_attribute(m_pLdap, pEntry, pElement);
  750. pszAttrib = GetNextAttribute(s_cszAttribFirstName,
  751. pLdapUserData->szFirst, CCHMAX(pLdapUserData->szFirst),
  752. pszAttrib, pEntry, pElement);
  753. pszAttrib = GetNextAttribute(s_cszAttribLastName,
  754. pLdapUserData->szLast, CCHMAX(pLdapUserData->szLast),
  755. pszAttrib, pEntry, pElement);
  756. CombineNames(pLdapUserData->szName, CCHMAX(pLdapUserData->szName),
  757. pLdapUserData->szFirst, pLdapUserData->szLast);
  758. pszAttrib = GetNextAttribute(s_cszAttribComment,
  759. pLdapUserData->szComment, CCHMAX(pLdapUserData->szComment),
  760. pszAttrib, pEntry, pElement);
  761. TCHAR szTemp[4];
  762. pszAttrib = GetNextAttribute(s_cszAttribAudio, szTemp, CCHMAX(szTemp),
  763. pszAttrib, pEntry, pElement);
  764. pLdapUserData->fAudioSend = _T('1') == szTemp[0];
  765. pszAttrib = GetNextAttribute(s_cszAttribVideo, szTemp, CCHMAX(szTemp),
  766. pszAttrib, pEntry, pElement);
  767. pLdapUserData->fVideoSend = _T('1') == szTemp[0];
  768. pszAttrib = GetNextAttribute(s_cszAttribVersion,
  769. pLdapUserData->szVersion, CCHMAX(pLdapUserData->szVersion),
  770. pszAttrib, pEntry, pElement);
  771. pszAttrib = GetNextAttribute(s_cszAttribCategory, szTemp, CCHMAX(szTemp),
  772. pszAttrib, pEntry, pElement);
  773. ConvertVersionInfo(pLdapUserData->szVersion, szTemp);
  774. }
  775. }
  776. WLDAP::ldap_msgfree(pResult);
  777. DBGEXIT(CLDAP::FGetUserData);
  778. return TRUE;
  779. }
  780. /* C O N V E R T V E R S I O N I N F O */
  781. /*-------------------------------------------------------------------------
  782. %%Function: ConvertVersionInfo
  783. -------------------------------------------------------------------------*/
  784. VOID ConvertVersionInfo(LPTSTR pszVersion, LPTSTR pszCategory)
  785. {
  786. UINT uVer = DecimalStringToUINT(pszVersion);
  787. if (0 == uVer)
  788. {
  789. lstrcpy(pszVersion, FEmptySz(pszCategory) ? TEXT("1.0") : TEXT("2"));
  790. }
  791. else
  792. {
  793. LPCTSTR pszRel;
  794. switch (LOBYTE(HIWORD(uVer)))
  795. {
  796. case 3: pszRel = TEXT("2.11"); break;
  797. case 4: pszRel = TEXT("3.0"); break;
  798. case 5: pszRel = TEXT("4.0"); break;
  799. default: pszRel = g_cszEmpty; break;
  800. }
  801. TCHAR szFormat[CCHMAXSZ];
  802. FLoadString(IDS_FORMAT_VERSION, szFormat, CCHMAX(szFormat));
  803. wsprintf(pszVersion, szFormat, pszRel,
  804. HIBYTE(HIWORD(uVer)), LOBYTE(HIWORD(uVer)), LOWORD(uVer));
  805. }
  806. }
  807. //--------------------------------------------------------------------------//
  808. // CLDAP::FreeDirCache. //
  809. //--------------------------------------------------------------------------//
  810. void
  811. CLDAP::FreeDirCache
  812. (
  813. DIRCACHE * pDirCache
  814. ){
  815. TRACE_OUT(("FreeDirCache [%s] filter=%d, expire=%d",
  816. pDirCache->pszServer, pDirCache->dwTickExpire));
  817. ASSERT(NULL != pDirCache);
  818. PBYTE pb = pDirCache->pData;
  819. delete pDirCache->pszServer;
  820. delete pDirCache;
  821. while (NULL != pb)
  822. {
  823. PBYTE pTemp = pb;
  824. pb = (PBYTE) * (DWORD_PTR *) pb;
  825. delete pTemp;
  826. }
  827. } // End of CLDAP::FreeDirCache.
  828. //--------------------------------------------------------------------------//
  829. // CLDAP::FreeDirCache. //
  830. //--------------------------------------------------------------------------//
  831. void
  832. CLDAP::DirComplete
  833. (
  834. bool //fPostUiUpdate
  835. ){
  836. if( m_fDirInProgress )
  837. {
  838. // Only cache if data took more than 2 seconds to retrieve
  839. m_fIsCacheable = ((::GetTickCount() - m_dwTickStart) > 2000);
  840. m_fDirInProgress = FALSE;
  841. }
  842. m_cTotalEntries = 0;
  843. m_cEntries = 0;
  844. } // End of CLDAP:DirComplete.
  845. //--------------------------------------------------------------------------//
  846. // CLDAP::GetSzName. //
  847. //--------------------------------------------------------------------------//
  848. BOOL
  849. CLDAP::GetSzName
  850. (
  851. LPTSTR psz,
  852. int cchMax,
  853. int iItem
  854. ){
  855. TCHAR szOrder[ MAX_PATH ];
  856. bool bFirstNameFirst = ((::LoadString( ::GetInstanceHandle(), IDS_NAME_ORDER, szOrder, CCHMAX(szOrder)) == 0) ||
  857. (_T( '1' ) == szOrder[ 1 ]));
  858. int iFirst = bFirstNameFirst? COLUMN_INDEX_FIRST_NAME: COLUMN_INDEX_LAST_NAME;
  859. int iLast = bFirstNameFirst? COLUMN_INDEX_LAST_NAME: COLUMN_INDEX_FIRST_NAME;
  860. GetSzData( psz, cchMax, iItem, iFirst );
  861. int length = lstrlen( psz );
  862. if( (length > 0) && (length < cchMax - 1) )
  863. {
  864. lstrcat( psz, TEXT( " " ) );
  865. length++;
  866. }
  867. GetSzData( &psz[ length ], cchMax - length, iItem, iLast );
  868. return( lstrlen( psz ) > 0 );
  869. } // End of CLDAP::GetSzName.
  870. static const int CDIRCACHE_SZ = 5; // number of strings
  871. static const int CDIRCACHE_IMAGE = 3; // number of images
  872. //--------------------------------------------------------------------------//
  873. // CLDAP::CacheServerData. //
  874. //--------------------------------------------------------------------------//
  875. void
  876. CLDAP::CacheServerData(void)
  877. {
  878. DIRCACHE * pDirCache;
  879. if (!m_fCacheDirectory)
  880. return; // User disabled directory caching
  881. if (!m_fIsCacheable)
  882. {
  883. TRACE_OUT(("CacheServerData: not caching [%s]", m_szServer));
  884. return;
  885. }
  886. if (m_fDirInProgress)
  887. return; // don't cache partial data
  888. // Remove any previous cached data
  889. POSITION pos = FindCachedData();
  890. if (NULL != pos)
  891. {
  892. pDirCache = (DIRCACHE *) m_listDirCache.RemoveAt(pos);
  893. ASSERT(NULL != pDirCache);
  894. FreeDirCache(pDirCache);
  895. }
  896. DWORD dwTickExpire = m_dwTickStart + (m_cMinutesExpire * 60000);
  897. if (dwTickExpire < GetTickCount())
  898. {
  899. TRACE_OUT(("CacheServerData: [%s] data has expired", m_szServer));
  900. return; // data is already expired
  901. }
  902. int cItems = ListView_GetItemCount(m_hWnd);
  903. if (0 == cItems)
  904. return; // nothing to cache
  905. pDirCache = new DIRCACHE;
  906. if (NULL == pDirCache)
  907. return;
  908. pDirCache->pszServer = PszAlloc(m_szServer);
  909. pDirCache->dwTickExpire = dwTickExpire;
  910. pDirCache->pData = NULL;
  911. LPTSTR pPrev = (LPTSTR) &pDirCache->pData;
  912. m_listDirCache.AddTail(pDirCache);
  913. LV_ITEM lvi;
  914. lvi.cchTextMax = MAX_PATH;
  915. for (lvi.iItem = 0; lvi.iItem < cItems; lvi.iItem++)
  916. {
  917. int iInCallImage = -1;
  918. int iAudioImage = -1;
  919. int iVideoImage = -1;
  920. int i = 0; // index into rgcb, rgsz
  921. int cb = 0; // total length of string data
  922. int rgcb[CDIRCACHE_SZ]; // size of each string
  923. TCHAR rgsz[CDIRCACHE_SZ][MAX_PATH]; // string buffers
  924. // Get the string data for each column
  925. lvi.mask = LVIF_IMAGE;
  926. for (lvi.iSubItem = 0; lvi.iSubItem < MAX_DIR_COLUMNS; lvi.iSubItem++)
  927. {
  928. if( (lvi.iSubItem != COLUMN_INDEX_AUDIO) && (lvi.iSubItem != COLUMN_INDEX_VIDEO) )
  929. {
  930. lvi.mask |= LVIF_TEXT;
  931. lvi.pszText = rgsz[i];
  932. ListView_GetItem(m_hWnd, &lvi);
  933. rgcb[i] = lstrlen(lvi.pszText);
  934. cb += rgcb[i] + 1; // Plus one for the NULL...
  935. i++;
  936. if( lvi.iSubItem == COLUMN_INDEX_ADDRESS )
  937. {
  938. iInCallImage = lvi.iImage;
  939. }
  940. }
  941. else
  942. {
  943. lvi.mask &= ~LVIF_TEXT;
  944. ListView_GetItem(m_hWnd, &lvi);
  945. if( lvi.iSubItem == COLUMN_INDEX_AUDIO )
  946. {
  947. iAudioImage = lvi.iImage;
  948. }
  949. else if( lvi.iSubItem == COLUMN_INDEX_VIDEO)
  950. {
  951. iVideoImage = lvi.iImage;
  952. }
  953. }
  954. }
  955. // allocate space for: a link (DWORD), strings (cb), images (CDIRCACHE_IMAGES)
  956. PBYTE pData = new BYTE[ sizeof(DWORD_PTR) + cb + CDIRCACHE_IMAGES ];
  957. if (NULL == pData)
  958. {
  959. // can't hold all data - give up and return
  960. ClearServerCache();
  961. return;
  962. }
  963. * ((DWORD_PTR *) pData) = 0; // link to next item is null
  964. PBYTE pb = pData + sizeof(DWORD_PTR);
  965. // copy the string data into the buffer
  966. for (i = 0; i < CDIRCACHE_SZ; i++)
  967. {
  968. lstrcpy((LPTSTR) pb, rgsz[i]);
  969. pb += rgcb[i] + 1;
  970. }
  971. *pb++ = (BYTE) iInCallImage;
  972. *pb++ = (BYTE) iAudioImage;
  973. *pb = (BYTE) iVideoImage;
  974. * ((DWORD_PTR *) pPrev) = (DWORD_PTR) pData; // link into the previous data
  975. pPrev = (LPTSTR) pData;
  976. }
  977. TRACE_OUT(("CacheServerData: [%s] expire=%d",
  978. m_szServer, dwTickExpire));
  979. } // End of CLDAP::CacheServerData.
  980. //--------------------------------------------------------------------------//
  981. // CLDAP::FindCachedData. //
  982. //--------------------------------------------------------------------------//
  983. POSITION
  984. CLDAP::FindCachedData(void)
  985. {
  986. DWORD dwTick = GetTickCount();
  987. TRACE_OUT(("Searching for cached data on [%s]", m_szServer));
  988. POSITION pos = m_listDirCache.GetHeadPosition();
  989. while (NULL != pos)
  990. {
  991. POSITION posSav = pos;
  992. DIRCACHE * pDirCache = (DIRCACHE *) m_listDirCache.GetNext(pos);
  993. ASSERT(NULL != pDirCache);
  994. if ((0 == lstrcmp(m_szServer, pDirCache->pszServer)) &&
  995. (pDirCache->dwTickExpire > dwTick))
  996. {
  997. return posSav;
  998. }
  999. }
  1000. return NULL;
  1001. } // End of CLDAP::FindCachedData.
  1002. //--------------------------------------------------------------------------//
  1003. // CLDAP::ClearServerCache. //
  1004. //--------------------------------------------------------------------------//
  1005. void
  1006. CLDAP::ClearServerCache(void)
  1007. {
  1008. DWORD dwTick = GetTickCount();
  1009. POSITION pos = m_listDirCache.GetHeadPosition();
  1010. while (NULL != pos)
  1011. {
  1012. POSITION posSav = pos;
  1013. DIRCACHE * pDirCache = (DIRCACHE *) m_listDirCache.GetNext(pos);
  1014. ASSERT(NULL != pDirCache);
  1015. if ( (0 == lstrcmp(m_szServer, pDirCache->pszServer)) || (pDirCache->dwTickExpire < dwTick) )
  1016. {
  1017. m_listDirCache.RemoveAt(posSav);
  1018. FreeDirCache(pDirCache);
  1019. }
  1020. #ifdef DEBUG
  1021. else
  1022. {
  1023. TRACE_OUT(("Keeping cached data for [%s] , expire=%d",
  1024. pDirCache->pszServer, pDirCache->dwTickExpire));
  1025. }
  1026. #endif /* DEBUG */
  1027. }
  1028. } // End of CLDAP::ClearServerCache.
  1029. //--------------------------------------------------------------------------//
  1030. // CLDAP::DisplayDirectory. //
  1031. //--------------------------------------------------------------------------//
  1032. void
  1033. CLDAP::DisplayDirectory(void)
  1034. {
  1035. POSITION pos = FindCachedData();
  1036. if (NULL == pos)
  1037. {
  1038. // no cached information - request new data
  1039. StartSearch();
  1040. return;
  1041. }
  1042. DIRCACHE * pDirCache = (DIRCACHE *) m_listDirCache.GetFromPosition(pos);
  1043. ASSERT(NULL != pDirCache);
  1044. LPTSTR pDirLine = (LPTSTR) pDirCache->pData;
  1045. StopSearch(); // In case the previous server is slow
  1046. CALV::ClearItems();
  1047. m_fIsCacheable = FALSE; // don't bother attempting to re-cache this data
  1048. // Restore the cached server information
  1049. TRACE_OUT(("Restoring cached data for [%s] expire=%d",
  1050. m_szServer, pDirCache->dwTickExpire));
  1051. SendMessage( m_hWnd, WM_SETREDRAW, FALSE, 0 );
  1052. while (NULL != pDirLine)
  1053. {
  1054. DWORD_PTR *pNext = * (DWORD_PTR * * ) pDirLine; pDirLine += sizeof(DWORD_PTR);
  1055. LPTSTR pszEmail = (LPTSTR) pDirLine; pDirLine += lstrlen(pDirLine)+1;
  1056. LPTSTR pszLast = (LPTSTR) pDirLine; pDirLine += lstrlen(pDirLine)+1;
  1057. LPTSTR pszFirst = (LPTSTR) pDirLine; pDirLine += lstrlen(pDirLine)+1;
  1058. LPTSTR pszLocation = (LPTSTR) pDirLine; pDirLine += lstrlen(pDirLine)+1;
  1059. LPTSTR pszComment = (LPTSTR) pDirLine; pDirLine += lstrlen(pDirLine)+1;
  1060. int iiCall = (int) * (char *) pDirLine; pDirLine++;
  1061. int iiAudio = (int) * (char *) pDirLine; pDirLine++;
  1062. int iiVideo = (int) * (char *) pDirLine;
  1063. lvAddItem( 0, iiCall, iiAudio, iiVideo, pszEmail, pszFirst, pszLast, pszLocation, pszComment );
  1064. pDirLine = (LPTSTR) pNext;
  1065. }
  1066. forceSort();
  1067. SendMessage( m_hWnd, WM_SETREDRAW, TRUE, 0 );
  1068. } // End of CLDAP::DisplayDirectory.
  1069. //--------------------------------------------------------------------------//
  1070. // CLDAP::forceSort. //
  1071. //--------------------------------------------------------------------------//
  1072. void
  1073. CLDAP::forceSort(void)
  1074. {
  1075. NM_LISTVIEW nmlv;
  1076. nmlv.hdr.code = LVN_COLUMNCLICK;
  1077. nmlv.hdr.hwndFrom = m_hWnd;
  1078. nmlv.iSubItem = -1; // default sort column...
  1079. SendMessage( GetParent( m_hWnd ), WM_NOTIFY, GetDlgCtrlID( m_hWnd ), (LPARAM) &nmlv );
  1080. } // End of CLDAP::forceSort.
  1081. //--------------------------------------------------------------------------//
  1082. // CLDAP::GetIconId. //
  1083. //--------------------------------------------------------------------------//
  1084. int
  1085. CLDAP::GetIconId(LPCTSTR psz)
  1086. {
  1087. return( CDirectoryManager::isWebDirectory( psz )? II_WEB_DIRECTORY: CALV::GetIconId( NULL ) );
  1088. } // End of CLDAP::GetIconId.