//--------------------------------------------------------------------------// // Application Header Files. // //--------------------------------------------------------------------------// #include "precomp.h" #include "callto.h" #include "calltoContext.h" #include "calltoResolver.h" //--------------------------------------------------------------------------// // CCalltoResolver::CCalltoResolver. // //--------------------------------------------------------------------------// CCalltoResolver::CCalltoResolver(void): m_registeredResolvers( 0 ) { addResolver( &m_phoneResolver ); addResolver( &m_emailResolver ); addResolver( &m_ipResolver ); addResolver( &m_computerResolver ); addResolver( &m_ilsResolver ); addResolver( &m_unrecognizedTypeResolver ); addResolver( &m_stringResolver ); } // End of CCalltoResolver::CCalltoResolver. //--------------------------------------------------------------------------// // CCalltoResolver::~CCalltoResolver. // //--------------------------------------------------------------------------// CCalltoResolver::~CCalltoResolver() { } // End of CCalltoResolver::~CCalltoResolver. //--------------------------------------------------------------------------// // CCalltoResolver::resolve. // //--------------------------------------------------------------------------// HRESULT CCalltoResolver::resolve ( ICalltoContext * const calltoContext, CCalltoProperties * const calltoProperties, CCalltoCollection * const resolvedCalltoCollection, const TCHAR * url, const bool strict ){ HRESULT result; if( (calltoContext == NULL) || (calltoProperties == NULL) || (resolvedCalltoCollection == NULL) ) { result = E_POINTER; } else { TCHAR * params = StrStrI( url, TEXT( "phone:+" ) ); params = StrChr( (params != NULL)? params + strlen_literal( TEXT( "phone:+" ) ): url, '+' ); int paramsLength = (params == NULL)? 0: lstrlen( params ); int urlLength = lstrlen( url ) - paramsLength + 1; int prefixLength = 0; if( !StrCmpNI_literal( url, TEXT( "callto:" ) ) ) { prefixLength = strlen_literal( TEXT( "callto:" ) ); } else if( StrCmpNI_literal( url, TEXT( "callto://" ) ) ) { prefixLength = strlen_literal( TEXT( "callto:" ) ); url += strlen_literal( TEXT( "callto://" ) ); urlLength -= strlen_literal( TEXT( "callto://" ) ) - strlen_literal( TEXT( "callto:" ) ); } TCHAR * urlBuffer = NULL; if( (urlBuffer = new TCHAR [ urlLength + prefixLength ]) == NULL ) { result = E_OUTOFMEMORY; } else { if( paramsLength > 0 ) { // Save params... calltoProperties->set_params( params ); } // Save original callto... calltoProperties->set_callto( url, urlLength ); result = S_FALSE; resolvedCalltoCollection->reset(); if( urlLength > 1 ) { bool strictChecked = !strict; for( int nn = 0; nn < m_registeredResolvers; nn++ ) { if( prefixLength > 0 ) { lstrcpy( urlBuffer, TEXT( "callto:" ) ); // Prepend default of callto: ... lstrcpyn( urlBuffer + strlen_literal( TEXT( "callto:" ) ), url, urlLength ); } else { lstrcpyn( urlBuffer, url, urlLength ); } if( !strictChecked ) { if( !strictCheck( urlBuffer ) ) { result = E_INVALIDARG; break; } strictChecked = true; } HRESULT resolveResult = m_resolvers[ nn ]->resolve( resolvedCalltoCollection, urlBuffer ); if( FAILED( resolveResult ) && (!FAILED( result )) ) { result = resolveResult; } } if( !FAILED( result ) ) { result = (resolvedCalltoCollection->get_count() > 0)? S_OK: S_FALSE; } } } delete [] urlBuffer; } return( result ); } // End of class CCalltoResolver::resolve. //--------------------------------------------------------------------------// // CCalltoResolver::addResolver. // //--------------------------------------------------------------------------// bool CCalltoResolver::addResolver ( IResolver * const resolver ){ //assert( resolver != NULL, TEXT( "attempted to add NULL resolver\r\n" ) ); //assert( m_registeredResolvers < elementsof( m_resolvers ), TEXT( "attempted to add to many resolvers: %d\r\n" ), m_registeredResolvers ); if( (resolver != NULL) && (m_registeredResolvers < elementsof( m_resolvers )) ) { m_resolvers[ m_registeredResolvers++ ] = resolver; } return( (resolver != NULL) && (m_registeredResolvers <= elementsof( m_resolvers )) ); } // End of CCalltoResolver::addResolver. //--------------------------------------------------------------------------// // CCalltoResolver::strictCheck. // //--------------------------------------------------------------------------// const bool CCalltoResolver::strictCheck ( const TCHAR * const url ) const { //assert( url != NULL, TEXT( "attempted to strictCheck NULL url\r\n" ) ); return( (url != NULL) && (StrCmpNI_literal( url, TEXT( "callto:phone:" ) ) || StrCmpNI_literal( url, TEXT( "callto:email:" ) ) || StrCmpNI_literal( url, TEXT( "callto:ip:" ) ) || StrCmpNI_literal( url, TEXT( "callto:computer:" ) ) || StrCmpNI_literal( url, TEXT( "callto:ils:" ) ) || StrCmpNI_literal( url, TEXT( "callto:string:" ) ) || (StrStrI( url, TEXT( "|phone:" ) ) != NULL) || (StrStrI( url, TEXT( "|email:" ) ) != NULL) || (StrStrI( url, TEXT( "|ip:" ) ) != NULL) || (StrStrI( url, TEXT( "|computer:" ) ) != NULL) || (StrStrI( url, TEXT( "|ils:" ) ) != NULL) || (StrStrI( url, TEXT( "|string:" ) ) != NULL)) ); } // End of CCalltoResolver::strictCheck. //--------------------------------------------------------------------------// // CPhoneResolver::resolve. // //--------------------------------------------------------------------------// HRESULT CPhoneResolver::resolve ( IMutableCalltoCollection * const calltoCollection, TCHAR * const url ){ HRESULT result = E_INVALIDARG; if( (calltoCollection != NULL) && (url != NULL) ) { TCHAR * phoneType; TCHAR * phoneNumber = NULL; result = S_FALSE; if( StrCmpNI_literal( url, TEXT( "callto:phone:" ) ) ) // Check for phone type without gateway... { phoneType = url; phoneNumber = url + strlen_literal( TEXT( "callto:phone:" ) ); } else if( (phoneType = StrStrI( url, TEXT( "|phone:" ) )) != NULL ) // Check for phone type with gateway... { phoneNumber = phoneType + strlen_literal( TEXT( "|phone:" ) ); } if( phoneNumber != NULL ) { // phone: type was specified for this callto:... if( CCalltoContext::toE164( phoneNumber, NULL, 0 ) ) { ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { CCalltoContext::toE164( phoneNumber, phoneNumber, lstrlen( phoneNumber ) ); resolvedCallto->set_qualifiedName( url ); resolvedCallto->set_confidence( S_CONFIDENCE_HIGH ); result = S_OK; } else { result = E_OUTOFMEMORY; } } } else { phoneNumber = url + strlen_literal( TEXT( "callto:" ) ); if( CCalltoContext::isPhoneNumber( phoneNumber ) ) { // It smells like E164... result = E_OUTOFMEMORY; CCalltoContext::toE164( phoneNumber, phoneNumber, lstrlen( phoneNumber ) ); TCHAR * buffer = new TCHAR [ lstrlen( phoneNumber ) + strlen_literal( TEXT( "callto:phone:%s" ) ) ]; if( buffer != NULL ) { ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { wsprintf( buffer, TEXT( "callto:phone:%s" ), phoneNumber ); resolvedCallto->set_qualifiedName( buffer ); resolvedCallto->set_confidence( S_CONFIDENCE_MEDIUM ); result = S_OK; } delete [] buffer; } } } } return( result ); } // End of CPhoneResolver::resolve. //--------------------------------------------------------------------------// // CEMailResolver::resolve. // //--------------------------------------------------------------------------// HRESULT CEMailResolver::resolve ( IMutableCalltoCollection * const calltoCollection, TCHAR * const url ){ HRESULT result = E_INVALIDARG; if( (calltoCollection != NULL) && (url != NULL) ) { TCHAR * emailType; TCHAR * emailAddress = NULL; result = S_FALSE; if( StrCmpNI_literal( url, TEXT( "callto:email:" ) ) ) // Check for email type without gateway... { emailType = url; emailAddress = url + strlen_literal( TEXT( "callto:email:" ) ); } else if( (emailType = StrStrI( url, TEXT( "|email:" ) )) != NULL ) // Check for email type with gateway... { emailAddress = emailType + strlen_literal( TEXT( "|email:" ) ); } if( emailAddress != NULL ) { // email: type was specified for this callto:... ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { resolvedCallto->set_qualifiedName( url ); resolvedCallto->set_confidence( S_CONFIDENCE_HIGH ); result = S_OK; } else { result = E_OUTOFMEMORY; } } else { emailAddress = url + strlen_literal( TEXT( "callto:" ) ); if( (StrChr( emailAddress, ':' ) == NULL) && // isn't some other type:... (StrChr( emailAddress, ' ' ) == NULL) && // doesn't contain spaces... (StrChr( emailAddress, '|' ) == NULL) && // doesn't contain a bar (gateway)... (StrChr( emailAddress, '/' ) == NULL) && // isn't an old style ilsserver/email... ((StrChr( emailAddress, '.' ) == NULL) || // doesn't have a dot unless it also (StrChr( emailAddress, '@' ) != NULL)) ) // has a @ so it can't be an ip address... { // It smells like an email address... result = E_OUTOFMEMORY; TCHAR * buffer = new TCHAR [ lstrlen( emailAddress ) + strlen_literal( TEXT( "callto:email:%s" ) ) ]; if( buffer != NULL ) { ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { wsprintf( buffer, TEXT( "callto:email:%s" ), emailAddress ); resolvedCallto->set_qualifiedName( buffer ); resolvedCallto->set_confidence( S_CONFIDENCE_MEDIUM ); result = S_OK; } delete [] buffer; } } } } return( result ); } // End of CEMailResolver::resolve. //--------------------------------------------------------------------------// // CIPResolver::resolve. // //--------------------------------------------------------------------------// HRESULT CIPResolver::resolve ( IMutableCalltoCollection * const calltoCollection, TCHAR * const url ){ HRESULT result = E_INVALIDARG; if( (calltoCollection != NULL) && (url != NULL) ) { TCHAR * ipType; TCHAR * ipAddress = NULL; result = S_FALSE; if( StrCmpNI_literal( url, TEXT( "callto:ip:" ) ) ) // Check for ip type without gateway... { ipType = url; ipAddress = url + strlen_literal( TEXT( "callto:ip:" ) ); } else if( (ipType = StrStrI( url, TEXT( "|ip:" ) )) != NULL ) // Check for ip type with gateway... { ipAddress = ipType + strlen_literal( TEXT( "|ip:" ) ); } if( (ipAddress != NULL) && CCalltoContext::isIPAddress( ipAddress ) ) { // ip: type was specified for this callto:... ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { resolvedCallto->set_qualifiedName( url ); resolvedCallto->set_confidence( S_CONFIDENCE_HIGH ); result = S_OK; } else { result = E_OUTOFMEMORY; } } else { ipAddress = url + strlen_literal( TEXT( "callto:" ) ); if( CCalltoContext::isIPAddress( ipAddress ) ) { // It smells like an ip address... ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { TCHAR buffer[ MAX_PATH ]; wsprintf( buffer, TEXT( "callto:ip:%s" ), ipAddress ); resolvedCallto->set_qualifiedName( buffer ); resolvedCallto->set_confidence( S_CONFIDENCE_MEDIUM ); result = S_OK; } else { result = E_OUTOFMEMORY; } } } } return( result ); } // End of CIPResolver::resolve. //--------------------------------------------------------------------------// // CComputerResolver::resolve. // //--------------------------------------------------------------------------// HRESULT CComputerResolver::resolve ( IMutableCalltoCollection * const calltoCollection, TCHAR * const url ){ HRESULT result = E_INVALIDARG; if( (calltoCollection != NULL) && (url != NULL) ) { TCHAR * computerType; TCHAR * hostName = NULL; result = S_FALSE; if( StrCmpNI_literal( url, TEXT( "callto:computer:" ) ) ) // Check for computer type without gateway... { computerType = url; hostName = url + strlen_literal( TEXT( "callto:computer:" ) ); } else if( (computerType = StrStrI( url, TEXT( "|computer:" ) )) != NULL ) // Check for computer type with gateway... { hostName = computerType + strlen_literal( TEXT( "|computer:" ) ); } if( hostName != NULL ) { // host: type was specified for this callto:... ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { resolvedCallto->set_qualifiedName( url ); resolvedCallto->set_confidence( S_CONFIDENCE_HIGH ); result = S_OK; } else { result = E_OUTOFMEMORY; } } else { hostName = url + strlen_literal( TEXT( "callto:" ) ); TCHAR * slash = hostName; // Remove any trailing /.... while( (slash = StrChr( slash, '/' )) != NULL ) { if( slash[ 1 ] == '\0' ) { slash[ 0 ] = '\0'; break; } slash++; } if( (StrChr( hostName, ':' ) == NULL) && // isn't some other type:... (StrChr( hostName, ' ' ) == NULL) && // doesn't contain spaces... (StrChr( hostName, '|' ) == NULL) && // doesn't contain a bar (gateway)... (StrChr( hostName, '/' ) == NULL) && // doesn't contain a slash (ils)... (StrChr( hostName, '@' ) == NULL) ) // doesn't contain an @... { // It smells like a dns host name... result = E_OUTOFMEMORY; TCHAR * buffer = new TCHAR [ lstrlen( hostName ) + strlen_literal( TEXT( "callto:computer:%s" ) ) ]; if( buffer != NULL ) { ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { wsprintf( buffer, TEXT( "callto:computer:%s" ), hostName ); resolvedCallto->set_qualifiedName( buffer ); resolvedCallto->set_confidence( StrCmpNI_literal( hostName, TEXT( "\\\\" ) )? S_CONFIDENCE_HIGH: S_CONFIDENCE_MEDIUM ); result = S_OK; } delete [] buffer; } } } } return( result ); } // End of CComputerResolver::resolve. //--------------------------------------------------------------------------// // CILSResolver::resolve. // //--------------------------------------------------------------------------// HRESULT CILSResolver::resolve ( IMutableCalltoCollection * const calltoCollection, TCHAR * const url ){ HRESULT result = E_INVALIDARG; if( (calltoCollection != NULL) && (url != NULL) ) { const TCHAR * ilsType; const TCHAR * emailAddress = NULL; result = S_FALSE; if( StrCmpNI_literal( url, TEXT( "callto:ils:" ) ) ) // Check for ils type without gateway... { ilsType = url; emailAddress = url + strlen_literal( TEXT( "callto:ils:" ) ); } else if( (ilsType = StrStrI( url, TEXT( "|ils:" ) )) != NULL ) // Check for ils type with gateway... { emailAddress = ilsType + strlen_literal( TEXT( "|ils:" ) ); } if( emailAddress != NULL ) { // ils: type was specified for this callto:... ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { resolvedCallto->set_qualifiedName( url ); resolvedCallto->set_confidence( S_CONFIDENCE_HIGH ); result = S_OK; } else { result = E_OUTOFMEMORY; } } else { emailAddress = url + strlen_literal( TEXT( "callto:" ) ); if( (StrChr( emailAddress, ' ' ) == NULL) && // doesn't contain spaces... (StrChr( emailAddress, '|' ) == NULL) && // doesn't contain a bar (gateway)... (StrChr( emailAddress, '/' ) != NULL) ) // has a /... { // It smells like an ilsserver/emailaddress... result = E_OUTOFMEMORY; TCHAR * buffer = new TCHAR [ lstrlen( emailAddress ) + strlen_literal( TEXT( "callto:ils:%s" ) ) ]; if( buffer != NULL ) { ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { wsprintf( buffer, TEXT( "callto:ils:%s" ), emailAddress ); resolvedCallto->set_qualifiedName( buffer ); resolvedCallto->set_confidence( S_CONFIDENCE_MEDIUM ); result = S_OK; } delete [] buffer; } } } } return( result ); } // End of CILSResolver::resolve. //--------------------------------------------------------------------------// // CUnrecognizedTypeResolver::resolve. // //--------------------------------------------------------------------------// HRESULT CUnrecognizedTypeResolver::resolve ( IMutableCalltoCollection * const calltoCollection, TCHAR * const url ){ HRESULT result = E_INVALIDARG; if( (calltoCollection != NULL) && (url != NULL) ) { TCHAR * type; TCHAR * unrecognized = url + strlen_literal( TEXT( "callto:" ) ); TCHAR * gateway = NULL; TCHAR * value = NULL; result = S_FALSE; if( ((type = StrChr( unrecognized, ':' )) != NULL) && // Check for a type, but not a known one... (!StrCmpNI_literal( url, TEXT( "callto:phone:" ) )) && (StrStrI( url, TEXT( "|phone:" ) ) == NULL) && // isn't a phone: type... (!StrCmpNI_literal( url, TEXT( "callto:email:" ) )) && (StrStrI( url, TEXT( "|email:" ) ) == NULL) && // isn't an email: type... (!StrCmpNI_literal( url, TEXT( "callto:computer:" ) )) && (StrStrI( url, TEXT( "|computer:" ) ) == NULL) && // isn't a computer: type... (!StrCmpNI_literal( url, TEXT( "callto:ils:" ) )) && (StrStrI( url, TEXT( "|ils:" ) ) == NULL) && // isn't an ils: type... (!StrCmpNI_literal( url, TEXT( "callto:ip:" ) )) && (StrStrI( url, TEXT( "|ip:" ) ) == NULL) && // isn't an ip: type... (!StrCmpNI_literal( url, TEXT( "callto:string:" ) )) && (StrStrI( url, TEXT( "|string:" ) ) == NULL) ) // isn't an string: type... { *type++ = NULL; value = type; if( (gateway = StrChr( url, '|' )) != NULL ) // Check for a gateway... { *gateway++ = NULL; type = gateway; gateway = unrecognized; } } if( value != NULL ) { // Some unrecognized type was specified... result = E_OUTOFMEMORY; int length = strlen_literal( TEXT( "callto:|%s" ) ) + lstrlen( value ); if( gateway == NULL ) { length += lstrlen( unrecognized ); } else { length += lstrlen( gateway ) + lstrlen( type ); } TCHAR * buffer = new TCHAR [ length ]; if( buffer != NULL ) { ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { if( gateway == NULL ) { wsprintf( buffer, TEXT( "callto:%s:%s" ), unrecognized, value ); } else { wsprintf( buffer, TEXT( "callto:%s|%s:%s" ), gateway, type, value ); } resolvedCallto->set_qualifiedName( buffer ); resolvedCallto->set_confidence( S_CONFIDENCE_LOW ); result = S_OK; } delete [] buffer; } } } return( result ); } // End of CUnrecognizedTypeResolver::resolve. //--------------------------------------------------------------------------// // CStringResolver::resolve. // //--------------------------------------------------------------------------// HRESULT CStringResolver::resolve ( IMutableCalltoCollection * const calltoCollection, TCHAR * const url ){ HRESULT result = E_INVALIDARG; if( (calltoCollection != NULL) && (url != NULL) ) { TCHAR * stringType; TCHAR * string = NULL; result = S_FALSE; if( StrCmpNI_literal( url, TEXT( "callto:string:" ) ) ) // Check for string type without gateway... { stringType = url; string = url + strlen_literal( TEXT( "callto:string:" ) ); } else if( (stringType = StrStrI( url, TEXT( "|string:" ) )) != NULL ) // Check for string type with gateway... { string = stringType + strlen_literal( TEXT( "|string:" ) ); } if( string != NULL ) { // string: type was specified for this callto:... ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { resolvedCallto->set_qualifiedName( url ); resolvedCallto->set_confidence( S_CONFIDENCE_HIGH ); result = S_OK; } else { result = E_OUTOFMEMORY; } } else { string = url + strlen_literal( TEXT( "callto:" ) ); if( StrChr( string, ':' ) == NULL ) { // It doesn't have a type so set it to string... result = E_OUTOFMEMORY; TCHAR * slash; TCHAR * buffer = new TCHAR [ lstrlen( string ) + strlen_literal( TEXT( "callto:%s|string:%s" ) ) ]; if( buffer != NULL ) { ICallto * const resolvedCallto = calltoCollection->get_nextUnused(); if( resolvedCallto != NULL ) { if( (slash = StrChr( string, '|' )) == NULL ) // Check for a gateway... { wsprintf( buffer, TEXT( "callto:string:%s" ), string ); } else { *slash++ = NULL; wsprintf( buffer, TEXT( "callto:%s|string:%s" ), string, slash ); } resolvedCallto->set_qualifiedName( buffer ); resolvedCallto->set_confidence( S_CONFIDENCE_LOW ); result = S_OK; } delete [] buffer; } } } } return( result ); } // End of CStringResolver::resolve.