///////////////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1997 Active Voice Corporation. All Rights Reserved. // // Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation. // // Other brand and product names used herein are trademarks of their respective owners. // // The entire program and user interface including the structure, sequence, selection, // and arrangement of the dialog, the exclusively "yes" and "no" choices represented // by "1" and "2," and each dialog message are protected by copyrights registered in // the United States and by international treaties. // // Protected by one or more of the following United States patents: 5,070,526, 5,488,650, // 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054. // // Active Voice Corporation // Seattle, Washington // USA // ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// // ThreadDialing.cpp // #include "stdafx.h" #include "TapiDialer.h" #include "ThreadDial.h" #include "AVTapi.h" #include "AVTapiCall.h" #include "ConfExp.h" #include "ThreadPub.h" CThreadDialingInfo::CThreadDialingInfo() { m_pITAddress = NULL; m_bstrName = NULL; m_bstrAddress = NULL; m_bstrOriginalAddress = NULL; m_bstrDisplayableAddress = NULL; m_bstrUser1 = NULL; m_bstrUser2 = NULL; m_dwAddressType = 0; m_bResolved = false; m_nCallType = AV_VOICE_CALL; m_lCallID = 0; m_hMem = NULL; } CThreadDialingInfo::~CThreadDialingInfo() { SysFreeString( m_bstrName ); SysFreeString( m_bstrAddress ); SysFreeString( m_bstrOriginalAddress ); SysFreeString( m_bstrDisplayableAddress ); SysFreeString( m_bstrUser1 ); SysFreeString( m_bstrUser2 ); if ( m_hMem ) GlobalFree( m_hMem ); RELEASE( m_pITAddress ); } HRESULT CThreadDialingInfo::set_ITAddress( ITAddress *pITAddress ) { RELEASE( m_pITAddress ); if ( pITAddress ) return pITAddress->QueryInterface( IID_ITAddress, (void **) &m_pITAddress ); return E_POINTER; } HRESULT CThreadDialingInfo::TranslateAddress() { // Only valid for dialing POTS, with a valid string that doesn't start with "x" if ( !m_pITAddress || (m_dwAddressType != LINEADDRESSTYPE_PHONENUMBER) || !m_bstrAddress || (SysStringLen(m_bstrAddress) == 0) ) { return S_OK; } ITAddressTranslation *pXlat; CErrorInfo er( IDS_ER_TRANSLATE_ADDRESS, IDS_ER_CREATE_TAPI_OBJECT ); if ( SUCCEEDED(er.set_hr(m_pITAddress->QueryInterface(IID_ITAddressTranslation, (void **) &pXlat))) ) { er.set_Details( IDS_ER_TRANSLATING_ADDRESS ); ITAddressTranslationInfo *pXlatInfo = NULL; // Translate the address int nTryCount = 0; while ( SUCCEEDED(er.m_hr) && (nTryCount < 2) ) { if ( SUCCEEDED(er.set_hr( pXlat->TranslateAddress( m_bstrAddress, 0, 0, &pXlatInfo) )) && pXlatInfo ) { BSTR bstrTemp = NULL; pXlatInfo->get_DialableString( &bstrTemp ); if ( bstrTemp && SysStringLen(bstrTemp) ) { #ifdef _DEBUG USES_CONVERSION; ATLTRACE(_T(".1.CThreadDialingProc::TranslateAddress() -- from %s to %s.\n"), OLE2CT(m_bstrAddress), OLE2CT(bstrTemp) ); #endif SysReAllocString( &m_bstrAddress, bstrTemp ); } SysFreeString( bstrTemp ); bstrTemp = NULL; // Displayable address as well pXlatInfo->get_DisplayableString( &bstrTemp ); if ( bstrTemp && SysStringLen(bstrTemp) ) SysReAllocString( &m_bstrDisplayableAddress, bstrTemp ); SysFreeString( bstrTemp ); // Clean up RELEASE( pXlatInfo ); break; } else if ( er.m_hr == TAPI_E_REGISTRY_SETTING_CORRUPT ) { HWND hWndParent = NULL; CComPtr pAVTapi; if ( SUCCEEDED(_Module.get_AVTapi(&pAVTapi)) ) pAVTapi->get_hWndParent( &hWndParent ); // Show translate address dialog pXlat->TranslateDialog( (TAPIHWND)hWndParent, m_bstrAddress ); er.set_hr( S_OK ); } nTryCount++; } pXlat->Release(); } return er.m_hr; } HRESULT CThreadDialingInfo::PutAllInfo( IAVTapiCall *pAVCall ) { _ASSERT( pAVCall ); pAVCall->put_dwAddressType( m_dwAddressType ); pAVCall->put_bstrOriginalAddress( m_bstrOriginalAddress ); pAVCall->put_bstrDisplayableAddress( m_bstrDisplayableAddress ); pAVCall->put_bstrName( m_bstrName ); pAVCall->put_dwThreadID( GetCurrentThreadId() ); pAVCall->put_bstrUser( 0, m_bstrUser1 ); pAVCall->put_bstrUser( 1, m_bstrUser2 ); pAVCall->put_bResolved( m_bResolved ); return S_OK; } void CThreadDialingInfo::FixupAddress() { if ( m_dwAddressType == LINEADDRESSTYPE_DOMAINNAME ) { if ( (SysStringLen(m_bstrAddress) > 2) && !wcsncmp(m_bstrAddress, L"\\\\", 2) ) { BSTR bstrTemp = SysAllocString( &m_bstrAddress[2] ); // // We have to verify the string allocation // if( IsBadStringPtr( bstrTemp, (UINT)-1) ) { return; } SysReAllocString( &m_bstrAddress, bstrTemp ); SysFreeString( bstrTemp ); } } } ///////////////////////////////////////////////////////////////////////////////// // ThreadDialingProc // DWORD WINAPI ThreadDialingProc( LPVOID lpInfo ) { #define FETCH_STRING( _CMS_, _IDS_ ) \ if ( bSliders ) { \ if ( LoadString(_Module.GetResourceInstance(), _IDS_, szText, ARRAYSIZE(szText)) > 0 ) { \ if ( SUCCEEDED(SysReAllocString(&bstrText, T2COLE(szText))) ) \ pAVTapi->fire_SetCallState_CMS( lCallID, _CMS_, bstrText ); \ } \ } ATLTRACE(_T(".enter.ThreadDialingProc().\n") ); HANDLE hThread = NULL; BOOL bDup = DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hThread, THREAD_ALL_ACCESS, TRUE, 0 ); _ASSERT( bDup ); _Module.AddThread( hThread ); // Data passed into thread USES_CONVERSION; _ASSERT( lpInfo ); CThreadDialingInfo *pInfo = (CThreadDialingInfo *) lpInfo; long lCallID; // Error info information CErrorInfo er; er.set_Operation( IDS_ER_PLACECALL ); er.set_Details( IDS_ER_COINITIALIZE ); HRESULT hr = er.set_hr( CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY) ); if ( SUCCEEDED(hr) ) { ATLTRACE(_T(".1.ThreadDialingProc() -- thread up and running.\n") ); CAVTapi *pAVTapi = NULL; IConfRoom *pConfRoom = NULL; IAVTapiCall *pAVCall = NULL; bool bSliders = (bool) (pInfo->m_dwAddressType != LINEADDRESSTYPE_SDP); if ( SUCCEEDED(hr = er.set_hr(_Module.GetAVTapi(&pAVTapi))) && SUCCEEDED(hr = er.set_hr(pAVTapi->get_ConfRoom(&pConfRoom))) ) { TCHAR szText[255]; BSTR bstrText = NULL; er.set_Details( IDS_ER_FIRE_NEW_CALL ); if ( bSliders ) { if ( SUCCEEDED(hr = er.set_hr(pAVTapi->fire_NewCall(pInfo->m_pITAddress, pInfo->m_dwAddressType, pInfo->m_lCallID, NULL, pInfo->m_nCallType, &pAVCall))) ) { // Retrieve call ID for convienence and set up called address info pAVCall->get_lCallID( &lCallID ); pInfo->PutAllInfo( pAVCall ); // Set the caller ID for the call pAVCall->ResolveAddress(); pAVCall->ForceCallerIDUpdate(); // Setting up media terminals pAVTapi->fire_ClearCurrentActions( lCallID ); pAVTapi->fire_AddCurrentAction( lCallID, CM_ACTIONS_DISCONNECT, NULL ); FETCH_STRING( CM_STATES_DIALING, IDS_PLACECALL_FETCH_ADDRESS ); } } else { // Joining a conference... hr = er.set_hr(pAVTapi->CreateNewCall(pInfo->m_pITAddress, &pAVCall) ); if ( SUCCEEDED(hr) ) { pInfo->PutAllInfo( pAVCall ); pAVTapi->fire_ActionSelected( CC_ACTIONS_SHOWCONFROOM ); hr = pConfRoom->EnterConfRoom( pAVCall ); } } if ( SUCCEEDED(hr) ) { // Did we make the address okay (in the case of a conference ) if ( SUCCEEDED(hr) && SUCCEEDED(hr = pAVCall->CheckKillMe()) ) { // Create the call and then dial ITBasicCallControl *pITControl = NULL; er.set_Details( IDS_ER_CREATE_CALL ); pInfo->FixupAddress(); // What kind of media types does the address support? long lSupportedMediaModes = 0; ITMediaSupport *pITMediaSupport; if ( SUCCEEDED(pInfo->m_pITAddress->QueryInterface(IID_ITMediaSupport, (void **) &pITMediaSupport)) ) { pITMediaSupport->get_MediaTypes( &lSupportedMediaModes ); pITMediaSupport->Release(); } lSupportedMediaModes &= (TAPIMEDIATYPE_AUDIO | TAPIMEDIATYPE_VIDEO); //////////////////////// // Create the call object // if ( SUCCEEDED(hr = er.set_hr(pInfo->m_pITAddress-> CreateCall( pInfo->m_bstrAddress, pInfo->m_dwAddressType, lSupportedMediaModes, &pITControl))) ) { // Set more call parameters pAVCall->put_ITBasicCallControl( pITControl ); /////////////////////////////////// // Set caller/calling ID // Set the terminals up for the call // ITCallInfo *pCallInfo; if ( SUCCEEDED(pITControl->QueryInterface(IID_ITCallInfo, (void **) &pCallInfo)) ) { // Set user user info if requested if ( pInfo->m_hMem ) { void *pbUU = GlobalLock( pInfo->m_hMem ); if ( pbUU ) { pCallInfo->SetCallInfoBuffer( CIB_USERUSERINFO, GlobalSize(pInfo->m_hMem), (BYTE *) pbUU ); GlobalUnlock( pInfo->m_hMem ); } } // Identify who it is that's calling! CComBSTR bstrName; MyGetUserName( &bstrName ); if ( bstrName ) { // Add the computer name to the end BSTR bstrIP = NULL, bstrComputer = NULL; GetIPAddress( &bstrIP, &bstrComputer ); if ( bstrComputer && SysStringLen(bstrComputer) ) { bstrName.Append( _T("\n") ); bstrName.Append( bstrComputer ); } SysFreeString( bstrIP ); SysFreeString( bstrComputer ); pCallInfo->put_CallInfoString( CIS_CALLINGPARTYID, bstrName ); } // Identify who it is that we think we're calling if ( pInfo->m_bstrName && (SysStringLen(pInfo->m_bstrName) > 0) ) pCallInfo->put_CallInfoString( CIS_CALLEDPARTYFRIENDLYNAME, pInfo->m_bstrName ); else pCallInfo->put_CallInfoString( CIS_CALLEDPARTYFRIENDLYNAME, pInfo->m_bstrAddress ); /////////////////////////////////// // Setting up media terminals // pAVTapi->fire_ClearCurrentActions( lCallID ); pAVTapi->fire_AddCurrentAction( lCallID, CM_ACTIONS_DISCONNECT, NULL ); FETCH_STRING( CM_STATES_DIALING, IDS_PLACECALL_FETCH_ADDRESS ); // Don't create terminals for data calls if ( pInfo->m_nCallType != AV_DATA_CALL ) { er.set_Details( IDS_ER_CREATETERMINALS ); hr = er.set_hr( pAVTapi->CreateTerminalArray(pInfo->m_pITAddress, pAVCall, pCallInfo) ); } pCallInfo->Release(); } //////////////////////////////// // Do the dialing // if ( SUCCEEDED(hr) && SUCCEEDED(hr = pAVCall->CheckKillMe()) ) { FETCH_STRING( CM_STATES_DIALING, IDS_PLACECALL_DIALING ); // Register the callback object and connect call if ( SUCCEEDED(hr) && SUCCEEDED(hr = pAVCall->CheckKillMe()) ) { er.set_Details( IDS_ER_CONNECT_CALL ); if ( bSliders && (pInfo->m_nCallType != AV_DATA_CALL) ) { pAVTapi->ShowMedia( lCallID, NULL, FALSE ); pAVTapi->ShowMediaPreview( lCallID, NULL, FALSE ); } hr = er.set_hr( pITControl->Connect(false) ); } else if ( bSliders ) { pConfRoom->Cancel(); } } else if ( bSliders ) { pConfRoom->Cancel(); } SAFE_DELETE( pInfo ) RELEASE( pAVCall ); pITControl->Release(); // Spin if ( SUCCEEDED(hr) ) CAVTapiCall::WaitWithMessageLoop(); } } // Failed to make the call, update the call control window if ( FAILED(hr) ) { if ( bSliders ) { pAVTapi->fire_ClearCurrentActions( lCallID ); pAVTapi->fire_AddCurrentAction( lCallID, CM_ACTIONS_CLOSE, NULL ); } else { pConfRoom->Cancel(); } // what was the problem? switch ( hr ) { case LINEERR_OPERATIONUNAVAIL: FETCH_STRING( CM_STATES_UNAVAILABLE, IDS_PLACECALL_DISCONNECT_UNAVAIL ); hr = er.set_hr( S_OK ); break; case LINEERR_INVALADDRESS: FETCH_STRING( CM_STATES_UNAVAILABLE, IDS_PLACECALL_DISCONNECT_BADADDRESS); hr = er.set_hr( S_OK ); break; default: if ( bSliders ) pAVTapi->fire_SetCallState_CMS( lCallID, CM_STATES_DISCONNECTED, NULL ); break; } } } // Release the string SysFreeString( bstrText ); } // Clean-up RELEASE( pConfRoom ); if ( pAVTapi ) (dynamic_cast (pAVTapi))->Release(); CoUninitialize(); } SAFE_DELETE( pInfo ); // Notify module of shutdown _Module.RemoveThread( hThread ); SetEvent( _Module.m_hEventThread ); ATLTRACE(_T(".exit.ThreadDialingProc(0x%08lx).\n"), hr ); return hr; }