windows-nt/Source/XPSP1/NT/enduser/netmeeting/ui/conf/nmldap.cpp
2020-09-26 16:20:57 +08:00

2336 lines
62 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "precomp.h"
#include "resource.h"
#include "pfnwldap.h"
#include "conf.h"
#include "cr.h"
#include <cstring.hpp>
#include <ulsreg.h>
#include "NmLdap.h"
#include "version.h"
#include "call.h"
#include "confapi.h"
#include "confutil.h"
#include "dirutil.h"
// One global instance
CNmLDAP* g_pLDAP = NULL;
CPing* g_pPing = NULL;
// This flag indicates weather or not we have loaded the LDAP dll ( WLDAP::Init() )
/*static*/ bool CNmLDAP::ms_bLdapDLLLoaded = false;
////////////////////////////////////////////////////////////////////////////////////////
// Helper Macros
// the ldap_modify function takes an LDAPMod** type
// If it took an array of LDAPMod ( an LDAPMod* type )
// Then life would be easier for us to make static lists
// Unfortunately, this is not how it works, so we have macros
// to pretty things up ( and hopefully not to confuse anyone )
// This is to declare an LDAPMod with one val
#define DECLARE_LDAP_MOD( t, x, y )\
LPTSTR aVals_##x[] = { y, NULL };\
LDAPMod LDAPMod_##x = { t, _T(#x), aVals_##x }
// This is to declare an LDAPMod with 2 vals
#define DECLARE_LDAP_MOD2( t, x, y1, y2 )\
LPTSTR aVals_##x[] = { y1, y2, NULL };\
LDAPMod LDAPMod_##x = { t, _T(#x), aVals_##x }
#define LDAP_MOD_ENTRY( x ) &LDAPMod_##x
#define LDAP_MOD_ADD_ENTRY( x ) &LDAPMod_add_##x
////////////////////////////////////////////////////////////////////////////////////////
// Some helpful deffinitions
#define LDAP_REFRESH_BASE_DN _T("objectClass=RTPerson")
#define RESOLVE_USER_SEARCH_FILTER _T("(&(objectClass=RTPerson)(cn=%s))")
//NOTE: The LDAP_REFRESH_FILTER... notice the sttl=10... aparently, this is how you request the
// server to restart the TTL countdown... the sttl= value can be anything BUT '*' ( the value you would
// expecte it to be... ) This is a link to the "Dynamir Ldap Extension RFC" if you want more info
// http://www.critical-angle.com/ldapworld/draft-ietf-asid-ldapv3ext-04.txt
#define LDAP_REFRESH_FILTER _T("(&(objectClass=RTPerson)(cn=%s)(sttl=10))")
#define LOGIN_USER_FILTER _T("c=-,o=Microsoft,cn=%s,objectClass=RTPerson")
#define IP_ADDRESS_ATTR_NAME _T("sipaddress")
#define STTL_ATTR_NAME _T("sttl")
#define CNmLDAP_WCNAME _T("CNmLDAP_WCNAME")
#define LDAP_MODOP_ADDAPP _T("0")
#define LDAP_MODOP_DELETEAPP _T("1")
#define LDAP_MODOP_MODIFYUSER _T("2")
#define LDAP_MODOP_MODIFYAPP _T("3")
#define LDAP_ATTR_FALSE _T("0")
#define LDAP_ATTR_TRUE _T("1")
#define LDAP_ATTR_BUSINESS _T("2")
// We are not using the country name anymore, but we can't leave the country
// field blank ( empty string ), it is just the way that SiteServer is written...
#define LDAP_ATTR_DUMMY_COUNTRYNAME _T("-")
#define INVALID_MSG_ID ((ULONG) -1) // same as ldap_****()
#define LDAP_RESULT_ERROR ((ULONG) -1)
#define LDAP_RESULT_TIMEOUT 0
// When the bind helper thread function gets the result to bind_s function
// it passes it to this thread via PostMessage( m_hWndHidder, WM_USER_BIND_COMPLETE, ret, err )
#define WM_USER_BIND_COMPLETE (WM_APP + 1) // wParam = Return code from bind_s, lParam = GetLastError()
#define WM_NEED_RELOGON (WM_APP + 2)
CNmLDAP::CNmLDAP()
: m_State(Uninitialized),
m_pKeepAlive(NULL),
m_hWndHidden(NULL),
m_pLdap(NULL),
m_ResultPollTimer(0),
m_LogoffTimer(0),
m_uMsgID(INVALID_MSG_ID),
m_CurrentOp(Op_NoOp),
m_bVisible(true),
m_bDirty(false),
m_bRefreshAfterBindCompletes(false),
m_bLogoffAfterBindCompletes(false),
m_bSendInCallAttrWhenDone(false),
m_bInCall(false),
m_hEventWaitForLogoffDone(NULL),
m_hBindThread(NULL),
m_iPort(DEFAULT_LDAP_PORT),
m_bAudioHardware(false),
m_bVideoHardware(false)
{
DBGENTRY(CNmLDAP::CNmLDAP);
SetLoggedOn( false );
DBGEXIT(CNmLDAP::CNmLDAP);
}
CNmLDAP::~CNmLDAP()
{
DBGENTRY(CNmLDAP::~CNmLDAP);
if (NULL != m_pKeepAlive)
{
m_pKeepAlive->End(TRUE); // synchronous end
m_pKeepAlive = NULL;
}
if((m_State != Idle) && (m_State != Uninitialized))
{
// Make sure that someone at least has already called Logoff()
ASSERT((LoggingOff == m_State) || (Op_Logoff == m_CurrentOp));
// We are logging off, but we would like to wait a while to make sure that
// all of our async operations are completed... We don't want to wait too long,
// Though... Basically we set a timer to pass a message to us... if we get that
// message, we signal m_hEventWaitForLogoffDone.... if any of the async operations
// complete during this time, they will also signal this event....We make sure to
// hawe a message loop ( AtlWaitWithWessageLoop ) so that our wndproc will be called
m_hEventWaitForLogoffDone = CreateEvent(NULL,TRUE,FALSE,NULL);
if(m_hEventWaitForLogoffDone)
{
m_LogoffTimer = ::SetTimer(m_hWndHidden, WaitForLogoffTimer, LOGOFF_WAIT_INTERVAL, NULL);
if(m_LogoffTimer)
{
AtlWaitWithMessageLoop(m_hEventWaitForLogoffDone);
}
CloseHandle(m_hEventWaitForLogoffDone);
m_hEventWaitForLogoffDone = NULL;
}
else
{
ERROR_OUT(("Create Event failed"));
}
if( Binding == m_State )
{
WARNING_OUT(("Aborting an ldap_bind because we are closing down in ~CNmLDAP"));
TerminateThread(m_hBindThread, 0);
CloseHandle(m_hBindThread);
}
else if(Idle != m_State)
{
WARNING_OUT(("Aborting pending LDAP operation in ~CNmLDAP"));
_AbandonAllAndSetToIdle();
}
}
if( NULL != m_hWndHidden )
{
DestroyWindow( m_hWndHidden );
m_hWndHidden = NULL;
}
m_State = Uninitialized;
SetLoggedOn( false );
DBGEXIT(CNmLDAP::~CNmLDAP);
}
HRESULT CNmLDAP::_bCallChangedHelper()
{
TRACE_OUT(("CNmLDAP::_bCallChangedHelper:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
HRESULT hr = S_OK;
if( IsLoggedOn() || IsBusy() )
{
if(LoggedIn == m_State)
{
// We simply have to bind and call ldap_modify
m_CurrentOp = Op_Modifying_InCallAttr;
hr = _BindAsync();
}
else if((SettingAppInfo == m_State) ||
(ModifyingAttrs == m_State) ||
(AddingUser == m_State)
)
{
// the other states will be calling ldap_mod( user Attributes ) which will pick up
// the change to m_bInCall. The states listed above are the ones that occur after
// the user attributes have been sent to the server... There are also other states
// that logoff, so they don't care about sending the update to the user attribute to the server
m_bSendInCallAttrWhenDone = true;
}
}
TRACE_OUT(("CNmLDAP::_bCallChangedHelper:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
return hr;
}
HRESULT CNmLDAP::OnCallStarted()
{
DBGENTRY(CNmLDAP::OnCallStarted);
TRACE_OUT(("CNmLDAP::OnCallStarted:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
HRESULT hr = S_OK;
ASSERT(ms_bLdapDLLLoaded);
if( !m_bInCall )
{
m_bInCall = true;
hr = _bCallChangedHelper();
}
TRACE_OUT(("CNmLDAP::OnCallStarted:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
DBGEXIT_HR(CNmLDAP::OnCallStarted,hr);
return hr;
}
HRESULT CNmLDAP::OnCallEnded()
{
DBGENTRY(CNmLDAP::OnCallEnded);
TRACE_OUT(("CNmLDAP::OnCallEnded:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
HRESULT hr = S_OK;
ASSERT(ms_bLdapDLLLoaded);
if( m_bInCall )
{
m_bInCall = false;
hr = _bCallChangedHelper();
}
TRACE_OUT(("CNmLDAP::OnCallEnded:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
DBGEXIT_HR(CNmLDAP::OnCallEnded,hr);
return hr;
}
bool CNmLDAP::IsLoggedOn() const
{
DBGENTRY(CNmLDAP::IsLoggedOn);
TRACE_OUT(("CNmLDAP::IsLoggedOn:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
bool bRet = ( ( LoggedIn == m_State ) ||
( ModifyingAttrs == m_State ) ||
( Op_Refresh_Logoff == m_CurrentOp ) ||
( Op_Modifying_InCallAttr == m_CurrentOp )
);
TRACE_OUT(("CNmLDAP::IsLoggedOn:exit(%d): m_State:%d: m_currentOp:%d", bRet, m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::IsLoggedOn);
return bRet;
}
bool CNmLDAP::IsLoggingOn() const
{
DBGENTRY(CNmLDAP::IsLoggingOn);
TRACE_OUT(("CNmLDAP::IsLoggingOn:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
bool bRet = ( ( AddingUser == m_State ) ||
( UserAdded == m_State ) ||
( SettingAppInfo == m_State ) ||
( Op_Logon == m_CurrentOp )
);
TRACE_OUT(("CNmLDAP::IsLoggingOn:exit(%d): m_State:%d: m_currentOp:%d", bRet, m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::IsLoggingOn);
return bRet;
}
bool CNmLDAP::IsBusy() const
{
DBGENTRY(CNmLDAP::IsBusy);
TRACE_OUT(("CNmLDAP::IsBusy:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
bool bRet = !((LoggedIn == m_State) || ( Idle == m_State ) || (Uninitialized == m_State));
TRACE_OUT(("CNmLDAP::IsBusy:exit(%d): m_State:%d: m_currentOp:%d", bRet, m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::IsBusy);
return bRet;
}
void CNmLDAP::_MakeStatusText(UINT uResID, LPTSTR psz, UINT cch) const
{
const TCHAR * const server = CDirectoryManager::get_displayName( m_strCurrentServer );
LPCTSTR pszFmt = RES2T(uResID);
LPTSTR pszStr = reinterpret_cast<LPTSTR>(_alloca(lstrlen(pszFmt) + lstrlen(server) - 1));
if(pszStr)
{
wsprintf(pszStr, pszFmt, server);
lstrcpyn(psz, pszStr, cch);
}
}
HRESULT CNmLDAP::GetStatusText(LPTSTR psz, int cch, UINT *idIcon ) const
{
DBGENTRY(CNmLDAP::GetStatusText);
UINT idDummy;
if (NULL == idIcon)
{
// Just so we don't need to do switches all over the place
idIcon = &idDummy;
}
HRESULT hr = S_OK;
TRACE_OUT(("m_State = %d", m_State));
TRACE_OUT(("CNmLDAP::GetStatusText:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
if(psz)
{
if( cch > 1 )
{
switch(m_State)
{
case LoggedIn:
case ModifyingAttrs:
*idIcon = IDI_NET;
_MakeStatusText(ID_STATUS_LOGGEDON_FORMAT, psz, cch);
break;
case Binding:
{
switch(m_CurrentOp)
{
case Op_Logon:
*idIcon = IDS_STATUS_WAITING;
_MakeStatusText(ID_STATUS_LOGON_FORMAT, psz, cch);
break;
case Op_Modifying_InCallAttr:
*idIcon = IDI_NET;
_MakeStatusText(ID_STATUS_LOGGEDON_FORMAT, psz, cch);
break;
case Op_Refresh_Logoff:
if( lstrcmpi(m_strServer,m_strCurrentServer))
{
*idIcon = IDS_STATUS_WAITING;
_MakeStatusText(ID_STATUS_LOGOFF_FORMAT, psz, cch);
}
else
{
*idIcon = IDI_NET;
_MakeStatusText(ID_STATUS_LOGGEDON_FORMAT, psz, cch);
}
break;
case Op_Logoff:
*idIcon = IDI_NETGRAY;
lstrcpyn(psz, RES2T(ID_STATUS_LOGGEDOFF), cch);
break;
}
break;
}
case AddingUser:
case UserAdded:
case SettingAppInfo:
*idIcon = IDS_STATUS_WAITING;
_MakeStatusText(ID_STATUS_LOGON_FORMAT, psz, cch);
break;
case LoggingOff:
*idIcon = IDS_STATUS_WAITING;
_MakeStatusText(ID_STATUS_LOGOFF_FORMAT, psz, cch);
break;
case Bound:
case Idle:
case Uninitialized:
*idIcon = IDI_NETGRAY;
lstrcpyn(psz, RES2T(ID_STATUS_LOGGEDOFF), cch);
break;
default:
ERROR_OUT(("Not a regognized state: %d", m_State));
break;
}
}
else
{
hr = E_INVALIDARG;
}
}
else
{
hr = E_POINTER;
}
TRACE_OUT(("CNmLDAP::GetStatusText:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
DBGEXIT_HR(CNmLDAP::GetStatusText,hr);
return hr;
}
HRESULT CNmLDAP::OnSettingsChanged()
{
DBGENTRY(CNmLDAP::OnSettingsChanged);
TRACE_OUT(("CNmLDAP::OnSettingsChanged:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
HRESULT hr = S_OK;
ASSERT(ms_bLdapDLLLoaded);
if(S_OK == _GetUserSettingsFromRegistryAndGlobals())
{
hr = OnReLogon();
}
TRACE_OUT(("CNmLDAP::OnSettingsChanged:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
DBGEXIT_HR(CNmLDAP::OnSettingsChanged,hr);
return hr;
}
HRESULT CNmLDAP::OnReLogon(void)
{
HRESULT hr = S_OK;
ASSERT(ms_bLdapDLLLoaded);
m_bDirty = true;
if(IsLoggedOn() || IsBusy())
{
hr = _RefreshServer();
}
return hr;
}
HRESULT CNmLDAP::_RefreshServer()
{
DBGENTRY(CNmLDAP::_RefreshServer);
TRACE_OUT(("CNmLDAP::_RefreshServer:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
HRESULT hr = S_OK;
ASSERT(ms_bLdapDLLLoaded);
if( m_bDirty )
{
if(Binding == m_State)
{
if(Op_Logon == m_CurrentOp) // we are logging on and haven't sent any user information yet
{
// Check to see if we have not changed the server name
if( !lstrcmpi(m_strServer, CDirectoryManager::get_defaultServer() ) )
{
// Simply update the user settings
_GetUserSettingsFromRegistryAndGlobals();
}
else
{
// Since the server has changed, we have to do a logoff(from old)/logon(to new)
_InternalLogoff(true);
}
}
else if(m_CurrentOp != Op_Logoff)
{
// If we are in the middle of a bind operation, which happens
// in another thread, we just have to wait for it to complete
// before we go any further
m_bRefreshAfterBindCompletes = true;
}
}
else if(Idle == m_State)
{
_GetUserSettingsFromRegistryAndGlobals();
LogonAsync();
}
else
{
_InternalLogoff(true);
}
}
TRACE_OUT(("CNmLDAP::_RefreshServer:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
DBGEXIT_HR(CNmLDAP::_RefreshServer,hr);
return hr;
}
void CNmLDAP::_AbandonAllAndSetState(eState new_state)
{
TRACE_OUT(("CNmLDAP::_AbandonAllAndSetState:enter: new_state=%d, m_State:%d: m_currentOp:%d", new_state, m_State, m_CurrentOp));
if(m_ResultPollTimer)
{
::KillTimer(m_hWndHidden,m_ResultPollTimer);
m_ResultPollTimer = 0;
}
if(m_pLdap)
{
if( INVALID_MSG_ID != m_uMsgID )
{
WLDAP::ldap_abandon(m_pLdap, m_uMsgID);
}
WLDAP::ldap_unbind(m_pLdap);
}
m_pLdap = NULL;
m_uMsgID = INVALID_MSG_ID;
m_State = new_state;
m_CurrentOp = Op_NoOp;
SetLoggedOn( IsLoggedOn() );
TRACE_OUT(("CNmLDAP::_AbandonAllAndSetState:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
}
HRESULT CNmLDAP::_InternalLogoff(bool bRefreshLogoff)
{
DBGENTRY(CNmLDAP::_InternalLogoff);
TRACE_OUT(("CNmLDAP::_InternalLogoff:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
HRESULT hr = S_OK;
ASSERT(ms_bLdapDLLLoaded);
if( ( LoggingOff != m_State ) && ( Idle != m_State ) )
{
if(bRefreshLogoff)
{
m_CurrentOp = Op_Refresh_Logoff;
// If the server names are different, this means
// that we should display "logging off" XXX
if( lstrcmpi(m_strServer, m_strCurrentServer) )
{
_OnLoggingOff();
}
}
else
{
_OnLoggingOff();
m_CurrentOp = Op_Logoff;
}
if( LoggedIn == m_State )
{
hr = _BindAsync();
}
else if( Binding == m_State )
{
m_bLogoffAfterBindCompletes = true;
}
else if( (INVALID_MSG_ID != m_uMsgID ) && (NULL != m_pLdap ))
{
// Kill the timer
ASSERT(m_ResultPollTimer);
::KillTimer(m_hWndHidden,m_ResultPollTimer);
m_ResultPollTimer = 0;
// Abandon the current op
WLDAP::ldap_abandon(m_pLdap, m_uMsgID);
m_uMsgID = INVALID_MSG_ID;
m_State = Bound;
SetLoggedOn( IsLoggedOn() );
}
if(Bound == m_State)
{
ASSERT(m_pLdap);
_DeleteUser();
}
}
TRACE_OUT(("CNmLDAP::_InternalLogoff:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
DBGEXIT_HR(CNmLDAP::_InternalLogoff,hr);
return hr;
}
HRESULT CNmLDAP::Logoff()
{
DBGENTRY(CNmLDAP::Logoff);
TRACE_OUT(("CNmLDAP::Logoff:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
HRESULT hr = _InternalLogoff(false);
TRACE_OUT(("CNmLDAP::Logoff:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
DBGEXIT_HR(CNmLDAP::Logoff,hr);
return hr;
}
HRESULT CNmLDAP::Initialize( HINSTANCE hInst )
{
HRESULT hr = S_OK;
DBGENTRY(CNmLDAP::Initialize);
TRACE_OUT(("CNmLDAP::Initialize:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
ASSERT( Uninitialized == m_State );
if( ms_bLdapDLLLoaded || SUCCEEDED( hr = WLDAP::Init()))
{
ms_bLdapDLLLoaded = true;
////////////////////////////////////////
// Initialize user data
_GetUserSettingsFromRegistryAndGlobals();
////////////////////////////////////////
// Initialize hidden Window
WNDCLASS wcHidden =
{
0L,
_sWndProc,
0,
0,
hInst,
NULL,
NULL,
NULL,
NULL,
CNmLDAP_WCNAME
};
if(RegisterClass(&wcHidden))
{
m_hWndHidden = ::CreateWindow( CNmLDAP_WCNAME, g_szEmpty, 0, 0, 0, 0, 0, NULL, NULL, hInst, this);
if( m_hWndHidden )
{
m_State = Idle;
SetLoggedOn( IsLoggedOn() );
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
else
{
ERROR_OUT(("WLDAP::Init failed ( could not load wldap32.dll? )"));
}
TRACE_OUT(("CNmLDAP::Initialize:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
DBGEXIT_HR(CNmLDAP::Initialize,hr);
return hr;
}
HRESULT CNmLDAP::_GetUserSettingsFromRegistryAndGlobals()
{
DBGENTRY(CNmLDAP::_GetUserSettingsFromRegistryAndGlobals);
TRACE_OUT(("CNmLDAP::_GetUserSettingsFromRegistryAndGlobals:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
HRESULT hr = S_FALSE; // this would indicate that nothing changed
RegEntry reULS(ISAPI_CLIENT_KEY, HKEY_CURRENT_USER);
if(lstrcmpi(m_strSurName, reULS.GetString(ULS_REGKEY_LAST_NAME)))
{
hr = S_OK;
m_strSurName = reULS.GetString(ULS_REGKEY_LAST_NAME);
}
if(lstrcmpi(m_strGivenName, reULS.GetString(ULS_REGKEY_FIRST_NAME)))
{
hr = S_OK;
m_strGivenName = reULS.GetString(ULS_REGKEY_FIRST_NAME);
}
if(lstrcmpi(m_strEmailName, reULS.GetString(REGVAL_ULS_EMAIL_NAME)))
{
hr = S_OK;
m_strEmailName = reULS.GetString(REGVAL_ULS_EMAIL_NAME);
}
if(lstrcmpi(m_strComment, reULS.GetString(ULS_REGKEY_COMMENTS)))
{
hr = S_OK;
m_strComment = reULS.GetString(ULS_REGKEY_COMMENTS);
}
if(lstrcmpi(m_strLocation, reULS.GetString(ULS_REGKEY_LOCATION)))
{
hr = S_OK;
m_strLocation = reULS.GetString(ULS_REGKEY_LOCATION);
}
if(lstrcmpi(m_strSecurityToken, reULS.GetString(ULS_REGKEY_CLIENT_ID)))
{
hr = S_OK;
m_strSecurityToken = reULS.GetString(ULS_REGKEY_CLIENT_ID);
}
if(*m_strSecurityToken == '\0')
{ // The string was not found...
// When we log onto the LDAP server, we pass a fairly unique ID
// This is passed as the value to the ssecurity attribute
// In the case that NetMeeting goes away without actually logging
// off of the ILS server, when NetMeeting tries to log back on,
// it will pass this unique ID... if the server has not closed the
// session account for the user, the server uses this ID to "authenticate"
// that we are the same user as the last session...
TCHAR szNewClientID[MAX_PATH];
wsprintf(szNewClientID,"%lu", ::GetTickCount());
m_strSecurityToken = szNewClientID;
reULS.SetValue(ULS_REGKEY_CLIENT_ID,szNewClientID);
hr = S_OK;
}
if( lstrcmpi(m_strServer, CDirectoryManager::get_defaultServer()))
{
hr = S_OK;
m_strServer = CDirectoryManager::get_defaultServer();
m_iPort = DEFAULT_LDAP_PORT;
}
if(m_bVisible != (!reULS.GetNumber(ULS_REGKEY_DONT_PUBLISH, REGVAL_ULS_DONT_PUBLISH_DEFAULT)))
{
m_bVisible = !reULS.GetNumber(ULS_REGKEY_DONT_PUBLISH, REGVAL_ULS_DONT_PUBLISH_DEFAULT);
hr = S_OK;
}
if(m_bAudioHardware != (0 != (g_uMediaCaps & CAPFLAG_SEND_AUDIO)))
{
m_bAudioHardware = (0 != (g_uMediaCaps & CAPFLAG_SEND_AUDIO));
hr = S_OK;
}
if(m_bVideoHardware != (0 != (g_uMediaCaps & CAPFLAG_SEND_VIDEO)))
{
m_bVideoHardware = (0 != (g_uMediaCaps & CAPFLAG_SEND_VIDEO));
hr = S_OK;
}
TRACE_OUT(("CNmLDAP::_GetUserSettingsFromRegistryAndGlobals:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
DBGEXIT_HR(CNmLDAP::_GetUserSettingsFromRegistryAndGlobals,hr);
return hr;
}
HRESULT CNmLDAP::LogonAsync( LPCTSTR pcszServer /*=NULL*/)
{
HRESULT hr = S_OK;
DBGENTRY(CNmLDAP::LogonAsync);
TRACE_OUT(("CNmLDAP::LogonAsync:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
// Idle // Normal logon
//Binding
// Op_Logoff // Change it to logon refresh
// Bound // ldap_umbind-> Logon normal
// LoggingOff // Change to Op_Refresh_Logoff
// Uninitialized // return error
// AddingUser // do nothing
// UserAdded // do nothing
// SettingAppInfo // do nothing
// ModifyingAttrs // do nothing
// LoggedIn // do nothing
// Op_Refresh_Logoff // Do nothing
// Op_Modifying_InCallAttr // Do Nothing
// Op_Logon // Do Nothing
if( Uninitialized != m_State)
{
if(Bound == m_State)
{
_AbandonAllAndSetToIdle();
}
if(Idle == m_State)
{
if(pcszServer)
{
m_strServer = pcszServer;
m_iPort = DEFAULT_LDAP_PORT;
}
else
{
if(!IsLoggedOn())
{
_GetUserSettingsFromRegistryAndGlobals();
}
}
m_strCurrentServer = m_strServer;
g_pCCallto->SetIlsServerName( m_strCurrentServer );
TCHAR* szDN = new TCHAR[ lstrlen( LOGIN_USER_FILTER ) + lstrlen(m_strEmailName) + 1 ];
if( szDN )
{
wsprintf(szDN, LOGIN_USER_FILTER, m_strEmailName);
m_strCurrentDN = szDN;
delete [] szDN;
m_CurrentOp = Op_Logon;
hr = _BindAsync();
if( SUCCEEDED(hr) )
{
_OnLoggingOn();
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
else if((Op_Logoff == m_CurrentOp) || (LoggingOff == m_State))
{
m_CurrentOp = Op_Refresh_Logoff;
}
}
else
{
hr = E_FAIL;
}
TRACE_OUT(("CNmLDAP::LogonAsync:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
DBGEXIT_HR(CNmLDAP::LogonAsync,hr);
return hr;
}
HRESULT CNmLDAP::_BindAsync()
{
DBGENTRY(CNmLDAP::_BindAsync);
TRACE_OUT(("CNmLDAP::_BindAsync:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
ASSERT(( LoggedIn == m_State ) || ( Idle == m_State ));
ASSERT( m_CurrentOp != Op_NoOp );
ASSERT(m_hBindThread == NULL);
HRESULT hr = S_OK;
// Set our state to Binding
m_State = Binding;
SetLoggedOn( IsLoggedOn() );
// Start the bind in another thread
DWORD dwBindThreadID = 0;
m_hBindThread = CreateThread(NULL, 0, _sAsyncBindThreadFn, this, 0, &dwBindThreadID);
if(NULL == m_hBindThread)
{
ERROR_OUT(("CreateThread failed"));
hr = HRESULT_FROM_WIN32(GetLastError());
WLDAP::ldap_unbind(m_pLdap);
m_pLdap = NULL;
m_CurrentOp = Op_NoOp;
m_State = Idle;
}
SetLoggedOn( IsLoggedOn() );
TRACE_OUT(("CNmLDAP::_BindAsync:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
DBGEXIT_HR(CNmLDAP::_BindAsync,hr);
return hr;
}
/*static*/
DWORD CNmLDAP::_sAsyncBindThreadFn(LPVOID lpParameter)
{
DBGENTRY(CNmLDAP::_sAsyncBindThreadFn);
ASSERT(lpParameter);
CNmLDAP* pThis = reinterpret_cast<CNmLDAP*>(lpParameter);
ASSERT(pThis);
ULONG ulRet = LDAP_OPERATIONS_ERROR;
ULONG ulErr = ERROR_INVALID_HANDLE;
if( pThis )
{
WSADATA wsaData;
if( WSAStartup( 0x0101, &wsaData ) == 0 )
{
if( wsaData.wVersion > 1 )
{
pThis->m_pLdap = WLDAP::ldap_init( const_cast<LPTSTR>((LPCTSTR)pThis->m_strCurrentServer), pThis->m_iPort );
if( pThis->m_pLdap )
{
::SetLastError(NO_ERROR);
ulRet = WLDAP::ldap_bind_s(pThis->m_pLdap, const_cast<LPTSTR>(g_szEmpty), const_cast<LPTSTR>(g_szEmpty), LDAP_AUTH_SIMPLE );
if( ulRet == LDAP_SUCCESS )
{
ulErr = ::GetLastError();
::SendMessage(pThis->m_hWndHidden, WM_USER_BIND_COMPLETE, ulRet, ulErr);
}
else if( pThis->m_iPort == DEFAULT_LDAP_PORT )
{
WLDAP::ldap_unbind( pThis->m_pLdap );
pThis->m_pLdap = WLDAP::ldap_init( const_cast<LPTSTR>((LPCTSTR)pThis->m_strCurrentServer), ALTERNATE_LDAP_PORT); // Automatically retry with alternate port...
if( pThis->m_pLdap != NULL )
{
::SetLastError(NO_ERROR);
ulRet = WLDAP::ldap_bind_s(pThis->m_pLdap, const_cast<LPTSTR>(g_szEmpty), const_cast<LPTSTR>(g_szEmpty), LDAP_AUTH_SIMPLE );
if( ulRet == LDAP_SUCCESS )
{
pThis->m_iPort = ALTERNATE_LDAP_PORT;
}
ulErr = ::GetLastError();
::SendMessage(pThis->m_hWndHidden, WM_USER_BIND_COMPLETE, ulRet, ulErr);
}
else
{
TRACE_OUT(("ldap_init failed"));
pThis->m_State = Idle;
pThis->m_CurrentOp = Op_NoOp;
}
}
}
else
{
TRACE_OUT(("ldap_init failed"));
pThis->m_State = Idle;
pThis->m_CurrentOp = Op_NoOp;
}
}
WSACleanup();
}
}
DBGEXIT(CNmLDAP::_sAsyncBindThreadFn);
return ulRet;
}
LRESULT CNmLDAP::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lr = TRUE;
DBGENTRY(CNmLDAP::WndProc);
switch( uMsg )
{
case WM_USER_BIND_COMPLETE:
_OnUserBindComplete((INT)wParam, (DWORD)lParam);
break;
case WM_TIMER:
lr = FALSE; // This means that we handle the message
_OnTimer(wParam);
break;
case WM_NEED_RELOGON:
OnReLogon();
break;
default:
lr = DefWindowProc(hwnd, uMsg, wParam, lParam);
break;
}
DBGEXIT_ULONG(CNmLDAP::WndProc,lr);
return lr;
}
void CNmLDAP::_OnTimer(UINT_PTR TimerID)
{
DBGENTRY(CNmLDAP::_OnTimer);
TRACE_OUT(("CNmLDAP::_OnTimer:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
// We check the timer ID values first because we may have killed the timer,
// and the message couldv be simply vestigal ( that means left over from an earlier time)...
if(m_LogoffTimer && (WaitForLogoffTimer == TimerID))
{
// We are waiting in the distructor for an async operation to complete
// and we have waited too long... kill the timer and set the m_hEventWaitForLogoffDone event
::KillTimer(m_hWndHidden, m_LogoffTimer);
m_LogoffTimer = 0;
if(m_hEventWaitForLogoffDone)
{
SetEvent(m_hEventWaitForLogoffDone);
}
}
else if( (INVALID_MSG_ID != m_uMsgID) && m_ResultPollTimer && (PollForResultTimer == TimerID ))
{
ASSERT(m_pLdap);
::KillTimer( m_hWndHidden, m_ResultPollTimer );
m_ResultPollTimer = 0;
LDAPMessage *pMsg = NULL;
LDAP_TIMEVAL TimeoutVal = { 0, 0 };
INT res = WLDAP::ldap_result( m_pLdap, m_uMsgID, LDAP_MSG_ALL, &TimeoutVal, &pMsg );
if( 0 == res )
{
// ldap_result timedout
m_ResultPollTimer = ::SetTimer( m_hWndHidden, PollForResultTimer, RESULT_POLL_INTERVAL, NULL );
if( !m_ResultPollTimer )
{
ERROR_OUT(("SetTimer failed!"));
_AbandonAllAndRecoverState();
}
}
else if( LDAP_RESULT_ERROR == res )
{
ERROR_OUT(("ldap_result failed"));
_AbandonAllAndRecoverState();
}
else
{
// We got the result, so reset this
m_uMsgID = INVALID_MSG_ID;
if( AddingUser == m_State )
{
_OnAddingUserResult(pMsg->lm_returncode);
WLDAP::ldap_msgfree(pMsg);
}
else if( ( SettingAppInfo == m_State ) || ( ModifyingAttrs == m_State ) )
{
_OnSettingAppInfoOrModifyingAttrsResult(pMsg->lm_returncode);
WLDAP::ldap_msgfree(pMsg);
}
else if( LoggingOff == m_State )
{
_OnLoggingOffResult(pMsg->lm_returncode);
WLDAP::ldap_msgfree(pMsg);
}
}
}
TRACE_OUT(("CNmLDAP::_OnTimer:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_OnTimer);
}
void CNmLDAP::_OnUserBindComplete(INT LdapResult, DWORD LastError )
{
DBGENTRY(CNmLDAP::_OnUserBindComplete);
TRACE_OUT(("CNmLDAP::_OnUserBindComplete:enter(%d): m_State:%d: m_currentOp:%d", LdapResult, m_State, m_CurrentOp));
ASSERT(m_hBindThread);
ASSERT(Binding == m_State);
CloseHandle(m_hBindThread);
m_hBindThread = NULL;
if(LDAP_SUCCESS == LdapResult)
{
m_State = Bound;
SetLoggedOn( IsLoggedOn() );
if( m_bRefreshAfterBindCompletes )
{
// If a refresh is attempted while
// the bind operation is in progress
// we just wait for the bind to complete
// then we well do the refresh
m_bRefreshAfterBindCompletes = false;
_RefreshServer();
}
else if( m_bLogoffAfterBindCompletes )
{
m_bLogoffAfterBindCompletes = false;
_DeleteUser();
}
else
{
if( Op_Logon == m_CurrentOp )
{
m_CurrentOp = Op_NoOp;
_AddUser();
}
else if( Op_Logoff == m_CurrentOp )
{
m_CurrentOp = Op_NoOp;
_DeleteUser();
}
else if( Op_Refresh_Logoff == m_CurrentOp )
{
_DeleteUser();
}
else if( Op_Modifying_InCallAttr == m_CurrentOp )
{
m_CurrentOp = Op_NoOp;
_ModifyInCallAttr();
}
}
}
else
{
eCurrentOp OldOp = m_CurrentOp;
_AbandonAllAndRecoverState(OldOp);
if( ( Op_Refresh_Logoff == OldOp ) && ( lstrcmpi( m_strCurrentServer, m_strServer ) ) )
{
// If the server names have changed...
// Suppose that the server you are logged on to
// goes down and then you change the server that you want
// to be logged on to ( before you have any indication that
// the server has gone down... You want to log off the old server
// But the server is not available... We are basically going to
// ignore the fact that there was a problem logging off
// from the server, and we are going to simply log on to the new server
_OnLoggedOff();
LogonAsync();
}
else if( Op_Logoff == OldOp )
{
// We don't have to put up a message box...
_OnLoggedOff();
}
else
{
if( (LDAP_SERVER_DOWN == LdapResult) || (LDAP_TIMEOUT == LdapResult) )
{
if (Op_Modifying_InCallAttr == OldOp)
{
ERROR_OUT(("ldap_bind for InCallAttr returns server-down or timeout"));
}
else
{
::PostConfMsgBox(IDS_ULSLOGON_BADSERVER);
_OnLoggedOff();
}
}
else
{
ERROR_OUT(("ldap_bind returned error 0x%08x LdapResult, GetLastError == 0x%08x", LdapResult, LastError));
}
}
}
TRACE_OUT(("CNmLDAP::_OnUserBindComplete:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_OnUserBindComplete);
}
void CNmLDAP::_OnLoggingOffResult(int Result)
{
DBGENTRY(CNmLDAP::_OnLoggingOffResult);
TRACE_OUT(("CNmLDAP::_OnLoggingOffResult:enter(%d): m_State:%d: m_currentOp:%d", Result, m_State, m_CurrentOp));
if( (LDAP_SUCCESS == Result) || (LDAP_NO_SUCH_OBJECT == Result) || (LDAP_SERVER_DOWN == Result))
{
// We are waiting in the destructor for the ldap logof operations to complete
// Now that it has, we hawe to signal the destructor unblocks
if(m_hEventWaitForLogoffDone)
{
SetEvent(m_hEventWaitForLogoffDone);
}
_OnLoggedOff();
}
else
{
ERROR_OUT(("Ldap Error 0x%08x", Result));
}
WLDAP::ldap_unbind(m_pLdap);
m_State = Idle;
m_pLdap = NULL;
SetLoggedOn( IsLoggedOn() );
if( Op_Refresh_Logoff == m_CurrentOp )
{
m_CurrentOp = Op_NoOp;
LogonAsync();
}
TRACE_OUT(("CNmLDAP::_OnLoggingOffResult:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_OnLoggingOffResult);
}
void CNmLDAP::_OnSettingAppInfoOrModifyingAttrsResult(int Result)
{
DBGENTRY(CNmLDAP::_OnSettingAppInfoOrModifyingAttrsResult);
TRACE_OUT(("CNmLDAP::_OnSettingAppInfoOrModifyingAttrsResult:enter(%d): m_State:%d: m_currentOp:%d", Result, m_State, m_CurrentOp));
if( LDAP_SUCCESS == Result)
{
// start the keep alive thread
if (NULL != m_pKeepAlive)
{
m_pKeepAlive->Start();
}
if(SettingAppInfo == m_State)
{
m_State = LoggedIn;
SetLoggedOn( IsLoggedOn() );
_OnLoggedOn();
}
else
{
m_State = LoggedIn;
SetLoggedOn( IsLoggedOn() );
}
if( m_bSendInCallAttrWhenDone )
{
m_bSendInCallAttrWhenDone = false;
_ModifyInCallAttr();
}
else
{
WLDAP::ldap_unbind(m_pLdap);
if(m_ResultPollTimer)
{
::KillTimer(m_hWndHidden,m_ResultPollTimer);
m_ResultPollTimer = 0;
}
m_uMsgID = INVALID_MSG_ID;
m_pLdap = NULL;
m_State = LoggedIn;
SetLoggedOn( IsLoggedOn() );
}
}
else
{
ERROR_OUT( ("Ldap Error 0x%08x, DN=%s", Result, m_strCurrentDN) );
if (ModifyingAttrs == m_State && NULL != m_pKeepAlive)
{
_AbandonAllAndRecoverState();
if(LDAP_NO_SUCH_OBJECT == Result)
{
_OnLoggedOff();
LogonAsync();
}
}
else
{
_AbandonAllAndSetToIdle();
_OnLoggedOff();
if(LDAP_NO_SUCH_OBJECT == Result)
{
LogonAsync();
}
}
}
TRACE_OUT(("CNmLDAP::_OnSettingAppInfoOrModifyingAttrsResult:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_OnSettingAppInfoOrModifyingAttrsResult);
}
void CNmLDAP::_OnAddingUserResult( int Result)
{
DBGENTRY(CNmLDAP::_OnAddingUserResult);
TRACE_OUT(("CNmLDAP::_OnAddingUserResult:enter(%d): m_State:%d: m_currentOp:%d", Result, m_State, m_CurrentOp));
if( LDAP_SUCCESS == Result )
{
m_State = UserAdded;
SetLoggedOn( IsLoggedOn() );
_SetAppInfo();
}
else
{
UINT uStringID;
switch( Result )
{
case LDAP_ALREADY_EXISTS:
uStringID = IDS_ULSLOGON_DUPLICATE;
break;
case LDAP_NAMING_VIOLATION:
uStringID = IDS_ULSLOGON_WORD_FILTER;
break;
case LDAP_UNWILLING_TO_PERFORM:
uStringID = IDS_ILLEGALEMAILNAME;
break;
case LDAP_UNDEFINED_TYPE:
case LDAP_SERVER_DOWN:
// W2K server returns this under heavy load situations...
uStringID = IDS_ULSLOGON_ERROR;
break;
default:
uStringID = IDS_ULSLOGON_ERROR;
ERROR_OUT( ("Ldap Error 0x%08x, DN=%s", Result, m_strCurrentDN) );
break;
}
::PostConfMsgBox( uStringID );
_OnLoggedOff();
WLDAP::ldap_unbind(m_pLdap);
m_pLdap = NULL;
m_State = Idle;
SetLoggedOn( IsLoggedOn() );
}
TRACE_OUT(("CNmLDAP::_OnAddingUserResult:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_OnAddingUserResult);
}
/*static*/
LRESULT CNmLDAP::_sWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lr = 0;
if( WM_NCCREATE != uMsg )
{
CNmLDAP* pNmLdap = reinterpret_cast<CNmLDAP*>( ::GetWindowLongPtr( hwnd, GWLP_USERDATA ) );
if( pNmLdap )
{
lr = pNmLdap->WndProc( hwnd, uMsg, wParam, lParam );
}
}
else
{
lr = TRUE; // This means to continue creating the window
CREATESTRUCT* pCreateStruct = reinterpret_cast<CREATESTRUCT*>(lParam);
if( pCreateStruct )
{
::SetWindowLongPtr( hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pCreateStruct->lpCreateParams));
}
}
return lr;
}
void CNmLDAP::_SetAppInfo()
{
DBGENTRY(CNmLDAP::_SetInfo);
TRACE_OUT(("CNmLDAP::_SetInfo:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
ASSERT(NULL != m_pLdap);
ASSERT(UserAdded == m_State);
ASSERT(INVALID_MSG_ID == m_uMsgID);
// These are the app attribute vals
DECLARE_LDAP_MOD(LDAP_MOD_ADD, smodop, LDAP_MODOP_ADDAPP);
DECLARE_LDAP_MOD(LDAP_MOD_ADD, sappid, _T("ms-netmeeting"));
DECLARE_LDAP_MOD(LDAP_MOD_ADD, smimetype, _T("text/iuls"));
DECLARE_LDAP_MOD(LDAP_MOD_ADD, sappguid, _T("008aff194794cf118796444553540000"));
DECLARE_LDAP_MOD2(LDAP_MOD_ADD, sprotid, _T("t120"), _T("h323"));
DECLARE_LDAP_MOD2(LDAP_MOD_ADD, sprotmimetype, _T("text/t120"), _T("text/h323"));
DECLARE_LDAP_MOD2(LDAP_MOD_ADD, sport, _T("1503"), _T("1720"));
// This is the app mod array
LDAPMod *apModApp[] =
{
LDAP_MOD_ENTRY(smodop),
LDAP_MOD_ENTRY(sappid),
LDAP_MOD_ENTRY(smimetype),
LDAP_MOD_ENTRY(sappguid),
LDAP_MOD_ENTRY(sprotid),
LDAP_MOD_ENTRY(sprotmimetype),
LDAP_MOD_ENTRY(sport),
NULL
};
m_uMsgID = WLDAP::ldap_modify( m_pLdap, const_cast<LPTSTR>((LPCTSTR)m_strCurrentDN), apModApp );
if( INVALID_MSG_ID != m_uMsgID )
{
m_ResultPollTimer = ::SetTimer( m_hWndHidden, PollForResultTimer, RESULT_POLL_INTERVAL, NULL );
ASSERT(m_ResultPollTimer);
m_State = SettingAppInfo;
}
else
{
DWORD dwErr;
ERROR_OUT(("ldap_modify returned error 0x%08x", (WLDAP::ldap_get_option(m_pLdap, LDAP_OPT_ERROR_NUMBER, &dwErr), dwErr)));
WLDAP::ldap_unbind(m_pLdap);
m_pLdap = NULL;
m_State = Idle;
}
SetLoggedOn( IsLoggedOn() );
TRACE_OUT(("CNmLDAP::_SetInfo:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_SetInfo);
}
void CNmLDAP::_ModifyInCallAttr()
{
TRACE_OUT(("CNmLDAP::_ModifyInCallAttr:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DECLARE_LDAP_MOD(LDAP_MOD_REPLACE, smodop, LDAP_MODOP_MODIFYUSER);
DECLARE_LDAP_MOD(LDAP_MOD_REPLACE, ilsA26214430, m_bInCall ? LDAP_ATTR_TRUE : LDAP_ATTR_FALSE);
LDAPMod *apMod[] =
{
LDAP_MOD_ENTRY(smodop),
LDAP_MOD_ENTRY(ilsA26214430),
NULL
};
TRACE_OUT(("About to modify InCallAttrs for this person: %s", m_strCurrentDN));
m_uMsgID = WLDAP::ldap_modify( m_pLdap, const_cast<LPTSTR>((LPCTSTR)m_strCurrentDN), apMod );
if( INVALID_MSG_ID != m_uMsgID )
{
m_ResultPollTimer = ::SetTimer( m_hWndHidden, PollForResultTimer, RESULT_POLL_INTERVAL, NULL );
ASSERT(m_ResultPollTimer);
m_State = ModifyingAttrs;
}
else
{
DWORD dwErr;
ERROR_OUT(("ldap_modify returned error 0x%08x", (WLDAP::ldap_get_option(m_pLdap, LDAP_OPT_ERROR_NUMBER, &dwErr), dwErr)));
WLDAP::ldap_unbind(m_pLdap);
m_pLdap = NULL;
m_State = (NULL != m_pKeepAlive) ? LoggedIn : Idle; // restore the state
}
SetLoggedOn( IsLoggedOn() );
TRACE_OUT(("CNmLDAP::_ModifyInCallAttr:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
}
void CNmLDAP::_DeleteUser()
{
DBGENTRY(CNmLDAP::_DeleteUser);
TRACE_OUT(("CNmLDAP::_DeleteUser:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
// end the keep alive thread
if (NULL != m_pKeepAlive)
{
m_pKeepAlive->End();
m_pKeepAlive = NULL;
}
ASSERT(NULL != m_pLdap);
ASSERT(Bound == m_State);
ASSERT(INVALID_MSG_ID == m_uMsgID);
m_uMsgID = WLDAP::ldap_delete(m_pLdap, const_cast<LPTSTR>((LPCTSTR)(m_strCurrentDN)));
if( INVALID_MSG_ID != m_uMsgID )
{
m_State = LoggingOff;
m_ResultPollTimer = ::SetTimer( m_hWndHidden, PollForResultTimer, RESULT_POLL_INTERVAL, NULL );
ASSERT(m_ResultPollTimer);
}
else
{
WLDAP::ldap_unbind(m_pLdap);
m_pLdap = NULL;
m_State = Idle;
}
SetLoggedOn( IsLoggedOn() );
TRACE_OUT(("CNmLDAP::_DeleteUser:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_DeleteUser);
}
void CNmLDAP::_AddUser()
{
DBGENTRY(CNmLDAP::_AddUser);
TRACE_OUT(("CNmLDAP::_AddUser:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
ASSERT(NULL != m_pLdap);
ASSERT(Bound == m_State);
ASSERT(INVALID_MSG_ID == m_uMsgID);
// These are the user attribute values
DECLARE_LDAP_MOD(LDAP_MOD_ADD, cn, const_cast<LPTSTR>((LPCTSTR)m_strEmailName));
DECLARE_LDAP_MOD(LDAP_MOD_ADD, givenname, const_cast<LPTSTR>((LPCTSTR)m_strGivenName));
DECLARE_LDAP_MOD(LDAP_MOD_ADD, surname, const_cast<LPTSTR>((LPCTSTR)m_strSurName));
DECLARE_LDAP_MOD(LDAP_MOD_ADD, rfc822mailbox, const_cast<LPTSTR>((LPCTSTR)m_strEmailName));
DECLARE_LDAP_MOD(LDAP_MOD_ADD, location, const_cast<LPTSTR>((LPCTSTR)m_strLocation));
DECLARE_LDAP_MOD(LDAP_MOD_ADD, comment, const_cast<LPTSTR>((LPCTSTR)m_strComment));
DECLARE_LDAP_MOD(LDAP_MOD_ADD, sflags, m_bVisible ? LDAP_ATTR_TRUE : LDAP_ATTR_FALSE );
DECLARE_LDAP_MOD(LDAP_MOD_ADD, ilsA26214430, m_bInCall ? LDAP_ATTR_TRUE : LDAP_ATTR_FALSE );
DECLARE_LDAP_MOD(LDAP_MOD_ADD, ilsA32833566, m_bAudioHardware ? LDAP_ATTR_TRUE : LDAP_ATTR_FALSE );
DECLARE_LDAP_MOD(LDAP_MOD_ADD, ilsA32964638, m_bVideoHardware ? LDAP_ATTR_TRUE : LDAP_ATTR_FALSE );
DECLARE_LDAP_MOD(LDAP_MOD_ADD, ilsA39321630, LDAP_ATTR_BUSINESS );
DECLARE_LDAP_MOD(LDAP_MOD_ADD, ssecurity, const_cast<LPTSTR>((LPCTSTR)m_strSecurityToken));
DECLARE_LDAP_MOD(LDAP_MOD_ADD, c, LDAP_ATTR_DUMMY_COUNTRYNAME);
// We have to get IP address dynamically
TCHAR szIpAddr[MAX_PATH];
szIpAddr[0] = _T('\0');
DWORD dwLocalIPAddress = INADDR_NONE;
_GetIpAddressOfLdapSession( szIpAddr, CCHMAX(szIpAddr), &dwLocalIPAddress );
DECLARE_LDAP_MOD(LDAP_MOD_ADD, sipaddress, szIpAddr);
// We store the version info on the server
TCHAR szVer[MAX_PATH];
wsprintf(szVer,"%lu",VER_PRODUCTVERSION_DW);
DECLARE_LDAP_MOD(LDAP_MOD_ADD, ilsA26279966, szVer);
// This is the user mod array
LDAPMod *apModUser[] =
{
LDAP_MOD_ENTRY(cn),
LDAP_MOD_ENTRY(givenname),
LDAP_MOD_ENTRY(surname),
LDAP_MOD_ENTRY(rfc822mailbox),
LDAP_MOD_ENTRY(location),
LDAP_MOD_ENTRY(comment),
LDAP_MOD_ENTRY(c),
LDAP_MOD_ENTRY(sipaddress),
LDAP_MOD_ENTRY(sflags),
LDAP_MOD_ENTRY(ssecurity),
LDAP_MOD_ENTRY(ilsA26214430),
LDAP_MOD_ENTRY(ilsA26279966),
LDAP_MOD_ENTRY(ilsA32833566),
LDAP_MOD_ENTRY(ilsA32964638),
LDAP_MOD_ENTRY(ilsA39321630),
NULL
};
TCHAR* szDN = new TCHAR[ lstrlen(LOGIN_USER_FILTER) + lstrlen(m_strEmailName) + 1 ];
if( szDN )
{
wsprintf(szDN, LOGIN_USER_FILTER, m_strEmailName);
m_strCurrentDN = szDN;
delete [] szDN;
}
TCHAR* szRefresh = new TCHAR[ lstrlen(LDAP_REFRESH_FILTER) + lstrlen(m_strEmailName) + 1 ];
if( szRefresh )
{
wsprintf(szRefresh, LDAP_REFRESH_FILTER, m_strEmailName);
}
m_uMsgID = WLDAP::ldap_add( m_pLdap, const_cast<LPTSTR>((LPCTSTR)m_strCurrentDN), apModUser );
if( INVALID_MSG_ID != m_uMsgID )
{
m_State = AddingUser;
m_ResultPollTimer = ::SetTimer( m_hWndHidden, PollForResultTimer, RESULT_POLL_INTERVAL, NULL );
ASSERT(m_ResultPollTimer);
// create the keep alive object
if (NULL != m_pKeepAlive)
{
m_pKeepAlive->End();
m_pKeepAlive = NULL;
}
BOOL fRet = FALSE;
m_pKeepAlive = new CKeepAlive(&fRet,
m_hWndHidden,
dwLocalIPAddress,
m_strCurrentServer, m_iPort,
szRefresh);
ASSERT(NULL != m_pKeepAlive && fRet);
}
else
{
WLDAP::ldap_unbind(m_pLdap);
m_pLdap = NULL;
m_State = Idle;
}
delete [] szRefresh;
SetLoggedOn( IsLoggedOn() );
TRACE_OUT(("CNmLDAP::_AddUser:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_AddUser);
}
void CNmLDAP::_OnLoggedOn()
{
DBGENTRY(CNmLDAP::_OnLoggedOn);
TRACE_OUT(("CNmLDAP::_OnLoggedOn:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
::UpdateUI(CRUI_STATUSBAR | CRUI_CALLANIM, TRUE);
TRACE_OUT(("CNmLDAP::_OnLoggedOn:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_OnLoggedOn);
}
void CNmLDAP::_OnLoggedOff()
{
DBGENTRY(CNmLDAP::_OnLoggedOff);
TRACE_OUT(("CNmLDAP::_OnLoggedOff:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
::UpdateUI(CRUI_STATUSBAR | CRUI_CALLANIM, TRUE);
TRACE_OUT(("CNmLDAP::_OnLoggedOff:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_OnLoggedOff);
}
void CNmLDAP::_OnLoggingOn()
{
DBGENTRY(CNmLDAP::_OnLoggingOn);
TRACE_OUT(("CNmLDAP::_OnLoggingOn:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
::UpdateUI(CRUI_STATUSBAR | CRUI_CALLANIM, TRUE);
TRACE_OUT(("CNmLDAP::_OnLoggingOn:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_OnLoggingOn);
}
void CNmLDAP::_OnLoggingOff()
{
DBGENTRY(CNmLDAP::_OnLoggingOff);
TRACE_OUT(("CNmLDAP::_OnLoggingOff:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
::UpdateUI(CRUI_STATUSBAR | CRUI_CALLANIM, TRUE);
TRACE_OUT(("CNmLDAP::_OnLoggingOff:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
DBGEXIT(CNmLDAP::_OnLoggingOff);
}
void CNmLDAP::_GetIpAddressOfLdapSession( LPTSTR szIpAddr, int cchMax, DWORD *pdwIPAddr )
{
DBGENTRY(CNmLDAP::_GetIpAddressOfLdapSession);
if (NULL != szIpAddr)
{
szIpAddr[0] = _T('\0');
}
SOCKET s = INVALID_SOCKET;
if( LDAP_SUCCESS == WLDAP::ldap_get_option(m_pLdap, LDAP_OPT_DESC, &s ))
{
SOCKADDR_IN addr;
int NameLen = sizeof(addr);
if(0 == getsockname(s, reinterpret_cast<SOCKADDR*>(&addr), &NameLen))
{
if (NULL != szIpAddr)
{
wsprintf(szIpAddr, "%u", addr.sin_addr.s_addr);
}
if (NULL != pdwIPAddr)
{
*pdwIPAddr = addr.sin_addr.s_addr;
}
}
}
DBGEXIT(CNmLDAP::_GetIpAddressOfLdapSession);
}
void InitNmLdapAndLogon()
{
ASSERT( NULL == g_pLDAP );
g_pLDAP = new CNmLDAP;
if(g_pLDAP)
{
// Initialize the LDAP object...
if( SUCCEEDED(g_pLDAP->Initialize( _Module.GetModuleInstance())))
{
g_pLDAP->LogonAsync();
}
else
{
delete g_pLDAP;
g_pLDAP = NULL;
}
}
else
{
ERROR_OUT(("new CNmLDAP returned NULL"));
}
}
/////////////////////////////////////////////////////////
//
// CKeepAlive
//
void CALLBACK KeepAliveTimerProc(HWND, UINT, UINT_PTR, DWORD)
{
// doing nothing at all
}
DWORD KeepAliveThreadProc(LPVOID pParam)
{
// make sure we have a valid socket
WSADATA wsaData;
int iRet = ::WSAStartup(0x0101, &wsaData);
ASSERT(! iRet);
if (! iRet)
{
CKeepAlive *pKeepAlive = (CKeepAlive *) pParam;
ASSERT(NULL != pKeepAlive);
// translate server name into ip address
if (pKeepAlive->SetServerIPAddress())
{
// start the timer
UINT nKeepAliveInterval = INITIAL_REFRESH_INTERVAL_MINUTES;
UINT_PTR nTimerID = ::SetTimer(NULL, 0, nKeepAliveInterval * 60 * 1000, KeepAliveTimerProc);
ASSERT(nTimerID);
// watch for the timer message
MSG msg, msg2;
while (::GetMessage(&msg, NULL, 0, 0))
{
msg2 = msg; // keep a copy of this message
// dispatch messages
::DispatchMessage(&msg);
// intercept the WM_TIMER message thru msg2
if (WM_TIMER == msg2.message && nTimerID == msg2.wParam)
{
BOOL fRetry = TRUE;
// kill the timer to avoid timer overrun
::KillTimer(NULL, nTimerID);
nTimerID = 0;
// ping the server in case of dialup networking
if (pKeepAlive->Ping())
{
// connect to the server
LDAP *ld = WLDAP::ldap_open(pKeepAlive->GetServerName(),
pKeepAlive->GetServerPortNumber());
if (NULL != ld)
{
if (pKeepAlive->Bind(ld))
{
if (pKeepAlive->KeepAlive(ld, &nKeepAliveInterval))
{
// successfully send a keep alive
fRetry = FALSE;
DWORD dwLocalIPAddress = pKeepAlive->GetLocalIPAddress(ld);
if (INADDR_NONE != dwLocalIPAddress)
{
if (pKeepAlive->GetLocalIPAddress() != dwLocalIPAddress)
{
pKeepAlive->SetLocalIPAddress(dwLocalIPAddress);
pKeepAlive->UpdateIPAddressOnServer();
}
}
}
}
WLDAP::ldap_unbind(ld);
}
}
// start the new timer based on the new internal
nTimerID = ::SetTimer(NULL, 0,
fRetry ? (15 * 1000) : (nKeepAliveInterval * 60 * 1000),
KeepAliveTimerProc);
ASSERT(nTimerID);
} // if wm timer
} // while get message
if (nTimerID)
{
::KillTimer(NULL, nTimerID);
}
}
delete pKeepAlive;
::WSACleanup();
}
return 0;
}
CKeepAlive::CKeepAlive
(
BOOL *pfRet,
HWND hwndMainThread,
DWORD dwLocalIPAddress,
const TCHAR * const pcszServerName,
UINT nPort,
LPTSTR pszKeepAliveFilter
)
:
m_hwndMainThread(hwndMainThread),
m_dwLocalIPAddress(dwLocalIPAddress),
m_dwServerIPAddress(INADDR_NONE),
m_pszServerName(NULL),
m_nPort(nPort),
m_pszKeepAliveFilter(NULL),
m_hThread(NULL),
m_dwThreadID(0),
m_fAborted(FALSE)
{
*pfRet = FALSE; // assume failure
// sanity check
ASSERT(NULL != hwndMainThread);
ASSERT(INADDR_NONE != dwLocalIPAddress && 0 != dwLocalIPAddress);
ASSERT(nPort);
// create the server name
ASSERT(NULL != pcszServerName);
ULONG nStrLen = ::lstrlen(pcszServerName) + 1;
m_pszServerName = new TCHAR[nStrLen];
if (NULL != m_pszServerName)
{
::CopyMemory(m_pszServerName, pcszServerName, nStrLen * sizeof(TCHAR));
TCHAR * const pszPort = StrChr( m_pszServerName, ':' );
if( pszPort != NULL )
{
// Truncate the server name here for dns lookup....
// and this port number overrides the nPort parameter...
*pszPort = '\0';
HRESULT hrResult = DecimalStringToUINT( pszPort + 1, m_nPort );
ASSERT( hrResult == S_OK );
if( hrResult != S_OK )
{
m_nPort = DEFAULT_LDAP_PORT;
}
}
// create the fresh filter
ASSERT(NULL != pszKeepAliveFilter);
nStrLen = ::lstrlen(pszKeepAliveFilter) + 1;
m_pszKeepAliveFilter = new TCHAR[nStrLen];
if (NULL != m_pszKeepAliveFilter)
{
::CopyMemory(m_pszKeepAliveFilter, pszKeepAliveFilter, nStrLen * sizeof(TCHAR));
*pfRet = TRUE;
}
}
}
CKeepAlive::~CKeepAlive(void)
{
delete m_pszServerName;
delete m_pszKeepAliveFilter;
}
BOOL CKeepAlive::Start(void)
{
if (! m_dwThreadID)
{
ASSERT(NULL == m_hThread);
// create the worker thread
m_hThread = ::CreateThread(NULL, 0, KeepAliveThreadProc, this, 0, &m_dwThreadID);
}
ASSERT(NULL != m_hThread);
return (NULL != m_hThread);
}
BOOL CKeepAlive::End(BOOL fSync)
{
DWORD dwRet = WAIT_OBJECT_0;
// cache thread handle and ID
HANDLE hThread = m_hThread;
DWORD dwThreadID = m_dwThreadID;
// abort any pending operation
m_fAborted = TRUE;
// notify the worker thread to go away
if (m_dwThreadID)
{
ASSERT(NULL != m_hThread);
m_dwThreadID = 0;
::PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
}
// wait for the worker thread exit for 5 seconds
if (NULL != hThread)
{
// need more work to unblock it
if (fSync)
{
dwRet = ::WaitForSingleObject(hThread, 5000); // 5 second timeout
ASSERT(WAIT_TIMEOUT != dwRet);
}
::CloseHandle(hThread);
}
return (WAIT_TIMEOUT != dwRet);
}
BOOL CKeepAlive::SetServerIPAddress(void)
{
ASSERT(NULL != m_pszServerName);
// check to see if the server name is a dotted IP address string
m_dwServerIPAddress = ::inet_addr(m_pszServerName);
if (INADDR_NONE == m_dwServerIPAddress)
{
// it is not a dotted string, it must be a name.
// get the host entry by name
PHOSTENT phe = ::gethostbyname(m_pszServerName);
if (phe != NULL)
{
// get info from the host entry
m_dwServerIPAddress = *(DWORD *) phe->h_addr;
}
}
ASSERT(INADDR_NONE != m_dwServerIPAddress);
return (INADDR_NONE != m_dwServerIPAddress);
}
BOOL CKeepAlive::Ping(void)
{
BOOL fRet = TRUE; // assume success
if (NULL != g_pPing)
{
if (g_pPing->IsAutodialEnabled())
{
ASSERT(INADDR_NONE != m_dwServerIPAddress);
HRESULT hr = g_pPing->Ping(m_dwServerIPAddress, PING_TIMEOUT_INTERVAL, PING_RETRIES);
fRet = (S_OK == hr);
}
}
return fRet;
}
BOOL CKeepAlive::Bind(LDAP *ld)
{
ASSERT(NULL != ld);
if (! m_fAborted)
{
// anonymous bind
ULONG nMsgID = WLDAP::ldap_bind(ld, TEXT(""), TEXT(""), LDAP_AUTH_SIMPLE);
if (INVALID_MSG_ID != nMsgID)
{
// poll the result every quarter second
const ULONG c_nTimeoutInQuarterSecond = 4 * LDAP_TIMEOUT_IN_SECONDS;
for (ULONG i = 0; (i < c_nTimeoutInQuarterSecond) && (! m_fAborted); i++)
{
// no timeout, if no result, return immediately
LDAP_TIMEVAL TimeVal;
TimeVal.tv_usec = 0;
TimeVal.tv_sec = 0;
// check the result
LDAPMessage *pMsg = NULL;
ULONG nResultType = WLDAP::ldap_result(ld, nMsgID, LDAP_MSG_ALL, &TimeVal, &pMsg);
if (nResultType == LDAP_RES_BIND)
{
ASSERT(NULL != pMsg);
WLDAP::ldap_msgfree(pMsg);
return TRUE;
}
// deal with timeout or error
if (LDAP_RESULT_TIMEOUT == nResultType)
{
if (! m_fAborted)
{
::Sleep(250); // sleep for a quarter second
continue;
}
}
ASSERT(LDAP_RESULT_ERROR != nResultType);
break;
}
// failure, do the cleanup
WLDAP::ldap_abandon(ld, nMsgID);
}
}
return FALSE;
}
DWORD CKeepAlive::GetLocalIPAddress(LDAP *ld)
{
SOCKET s = INVALID_SOCKET;
if (LDAP_SUCCESS == WLDAP::ldap_get_option(ld, LDAP_OPT_DESC, &s))
{
SOCKADDR_IN addr;
int NameLen = sizeof(addr);
if (0 == ::getsockname(s, (SOCKADDR *) &addr, &NameLen))
{
return addr.sin_addr.s_addr;
}
}
return INADDR_NONE;
}
BOOL CKeepAlive::KeepAlive(LDAP *ld, UINT *pnKeepAliveInterval)
{
LPTSTR aTTLAttr[] = { STTL_ATTR_NAME, NULL };
UINT nMsgID = WLDAP::ldap_search(ld,
LDAP_REFRESH_BASE_DN,
LDAP_SCOPE_BASE,
m_pszKeepAliveFilter,
aTTLAttr,
FALSE);
if (INVALID_MSG_ID != nMsgID)
{
// poll the result every quarter second
const ULONG c_nTimeoutInQuarterSecond = 4 * LDAP_TIMEOUT_IN_SECONDS;
BOOL fError = FALSE;
for (ULONG i = 0; (i < c_nTimeoutInQuarterSecond) && (! m_fAborted) && (! fError); i++)
{
// no timeout, if no result, return immediately
LDAP_TIMEVAL TimeVal;
TimeVal.tv_usec = 0;
TimeVal.tv_sec = 0;
// check the result
LDAPMessage *pMsg = NULL;
ULONG nResultType = WLDAP::ldap_result(ld, nMsgID, LDAP_MSG_ALL, &TimeVal, &pMsg);
switch (nResultType)
{
case LDAP_RESULT_TIMEOUT:
if (! m_fAborted)
{
::Sleep(250); // sleep for a quarter second
}
break;
case LDAP_RESULT_ERROR:
fError = TRUE;
break;
default:
ASSERT(LDAP_RES_SEARCH_ENTRY == nResultType ||
LDAP_RES_SEARCH_RESULT == nResultType);
ASSERT(NULL != pMsg);
switch (pMsg->lm_returncode)
{
case LDAP_SUCCESS:
GetNewInterval(ld, pMsg, pnKeepAliveInterval);
break;
case LDAP_NO_SUCH_OBJECT:
ReLogon();
fError = TRUE;
break;
default:
break;
}
WLDAP::ldap_msgfree(pMsg);
return (! fError);
}
}
// failure, do the cleanup
WLDAP::ldap_abandon(ld, nMsgID);
}
return FALSE;
}
void CKeepAlive::GetNewInterval(LDAP *ld, LDAPMessage *pMsg, UINT *pnKeepAliveInterval)
{
// get the first entry which should contain the new ttl value
LDAPMessage *pEntry = WLDAP::ldap_first_entry(ld, pMsg);
if (NULL != pEntry)
{
// get the first attribute which should be the new ttl value
BerElement *pElement = NULL;
LPTSTR pszAttrib = WLDAP::ldap_first_attribute(ld, pEntry, &pElement);
if (NULL != pszAttrib)
{
// it should be ttl attribute
ASSERT(! lstrcmpi(STTL_ATTR_NAME, pszAttrib));
// get the value
LPTSTR *ppszTTL = WLDAP::ldap_get_values(ld, pEntry, pszAttrib);
if (NULL != ppszTTL)
{
if (NULL != ppszTTL[0])
{
int iRefresh = ::RtStrToInt(ppszTTL[0]) - REFRESH_TIMEOUT_MARGIN;
if (iRefresh > 0)
{
if (iRefresh < MIN_REFRESH_TIMEOUT_INTERVAL_MINUTES)
{
iRefresh = MIN_REFRESH_TIMEOUT_INTERVAL_MINUTES;
}
*pnKeepAliveInterval = (UINT) iRefresh;
}
}
WLDAP::ldap_value_free(ppszTTL);
}
}
}
}
void CKeepAlive::ReLogon(void)
{
::PostMessage(m_hwndMainThread, WM_NEED_RELOGON, 0, 0);
}
void CKeepAlive::UpdateIPAddressOnServer(void)
{
::PostMessage(m_hwndMainThread, WM_NEED_RELOGON, 0, 0);
}
/////////////////////////////////////////////////////////
//
// ResolveUser
//
typedef struct tagResolveInfo
{
// given
DWORD cchMax;
LPTSTR pszIPAddress;
// created
LPTSTR pszSearchFilter;
LDAP *ld;
}
RESOLVE_INFO;
void FreeResolveInfo(RESOLVE_INFO *pInfo)
{
if (NULL != pInfo)
{
delete pInfo->pszSearchFilter;
if (NULL != pInfo->ld)
{
WLDAP::ldap_unbind(pInfo->ld);
}
delete pInfo;
}
}
DWORD ResolveUserThreadProc(LPVOID pParam)
{
RESOLVE_INFO *pInfo = (RESOLVE_INFO *) pParam;
ASSERT(NULL != pInfo);
// send the search request
TCHAR* attrs[] = { IP_ADDRESS_ATTR_NAME, NULL };
ULONG nMsgID = WLDAP::ldap_search(pInfo->ld,
TEXT("objectClass=RTPerson"),
LDAP_SCOPE_BASE,
pInfo->pszSearchFilter,
attrs,
0);
if (INVALID_MSG_ID != nMsgID)
{
LDAPMessage *pMsg = NULL;
LDAP_TIMEVAL SearchTimeout = { LDAP_TIMEOUT_IN_SECONDS, 0 };
ULONG nResultType = WLDAP::ldap_result(pInfo->ld,
nMsgID,
LDAP_MSG_ALL,
&SearchTimeout,
&pMsg);
switch (nResultType)
{
case LDAP_RESULT_TIMEOUT:
case LDAP_RESULT_ERROR:
WLDAP::ldap_abandon(pInfo->ld, nMsgID);
break;
default:
{
ASSERT(LDAP_RES_SEARCH_ENTRY == nResultType ||
LDAP_RES_SEARCH_RESULT == nResultType);
ASSERT(NULL != pMsg);
// get the first entry
LDAPMessage *pEntry = WLDAP::ldap_first_entry(pInfo->ld, pMsg);
if (NULL != pEntry)
{
BerElement *pElement = NULL;
// get the first attribute
LPTSTR pszAttrib = WLDAP::ldap_first_attribute(pInfo->ld, pEntry, &pElement);
if (NULL != pszAttrib)
{
ASSERT(! lstrcmpi(IP_ADDRESS_ATTR_NAME, pszAttrib));
// get the value
LPTSTR *ppszIPAddress = WLDAP::ldap_get_values(pInfo->ld, pEntry, pszAttrib);
if (NULL != ppszIPAddress)
{
if (NULL != ppszIPAddress[0])
{
BYTE temp[sizeof(DWORD)];
*(DWORD *) &temp[0] = ::RtStrToInt(ppszIPAddress[0]);
::wsprintf(pInfo->pszIPAddress, TEXT("%u.%u.%u.%u"),
(UINT) temp[0], (UINT) temp[1],
(UINT) temp[2], (UINT) temp[3]);
}
WLDAP::ldap_value_free(ppszIPAddress);
}
} // if attribute
} // if entry
WLDAP::ldap_msgfree(pMsg);
}
break;
} // switch
} // if msg id
return 0;
}
/*static*/
HRESULT CNmLDAP::ResolveUser( LPCTSTR pcszName, LPCTSTR pcszServer, LPTSTR pszIPAddress, DWORD cchMax, int port )
{
HRESULT hr = E_OUTOFMEMORY;
RESOLVE_INFO *pInfo = NULL;
// clean up the return buffer
*pszIPAddress = TEXT('\0');
// make sure the wldap32.dll is loaded
if( ms_bLdapDLLLoaded || SUCCEEDED( hr = WLDAP::Init()))
{
ms_bLdapDLLLoaded = true;
// create a resolve info which exchanges info between this thread and a background thread.
pInfo = new RESOLVE_INFO;
if (NULL != pInfo)
{
// cleanup
::ZeroMemory(pInfo, sizeof(*pInfo));
// remember return buffer and its size
pInfo->pszIPAddress = pszIPAddress;
pInfo->cchMax = cchMax;
// create search filter
ULONG cbFilterSize = ::lstrlen(RESOLVE_USER_SEARCH_FILTER) + ::lstrlen(pcszName) + 2;
pInfo->pszSearchFilter = new TCHAR[cbFilterSize];
if (NULL != pInfo->pszSearchFilter)
{
// construct search filter
::wsprintf(pInfo->pszSearchFilter, RESOLVE_USER_SEARCH_FILTER, pcszName);
// create ldap block that is NOT connected to server yet.
pInfo->ld = WLDAP::ldap_init(const_cast<LPTSTR>(pcszServer), port);
if( pInfo->ld != NULL )
{
ULONG ulResult = WLDAP::ldap_bind_s(pInfo->ld, TEXT(""), TEXT(""), LDAP_AUTH_SIMPLE);
if( (ulResult != LDAP_SUCCESS) && (port == DEFAULT_LDAP_PORT) )
{
WLDAP::ldap_unbind(pInfo->ld);
pInfo->ld = WLDAP::ldap_init(const_cast<LPTSTR>(pcszServer), ALTERNATE_LDAP_PORT); // Automatically retry with alternate port...
if( pInfo->ld != NULL )
{
ulResult = WLDAP::ldap_bind_s(pInfo->ld, TEXT(""), TEXT(""), LDAP_AUTH_SIMPLE);
if( ulResult != LDAP_SUCCESS )
{
WLDAP::ldap_unbind(pInfo->ld);
pInfo->ld = NULL;
}
}
}
}
ASSERT(NULL != pInfo->ld);
if (NULL != pInfo->ld)
{
DWORD dwThreadID = 0;
HANDLE hThread = ::CreateThread(NULL, 0, ResolveUserThreadProc, pInfo, 0, &dwThreadID);
if (NULL != hThread)
{
// wait for the thread to exit
hr = ::WaitWithMessageLoop(hThread);
DWORD dwIPAddr = ::inet_addr(pszIPAddress);
hr = (dwIPAddr && INADDR_NONE != dwIPAddr) ? S_OK : E_FAIL;
// close thread
::CloseHandle(hThread);
}
} // if ld
} // if search filter
} // if new resolve info
} // if init
::FreeResolveInfo(pInfo);
return hr;
}