|
|
// File: ldap.cpp
#include "precomp.h"
#include "resource.h"
#include "mapidefs.h"
#include "pfnwldap.h"
#include "ldap.h"
#include "wab.h"
#include "dirutil.h"
#include "dlgcall2.h" // for WM_DISPLAY_MESSAGE
#include "upropdlg.h"
#define CDIRCACHE_IMAGES 3
// static strings
static const TCHAR s_szSearchFormat3[] = TEXT("(&(objectClass=RTPerson)(cn=%s)%s)"); static const TCHAR s_szSearchFormat2[] = TEXT("(&(objectClass=RTPerson)(cn=%s)(sappid=ms-netmeeting)(sprotid=h323)%s)"); static const TCHAR s_szSearchCategory[] = TEXT("(ILSA39321630=%d)");
static LPCTSTR s_pszOrg = TEXT("o=Microsoft");
static const TCHAR s_cszAttribShow[] = TEXT("sFlags"); // "Hide Me" (1=Show, 0=Hidden)
static const TCHAR s_cszAttribEmail[] = TEXT("cn"); // Email address
static const TCHAR s_cszAttribFirstName[] = TEXT("givenName"); // First Name
static const TCHAR s_cszAttribLastName[] = TEXT("surName"); // Last Name
static const TCHAR s_cszAttribLocation[] = TEXT("location"); // Location
static const TCHAR s_cszAttribComment[] = TEXT("comment"); // Comments
static const TCHAR s_cszAttribInACall[] = TEXT("ilsA26214430"); // 400 = in a call
static const TCHAR s_cszAttribVersion[] = TEXT("ilsA26279966"); // 401 = version number
static const TCHAR s_cszAttribAudio[] = TEXT("ilsA32833566"); // 501 = send audio
static const TCHAR s_cszAttribVideo[] = TEXT("ilsA32964638"); // 503 = send video
static const TCHAR s_cszAttribCategory[] = TEXT("ilsA39321630"); // 600 = category
static LPCTSTR s_rgAttrNameAddr[] = { (LPTSTR) s_cszAttribShow, (LPTSTR) s_cszAttribEmail, (LPTSTR) s_cszAttribFirstName, (LPTSTR) s_cszAttribLastName, (LPTSTR) s_cszAttribLocation, (LPTSTR) s_cszAttribInACall, (LPTSTR) s_cszAttribAudio, (LPTSTR) s_cszAttribVideo, (LPTSTR) s_cszAttribComment, NULL};
static LPCTSTR s_rgAttrAll[] = { (LPTSTR) s_cszAttribFirstName, (LPTSTR) s_cszAttribLastName, (LPTSTR) s_cszAttribComment, (LPTSTR) s_cszAttribAudio, (LPTSTR) s_cszAttribVideo, (LPTSTR) s_cszAttribVersion, (LPTSTR) s_cszAttribCategory, NULL};
static const int _rgIdMenu[] = { IDM_DLGCALL_SPEEDDIAL, IDM_DLGCALL_WAB, -1, IDM_DLGCALL_REFRESH, IDM_DLGCALL_STOP, 0 };
// Local functions
VOID ConvertVersionInfo(LPTSTR pszVersion, LPTSTR pszCategory);
///////////////////////////////////////////////////////////////////////
CLDAP::CLDAP() : CALV(0, II_SERVER, _rgIdMenu), m_pLdap(NULL), m_ulPort(DEFAULT_LDAP_PORT), m_msgId(0), m_hThread(NULL), m_hWnd( NULL ), m_hSearchMutex( NULL ),
m_fDirInProgress( FALSE ), m_cTotalEntries( 0 ), m_cEntries( 0 ), m_fHaveRefreshed( FALSE ), m_dwTickStart( 0 ), m_fIsCacheable( FALSE ), m_fNeedsRefresh( FALSE ), m_bSearchCancelled( false ), m_uniqueId( 0 ) { DbgMsg(iZONE_OBJECTS, "CLDAP - Constructed(%08X)", this);
HRESULT hr = WLDAP::Init(); SetAvailable(S_OK == hr);
m_szServer[0] = _T('\0'); m_szAddress[0] = _T('\0'); m_hSearchMutex = CreateMutex( NULL, false, NULL );
RegEntry reUI(UI_KEY, HKEY_CURRENT_USER); m_fCacheDirectory = (0 != reUI.GetNumber( REGVAL_CACHE_DIRECTORY, DEFAULT_CACHE_DIRECTORY)); m_cMinutesExpire = reUI.GetNumber( REGVAL_CACHE_DIRECTORY_EXPIRATION, DEFAULT_CACHE_DIRECTORY_EXPIRATION);
}
CLDAP::~CLDAP() { CloseServer();
if (NULL != m_hThread) { WARNING_OUT(("CLDAP - waiting for AsyncSearch Thread to exit (start)")); WaitForSingleObject(m_hThread, 10000); // 10 seconds max
WARNING_OUT(("CLDAP - waiting for AsyncSearch to exit (end)")); }
if( m_hSearchMutex ) { CloseHandle( m_hSearchMutex ); }
// Free any cached data
while (!m_listDirCache.IsEmpty()) { DIRCACHE * pDirCache = (DIRCACHE *) m_listDirCache.RemoveHead(); ASSERT(NULL != pDirCache); FreeDirCache(pDirCache); }
DbgMsg(iZONE_OBJECTS, "CLDAP - Destroyed(%08X)", this); }
///////////////////////////////////////////////////////////////////////////
// CALV methods
/* S H O W I T E M S */ /*-------------------------------------------------------------------------
%%Function: ShowItems
-------------------------------------------------------------------------*/ VOID CLDAP::ShowItems(HWND hwnd) { DBGENTRY(CLDAP::ShowItems);
m_hWnd = hwnd; SetWindow( hwnd ); // set in base class too...
CALV::ClearItems(); DisplayDirectory();
DBGEXIT(CLDAP::ShowItems); }
/* C L E A R I T E M S */ /*-------------------------------------------------------------------------
%%Function: ClearItems
-------------------------------------------------------------------------*/ VOID CLDAP::ClearItems(void) { DBGENTRY( CLDAP::ClearItems );
StopSearch();
DBGEXIT( CLDAP::ClearItems ); }
/* virtual */ RAI * CLDAP::GetAddrInfo(void) { DBGENTRY(CLDAP::GetAddrInfo);
int selectedItem = CALV::GetSelection(); RAI * pRai = NULL;
if( selectedItem != -1 ) { if( (pRai = new RAI) != NULL ) { pRai->cItems = 1; pRai->rgDwStr->dw = NM_ADDR_ULS;
GetSzName( pRai->szName, CCHMAX( pRai->szName ), selectedItem );
TCHAR buffer[ CCHMAXSZ ];
GetSzAddress( buffer, CCHMAX( buffer ),selectedItem ); pRai->rgDwStr->psz = PszAlloc( buffer ); } }
DBGEXIT(CLDAP::GetAddrInfo);
return( pRai ); }
/* G E T S Z A D D R E S S */ /*-------------------------------------------------------------------------
%%Function: GetSzAddress
-------------------------------------------------------------------------*/ BOOL CLDAP::GetSzAddress(LPTSTR psz, int cchMax, int iItem) { DBGENTRY(CLDAP::GetSzAddress);
BOOL bRet = TRUE;
int cch = lstrlen(m_szServer);
if ((cch+2) < cchMax) { lstrcpy(psz, m_szServer); psz += cch; *psz++ = _T('/'); cchMax -= (cch+1);
bRet = CALV::GetSzData( psz, cchMax, iItem, COLUMN_INDEX_ADDRESS ); } else { bRet = FALSE; }
DBGEXIT(CLDAP::GetSzAddress); return bRet; }
/* O N C O M M A N D */ /*-------------------------------------------------------------------------
%%Function: OnCommand
-------------------------------------------------------------------------*/ VOID CLDAP::OnCommand(WPARAM wParam, LPARAM lParam) { switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDM_DLGCALL_STOP: StopSearch(); break; case IDM_DLGCALL_REFRESH: if (NULL == m_hThread) { CALV::ClearItems(); StartSearch(); } break; case IDM_DLGCALL_WAB: CmdAddToWab(); break; default: CALV::OnCommand(wParam, lParam); break; } }
/* C M D P R O P E R T I E S */ /*-------------------------------------------------------------------------
%%Function: CmdProperties
-------------------------------------------------------------------------*/ VOID CLDAP::CmdProperties(void) { DBGENTRY(CLDAP::CmdProperties);
DWORD dwThID;
HANDLE hThread = CreateThread(NULL, 0, _sAsyncPropertyThreadFn, (LPVOID) this, 0, &dwThID); CloseHandle(hThread);
DBGEXIT(CLDAP::CmdProperties); }
DWORD CALLBACK CLDAP::_sAsyncPropertyThreadFn(LPVOID pv) { DBGENTRY(CLDAP::_sAsyncPropertyThreadFn);
CLDAP * pThis = (CLDAP *) pv; ASSERT(NULL != pThis); pThis->ShowProperties();
DBGEXIT(CLDAP::_sAsyncPropertyThreadFn);
return 0; }
VOID CLDAP::ShowProperties(void) { DBGENTRY(CLDAP::ShowProperties);
SetBusyCursor(TRUE); LDAPUSERDATA ldapUserData; BOOL fOk = FGetUserData(&ldapUserData); SetBusyCursor(FALSE); if (!fOk) return;
TCHAR szHasHardware[CCHMAXSZ]; FLoadString(IDS_HARDWARE_DETECTED, szHasHardware, CCHMAX(szHasHardware)); TCHAR szNoHardware[CCHMAXSZ]; FLoadString(IDS_NO_HARDWARE_DETECTED, szNoHardware, CCHMAX(szNoHardware));
UPROPDLGENTRY rgProp[] = { {IDS_UPROP_EMAIL, ldapUserData.szEmail}, {IDS_UPROP_COMMENTS, ldapUserData.szComment}, {IDS_UPROP_VIDEO, ldapUserData.fVideoSend ? szHasHardware : szNoHardware}, {IDS_UPROP_AUDIO, ldapUserData.fAudioSend ? szHasHardware : szNoHardware}, {IDS_UPROP_VERSION, ldapUserData.szVersion}, };
CUserPropertiesDlg dlgUserProp(GetHwnd(), IDI_LARGE); dlgUserProp.DoModal(rgProp, ARRAY_ELEMENTS(rgProp), ldapUserData.szName, NULL);
DBGEXIT(CLDAP::ShowProperties); }
/* C M D A D D T O W A B */ /*-------------------------------------------------------------------------
%%Function: CmdAddToWab
-------------------------------------------------------------------------*/ VOID CLDAP::CmdAddToWab(void) { DBGENTRY(CLDAP::CmdAddToWab);
LDAPUSERDATA ldapUserData; if (!FGetUserData(&ldapUserData)) return;
CreateWabEntry(ldapUserData.szName, ldapUserData.szFirst, ldapUserData.szLast, ldapUserData.szEmail, NULL, NULL, ldapUserData.szComment, m_szServer);
DBGEXIT(CLDAP::CmdAddToWab); }
///////////////////////////////////////////////////////////////////////////
/* S E T S E R V E R */ /*-------------------------------------------------------------------------
%%Function: SetServer
-------------------------------------------------------------------------*/ VOID CLDAP::SetServer(LPCTSTR pcszServer) { DBGENTRY(CLDAP::SetServer);
if ((0 != lstrcmpi(m_szServer, pcszServer)) || (DEFAULT_LDAP_PORT != m_ulPort)) { CloseServer(); int cch; LPCTSTR pszSeparator = _StrChr(pcszServer, _T(':')); if (NULL != pszSeparator) { cch = (pszSeparator - pcszServer) + 1; if (cch >= CCHMAX(m_szAddress)) return; m_ulPort = DecimalStringToUINT(pszSeparator + 1); } else { cch = CCHMAX(m_szAddress); m_ulPort = DEFAULT_LDAP_PORT; }
// save the information before changing the server name
CacheServerData();
lstrcpyn(m_szAddress, pcszServer, cch); lstrcpyn(m_szServer, pcszServer, CCHMAX(m_szServer)); }
DBGEXIT(CLDAP::SetServer); }
/* D I R E C T O R Y S T A R T */ /*-------------------------------------------------------------------------
%%Function: DirectoryStart
Initiate directory request -------------------------------------------------------------------------*/ VOID CLDAP::StartSearch(void) { DBGENTRY(CLDAP::StartSearch);
if (NULL == m_hThread) { DWORD dwThID;
AddRef(); m_bSearchCancelled = false; HANDLE hThread = CreateThread(NULL, 0, _sAsyncSearchThreadFn, (LPVOID) this, CREATE_SUSPENDED, &dwThID); if (NULL != hThread) { m_hThread = hThread; ResumeThread(hThread); } else { Release(); } }
DBGEXIT(CLDAP::StartSearch); }
DWORD CALLBACK CLDAP::_sAsyncSearchThreadFn(LPVOID pv) {
DBGENTRY(CLDAP::_sAsyncSearchThreadFn);
CLDAP * pThis = (CLDAP *) pv; ASSERT(NULL != pThis); pThis->AsyncSearch(); pThis->Release();
DBGEXIT(CLDAP::_sAsyncSearchThreadFn);
return 0; }
VOID CLDAP::AsyncSearch(void) { DBGENTRY(CLDAP::AsyncSearch); HRESULT hr;
WARNING_OUT(("AsyncSearch Started")); ASSERT(NULL != m_hThread);
SetBusyCursor(TRUE); // We can not call EnableWindow() from this thread as it av's some of the time. This is a
// known windows bug. It also doesn't really solve the problem (#4726) it was put in here
// to solve anyway. We will work around this in a future build by re-architecting this so
// this little helper thread doesn't mess with the ui at all. It is problematic and very
// inefficient anyway.
// ::EnableWindow(GetDlgItem(GetParent(GetHwnd()), IDM_DLGCALL_REFRESH), FALSE);
m_fDirInProgress = TRUE; m_dwTickStart = ::GetTickCount(); m_uniqueId = 0;
if( SUCCEEDED( WaitWithMessageLoop( m_hSearchMutex ) ) ) { if (!FAvailable()) { hr = E_ACCESSDENIED; } else if (!FOpenServer()) { CloseServer(); hr = E_FAIL; } else { hr = DoQuery(); }
SetBusyCursor(FALSE); // This should be moved outside the if so it is always executed...
// We can not call EnableWindow() from this thread as it av's some of the time. This is a
// known windows bug. It also doesn't really solve the problem (#4726) it was put in here
// to solve anyway. We will work around this in a future build by re-architecting this so
// this little helper thread doesn't mess with the ui at all. It is problematic and very
// inefficient anyway.
// ::EnableWindow(GetDlgItem(GetParent(GetHwnd()), IDM_DLGCALL_REFRESH), TRUE);
HWND hwnd = GetHwnd(); if (-1 == ListView_GetNextItem(hwnd, -1, LVNI_ALL | LVNI_FOCUSED)) { // No selection - set focus to the first item
ListView_SetItemState(hwnd, 0, LVIS_FOCUSED, LVIS_FOCUSED); }
ReleaseMutex( m_hSearchMutex );
if (FAILED(hr)) { PostMessage(GetParent(hwnd), WM_DISPLAY_MSG, IDS_ULSLOGON_ERROR, 0); }
WARNING_OUT(("AsyncSearch Complete"));
// Close the thread handle safely
HANDLE hThread = m_hThread; m_hThread = NULL; CloseHandle(hThread); }
if (m_fDirInProgress) { // Only cache if data took more than 2 seconds to retrieve
m_fIsCacheable = ((::GetTickCount() - m_dwTickStart) > 2000); m_fDirInProgress = FALSE; }
DBGEXIT(CLDAP::AsyncSearch); }
///////////////////////////////////////////////////////////////////////////
/* F O P E N S E R V E R */ /*-------------------------------------------------------------------------
%%Function: FOpenServer
Make sure the connection to the LDAP server is open -------------------------------------------------------------------------*/ BOOL CLDAP::FOpenServer(void) { DBGENTRY(CLDAP::FOpenServer);
BOOL bRet = TRUE; if( NULL == m_pLdap ) { if( m_bSearchCancelled ) { bRet = FALSE; } else { WARNING_OUT(("Opening Server [%s] Port [%d]", m_szAddress, m_ulPort));
m_pLdap = WLDAP::ldap_open(m_szAddress, m_ulPort);
if( (m_pLdap == NULL) && (m_ulPort == DEFAULT_LDAP_PORT) ) { m_pLdap = WLDAP::ldap_open(m_szAddress, ALTERNATE_LDAP_PORT); // Automatically retry with alternate port...
if( m_pLdap != NULL ) { m_ulPort = ALTERNATE_LDAP_PORT; } }
if(NULL != m_pLdap) { LONG lTimeOut = 30; // seconds for timeout
WLDAP::ldap_set_option(m_pLdap, LDAP_OPT_TIMELIMIT, &lTimeOut);
// Defaults to ILS 2
ASSERT(LDAP_VERSION2 == m_pLdap->ld_version);
ULONG ulRet = WLDAP::ldap_simple_bind_s(m_pLdap, NULL, NULL);
WARNING_OUT(("Logon [%s] complete", m_szServer)); } else { WARNING_OUT(("ldap_open err=%d", GetLastError())); return FALSE; } } }
DBGEXIT(CLDAP::FOpenServer); return bRet; }
/* C L O S E S E R V E R */ /*-------------------------------------------------------------------------
%%Function: CloseServer
-------------------------------------------------------------------------*/ VOID CLDAP::CloseServer(void) { DBGENTRY(CLDAP::CloseServer);
if(m_pLdap) { StopSearch();
if( SUCCEEDED( WaitWithMessageLoop( m_hSearchMutex ) ) ) {
WLDAP::ldap_unbind(m_pLdap); m_pLdap = NULL;
ReleaseMutex( m_hSearchMutex ); }
WARNING_OUT(("Logoff [%s] complete", m_szServer)); } }
/* G E T N E X T A T T R I B U T E */ /*-------------------------------------------------------------------------
%%Function: GetNextAttribute
-------------------------------------------------------------------------*/ LPTSTR CLDAP::GetNextAttribute(LPCTSTR pszExpect, LPTSTR psz, int cchMax, LPTSTR pszAttrib, LDAPMessage * pEntry, BerElement * pElement) { DBGENTRY(CLDAP::GetNextAttribute);
ASSERT(NULL != psz);
if ((NULL == pszAttrib) || (0 != lstrcmpi(pszAttrib, pszExpect))) { *psz = _T('\0'); } else { LPTSTR * rgVal = WLDAP::ldap_get_values(m_pLdap, pEntry, pszAttrib); if( rgVal[0] ) { lstrcpyn(psz, rgVal[0], cchMax); } else { psz[0] = _T('\0'); } WLDAP::ldap_value_free(rgVal);
pszAttrib = WLDAP::ldap_next_attribute(m_pLdap, pEntry, pElement); }
DBGEXIT(CLDAP::GetNextAttribute);
return pszAttrib; }
/* D O Q U E R Y */ /*-------------------------------------------------------------------------
%%Function: DoQuery
-------------------------------------------------------------------------*/ HRESULT CLDAP::DoQuery(void) {
DBGENTRY(CLDAP::DoQuery);
HRESULT hr = S_FALSE;
ASSERT(FLoggedOn());
TCHAR szSearch[MAX_PATH]; ASSERT(CCHMAX(s_szSearchFormat3) + CCHMAX(s_szSearchCategory) < CCHMAX(szSearch)); ASSERT(CCHMAX(s_szSearchFormat2) + CCHMAX(s_szSearchCategory) < CCHMAX(szSearch));
if( !m_bSearchCancelled ) { wsprintf(szSearch, (LDAP_VERSION2 == m_pLdap->ld_version) ? s_szSearchFormat2 : s_szSearchFormat3, (LDAP_VERSION2 == m_pLdap->ld_version) ? TEXT("%") : TEXT("*"), _T("")); ASSERT(lstrlen(szSearch) < CCHMAX(szSearch));
ASSERT(0 == m_msgId); // one search at a time
m_msgId = WLDAP::ldap_search(m_pLdap, (PCHAR) "objectClass=RTPerson", LDAP_SCOPE_BASE, szSearch, (PCHAR *) s_rgAttrNameAddr, 0);
if( m_msgId == -1 ) { m_msgId = 0; hr = E_FAIL; } else { SendMessage( m_hWnd, WM_SETREDRAW, FALSE, 0 );
while( (0 != m_msgId) && (!m_bSearchCancelled) ) { LDAP_TIMEVAL timeOut = {2, 0}; LDAPMessage * pResult = NULL; WARNING_OUT(("DoQuery calling ldap_result")); int iResult = WLDAP::ldap_result(m_pLdap, m_msgId, 0, &timeOut, &pResult); WARNING_OUT( ("DoQuery back from ldap_result: 0x%08X", iResult) ); if (0 == iResult) { SendMessage( m_hWnd, WM_SETREDRAW, TRUE, 0 ); UpdateWindow( m_hWnd ); SendMessage( m_hWnd, WM_SETREDRAW, FALSE, 0 ); continue; }
if (LDAP_RES_SEARCH_ENTRY != iResult) { // S_FALSE = abandoned
// hr = (-1 == iResult) ? S_OK : S_FALSE;
hr = (-1 == iResult) ? E_FAIL : S_FALSE; break; }
AddEntries(pResult);
WLDAP::ldap_msgfree(pResult); }
SendMessage( m_hWnd, WM_SETREDRAW, TRUE, 0 );
m_msgId = 0; DirComplete( TRUE );
forceSort(); } }
DBGEXIT(CLDAP::DoQuery); return hr; }
/* A D D E N T R I E S */ /*-------------------------------------------------------------------------
%%Function: AddEntries
Add the Entries to the listbox. (Data ordered by s_rgAttrNameAddr.) -------------------------------------------------------------------------*/ VOID CLDAP::AddEntries(LDAPMessage * pResult) { DBGENTRY(CLDAP::AddEntries);
LDAPMessage * pEntry; BerElement * pElement;
for (pEntry = WLDAP::ldap_first_entry(m_pLdap, pResult); NULL != pEntry; pEntry = WLDAP::ldap_next_entry(m_pLdap, pEntry)) { LPTSTR pszAttrib = WLDAP::ldap_first_attribute(m_pLdap, pEntry, &pElement); if (NULL == pszAttrib) break;
// Must have a "Show Me" attribute
if (0 != lstrcmpi(pszAttrib, s_cszAttribShow)) continue;
LPTSTR * rgVal = WLDAP::ldap_get_values(m_pLdap, pEntry, pszAttrib); BOOL fShow = (_T('1') == *rgVal[0]); WLDAP::ldap_value_free(rgVal);
if (!fShow) continue; pszAttrib = WLDAP::ldap_next_attribute(m_pLdap, pEntry, pElement);
TCHAR szEmail[CCHMAXSZ_EMAIL]; pszAttrib = GetNextAttribute(s_cszAttribEmail, szEmail, CCHMAX(szEmail), pszAttrib, pEntry, pElement);
TCHAR szFirstName[CCHMAXSZ_FIRSTNAME]; pszAttrib = GetNextAttribute(s_cszAttribFirstName, szFirstName, CCHMAX(szFirstName), pszAttrib, pEntry, pElement);
TCHAR szLastName[CCHMAXSZ_LASTNAME]; pszAttrib = GetNextAttribute(s_cszAttribLastName, szLastName, CCHMAX(szLastName), pszAttrib, pEntry, pElement);
TCHAR szLocation[CCHMAXSZ_LASTNAME]; pszAttrib = GetNextAttribute(s_cszAttribLocation, szLocation, CCHMAX(szLocation), pszAttrib, pEntry, pElement);
TCHAR szTemp[4]; pszAttrib = GetNextAttribute(s_cszAttribInACall, szTemp, CCHMAX(szTemp), pszAttrib, pEntry, pElement);
int iInCallImage = (szTemp[0] == _T('1')) ? II_IN_A_CALL : II_COMPUTER;
pszAttrib = GetNextAttribute(s_cszAttribAudio, szTemp, CCHMAX(szTemp), pszAttrib, pEntry, pElement);
int iAudioImage = (szTemp[0] == _T('1')) ? II_AUDIO_CAPABLE : 0;
pszAttrib = GetNextAttribute(s_cszAttribVideo, szTemp, CCHMAX(szTemp), pszAttrib, pEntry, pElement);
int iVideoImage = (szTemp[0] == _T('1')) ? II_VIDEO_CAPABLE : 0;
TCHAR szComment[CCHMAXSZ_COMMENT]; pszAttrib = GetNextAttribute(s_cszAttribComment, szComment, CCHMAX(szComment), pszAttrib, pEntry, pElement);
lvAddItem( 0, iInCallImage, iAudioImage, iVideoImage, szEmail, szFirstName, szLastName, szLocation, szComment ); }
DBGEXIT(CLDAP::AddEntries); }
//--------------------------------------------------------------------------//
// CLDAP::lvAddItem. //
//--------------------------------------------------------------------------//
int CLDAP::lvAddItem ( int item, int iInCallImage, int iAudioImage, int iVideoImage, LPCTSTR address, LPCTSTR firstName, LPCTSTR lastName, LPCTSTR location, LPCTSTR comments ){ LV_ITEM lvItem;
ClearStruct( &lvItem );
lvItem.mask = LVIF_PARAM; lvItem.iItem = item; lvItem.lParam = m_uniqueId++; // assign a unique lParam for this item
int index = ListView_InsertItem( m_hWnd, &lvItem );
if( index != -1 ) { if( lastName ) { ListView_SetItemText( m_hWnd, index, COLUMN_INDEX_LAST_NAME, (LPTSTR) lastName ); }
if( firstName ) { ListView_SetItemText( m_hWnd, index, COLUMN_INDEX_FIRST_NAME, (LPTSTR) firstName ); }
if( iAudioImage != 0 ) { lvItem.mask = LVIF_IMAGE; lvItem.iSubItem = COLUMN_INDEX_AUDIO; lvItem.iImage = iAudioImage;
ListView_SetItem( m_hWnd, &lvItem ); }
if( iVideoImage != 0 ) { lvItem.mask = LVIF_IMAGE; lvItem.iSubItem = COLUMN_INDEX_VIDEO; lvItem.iImage = iVideoImage;
ListView_SetItem( m_hWnd, &lvItem ); }
if( address ) { lvItem.mask = LVIF_IMAGE | LVIF_TEXT; lvItem.iSubItem = COLUMN_INDEX_ADDRESS; lvItem.iImage = iInCallImage; lvItem.pszText = (LPTSTR) address; lvItem.cchTextMax = lstrlen( lvItem.pszText );
ListView_SetItem( m_hWnd, &lvItem ); }
if( location ) { ListView_SetItemText( m_hWnd, index, COLUMN_INDEX_LOCATION, (LPTSTR) location ); }
if( comments ) { ListView_SetItemText( m_hWnd, index, COLUMN_INDEX_COMMENTS, (LPTSTR) comments ); } }
return( index );
} // End of CLDAP::lvAddItem.
/* S T O P S E A R C H */ /*-------------------------------------------------------------------------
%%Function: StopSearch
-------------------------------------------------------------------------*/ VOID CLDAP::StopSearch(void) { DBGENTRY(CLDAP::StopSearch);
m_bSearchCancelled = true;
if (0 != m_msgId) { // Dont call ldap_abandon() from this thread as the search thread may be inside ldap_result()
// at the time. For now just set m_msgId to zero and the search thread will stop when ldap_result()
// returns.
// ULONG uResult = WLDAP::ldap_abandon(m_pLdap, m_msgId);
WARNING_OUT(("Stopping Search...")); m_msgId = 0;
m_fDirInProgress = FALSE; m_fIsCacheable = FALSE;
DirComplete(FALSE); }
DBGEXIT(CLDAP::StopSearch); }
/* F G E T U S E R D A T A */ /*-------------------------------------------------------------------------
%%Function: FGetUserData
Get the data for a single user. -------------------------------------------------------------------------*/ BOOL CLDAP::FGetUserData(LDAPUSERDATA * pLdapUserData) { DBGENTRY(CLDAP::FGetUserData); ClearStruct(pLdapUserData);
if (!FLoggedOn()) { DBGEXIT(CLDAP::FGetUserData); return FALSE; }
int iItem = CALV::GetSelection(); if (-1 == iItem) { DBGEXIT(CLDAP::FGetUserData); return FALSE; } if (!GetSzData(pLdapUserData->szEmail, CCHMAX(pLdapUserData->szEmail), iItem, COLUMN_INDEX_ADDRESS)) { DBGEXIT(CLDAP::FGetUserData); return FALSE; }
TCHAR szSearch[CCHMAX(s_szSearchFormat2) + CCHMAXSZ_EMAIL]; wsprintf(szSearch, (LDAP_VERSION2 == m_pLdap->ld_version) ? s_szSearchFormat2 : s_szSearchFormat3, pLdapUserData->szEmail, g_cszEmpty); ASSERT(lstrlen(szSearch) < CCHMAX(szSearch));
LDAPMessage * pResult = NULL;
ULONG ulRet = WLDAP::ldap_search_s(m_pLdap, (LPTSTR) "objectClass=RTPerson", LDAP_SCOPE_BASE, szSearch, (PCHAR *) s_rgAttrAll, FALSE, &pResult); if (LDAP_SUCCESS != ulRet) { WLDAP::ldap_msgfree(pResult); WARNING_OUT(("ldap_search (code=%08X)", ulRet)); DBGEXIT(CLDAP::FGetUserData); return FALSE; }
LDAPMessage * pEntry = WLDAP::ldap_first_entry(m_pLdap, pResult); if (NULL != pEntry) { BerElement * pElement; LPTSTR pszAttrib = WLDAP::ldap_first_attribute(m_pLdap, pEntry, &pElement); // Make sure that the first attribute is s_cszAttribFirstName...
if ((NULL != pszAttrib) && (0 == lstrcmpi(pszAttrib, s_cszAttribFirstName))) { LPTSTR * rgVal = WLDAP::ldap_get_values(m_pLdap, pEntry, pszAttrib); WLDAP::ldap_value_free(rgVal); // pszAttrib = WLDAP::ldap_next_attribute(m_pLdap, pEntry, pElement);
pszAttrib = GetNextAttribute(s_cszAttribFirstName, pLdapUserData->szFirst, CCHMAX(pLdapUserData->szFirst), pszAttrib, pEntry, pElement);
pszAttrib = GetNextAttribute(s_cszAttribLastName, pLdapUserData->szLast, CCHMAX(pLdapUserData->szLast), pszAttrib, pEntry, pElement);
CombineNames(pLdapUserData->szName, CCHMAX(pLdapUserData->szName), pLdapUserData->szFirst, pLdapUserData->szLast);
pszAttrib = GetNextAttribute(s_cszAttribComment, pLdapUserData->szComment, CCHMAX(pLdapUserData->szComment), pszAttrib, pEntry, pElement);
TCHAR szTemp[4]; pszAttrib = GetNextAttribute(s_cszAttribAudio, szTemp, CCHMAX(szTemp), pszAttrib, pEntry, pElement); pLdapUserData->fAudioSend = _T('1') == szTemp[0]; pszAttrib = GetNextAttribute(s_cszAttribVideo, szTemp, CCHMAX(szTemp), pszAttrib, pEntry, pElement); pLdapUserData->fVideoSend = _T('1') == szTemp[0];
pszAttrib = GetNextAttribute(s_cszAttribVersion, pLdapUserData->szVersion, CCHMAX(pLdapUserData->szVersion), pszAttrib, pEntry, pElement); pszAttrib = GetNextAttribute(s_cszAttribCategory, szTemp, CCHMAX(szTemp), pszAttrib, pEntry, pElement); ConvertVersionInfo(pLdapUserData->szVersion, szTemp); } }
WLDAP::ldap_msgfree(pResult);
DBGEXIT(CLDAP::FGetUserData); return TRUE; }
/* C O N V E R T V E R S I O N I N F O */ /*-------------------------------------------------------------------------
%%Function: ConvertVersionInfo
-------------------------------------------------------------------------*/ VOID ConvertVersionInfo(LPTSTR pszVersion, LPTSTR pszCategory) { UINT uVer = DecimalStringToUINT(pszVersion);
if (0 == uVer) { lstrcpy(pszVersion, FEmptySz(pszCategory) ? TEXT("1.0") : TEXT("2")); } else { LPCTSTR pszRel;
switch (LOBYTE(HIWORD(uVer))) { case 3: pszRel = TEXT("2.11"); break; case 4: pszRel = TEXT("3.0"); break; case 5: pszRel = TEXT("4.0"); break; default: pszRel = g_cszEmpty; break; }
TCHAR szFormat[CCHMAXSZ]; FLoadString(IDS_FORMAT_VERSION, szFormat, CCHMAX(szFormat)); wsprintf(pszVersion, szFormat, pszRel, HIBYTE(HIWORD(uVer)), LOBYTE(HIWORD(uVer)), LOWORD(uVer)); } }
//--------------------------------------------------------------------------//
// CLDAP::FreeDirCache. //
//--------------------------------------------------------------------------//
void CLDAP::FreeDirCache ( DIRCACHE * pDirCache ){ TRACE_OUT(("FreeDirCache [%s] filter=%d, expire=%d", pDirCache->pszServer, pDirCache->dwTickExpire));
ASSERT(NULL != pDirCache); PBYTE pb = pDirCache->pData; delete pDirCache->pszServer; delete pDirCache;
while (NULL != pb) { PBYTE pTemp = pb; pb = (PBYTE) * (DWORD_PTR *) pb; delete pTemp; }
} // End of CLDAP::FreeDirCache.
//--------------------------------------------------------------------------//
// CLDAP::FreeDirCache. //
//--------------------------------------------------------------------------//
void CLDAP::DirComplete ( bool //fPostUiUpdate
){
if( m_fDirInProgress ) { // Only cache if data took more than 2 seconds to retrieve
m_fIsCacheable = ((::GetTickCount() - m_dwTickStart) > 2000); m_fDirInProgress = FALSE; }
m_cTotalEntries = 0; m_cEntries = 0;
} // End of CLDAP:DirComplete.
//--------------------------------------------------------------------------//
// CLDAP::GetSzName. //
//--------------------------------------------------------------------------//
BOOL CLDAP::GetSzName ( LPTSTR psz, int cchMax, int iItem ){ TCHAR szOrder[ MAX_PATH ];
bool bFirstNameFirst = ((::LoadString( ::GetInstanceHandle(), IDS_NAME_ORDER, szOrder, CCHMAX(szOrder)) == 0) || (_T( '1' ) == szOrder[ 1 ]));
int iFirst = bFirstNameFirst? COLUMN_INDEX_FIRST_NAME: COLUMN_INDEX_LAST_NAME; int iLast = bFirstNameFirst? COLUMN_INDEX_LAST_NAME: COLUMN_INDEX_FIRST_NAME;
GetSzData( psz, cchMax, iItem, iFirst );
int length = lstrlen( psz );
if( (length > 0) && (length < cchMax - 1) ) { lstrcat( psz, TEXT( " " ) ); length++; }
GetSzData( &psz[ length ], cchMax - length, iItem, iLast );
return( lstrlen( psz ) > 0 );
} // End of CLDAP::GetSzName.
static const int CDIRCACHE_SZ = 5; // number of strings
static const int CDIRCACHE_IMAGE = 3; // number of images
//--------------------------------------------------------------------------//
// CLDAP::CacheServerData. //
//--------------------------------------------------------------------------//
void CLDAP::CacheServerData(void) { DIRCACHE * pDirCache;
if (!m_fCacheDirectory) return; // User disabled directory caching
if (!m_fIsCacheable) { TRACE_OUT(("CacheServerData: not caching [%s]", m_szServer)); return; }
if (m_fDirInProgress) return; // don't cache partial data
// Remove any previous cached data
POSITION pos = FindCachedData();
if (NULL != pos) { pDirCache = (DIRCACHE *) m_listDirCache.RemoveAt(pos); ASSERT(NULL != pDirCache); FreeDirCache(pDirCache); }
DWORD dwTickExpire = m_dwTickStart + (m_cMinutesExpire * 60000);
if (dwTickExpire < GetTickCount()) { TRACE_OUT(("CacheServerData: [%s] data has expired", m_szServer)); return; // data is already expired
}
int cItems = ListView_GetItemCount(m_hWnd); if (0 == cItems) return; // nothing to cache
pDirCache = new DIRCACHE; if (NULL == pDirCache) return;
pDirCache->pszServer = PszAlloc(m_szServer); pDirCache->dwTickExpire = dwTickExpire; pDirCache->pData = NULL;
LPTSTR pPrev = (LPTSTR) &pDirCache->pData;
m_listDirCache.AddTail(pDirCache);
LV_ITEM lvi; lvi.cchTextMax = MAX_PATH; for (lvi.iItem = 0; lvi.iItem < cItems; lvi.iItem++) { int iInCallImage = -1; int iAudioImage = -1; int iVideoImage = -1; int i = 0; // index into rgcb, rgsz
int cb = 0; // total length of string data
int rgcb[CDIRCACHE_SZ]; // size of each string
TCHAR rgsz[CDIRCACHE_SZ][MAX_PATH]; // string buffers
// Get the string data for each column
lvi.mask = LVIF_IMAGE; for (lvi.iSubItem = 0; lvi.iSubItem < MAX_DIR_COLUMNS; lvi.iSubItem++) { if( (lvi.iSubItem != COLUMN_INDEX_AUDIO) && (lvi.iSubItem != COLUMN_INDEX_VIDEO) ) { lvi.mask |= LVIF_TEXT; lvi.pszText = rgsz[i]; ListView_GetItem(m_hWnd, &lvi); rgcb[i] = lstrlen(lvi.pszText); cb += rgcb[i] + 1; // Plus one for the NULL...
i++;
if( lvi.iSubItem == COLUMN_INDEX_ADDRESS ) { iInCallImage = lvi.iImage; } } else { lvi.mask &= ~LVIF_TEXT; ListView_GetItem(m_hWnd, &lvi);
if( lvi.iSubItem == COLUMN_INDEX_AUDIO ) { iAudioImage = lvi.iImage; } else if( lvi.iSubItem == COLUMN_INDEX_VIDEO) { iVideoImage = lvi.iImage; } } }
// allocate space for: a link (DWORD), strings (cb), images (CDIRCACHE_IMAGES)
PBYTE pData = new BYTE[ sizeof(DWORD_PTR) + cb + CDIRCACHE_IMAGES ]; if (NULL == pData) { // can't hold all data - give up and return
ClearServerCache(); return; } * ((DWORD_PTR *) pData) = 0; // link to next item is null
PBYTE pb = pData + sizeof(DWORD_PTR);
// copy the string data into the buffer
for (i = 0; i < CDIRCACHE_SZ; i++) { lstrcpy((LPTSTR) pb, rgsz[i]); pb += rgcb[i] + 1; }
*pb++ = (BYTE) iInCallImage; *pb++ = (BYTE) iAudioImage; *pb = (BYTE) iVideoImage; * ((DWORD_PTR *) pPrev) = (DWORD_PTR) pData; // link into the previous data
pPrev = (LPTSTR) pData; }
TRACE_OUT(("CacheServerData: [%s] expire=%d", m_szServer, dwTickExpire));
} // End of CLDAP::CacheServerData.
//--------------------------------------------------------------------------//
// CLDAP::FindCachedData. //
//--------------------------------------------------------------------------//
POSITION CLDAP::FindCachedData(void) { DWORD dwTick = GetTickCount(); TRACE_OUT(("Searching for cached data on [%s]", m_szServer));
POSITION pos = m_listDirCache.GetHeadPosition(); while (NULL != pos) { POSITION posSav = pos; DIRCACHE * pDirCache = (DIRCACHE *) m_listDirCache.GetNext(pos); ASSERT(NULL != pDirCache); if ((0 == lstrcmp(m_szServer, pDirCache->pszServer)) && (pDirCache->dwTickExpire > dwTick)) { return posSav; } }
return NULL;
} // End of CLDAP::FindCachedData.
//--------------------------------------------------------------------------//
// CLDAP::ClearServerCache. //
//--------------------------------------------------------------------------//
void CLDAP::ClearServerCache(void) { DWORD dwTick = GetTickCount();
POSITION pos = m_listDirCache.GetHeadPosition(); while (NULL != pos) { POSITION posSav = pos; DIRCACHE * pDirCache = (DIRCACHE *) m_listDirCache.GetNext(pos); ASSERT(NULL != pDirCache); if ( (0 == lstrcmp(m_szServer, pDirCache->pszServer)) || (pDirCache->dwTickExpire < dwTick) ) { m_listDirCache.RemoveAt(posSav); FreeDirCache(pDirCache); } #ifdef DEBUG
else { TRACE_OUT(("Keeping cached data for [%s] , expire=%d", pDirCache->pszServer, pDirCache->dwTickExpire)); } #endif /* DEBUG */
}
} // End of CLDAP::ClearServerCache.
//--------------------------------------------------------------------------//
// CLDAP::DisplayDirectory. //
//--------------------------------------------------------------------------//
void CLDAP::DisplayDirectory(void) { POSITION pos = FindCachedData();
if (NULL == pos) { // no cached information - request new data
StartSearch(); return; }
DIRCACHE * pDirCache = (DIRCACHE *) m_listDirCache.GetFromPosition(pos); ASSERT(NULL != pDirCache); LPTSTR pDirLine = (LPTSTR) pDirCache->pData;
StopSearch(); // In case the previous server is slow
CALV::ClearItems();
m_fIsCacheable = FALSE; // don't bother attempting to re-cache this data
// Restore the cached server information
TRACE_OUT(("Restoring cached data for [%s] expire=%d", m_szServer, pDirCache->dwTickExpire));
SendMessage( m_hWnd, WM_SETREDRAW, FALSE, 0 );
while (NULL != pDirLine) { DWORD_PTR *pNext = * (DWORD_PTR * * ) pDirLine; pDirLine += sizeof(DWORD_PTR); LPTSTR pszEmail = (LPTSTR) pDirLine; pDirLine += lstrlen(pDirLine)+1; LPTSTR pszLast = (LPTSTR) pDirLine; pDirLine += lstrlen(pDirLine)+1; LPTSTR pszFirst = (LPTSTR) pDirLine; pDirLine += lstrlen(pDirLine)+1; LPTSTR pszLocation = (LPTSTR) pDirLine; pDirLine += lstrlen(pDirLine)+1; LPTSTR pszComment = (LPTSTR) pDirLine; pDirLine += lstrlen(pDirLine)+1; int iiCall = (int) * (char *) pDirLine; pDirLine++; int iiAudio = (int) * (char *) pDirLine; pDirLine++; int iiVideo = (int) * (char *) pDirLine;
lvAddItem( 0, iiCall, iiAudio, iiVideo, pszEmail, pszFirst, pszLast, pszLocation, pszComment );
pDirLine = (LPTSTR) pNext; }
forceSort(); SendMessage( m_hWnd, WM_SETREDRAW, TRUE, 0 );
} // End of CLDAP::DisplayDirectory.
//--------------------------------------------------------------------------//
// CLDAP::forceSort. //
//--------------------------------------------------------------------------//
void CLDAP::forceSort(void) { NM_LISTVIEW nmlv;
nmlv.hdr.code = LVN_COLUMNCLICK; nmlv.hdr.hwndFrom = m_hWnd; nmlv.iSubItem = -1; // default sort column...
SendMessage( GetParent( m_hWnd ), WM_NOTIFY, GetDlgCtrlID( m_hWnd ), (LPARAM) &nmlv );
} // End of CLDAP::forceSort.
//--------------------------------------------------------------------------//
// CLDAP::GetIconId. //
//--------------------------------------------------------------------------//
int CLDAP::GetIconId(LPCTSTR psz) {
return( CDirectoryManager::isWebDirectory( psz )? II_WEB_DIRECTORY: CALV::GetIconId( NULL ) );
} // End of CLDAP::GetIconId.
|