#include "precomp.h" #include "call.h" #include "callto.h" #include "conf.h" #include "confroom.h" #include "confpolicies.h" #include "confutil.h" #include "nmldap.h" const int CCallto::s_iMaxCalltoLength = 255; const int CCallto::s_iMaxAddressLength = 255; //--------------------------------------------------------------------------// // CCallto::CCallto. // //--------------------------------------------------------------------------// CCallto::CCallto(void): m_bUnescapedAddressOnly( false ), m_ulDestination( INADDR_NONE ), m_bGatekeeperEnabled( false ), m_pszGatekeeperName( NULL ), m_ulGatekeeperAddress( INADDR_NONE ), m_bGatewayEnabled( false ), m_pszGatewayName( NULL ), m_ulGatewayAddress( INADDR_NONE ), m_pszDefaultIlsServerName( NULL ), m_pszCalltoBuffer( NULL ), m_pszDisplayName( NULL ) { } // End of CCallto::CCallto. //--------------------------------------------------------------------------// // CCallto::~CCallto. // //--------------------------------------------------------------------------// CCallto::~CCallto(void) { delete [] m_pszGatekeeperName; delete [] m_pszGatewayName; delete [] m_pszDefaultIlsServerName; delete [] m_pszCalltoBuffer; delete [] m_pszDisplayName; } // End of CCallto::~CCallto. //--------------------------------------------------------------------------// // CCallto::Callto. // //--------------------------------------------------------------------------// HRESULT CCallto::Callto ( const TCHAR * const pszCallto, // pointer to the callto url to try to place the call with... const TCHAR * const pszDisplayName, // pointer to the display name to use... const NM_ADDR_TYPE nmType, // callto type to resolve this callto as... const bool bAddressOnly, // the pszCallto parameter is to be interpreted as a pre-unescaped addressing component vs a full callto... const bool * const pbSecurityPreference, // pointer to security preference, NULL for none. must be "compatible" with secure param if present... const bool bAddToMru, // whether or not save in mru... const bool bUIEnabled, // whether or not to perform user interaction on errors... const HWND hwndParent, // if bUIEnabled is true this is the window to parent error/status windows to... INmCall ** const ppInternalCall // out pointer to INmCall * to receive INmCall * generated by placing call... ){ ASSERT( pszCallto != NULL ); ASSERT( (hwndParent == NULL) || IsWindow( hwndParent ) ); HRESULT hrResult; // These members need to be reset at the beginning of every call... m_bUIEnabled = bUIEnabled; m_hwndParent = hwndParent; m_ulDestination = INADDR_NONE; m_bUnescapedAddressOnly = bAddressOnly; m_pszDisplayName = PszAlloc( pszDisplayName ); m_Parameters.SetParams( NULL ); // Need to reset all parameter settings too... // Process the callto... if( (hrResult = Parse( pszCallto )) == S_OK ) { // Validate that the security specified (if any) is compatible with current NM state. bool bValidatedSecurity; if( (hrResult = GetValidatedSecurity( pbSecurityPreference, bValidatedSecurity )) == S_OK ) { if( (hrResult = Resolve( nmType )) == S_OK ) { hrResult = PlaceCall( pszCallto, bAddToMru, bValidatedSecurity, ppInternalCall ); } } } if( FAILED( hrResult ) && m_bUIEnabled ) { DisplayCallError( hrResult, (pszDisplayName != NULL)? pszDisplayName: pszCallto ); } delete [] m_pszCalltoBuffer; delete [] m_pszDisplayName; m_pszCalltoBuffer = NULL; m_pszDisplayName = NULL; return( hrResult ); } // End of CCallto::Callto. //--------------------------------------------------------------------------// // CCallto::Parse. // //--------------------------------------------------------------------------// HRESULT CCallto::Parse ( const TCHAR * const pszCallto // pointer to the callto url to parse... ){ ASSERT( pszCallto != NULL ); ASSERT( m_ulDestination == INADDR_NONE ); HRESULT hrResult; if( (m_pszCalltoBuffer = PszAlloc( pszCallto )) == NULL ) // Make a copy that we can modify in place... { hrResult = E_OUTOFMEMORY; } else if( TrimSzCallto( m_pszCalltoBuffer ) == 0 ) // Remove any leading/trailing blanks... { hrResult = NM_CALLERR_PARAM_ERROR; // Entire string was blanks... } else { hrResult = S_OK; m_pszParsePos = m_pszCalltoBuffer; if( !m_bUnescapedAddressOnly ) { // Skip over "callto:" or "callto://" which mean nothing to us now... static const TCHAR pszCallto2[] = TEXT( "callto:" ); static const TCHAR pszDoubleSlash[] = TEXT( "//" ); if( StrCmpNI_literal( m_pszCalltoBuffer, pszCallto2 ) ) { m_pszParsePos = m_pszCalltoBuffer + strlen_literal( pszCallto2 ); if( StrCmpNI_literal( m_pszParsePos, pszDoubleSlash ) ) { m_pszParsePos += strlen_literal( pszDoubleSlash ); } } int iLength = lstrlen( m_pszCalltoBuffer ); if( m_pszCalltoBuffer[ iLength - 1 ] == '/' ) { m_pszCalltoBuffer[ iLength - 1 ] = '\0'; // The shell seems to add a trailing slash before calling us... } } // Break the callto into two pieces at the start of the parameters (if any)... m_pszParameters = StrChr( m_pszCalltoBuffer, '+' ); if( m_pszParameters != NULL ) { if( m_bUnescapedAddressOnly ) { // Sorry but '+' not allowed in addressing component... hrResult = NM_CALLERR_INVALID_ADDRESS; } else { *m_pszParameters++ = '\0'; } } if( hrResult == S_OK ) { // Make sure we have something left before going on... if( m_pszParsePos[ 0 ] == '\0' ) { hrResult = NM_CALLERR_NO_ADDRESS; } else { // Not really a parsing thing but what we have at this point is conveiniently // exactly what we want to use for a display name if one wasn't specified so // save a copy of it before ParseAddress breaks it up into pieces... if( m_pszDisplayName == NULL ) { m_pszDisplayName = PszAlloc( m_pszParsePos ); } if( m_pszParameters != NULL ) { // Send the parameters off to be parsed... hrResult = m_Parameters.SetParams( m_pszParameters ); } if( hrResult == S_OK ) { // Go parse the addressing component... hrResult = ParseAddress(); } } } } return( hrResult ); } // End of CCallto::Parse. //--------------------------------------------------------------------------// // CCallto::ParseAddress. // //--------------------------------------------------------------------------// HRESULT CCallto::ParseAddress(void) { ASSERT( m_pszCalltoBuffer != NULL ); HRESULT hrResult = NM_CALLERR_INVALID_ADDRESS; if( m_Parameters.GetBooleanParam( TEXT( "h323" ), true ) && inGatekeeperMode() ) { m_pszAddress = m_pszParsePos; hrResult = S_OK; // Bless you gatekeeper... } else if( StrChr( m_pszParsePos, '=' ) == NULL ) // We're not going to allow the address component to contain an '='... { // The address is allowed to be one of these formats... // (1) string // (2) server/email // (3) server:port/email // This means it may contain at most one ':', at most one '/', // and given a ':', there must be a following '/'... TCHAR * const pszColon = StrChr( m_pszParsePos, ':' ); TCHAR * const pszSlash = StrChr( m_pszParsePos, '/' ); if( (pszSlash == NULL) && (pszColon == NULL) ) { // It's a valid simple (1) string format... m_pszAddress = m_pszParsePos; m_pszIlsServer = NULL; m_uiIlsPort = DEFAULT_LDAP_PORT; m_pszEmail = m_pszParsePos; if( m_bUnescapedAddressOnly ) { hrResult = S_OK; // Done... } else { // Need to unescape m_pszAddress but not m_pszEmail because it points to the same place... hrResult = Unescape( m_pszAddress ); } } else if( (pszSlash != NULL) && (pszColon == NULL) ) { if( StrChr( pszSlash + 1, '/' ) == NULL ) { // No colon and only one slash so it's a valid (2) format // as long as each side is non zero length... if( (pszSlash > m_pszParsePos) && (lstrlen( pszSlash ) > 1) ) { m_pszAddress = TEXT( "" ); m_pszIlsServer = m_pszParsePos; m_uiIlsPort = DEFAULT_LDAP_PORT; m_pszEmail = pszSlash + 1; *pszSlash = '\0'; if( m_bUnescapedAddressOnly ) { hrResult = S_OK; // Done... } else { if( (hrResult = Unescape( m_pszIlsServer )) == S_OK ) { hrResult = Unescape( m_pszEmail ); } } } } } else if( (pszSlash != NULL) && (pszColon != NULL) ) { // Make sure the ':' preceeds the '/' and there's only one of each... if( (pszColon < pszSlash) && (StrChr( pszSlash + 1, '/') == NULL) && (StrChr( pszColon + 1, ':' ) == NULL) ) { // One colon and one slash in the correct order so it's a valid (3) format as long // as all three pieces are non zero length and the port piece is a number... if( (pszColon > m_pszParsePos) && (pszSlash > pszColon + 1) && (lstrlen( pszSlash ) > 1) ) { // We're not in gatekeeper mode so break it up into server, port, and email... m_pszAddress = TEXT( "" ); m_pszIlsServer = m_pszParsePos; m_pszEmail = pszSlash + 1; *pszColon = '\0'; *pszSlash = '\0'; if( m_bUnescapedAddressOnly ) { hrResult = DecimalStringToUINT( pszColon + 1, m_uiIlsPort ); } else { if( (hrResult = Unescape( m_pszIlsServer )) == S_OK ) { if( (hrResult = Unescape( m_pszEmail )) == S_OK ) { if( (hrResult = Unescape( pszColon + 1 )) == S_OK ) { hrResult = DecimalStringToUINT( pszColon + 1, m_uiIlsPort ); } } } } } } } } return( hrResult ); } // End of CCallto::ParseAddress. //--------------------------------------------------------------------------// // CCallto::Resolve. // //--------------------------------------------------------------------------// HRESULT CCallto::Resolve ( const NM_ADDR_TYPE nmType // callto type to resolve this callto as... ){ HRESULT hrResult; // First set our address type... if( (nmType != NM_ADDR_UNKNOWN) && (nmType != NM_ADDR_CALLTO) ) { m_nmAddressType = nmType; } else { const TCHAR * const pszType = m_Parameters.GetParam( TEXT( "type" ), NULL ); if(NULL != pszType) { if( lstrcmpi( pszType, TEXT( "phone" ) ) == 0 ) { m_nmAddressType = NM_ADDR_ALIAS_E164; } else if( lstrcmpi( pszType, TEXT( "ip" ) ) == 0 ) { m_nmAddressType = NM_ADDR_IP; } else if( lstrcmpi( pszType, TEXT( "host" ) ) == 0 ) { m_nmAddressType = NM_ADDR_MACHINENAME; } else if( lstrcmpi( pszType, TEXT( "directory" ) ) == 0 ) { m_nmAddressType = NM_ADDR_ULS; } else { m_nmAddressType = NM_ADDR_UNKNOWN; } } else { m_nmAddressType = NM_ADDR_UNKNOWN; } } // Then see what we should do with it... if( m_Parameters.GetBooleanParam( TEXT( "h323" ), true ) && inGatekeeperMode() ) { if (!IsGatekeeperLoggedOn() && !IsGatekeeperLoggingOn()) { hrResult = NM_CALLERR_NOT_REGISTERED; } else { // We can always send anything to the gatekeeper for actual resolution... if( (hrResult = GetGatekeeperIpAddress( m_ulDestination )) == S_OK ) { if( m_nmAddressType == NM_ADDR_ALIAS_E164 ) // should this also check for NM_ADDR_H323_GATEWAY??? { CleanupE164StringEx( m_pszAddress ); } else { m_nmAddressType = NM_ADDR_ALIAS_ID; } } } } else { switch( m_nmAddressType ) { case NM_ADDR_ALIAS_ID: { hrResult = NM_CALLERR_NO_GATEKEEPER; } break; case NM_ADDR_ALIAS_E164: case NM_ADDR_H323_GATEWAY: { if( inGatewayMode() ) { if( (hrResult = GetGatewayIpAddress( m_ulDestination )) == S_OK ) { // Explicit phone types are also still resolvable in gateway mode... CleanupE164StringEx( m_pszAddress ); } } else { hrResult = NM_CALLERR_NO_PHONE_SUPPORT; } } break; case NM_ADDR_IP: { if( (hrResult = GetIpAddress( m_pszAddress, m_ulDestination )) != S_OK ) { hrResult = NM_CALLERR_INVALID_IPADDRESS; } } break; case NM_ADDR_MACHINENAME: { if( (hrResult = GetIpAddressFromHostName( m_pszAddress, m_ulDestination )) != S_OK ) { hrResult = NM_CALLERR_HOST_RESOLUTION_FAILED; } } break; case NM_ADDR_ULS: { // Ils types need to be resolved against an ils... hrResult = GetIpAddressFromIls( m_ulDestination ); } break; default: { // If we get here the type was unspecified (Automatic or 2.xx)... // Our order of precedence is ipaddress,hostname,ils,fail... // We will not try phone since it didn't explicitly have a phone type... if( (hrResult = GetIpAddress( m_pszAddress, m_ulDestination )) == S_OK ) { m_nmAddressType = NM_ADDR_IP; } else { // It's not a valid ip address so try it next as a host name... if( (hrResult = GetIpAddressFromHostName( m_pszAddress, m_ulDestination )) == S_OK ) { m_nmAddressType = NM_ADDR_MACHINENAME; } else { // It's not a valid host name either so try it finally as an ils lookup... if ( (hrResult = GetIpAddressFromIls( m_ulDestination )) == S_OK ) { m_nmAddressType = NM_ADDR_ULS; } } } } } } return( hrResult ); } // End of CCallto::Resolve. //--------------------------------------------------------------------------// // CCallto::PlaceCall. // //--------------------------------------------------------------------------// HRESULT CCallto::PlaceCall ( const TCHAR * const pszCallto, // pointer to the original callto... const bool bAddToMru, // whether or not save in mru... const bool bSecure, // whether or not to place the call securely... INmCall ** const ppInternalCall // out pointer to INmCall * to receive INmCall * generated by placing call... ){ ASSERT( m_ulDestination != INADDR_NONE ); const TCHAR * const pszConferenceName = m_Parameters.GetParam( TEXT( "conference" ), NULL ); const TCHAR * const pszPassword = m_Parameters.GetParam( TEXT( "password" ), NULL ); const bool bH323 = m_Parameters.GetBooleanParam( TEXT( "h323" ), true ); const bool bAV = m_Parameters.GetBooleanParam( TEXT( "av" ), true ); const bool bData = m_Parameters.GetBooleanParam( TEXT( "data" ), true ); const TCHAR * const pszAlias = NULL; const TCHAR * const pszE164 = NULL; HRESULT hrResult; if( IsLocalIpAddress( m_ulDestination ) ) { // We don't want to go any further if we are attempting to call ourselves... hrResult = NM_CALLERR_LOOPBACK; } else { // Map to old style call flags... DWORD dwCallFlags = 0; if( pszConferenceName != NULL ) { dwCallFlags |= CRPCF_JOIN; } if( bH323 ) { dwCallFlags |= CRPCF_H323CC; } if( bSecure ) { dwCallFlags |= CRPCF_SECURE; } else if( bAV ) { if( g_uMediaCaps & (CAPFLAG_RECV_AUDIO | CAPFLAG_SEND_AUDIO) ) { dwCallFlags |= CRPCF_AUDIO; } if( g_uMediaCaps & (CAPFLAG_RECV_VIDEO | CAPFLAG_SEND_VIDEO) ) { dwCallFlags |= CRPCF_VIDEO; } } if( bData ) { dwCallFlags |= CRPCF_DATA | CRPCF_T120; } if (((CRPCF_T120 | CRPCF_DATA) != (dwCallFlags & (CRPCF_T120 | CRPCF_DATA))) && ((CRPCF_H323CC | CRPCF_AUDIO) != ( dwCallFlags & (CRPCF_H323CC | CRPCF_AUDIO))) && ((CRPCF_H323CC | CRPCF_VIDEO) != ( dwCallFlags & (CRPCF_H323CC | CRPCF_VIDEO)))) { hrResult = NM_CALLERR_UNKNOWN; } CConfRoom * pConfRoom = ::GetConfRoom(); ASSERT(pConfRoom); if (_Module.IsUIActive()) { pConfRoom->BringToFront(); } if( !(pConfRoom->GetMeetingPermissions() & NM_PERMIT_OUTGOINGCALLS) ) { ERROR_OUT( ("CCallto::PlaceCall: meeting setting permissions do not permit outgoing calls...") ); } else { CCall * pCall = new CCall( pszCallto, m_pszDisplayName, m_nmAddressType, bAddToMru, FALSE ); if( pCall == NULL ) { ERROR_OUT( ("CCallto::PlaceCall: CCall object not created...") ); hrResult = E_OUTOFMEMORY; } else { pCall->AddRef(); // Protect against another thread canceling this call IncrementBusyOperations(); { const TCHAR * pszCallAlias = (m_nmAddressType == NM_ADDR_ULS)? m_pszEmail: m_pszAddress; const char * const pszDestination = inet_ntoa( *reinterpret_cast(&m_ulDestination) ); hrResult = pCall->PlaceCall( dwCallFlags, // call flags bit mask, is there a good reason why they're not named? m_nmAddressType, // address type. pszDestination, // setup address. pszDestination, // destination address. pszCallAlias, // alias. NULL, // callto url. pszConferenceName, // conference name. pszPassword, // conference password. NULL ); // user data. } DecrementBusyOperations(); if( FAILED( hrResult ) && (pCall->GetState() == NM_CALL_INVALID) ) { // just release the call to free the data // otherwise wait for the call state to be changed pCall->Release(); } if( ppInternalCall ) { *ppInternalCall = pCall->GetINmCall(); (*ppInternalCall)->AddRef(); } pCall->Release(); } } } return( hrResult ); } // End of CCallto::PlaceCall. //--------------------------------------------------------------------------// // CCallto::GetValidatedSecurity. // //--------------------------------------------------------------------------// HRESULT CCallto::GetValidatedSecurity ( const bool * const pbSecurityPreference, // pointer to security preference, NULL for none. must be "compatible" with secure param if present... bool & bValidatedSecurity // out bool reference to recieve validated security setting ){ HRESULT hrResult; // First figure out what security setting is desired... if( pbSecurityPreference != NULL ) { // A preference was specified so use it. bValidatedSecurity = *pbSecurityPreference; } else { // No preference was specified either so check for secure param // passing the current system settings to use as the default. bool bUserAlterable; bool bDefaultSecurity; CConfRoom::get_securitySettings( bUserAlterable, bDefaultSecurity ); bValidatedSecurity = m_Parameters.GetBooleanParam( TEXT( "secure" ), bDefaultSecurity ); } // And then validate that the desired setting is allowed... int iSecurityPolicy = ConfPolicies::GetSecurityLevel(); if( (bValidatedSecurity && (iSecurityPolicy == DISABLED_POL_SECURITY)) || ((!bValidatedSecurity) && (iSecurityPolicy == REQUIRED_POL_SECURITY)) ) { // There was a mismatch between what they want and what they can have... // Set security to what they can have and return mismatch error... bValidatedSecurity = (iSecurityPolicy == REQUIRED_POL_SECURITY); hrResult = NM_CALLERR_SECURITY_MISMATCH; } else { hrResult = S_OK; } return( hrResult ); } // End of CCallto::GetValidatedSecurity. //--------------------------------------------------------------------------// // CCallto::inGatekeeperMode. // //--------------------------------------------------------------------------// bool CCallto::inGatekeeperMode(void) { return(ConfPolicies::CallingMode_GateKeeper == ConfPolicies::GetCallingMode() ); } // End of CCallto::inGatekeeperMode. //--------------------------------------------------------------------------// // CCallto::SetGatekeeperEnabled. // //--------------------------------------------------------------------------// void CCallto::SetGatekeeperEnabled ( const bool bEnabled // new Gatekeeper state ){ m_bGatekeeperEnabled = bEnabled; } // End of CCallto::SetGatekeeperEnabled. //--------------------------------------------------------------------------// // CCallto::SetGatekeeperName. // //--------------------------------------------------------------------------// HRESULT CCallto::SetGatekeeperName ( const TCHAR * const pszGatekeeperName // pointer to new Gatekeeper name ){ if( lstrcmpi( pszGatekeeperName, m_pszGatekeeperName ) != 0 ) { delete [] m_pszGatekeeperName; m_pszGatekeeperName = PszAlloc( pszGatekeeperName ); m_ulGatekeeperAddress = INADDR_NONE; // We reset this cached value when the name changes... } ASSERT( (m_pszGatekeeperName != NULL) || (pszGatekeeperName == NULL) ); return( ((pszGatekeeperName != NULL) && (m_pszGatekeeperName == NULL))? E_OUTOFMEMORY: S_OK ); } // End of CCallto::SetGatekeeperName. //--------------------------------------------------------------------------// // CCallto::GetGatekeeperIpAddress. // //--------------------------------------------------------------------------// HRESULT CCallto::GetGatekeeperIpAddress ( unsigned long & ulIpAddress // out unsigned long reference to receive gatekeeper IP address ){ ASSERT( m_pszGatekeeperName != NULL ); if( m_ulGatekeeperAddress == INADDR_NONE ) { GetIpAddressFromHostName( m_pszGatekeeperName, m_ulGatekeeperAddress ); } ulIpAddress = m_ulGatekeeperAddress; return( (m_ulGatekeeperAddress != INADDR_NONE)? S_OK: NM_CALLERR_NO_GATEKEEPER ); } // End of CCallto::GetGatekeeperIpAddress. //--------------------------------------------------------------------------// // CCallto::inGatewayMode. // //--------------------------------------------------------------------------// bool CCallto::inGatewayMode(void) { return( (m_bGatewayEnabled && (m_pszGatewayName != NULL)) || (m_Parameters.GetParam( TEXT( "gateway" ), NULL ) != NULL) ); } // End of CCallto::inGatewayMode. //--------------------------------------------------------------------------// // CCallto::SetGatewayEnabled. // //--------------------------------------------------------------------------// void CCallto::SetGatewayEnabled ( const bool bEnabled // new Gateway state ){ m_bGatewayEnabled = bEnabled; } // End of CCallto::SetGatewayEnabled. //--------------------------------------------------------------------------// // CCallto::SetGatewayName. // //--------------------------------------------------------------------------// HRESULT CCallto::SetGatewayName ( const TCHAR * const pszGatewayName // pointer to new Gateway name ){ if( lstrcmpi( pszGatewayName, m_pszGatewayName ) != 0 ) { delete [] m_pszGatewayName; m_pszGatewayName = PszAlloc( pszGatewayName ); m_ulGatewayAddress = INADDR_NONE; // We reset this cached value when the name changes... } ASSERT( (m_pszGatewayName != NULL) || (pszGatewayName == NULL) ); return( ((pszGatewayName != NULL) && (m_pszGatewayName == NULL))? E_OUTOFMEMORY: S_OK ); } // End of CCallto::SetGatewayName. //--------------------------------------------------------------------------// // CCallto::GetGatewayIpAddress. // //--------------------------------------------------------------------------// HRESULT CCallto::GetGatewayIpAddress ( unsigned long & ulIpAddress // out unsigned long reference to receive gateway IP address ){ const TCHAR * const pszGateway = m_Parameters.GetParam( TEXT( "gateway" ), NULL ); if( pszGateway != NULL ) { // A non-default gateway was specified with this callto... GetIpAddressFromHostName( pszGateway, ulIpAddress ); } else { if( m_ulGatewayAddress == INADDR_NONE ) { GetIpAddressFromHostName( m_pszGatewayName, m_ulGatewayAddress ); } ulIpAddress = m_ulGatewayAddress; } return( (ulIpAddress != INADDR_NONE)? S_OK: NM_CALLERR_NO_GATEWAY ); } // End of CCallto::GetGatewayIpAddress. //--------------------------------------------------------------------------// // CCallto::SetIlsServerName. // //--------------------------------------------------------------------------// HRESULT CCallto::SetIlsServerName ( const TCHAR * const pszServerName // pointer to new default Ils server name ){ delete [] m_pszDefaultIlsServerName; m_pszDefaultIlsServerName = PszAlloc( pszServerName ); ASSERT( (m_pszDefaultIlsServerName != NULL) || (pszServerName == NULL) ); return( ((pszServerName != NULL) && (m_pszDefaultIlsServerName == NULL))? E_OUTOFMEMORY: S_OK ); } // End of CCallto::SetIlsServerName. //--------------------------------------------------------------------------// // CCallto::GetIpAddressFromIls. // //--------------------------------------------------------------------------// HRESULT CCallto::GetIpAddressFromIls ( unsigned long & ulIpAddress // out unsigned long reference to receive IP address ){ ASSERT( m_pszEmail != NULL ); HRESULT hrResult; const TCHAR * const pszActiveIlsServer = (m_pszIlsServer != NULL)? m_pszIlsServer: m_pszDefaultIlsServerName; if( pszActiveIlsServer == NULL ) { hrResult = NM_CALLERR_NO_ILS; } if( g_pLDAP == NULL ) { g_pLDAP = new CNmLDAP; } ASSERT( g_pLDAP != NULL ); if( g_pLDAP == NULL ) { hrResult = E_OUTOFMEMORY; } else { TCHAR szIpAddress[ 64 ]; hrResult = g_pLDAP->ResolveUser( m_pszEmail, pszActiveIlsServer, szIpAddress, ARRAY_ELEMENTS( szIpAddress ), m_uiIlsPort ); if( hrResult == S_OK ) { // Verify that it gave back a good IP address... hrResult = GetIpAddress( szIpAddress, ulIpAddress ); } if( hrResult != S_OK ) { hrResult = NM_CALLERR_ILS_RESOLUTION_FAILED; } } return( hrResult ); } // End of CCallto::GetIpAddressFromIls. //--------------------------------------------------------------------------// // CCallto::DoUserValidation // //--------------------------------------------------------------------------// bool CCallto::DoUserValidation(const TCHAR * const pszCallto) { bool bRet = false; CCallto callto; TCHAR szCaption[MAX_PATH]; TCHAR *pszText = NULL; // Parse input string to retrieve display name if(FAILED(callto.Parse(pszCallto))) goto Exit; // Verify we have a valid display name if(NULL == callto.m_pszDisplayName) goto Exit; // Allocate message buffer. MAX_PATH represents max format string size pszText = new TCHAR[_tcslen(callto.m_pszDisplayName) + MAX_PATH]; if(NULL == pszText) goto Exit; // Compose message string if(!FLoadString1(IDS_JOIN_PERMISSION, pszText, callto.m_pszDisplayName)) goto Exit; if(!FLoadString(IDS_MSGBOX_TITLE, szCaption, CCHMAX(szCaption))) goto Exit; // Display message box if(IDOK != MessageBox(NULL, pszText, szCaption, MB_ICONWARNING | MB_OKCANCEL | MB_TOPMOST)) goto Exit; bRet = true; Exit: // Free allocated buffer if(NULL != pszText) { delete [] pszText; } return bRet; } //--------------------------------------------------------------------------// // CCalltoParams::CCalltoParams. // //--------------------------------------------------------------------------// CCalltoParams::CCalltoParams(void): m_chNameDelimiter( '+' ), m_chValueDelimiter( '=' ), m_pszParams( NULL ), m_iCount( 0 ) { } // End of CCalltoParams::CCalltoParams. //--------------------------------------------------------------------------// // CCalltoParams::CCalltoParams. // //--------------------------------------------------------------------------// CCalltoParams::~CCalltoParams() { delete [] m_pszParams; } // End of CCalltoParams::~CCalltoParams. //--------------------------------------------------------------------------// // CCalltoParams::SetParams. // //--------------------------------------------------------------------------// HRESULT CCalltoParams::SetParams ( const TCHAR * const pszParams ){ HRESULT hrResult; delete [] m_pszParams; m_pszParams = NULL; m_iCount = 0; if( pszParams == NULL ) { hrResult = S_OK; } else if( (m_pszParams = new TCHAR [ lstrlen( pszParams ) + 1 ]) == NULL ) { hrResult = E_OUTOFMEMORY; } else { hrResult = S_OK; lstrcpy( m_pszParams, pszParams ); TCHAR * pszPos = m_pszParams; TCHAR * pszEnd; while( (*pszPos != '\0') && (m_iCount < ARRAY_ELEMENTS( m_pszNames )) ) { m_pszNames[ m_iCount ] = pszPos; m_pszValues[ m_iCount ] = NULL; while( *pszPos != '\0' ) { if( (*pszPos == '+') || (*pszPos == '=') ) { break; } pszPos = CharNext( pszPos ); } if( *pszPos != '=' ) { // Valueless param... if( m_pszNames[ m_iCount ] == pszPos ) { hrResult = NM_CALLERR_PARAM_ERROR; // Can't have zero length param names... break; } pszEnd = pszPos; pszPos = CharNext( pszPos ); if( (pszPos != pszEnd) && (*pszPos == '\0') ) { hrResult = NM_CALLERR_PARAM_ERROR; // Can't have trailing + or =... break; } *pszEnd = '\0'; m_iCount++; } else { // Value follows... pszEnd = pszPos; pszPos = CharNext( pszPos ); *pszEnd = '\0'; m_pszValues[ m_iCount ] = pszPos; while( *pszPos != '\0' ) { if( (*pszPos == '+') || (*pszPos == '=') ) { break; } pszPos = CharNext( pszPos ); } if( (*pszPos == '=') || (m_pszValues[ m_iCount ] == pszPos) ) { hrResult = NM_CALLERR_PARAM_ERROR; // Can't have '=' or zero length param names... break; } pszEnd = pszPos; pszPos = CharNext( pszPos ); if( (pszPos != pszEnd) && (*pszPos == '\0') ) { hrResult = NM_CALLERR_PARAM_ERROR; // Can't have trailing + or =... break; } *pszEnd = '\0'; m_iCount++; } } if( hrResult == S_OK ) { if( m_iCount == ARRAY_ELEMENTS( m_pszNames ) ) { hrResult = NM_CALLERR_PARAM_ERROR; // Too many params... } else { for( int nn = 0; nn < m_iCount; nn++ ) { if( (hrResult = Unescape( m_pszNames[ nn ] )) != S_OK ) { break; } if( m_pszValues[ nn ] != NULL ) { if( (hrResult = Unescape( m_pszValues[ nn ] )) != S_OK ) { break; } } } } } } return( hrResult ); } // End of CCalltoParams::SetParams. //--------------------------------------------------------------------------// // CCalltoParams::GetParam. // //--------------------------------------------------------------------------// const TCHAR * const CCalltoParams::GetParam ( const TCHAR * const pszName, const TCHAR * const pszDefaultValue ) const { ASSERT( pszName != NULL ); TCHAR * pszValue = NULL; if( m_pszParams != NULL ) { for( int nn = 0; nn < m_iCount; nn++ ) { if( lstrcmpi( pszName, m_pszNames[ nn ] ) == 0 ) { pszValue = m_pszValues[ nn ]; break; } } } return( (pszValue == NULL)? pszDefaultValue: pszValue ); } // End of CCalltoParams::GetParam. //--------------------------------------------------------------------------// // CCalltoParams::GetBooleanParam. // //--------------------------------------------------------------------------// bool CCalltoParams::GetBooleanParam ( const TCHAR * const pszParamName, const bool bDefaultValue ) const { ASSERT( pszParamName != NULL ); const TCHAR * const pszValue = GetParam( pszParamName, NULL ); bool bResult; if( pszValue == NULL ) // this parameter wasn't specified... { bResult = bDefaultValue; } else if( *pszValue == 0 ) // this parameter was specified but with no value... { bResult = true; } else if( (lstrcmpi( pszValue, TEXT( "1" ) ) == 0) || (lstrcmpi( pszValue, TEXT( "true" ) ) == 0) || (lstrcmpi( pszValue, TEXT( "y" ) ) == 0) || (lstrcmpi( pszValue, TEXT( "yes" ) ) == 0) || (lstrcmpi( pszValue, TEXT( "on" ) ) == 0) ) { bResult = true; } else if( (lstrcmpi( pszValue, TEXT( "0" ) ) == 0) || (lstrcmpi( pszValue, TEXT( "false" ) ) == 0) || (lstrcmpi( pszValue, TEXT( "n" ) ) == 0) || (lstrcmpi( pszValue, TEXT( "no" ) ) == 0) || (lstrcmpi( pszValue, TEXT( "off" ) ) == 0) ) { bResult = false; } else { bResult = bDefaultValue; } return( bResult ); } // End of CCalltoParams::GetBooleanParam. //--------------------------------------------------------------------------// // IsLocalIpAddress. // //--------------------------------------------------------------------------// bool IsLocalIpAddress ( const unsigned long ulIpAddress // IP Address to verify is not local ){ bool bResult = (ulIpAddress == INADDR_LOOPBACK); // First check right away if it's the prefined loop back ip address... if( !bResult ) { char szHostName[ MAX_PATH ]; // Get our own local hostname... if( gethostname( szHostName, ARRAY_ELEMENTS( szHostName ) ) == SOCKET_ERROR ) { WARNING_OUT( ("IsLocalIpAddress: gethostname() failed with error=%s", PszWSALastError()) ); } else { // Now find out which IP addresses are associated with it... HOSTENT * pHostEnt = gethostbyname( szHostName ); if( pHostEnt == NULL ) { WARNING_OUT( ("IsLocalIpAddress: gethostbyname() failed with error=%s", PszWSALastError()) ); } else if( (pHostEnt->h_addrtype != AF_INET) || (pHostEnt->h_length != sizeof( ulIpAddress )) ) { WARNING_OUT( ("IsLocalIpAddress: gethostbyname() returned unexpected address type: 0x%08X (%d)", pHostEnt->h_addrtype, pHostEnt->h_addrtype) ); } else { ASSERT( reinterpret_cast(pHostEnt->h_addr_list) != NULL ); // Compare all the IP addresses associated with this machine to see if any of them match the one specified... for( unsigned long ** ppIpAddress = reinterpret_cast(pHostEnt->h_addr_list); *ppIpAddress != NULL; ppIpAddress++ ) { if( **ppIpAddress == ulIpAddress ) { bResult = true; break; } } } } } return( bResult ); } // End of IsLocalIpAddress. //--------------------------------------------------------------------------// // DecimalStringToUINT. // //--------------------------------------------------------------------------// HRESULT DecimalStringToUINT ( const TCHAR * const pszDecimalString, // Pointer to string to convert... unsigned int & uiValue // out unsigned int reference to receive converted value... ){ ASSERT( pszDecimalString != NULL ); HRESULT hrResult; if( lstrlen( pszDecimalString ) > 10 ) { hrResult = E_INVALIDARG; // Limit it to billions.... } else { hrResult = S_OK; const TCHAR * pszDigit; for( pszDigit = pszDecimalString, uiValue = 0; *pszDigit != '\0'; pszDigit = CharNext( pszDigit ) ) { if( (*pszDigit < '0') || (*pszDigit > '9') ) { // There's a non digit character in the string so fail... hrResult = E_INVALIDARG; break; } uiValue = (uiValue * 10) + *pszDigit - '0'; } } return( hrResult ); } // End of DecimalStringToUINT. //--------------------------------------------------------------------------// // TrimSzCallto. // //--------------------------------------------------------------------------// int TrimSzCallto ( TCHAR * const pszSrc // Pointer to string to trim blanks from in place... ){ ASSERT( pszSrc != NULL ); TCHAR * pszFirst; int iResult; for( pszFirst = pszSrc; *pszFirst == ' '; pszFirst = CharNext( pszFirst ) ){}; if( *pszFirst == '\0' ) { *pszSrc = '\0'; iResult = 0; } else { TCHAR * pszLast; TCHAR * psz; for( pszLast = pszFirst, psz = pszFirst; *psz != '\0'; psz = CharNext( psz ) ) { if( *psz != ' ' ) { pszLast = psz; } } pszLast = CharNext( pszLast ); *pszLast = '\0'; lstrcpy( pszSrc, pszFirst ); iResult = lstrlen( pszSrc ); } return( iResult ); } // End of TrimSzCallto. //--------------------------------------------------------------------------// // GetIpAddress. // //--------------------------------------------------------------------------// HRESULT GetIpAddress ( const TCHAR * const pszIpAddress, // pointer to dotted IP address string unsigned long & ulIpAddress // out unsigned long reference to receive IP address ){ ASSERT( pszIpAddress != NULL ); ulIpAddress = INADDR_NONE; int ipByte = 0; int parts = 0; const TCHAR * ptr = pszIpAddress; bool newPart = true; bool result = true; while( result && (*ptr != NULL) && (parts <= 4) ) { if( (*ptr >= '0') && (*ptr <= '9') ) { if( newPart ) { parts++; newPart = false; } ipByte = (ipByte * 10) + (*ptr - '0'); if( ipByte > 255 ) { result = false; } } else if( *ptr == '.' ) { newPart = true; ipByte = 0; } else { result = false; } ptr++; } if( result && (parts == 4) ) { #if !defined( UNICODE ) ulIpAddress = inet_addr( pszIpAddress ); #else char * ansiIPAddress; int size; size = WideCharToMultiByte( CP_ACP, // code page 0, // performance and mapping flags ipAddress, // address of wide-character string -1, // number of characters in string NULL, // address of buffer for new string 0, // size of buffer NULL, // address of default for unmappable characters NULL ); // address of flag set when default char. used if( (ansiIPAddress = new char [ size ]) != NULL ) { size = WideCharToMultiByte( CP_ACP, // code page 0, // performance and mapping flags pszIpAddress, // address of wide-character string -1, // number of characters in string ansiIPAddress, // address of buffer for new string size, // size of buffer NULL, // address of default for unmappable characters NULL ); // address of flag set when default char. used if( size != 0 ) { ulIpAddress = inet_addr( ansiIPAddress ); } delete [] ansiIPAddress; } #endif // !defined( UNICODE ) } return( (ulIpAddress != INADDR_NONE)? S_OK: E_FAIL ); } // End of GetIpAddress. //--------------------------------------------------------------------------// // GetIpAddressFromHostName. // //--------------------------------------------------------------------------// HRESULT GetIpAddressFromHostName ( const TCHAR * const pszName, // pointer to host name to get IP address of unsigned long & ulIpAddress // out unsigned long reference to receive IP address ){ ASSERT( pszName != NULL ); HRESULT hrResult = E_FAIL; if( pszName[ 0 ] == '\0' ) { ulIpAddress = INADDR_NONE; } else if( (hrResult = GetIpAddress( pszName, ulIpAddress )) != S_OK ) { // Wasn't already in dotted IP address form... HOSTENT * pHostEnt; #if !defined( UNICODE ) TCHAR * pszOemName = new TCHAR [ lstrlen( pszName ) + 1 ]; if( pszOemName == NULL ) { hrResult = E_OUTOFMEMORY; } else { lstrcpy( pszOemName, pszName ); CharUpper ( pszOemName ); CharToOem( pszOemName, pszOemName ); pHostEnt = gethostbyname( pszOemName ); if( pHostEnt == NULL ) { WARNING_OUT( ("GetIpAddressFromHostName: gethostbyname() failed with error=%s", PszWSALastError()) ); } else if( (pHostEnt->h_addrtype != AF_INET) || (pHostEnt->h_length != sizeof( ulIpAddress )) ) { WARNING_OUT( ("GetIpAddressFromHostName: gethostbyname() returned unexpected address type: 0x%08X (%d)", pHostEnt->h_addrtype, pHostEnt->h_addrtype) ); } else { if( pHostEnt->h_addr_list[ 0 ] != NULL ) { ulIpAddress = *reinterpret_cast(pHostEnt->h_addr_list[ 0 ]); // Just use the first IP address hrResult = S_OK; } } delete [] pszOemName; } #else // Need to figure out OEM'ing the name... char * pszMultiByteName; int iSize; iSize = WideCharToMultiByte( CP_ACP, // code page 0, // performance and mapping flags pszName, // address of wide-character string -1, // number of characters in string NULL, // address of buffer for new string 0, // size of buffer NULL, // address of default for unmappable characters NULL ); // address of flag set when default char. used if( (pszMultiByteName = new char [ iSize ]) == NULL ) { hrResult = E_OUTOFMEMORY; } else { iSize = WideCharToMultiByte( CP_ACP, // code page 0, // performance and mapping flags pszName, // address of wide-character string -1, // number of characters in string pszMultiByteName, // address of buffer for new string iSize, // size of buffer NULL, // address of default for unmappable characters NULL ); // address of flag set when default char. used if( iSize != 0 ) { pHostEnt = gethostbyname( ansiHost ); if( pHostEnt == NULL ) { WARNING_OUT( ("GetIpAddressFromHostName: gethostbyname() failed with error=%s", PszWSALastError()) ); } else if( (pHostEnt->h_addrtype != AF_INET) || (pHostEnt->h_length != sizeof( ulIpAddress )) ) { WARNING_OUT( ("GetIpAddressFromHostName: gethostbyname() returned unexpected address type: 0x%08X (%d)", pHostEnt->h_addrtype, pHostEnt->h_addrtype) ); } else { if( pHostEnt->h_addr_list[ 0 ] != NULL ) { ulIpAddress = *reinterpret_cast(pHostEnt->h_addr_list[ 0 ]); // Just use the first IP address hrResult = S_OK; } } } delete [] pszMultiByteName; } #endif // !defined( UNICODE ) } return( hrResult ); } // End of GetIpAddressFromHostName. //--------------------------------------------------------------------------// // IsPhoneNumber. // //--------------------------------------------------------------------------// bool IsPhoneNumber ( const TCHAR * pszPhone // string to check for invalid phone number characters ){ ASSERT( pszPhone != NULL ); ASSERT( pszPhone[ 0 ] != '\0' ); bool bResult = true; while( pszPhone[ 0 ] != '\0' ) { switch( pszPhone[ 0 ] ) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '(': case ')': case '#': case '*': case '-': case ',': case ' ': break; default: bResult = false; break; } pszPhone++; } return( bResult ); } // End of IsPhoneNumber. //--------------------------------------------------------------------------// // bCanCallAsPhoneNumber. // //--------------------------------------------------------------------------// bool bCanCallAsPhoneNumber ( const TCHAR * const pszPhone ){ ASSERT( pszPhone != NULL ); ASSERT( pszPhone[ 0 ] != '\0' ); bool bResult = FALSE; if( IsPhoneNumber( pszPhone ) ) { if( ConfPolicies::CallingMode_GateKeeper == ConfPolicies::GetCallingMode() ) { bResult = true; } else { RegEntry reConf( CONFERENCING_KEY, HKEY_CURRENT_USER ); bResult = (reConf.GetNumber( REGVAL_USE_H323_GATEWAY ) != 0); } } return( bResult ); } // End of bCanCallAsPhoneNumber. //--------------------------------------------------------------------------// // unescape. // //--------------------------------------------------------------------------// HRESULT Unescape ( TCHAR * const pszSrc // pointer to string to unescape in place ){ ASSERT( pszSrc != NULL ); TCHAR * pszPercentSign; HRESULT hrResult; for( hrResult = S_OK, pszPercentSign = pszSrc; pszPercentSign != NULL; ) { if( (pszPercentSign = StrChr( pszPercentSign, '%' )) != NULL ) { TCHAR chHighNibble = pszPercentSign[ 1 ]; if( ((chHighNibble >= '0') && (chHighNibble <= '9')) || ((chHighNibble >= 'a') && (chHighNibble <= 'f')) || ((chHighNibble >= 'A') && (chHighNibble <= 'F')) ) { TCHAR chLowNibble = pszPercentSign[ 2 ]; if( ((chLowNibble >= '0') && (chLowNibble <= '9')) || ((chLowNibble >= 'a') && (chLowNibble <= 'f')) || ((chLowNibble >= 'A') && (chLowNibble <= 'F')) ) { chHighNibble = ((chHighNibble >= '0') && (chHighNibble <= '9'))? chHighNibble - '0': ((chHighNibble >= 'a') && (chHighNibble <= 'f'))? chHighNibble - 'a' + 10: chHighNibble - 'A' + 10; chLowNibble = ((chLowNibble >= '0') && (chLowNibble <= '9'))? chLowNibble - '0': ((chLowNibble >= 'a') && (chLowNibble <= 'f'))? chLowNibble - 'a' + 10: chLowNibble - 'A' + 10; *pszPercentSign++ = (chHighNibble << 4) | chLowNibble; lstrcpy( pszPercentSign, &pszPercentSign[ 2 ] ); } else { hrResult = NM_CALLERR_UNESCAPE_ERROR; break; } } else { hrResult = NM_CALLERR_UNESCAPE_ERROR; break; } } } return( hrResult ); } // End of Unescape.