// File: imanager.cpp #include "precomp.h" extern "C" { #include "t120.h" } #include #include #include "icall.h" #include "icall_in.h" #include "imanager.h" #include "ichnlvid.h" #include "isysinfo.h" #include #include #include #include #include // GUID to receive userdata from "callto:" via INmCall::GetUserData // // {068B0780-718C-11d0-8B1A-00A0C91BC90E} DEFINE_GUID(GUID_CallToUserData, 0x068b0780, 0x718c, 0x11d0, 0x8b, 0x1a, 0x0, 0xa0, 0xc9, 0x1b, 0xc9, 0x0e); class CH323ChannelEvent { private: ICommChannel *m_pIChannel; IH323Endpoint *m_lpConnection; DWORD m_dwStatus; public: static DWORD ms_msgChannelEvent; CH323ChannelEvent(ICommChannel *pIChannel, IH323Endpoint *lpConnection, DWORD dwStatus): m_pIChannel(pIChannel), m_lpConnection(lpConnection), m_dwStatus(dwStatus) { if(!ms_msgChannelEvent) { ms_msgChannelEvent = RegisterWindowMessage(_TEXT("NetMeeting::H323ChannelEvent")); } m_pIChannel->AddRef(); m_lpConnection->AddRef(); } ~CH323ChannelEvent() { m_pIChannel->Release(); m_lpConnection->Release(); } ICommChannel* GetChannel() { return m_pIChannel; } IH323Endpoint* GetEndpoint() { return m_lpConnection; } DWORD GetStatus() { return m_dwStatus; } }; //static DWORD CH323ChannelEvent::ms_msgChannelEvent = 0; static HRESULT OnNotifyConferenceCreated(IUnknown *pManagerNotify, PVOID pv, REFIID riid); static HRESULT OnNotifyCallCreated(IUnknown *pManagerNotify, PVOID pv, REFIID riid); GUID g_csguidRosterCaps = GUID_CAPS; GUID g_csguidSecurity = GUID_SECURITY; GUID g_csguidMeetingSettings = GUID_MTGSETTINGS; GUID g_csguidUserString = GUID_CallToUserData; GUID g_csguidNodeIdTag = GUID_NODEID; // this guid is dynamically created each time we start GUID g_guidLocalNodeId; CH323UI* g_pH323UI = NULL; INodeController* g_pNodeController = NULL; SOCKADDR_IN g_sinGateKeeper; const TCHAR cszDllHiddenWndClassName[] = _TEXT("OPNCUI_HiddenWindow"); COprahNCUI *COprahNCUI::m_pOprahNCUI = NULL; static const IID * g_apiidCP_Manager[] = { {&IID_INmManagerNotify} }; COprahNCUI::COprahNCUI(OBJECTDESTROYEDPROC ObjectDestroyed) : RefCount(ObjectDestroyed), CConnectionPointContainer(g_apiidCP_Manager, ARRAY_ELEMENTS(g_apiidCP_Manager)), m_uCaps(0), m_pQoS(NULL), m_pPreviewChannel(NULL), m_fAllowAV(TRUE), m_pAVConnection(NULL), m_hwnd(NULL), m_pSysInfo(NULL), m_pOutgoingCallManager(NULL), m_pIncomingCallManager(NULL), m_pConfObject(NULL) { DbgMsg(iZONE_OBJECTS, "Obj: %08X created CNmManager", this); // DllLock() is called by CClClassFactory::CreateInstance m_pOprahNCUI = this; ClearStruct(&g_sinGateKeeper); g_sinGateKeeper.sin_addr.s_addr = INADDR_NONE; m_pSysInfo = new CNmSysInfo(); } COprahNCUI::~COprahNCUI() { // need to unregister the H323 callback // need to unregister the T120 callback delete m_pIncomingCallManager; m_pIncomingCallManager = NULL; delete m_pOutgoingCallManager; m_pOutgoingCallManager = NULL; if( m_pSysInfo ) { m_pSysInfo->Release(); m_pSysInfo = NULL; } if (m_pConfObject) { // turn off stream notifications if (g_pH323UI) { IMediaChannelBuilder *pStreamProvider = NULL; pStreamProvider = g_pH323UI->GetStreamProvider(); if (pStreamProvider) { pStreamProvider->SetStreamEventObj(NULL); pStreamProvider->Release(); } } m_pConfObject->Release(); m_pConfObject = NULL; } if (NULL != m_pPreviewChannel) { m_pPreviewChannel->Release(); m_pPreviewChannel = NULL; } // Shutdown H323 delete g_pH323UI; g_pH323UI = NULL; if (NULL != m_hwnd) { HWND hwnd = m_hwnd; m_hwnd = NULL; #if 0 // if we start leaking th CH323ChannelEvents we may need to reenable this MSG msg; while (::PeekMessage(&msg, hwnd, CH323ChannelEvent::ms_msgChannelEvent, CH323ChannelEvent::ms_msgChannelEvent, PM_REMOVE)) { CH323ChannelEvent *pEvent = reinterpret_cast(msg.lParam); delete pEvent; } #endif ::DestroyWindow(hwnd); } if (0==UnregisterClass(cszDllHiddenWndClassName, GetInstanceHandle())) { ERROR_OUT(("COprahNCUI::~COprahNCUI - failed to unregister window class")); } // cleanup the node controller: if (NULL != g_pNodeController) { g_pNodeController->ReleaseInterface(); g_pNodeController = NULL; } // Shutdown QoS delete m_pQoS; m_pQoS = NULL; m_pOprahNCUI = NULL; DbgMsg(iZONE_OBJECTS, "Obj: %08X destroyed CNmManager", this); } BSTR COprahNCUI::GetUserName() { return m_pSysInfo ? m_pSysInfo->GetUserName() : NULL; } UINT COprahNCUI::GetOutgoingCallCount() { return m_pOutgoingCallManager->GetCallCount(); } VOID COprahNCUI::OnOutgoingCallCreated(INmCall* pCall) { // notify the UI about this outgoing call NotifySink(pCall, OnNotifyCallCreated); if (!m_pConfObject->IsConferenceCreated()) { m_pConfObject->OnConferenceCreated(); NotifySink((INmConference*) m_pConfObject, OnNotifyConferenceCreated); } } VOID COprahNCUI::OnOutgoingCallCanceled(COutgoingCall* pCall) { m_pOutgoingCallManager->RemoveFromList(pCall); } VOID COprahNCUI::OnIncomingCallAccepted() { if (!m_pConfObject->IsConferenceCreated()) { m_pConfObject->OnConferenceCreated(); NotifySink((INmConference*) m_pConfObject, OnNotifyConferenceCreated); } } VOID COprahNCUI::OnIncomingCallCreated(INmCall* pCall) { NotifySink(pCall, OnNotifyCallCreated); } VOID COprahNCUI::CancelCalls() { m_pOutgoingCallManager->CancelCalls(); m_pIncomingCallManager->CancelCalls(); } BOOL COprahNCUI::AcquireAV(IH323Endpoint* pConnection) { if (NULL == m_pAVConnection) { m_pAVConnection = pConnection; TRACE_OUT(("AV acquired")); return TRUE; } TRACE_OUT(("AV not acquired")); return FALSE; } BOOL COprahNCUI::ReleaseAV(IH323Endpoint* pConnection) { if (m_pAVConnection == pConnection) { m_pAVConnection = NULL; TRACE_OUT(("AV released")); return TRUE; } return FALSE; } HRESULT COprahNCUI::AllowH323(BOOL fAllowAV) { m_fAllowAV = fAllowAV; if (m_pConfObject->IsConferenceActive()) { // Force a roster update CONF_HANDLE hConf = m_pConfObject->GetConfHandle(); if (NULL != hConf) { ASSERT(g_pNodeController); hConf->UpdateUserData(); } } return S_OK; } CREQ_RESPONSETYPE COprahNCUI::OnH323IncomingCall(IH323Endpoint* pConnection, P_APP_CALL_SETUP_DATA lpvMNMData) { CREQ_RESPONSETYPE resp = m_pIncomingCallManager->OnIncomingH323Call(this, pConnection, lpvMNMData); if ((CRR_REJECT == resp) || (CRR_BUSY == resp) || (CRR_SECURITY_DENIED == resp)) { ReleaseAV(pConnection); } return resp; } VOID COprahNCUI::OnH323Connected(IH323Endpoint * lpConnection) { DebugEntry(COprahNCUI::OnH323Connected); if (!m_pOutgoingCallManager->OnH323Connected(lpConnection)) { m_pIncomingCallManager->OnH323Connected(lpConnection); } DebugExitVOID(COprahNCUI::OnH323Connected); } VOID COprahNCUI::OnH323Disconnected(IH323Endpoint * lpConnection) { DebugEntry(COprahNCUI::OnH323Disconnected); if (!m_pOutgoingCallManager->OnH323Disconnected(lpConnection)) { m_pIncomingCallManager->OnH323Disconnected(lpConnection); } m_pConfObject->OnH323Disconnected(lpConnection, IsOwnerOfAV(lpConnection)); ReleaseAV(lpConnection); DebugExitVOID(COprahNCUI::OnH323Disconnected); } VOID COprahNCUI::OnT120ChannelOpen(ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus) { DebugEntry(COprahNCUI::OnT120ChannelOpen); m_pOutgoingCallManager->OnT120ChannelOpen(pIChannel, lpConnection, dwStatus); DebugExitVOID(COprahNCUI::OnT120ChannelOpen); } VOID COprahNCUI::OnVideoChannelStatus(ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus) { DebugEntry(COprahNCUI::OnVideoChannelStatus); m_pConfObject->OnVideoChannelStatus(pIChannel, lpConnection, dwStatus); DebugExitVOID(COprahNCUI::OnVideoChannelStatus); } VOID COprahNCUI::OnAudioChannelStatus(ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus) { DebugEntry(COprahNCUI::OnAudioChannelStatus); m_pConfObject->OnAudioChannelStatus(pIChannel, lpConnection, dwStatus); DebugExitVOID(COprahNCUI::OnAudioChannelStatus); } BOOL COprahNCUI::GetULSName(CRosterInfo *pri) { if (FIsLoggedOn()) { RegEntry reULS( ISAPI_KEY _TEXT("\\") REGKEY_USERDETAILS, HKEY_CURRENT_USER); CUSTRING custrULSName(reULS.GetString(REGVAL_ULS_RES_NAME)); if ((NULL != (PWSTR)custrULSName) && (L'\0' != ((PWSTR)custrULSName)[0])) { pri->AddItem(g_cwszULSTag, (PWSTR)custrULSName); return TRUE; } } return FALSE; } VOID COprahNCUI::GetRosterInfo(CRosterInfo *pri) { RegEntry reULS( ISAPI_KEY _TEXT("\\") REGKEY_USERDETAILS, HKEY_CURRENT_USER); // This code is here in addition to the code above to fix bug 3367. // Add the single IP address to the list that is obtained by calling // gethostname() and then gethostbyname(). // This shouldn't be detrimental, even though we may end up adding the // same IP address that has already been added by the code above. // This is because the code that looks for matching IP addresses searches // through all of them until it finds a match. CHAR szHostName[MAX_PATH]; if (SOCKET_ERROR != gethostname(szHostName, CCHMAX(szHostName))) { HOSTENT* phe = gethostbyname(szHostName); if (NULL != phe) { ASSERT(phe->h_addrtype == AF_INET); ASSERT(phe->h_length == sizeof(DWORD)); struct in_addr in; in.s_addr = *((DWORD *)phe->h_addr); CHAR szIPAddress[MAX_PATH]; lstrcpyn(szIPAddress, inet_ntoa(in), CCHMAX(szIPAddress)); pri->AddItem( g_cwszIPTag, CUSTRING(szIPAddress)); } } // Add the build/version string pri->AddItem(g_cwszVerTag, (PWSTR)VER_PRODUCTVERSION_DWSTR); if (FIsLoggedOn()) { CUSTRING custrULSName(reULS.GetString(REGVAL_ULS_RES_NAME)); if ((NULL != (PWSTR)custrULSName) && (L'\0' != ((PWSTR)custrULSName)[0])) { pri->AddItem(g_cwszULSTag, (PWSTR)custrULSName); } } CUSTRING custrULSEmail(reULS.GetString(REGVAL_ULS_EMAIL_NAME)); if ((NULL != (PWSTR)custrULSEmail) && (L'\0' != ((PWSTR)custrULSEmail)[0])) { pri->AddItem(g_cwszULS_EmailTag, (PWSTR)custrULSEmail); } CUSTRING custrULSLocation(reULS.GetString(REGVAL_ULS_LOCATION_NAME)); if ((NULL != (PWSTR)custrULSLocation) && (L'\0' != ((PWSTR)custrULSLocation)[0])) { pri->AddItem(g_cwszULS_LocationTag, (PWSTR)custrULSLocation); } CUSTRING custrULSPhoneNum(reULS.GetString(REGVAL_ULS_PHONENUM_NAME)); if ((NULL != (PWSTR)custrULSPhoneNum) && (L'\0' != ((PWSTR)custrULSPhoneNum)[0])) { pri->AddItem(g_cwszULS_PhoneNumTag, (PWSTR)custrULSPhoneNum); } } ULONG COprahNCUI::GetRosterCaps() { ULONG uCaps = m_uCaps; CNmMember * pMember = m_pConfObject->GetLocalMember(); if (NULL != pMember) { DWORD dwFlags = pMember->GetDwFlags(); if (dwFlags & PF_MEDIA_VIDEO) { uCaps |= CAPFLAG_VIDEO_IN_USE; } if (dwFlags & PF_MEDIA_AUDIO) { uCaps |= CAPFLAG_AUDIO_IN_USE; } if (dwFlags & PF_MEDIA_DATA) { uCaps |= CAPFLAG_DATA_IN_USE; } if (dwFlags & PF_H323) { uCaps |= CAPFLAG_H323_IN_USE; } } if (!m_fAllowAV) { uCaps &= ~(CAPFLAGS_AV_ALL); } return uCaps; } ULONG COprahNCUI::GetAuthenticatedName(PBYTE * ppb) { // Buffer created here should be freed by caller. ULONG cb; if (::T120_GetSecurityInfoFromGCCID(0,NULL,&cb)) { (*ppb) = new BYTE[cb]; if ((*ppb) != NULL) { ::T120_GetSecurityInfoFromGCCID(0,*ppb,&cb); return cb; } } (* ppb) = NULL; return 0; } HRESULT COprahNCUI::OnUpdateUserData(CONF_HANDLE hConference) { CRosterInfo ri; // This string will contain addresses in the form: // L"TCP:157.55.143.3\0TCP:157.55.143.4\0\0" - 512 character max for now WCHAR wszAddresses[512]; ASSERT(g_pNodeController); ASSERT(hConference); if (NOERROR == hConference->GetLocalAddressList(wszAddresses, CCHMAX(wszAddresses))) { ri.Load(wszAddresses); } // First, handle roster information GetRosterInfo(&ri); PVOID pvData; UINT cbDataLen; if (SUCCEEDED(ri.Save(&pvData, &cbDataLen))) { ASSERT(g_pNodeController); ASSERT(hConference); hConference->SetUserData(&g_csguidRostInfo, cbDataLen, pvData); } // Next, handle caps information ULONG uCaps = GetRosterCaps(); ASSERT(g_pNodeController); ASSERT(hConference); hConference->SetUserData(&g_csguidRosterCaps, sizeof(uCaps), &uCaps); // Next, handle credentials if ( hConference->IsSecure() ) { BYTE * pb = NULL; ULONG cb = GetAuthenticatedName(&pb); if (cb > 0) { ASSERT(g_pNodeController); ASSERT(hConference); TRACE_OUT(("COprahNCUI::OnUpdateUserData: adding %d bytes SECURITY data", cb)); hConference->SetUserData(&g_csguidSecurity, cb, pb); } else { WARNING_OUT(("OnUpdateUserData: 0 bytes security data?")); } delete [] pb; } // Next, set meeting settings if we hosted the meeting ASSERT(m_pConfObject); if (m_pConfObject->IsHosting() == S_OK) { NM30_MTG_PERMISSIONS attendeePermissions = m_pConfObject->GetConfAttendeePermissions(); WARNING_OUT(("Hosted Meeting Settings 0x%08lx", attendeePermissions)); hConference->SetUserData(&g_csguidMeetingSettings, sizeof(attendeePermissions), &attendeePermissions); } ULONG nRecords; GCCUserData ** ppUserData = NULL; if (m_pSysInfo) { m_pSysInfo->GetUserDataList(&nRecords,&ppUserData); for (unsigned int i = 0; i < nRecords; i++) { // Do not add user data that was already set above. if (memcmp(ppUserData[i]->octet_string->value,(PVOID)&g_csguidRostInfo,sizeof(GUID)) == 0) continue; if (memcmp(ppUserData[i]->octet_string->value,(PVOID)&g_csguidRosterCaps,sizeof(GUID)) == 0) continue; if (memcmp(ppUserData[i]->octet_string->value,(PVOID)&g_csguidSecurity,sizeof(GUID)) == 0) continue; if (memcmp(ppUserData[i]->octet_string->value,(PVOID)&g_csguidMeetingSettings,sizeof(GUID)) == 0) continue; ASSERT(g_pNodeController); ASSERT(hConference); hConference->SetUserData((GUID *)(ppUserData[i]->octet_string->value), ppUserData[i]->octet_string->length - sizeof(GUID), ppUserData[i]->octet_string->value + sizeof(GUID)); } } // only add the LocalNodeId to the roster if H323 is enabled if (IsH323Enabled()) { hConference->SetUserData((GUID *)(&g_csguidNodeIdTag), sizeof(GUID), (PVOID)&g_guidLocalNodeId); } return S_OK; } HRESULT COprahNCUI::OnIncomingInviteRequest(CONF_HANDLE hConference, PCWSTR pcwszNodeName, PT120PRODUCTVERSION pRequestorVersion, PUSERDATAINFO pUserDataInfoEntries, UINT cUserDataEntries, BOOL fSecure) { DebugEntry(COprahNCUI::OnIncomingInviteRequest); // Fix an AV problem ONLY for RTC client if (m_pConfObject == NULL) { return S_OK; } if (!m_pConfObject->OnT120Invite(hConference, fSecure)) { // Respond negatively - already in a call TRACE_OUT(("Rejecting invite - already in a call")); ASSERT(g_pNodeController); ASSERT(hConference); hConference->InviteResponse(FALSE); } else { m_pIncomingCallManager->OnIncomingT120Call( this, TRUE, hConference, pcwszNodeName, pUserDataInfoEntries, cUserDataEntries, fSecure); // // This will simply notify the UI about the call state. // m_pConfObject->SetConfSecurity(fSecure); } DebugExitHRESULT(COprahNCUI::OnIncomingInviteRequest, S_OK); return S_OK; } HRESULT COprahNCUI::OnIncomingJoinRequest( CONF_HANDLE hConference, PCWSTR pcwszNodeName, PT120PRODUCTVERSION pRequestorVersion, PUSERDATAINFO pUserDataInfoEntries, UINT cUserDataEntries) { DebugEntry(COprahNCUI::OnIncomingJoinRequest); // shouldn't we be checking for an active conference before accepting a join // or will T120 not present this m_pIncomingCallManager->OnIncomingT120Call( this, FALSE, hConference, pcwszNodeName, pUserDataInfoEntries, cUserDataEntries, m_pConfObject->IsConfObjSecure()); DebugExitHRESULT(COprahNCUI::OnIncomingJoinRequest, S_OK); return S_OK; } HRESULT COprahNCUI::OnConferenceStarted(CONF_HANDLE hConference, HRESULT hResult) { DebugEntry(COprahNCUI::OnConferenceStarted); if (m_pConfObject->GetConfHandle() == hConference) { m_pConfObject->OnConferenceStarted(hConference, hResult); m_pOutgoingCallManager->OnConferenceStarted(hConference, hResult); } DebugExitHRESULT(COprahNCUI::OnConferenceStarted, S_OK); return S_OK; } HRESULT COprahNCUI::OnQueryRemoteResult(PVOID pvCallerContext, HRESULT hResult, BOOL fMCU, PWSTR* ppwszConferenceNames, PT120PRODUCTVERSION pVersion, PWSTR* ppwszConfDescriptors) { DebugEntry(COprahNCUI::OnQueryRemoteResult); if (NO_ERROR == hResult) { TRACE_OUT(("COprahNCUI: OnQueryRemoteResult Success!")); } else { TRACE_OUT(("COprahNCUI: OnQueryRemoteResult Failure!")); } m_pOutgoingCallManager->OnQueryRemoteResult(pvCallerContext, hResult, fMCU, ppwszConferenceNames, pVersion, ppwszConfDescriptors); DebugExitHRESULT(COprahNCUI::OnQueryRemoteResult, S_OK); return S_OK; } HRESULT COprahNCUI::OnInviteResult( CONF_HANDLE hConference, REQUEST_HANDLE hRequest, UINT uNodeID, HRESULT hResult, PT120PRODUCTVERSION pVersion) { DebugEntry(COprahNCUI::OnInviteResult); if (hConference == m_pConfObject->GetConfHandle()) { m_pOutgoingCallManager->OnInviteResult( hConference, hRequest, uNodeID, hResult, pVersion); } DebugExitHRESULT(COprahNCUI::OnInviteResult, S_OK); return S_OK; } HRESULT COprahNCUI::OnConferenceEnded(CONF_HANDLE hConference) { DebugEntry(COprahNCUI::OnConferenceEnded); if (m_pConfObject && (hConference == m_pConfObject->GetConfHandle())) { m_pConfObject->OnConferenceEnded(); m_pOutgoingCallManager->OnConferenceEnded(hConference); m_pIncomingCallManager->OnT120ConferenceEnded(hConference); } DebugExitHRESULT(COprahNCUI::OnConferenceEnded, S_OK); return S_OK; } HRESULT COprahNCUI::OnRosterChanged(CONF_HANDLE hConf, PNC_ROSTER pRoster) { TRACE_OUT(("COprahNCUI::OnRosterChanged")); if (hConf == m_pConfObject->GetConfHandle()) { m_pConfObject->OnRosterChanged(pRoster); } return S_OK; } ULONG STDMETHODCALLTYPE COprahNCUI::AddRef(void) { return RefCount::AddRef(); } ULONG STDMETHODCALLTYPE COprahNCUI::Release(void) { return RefCount::Release(); } HRESULT STDMETHODCALLTYPE COprahNCUI::QueryInterface(REFIID riid, PVOID *ppv) { HRESULT hr = S_OK; if ((riid == IID_INmManager2) || (riid == IID_INmManager) || (riid == IID_IUnknown)) { *ppv = (INmManager2 *)this; ApiDebugMsg(("COprahNCUI::QueryInterface()")); } else if (riid == IID_IConnectionPointContainer) { *ppv = (IConnectionPointContainer *) this; ApiDebugMsg(("COprahNCUI::QueryInterface(): Returning IConnectionPointContainer.")); } else { hr = E_NOINTERFACE; *ppv = NULL; ApiDebugMsg(("COprahNCUI::QueryInterface(): Called on unknown interface.")); } if (S_OK == hr) { AddRef(); } return hr; } /* I N I T I A L I Z E */ /*------------------------------------------------------------------------- %%Function: Initialize REVIEW: What should the return value be if any of these parts fail to initialize or load? -------------------------------------------------------------------------*/ HRESULT COprahNCUI::Initialize(ULONG *puOptions, ULONG *puchCaps) { HRESULT hr = S_OK; // puOptions is UNUSED ASSERT(puchCaps); m_pOutgoingCallManager = new COutgoingCallManager; if (!m_pOutgoingCallManager) { ERROR_OUT(("COprahNCUI::Initialize -- failed to create outgoing call mgr")); return(E_OUTOFMEMORY); } m_pIncomingCallManager = new CIncomingCallManager; if (!m_pIncomingCallManager) { ERROR_OUT(("COprahNCUI::Initialize -- failed to create incoming call mgr")); return(E_OUTOFMEMORY); } // The lifetime of this object is up to the reference counting crap m_pConfObject = new CConfObject; if (!m_pConfObject) { ERROR_OUT(("COprahNCUI::Initialize -- failed to create conf object")); return(E_OUTOFMEMORY); } m_pConfObject->Init(this); WNDCLASS wcHidden = { 0L, COprahNCUI::WndProc, 0, 0, GetInstanceHandle(), NULL, NULL, NULL, NULL, cszDllHiddenWndClassName }; if (!RegisterClass(&wcHidden)) { ERROR_OUT(("COprahNCUI::Initialize -- failed to register HiddenWnd class")); return(E_OUTOFMEMORY); } // Create a hidden window for event processing: m_hwnd = ::CreateWindow(cszDllHiddenWndClassName, _TEXT(""), WS_POPUP, // not visible! 0, 0, 0, 0, NULL, NULL, GetInstanceHandle(), NULL); if (NULL == m_hwnd) { return E_FAIL; } // // INIT QOS only if AV is in the picture (otherwise, there's nothing // to arbitrate). // if (CAPFLAGS_AV_STREAMS & *puchCaps) { m_pQoS = new CQoS(); if (NULL != m_pQoS) { hr = m_pQoS->Initialize(); if (FAILED(hr)) { WARNING_OUT(("CQoS::Init() failed!")); // let NetMeeting hobble along without QoS. delete m_pQoS; m_pQoS = NULL; hr = S_FALSE; // we can live without QOS } } else { WARNING_OUT(("Could not allocate CQoS object")); } } // // IF DATA CONFERENCING IS ALLOWED // if (CAPFLAG_DATA & *puchCaps) { // // Create the node controller // hr = ::T120_CreateNodeController(&g_pNodeController, this); if (FAILED(hr)) { ERROR_OUT(("T120_CreateNodeController() failed!")); return hr; } } // Initialize audio/video if (CAPFLAGS_AV_ALL & *puchCaps) { g_pH323UI = new CH323UI(); if (NULL != g_pH323UI) { hr = g_pH323UI->Init(m_hwnd, ::GetInstanceHandle(), *puchCaps, this, this); if (FAILED(hr)) { WARNING_OUT(("CH323UI::Init() failed!")); delete g_pH323UI; g_pH323UI = NULL; *puchCaps &= ~(CAPFLAGS_AV_ALL); hr = S_FALSE; // We can run without AV } else { if (CAPFLAGS_VIDEO & *puchCaps) { // if we can get a Preview channel, we can send video m_pPreviewChannel = CNmChannelVideo::CreatePreviewChannel(); if (NULL == m_pPreviewChannel) { *puchCaps &= ~CAPFLAG_SEND_VIDEO; } } if (m_pConfObject && (CAPFLAGS_AV_STREAMS & *puchCaps)) { IMediaChannelBuilder *pStreamProvider; pStreamProvider = g_pH323UI->GetStreamProvider(); if (pStreamProvider) { pStreamProvider->SetStreamEventObj(m_pConfObject); pStreamProvider->Release(); } } } } else { ERROR_OUT(("Could not allocate CH323UI object")); } } m_uCaps = *puchCaps; return CoCreateGuid(&g_guidLocalNodeId); } HRESULT COprahNCUI::GetSysInfo(INmSysInfo **ppSysInfo) { HRESULT hr = S_OK; if( ppSysInfo ) { if(m_pSysInfo ) { m_pSysInfo->AddRef(); *ppSysInfo = m_pSysInfo; } else { hr = E_OUTOFMEMORY; } } else { hr = E_POINTER; } return hr; } HRESULT COprahNCUI::EnumConference(IEnumNmConference **ppEnum) { return E_NOTIMPL; } HRESULT COprahNCUI::CreateConference( INmConference **ppConference, BSTR bstrName, BSTR bstrPassword, ULONG uchCaps) { return(CreateConferenceEx(ppConference, bstrName, bstrPassword, uchCaps, NM_PERMIT_ALL, (UINT)-1)); } HRESULT COprahNCUI::EnumCall(IEnumNmCall **ppEnum) { return E_NOTIMPL; } HRESULT COprahNCUI::CreateCall( INmCall **ppCall, NM_CALL_TYPE callType, NM_ADDR_TYPE addrType, BSTR bstrAddress, INmConference * pConference) { return E_NOTIMPL; } HRESULT COprahNCUI::CallConference( INmCall **ppCall, NM_CALL_TYPE callType, NM_ADDR_TYPE addrType, BSTR bstrAddress, BSTR bstrConfToJoin, BSTR bstrPassword) { return E_NOTIMPL; } STDMETHODIMP COprahNCUI::GetPreviewChannel(INmChannelVideo **ppChannelVideo) { HRESULT hr = E_POINTER; if (NULL != ppChannelVideo) { *ppChannelVideo = m_pPreviewChannel; if (NULL != m_pPreviewChannel) { m_pPreviewChannel->AddRef(); hr = S_OK; } else { hr = E_FAIL; } } return hr; } STDMETHODIMP COprahNCUI::CreateASObject ( IUnknown * pNotify, ULONG flags, IUnknown ** ppAS ) { return(::CreateASObject((IAppSharingNotify *)pNotify, flags, (IAppSharing **)ppAS)); } HRESULT COprahNCUI::CallEx( INmCall **ppCall, DWORD dwFlags, NM_ADDR_TYPE addrType, BSTR bstrName, BSTR bstrSetup, BSTR bstrDest, BSTR bstrAlias, BSTR bstrURL, BSTR bstrConference, BSTR bstrPassword, BSTR bstrUserData) { DebugEntry(COprahNCUI::CallEx); HRESULT hr = m_pOutgoingCallManager->Call( ppCall, this, dwFlags, addrType, bstrName, bstrSetup, bstrDest, bstrAlias, bstrURL, bstrConference, bstrPassword, bstrUserData); DebugExitHRESULT(COprahNCUI::CallEx, hr); return hr; } HRESULT COprahNCUI::CreateConferenceEx ( INmConference **ppConference, BSTR bstrName, BSTR bstrPassword, DWORD uchCaps, DWORD attendeePermissions, DWORD maxParticipants ) { if (NULL == ppConference) { ERROR_OUT(("CreateConferenceEx: null ppConference passed in")); return E_POINTER; } if (maxParticipants < 2) { ERROR_OUT(("CreateConferenceEx: bad maxParticipants %d", maxParticipants)); return E_INVALIDARG; } if (m_pConfObject->IsConferenceActive()) { WARNING_OUT(("CreateConference is failing because IsConferenceActive return TRUE")); return NM_CALLERR_IN_CONFERENCE; } m_pConfObject->SetConfName(bstrName); if (uchCaps & NMCH_SRVC) m_pConfObject->SetConfHashedPassword(bstrPassword); else m_pConfObject->SetConfPassword(bstrPassword); if (uchCaps & NMCH_SECURE) m_pConfObject->SetConfSecurity(TRUE); else m_pConfObject->SetConfSecurity(FALSE); m_pConfObject->SetConfAttendeePermissions(attendeePermissions); m_pConfObject->SetConfMaxParticipants(maxParticipants); if (!m_pConfObject->IsConferenceCreated()) { m_pConfObject->OnConferenceCreated(); } NotifySink((INmConference*) m_pConfObject, OnNotifyConferenceCreated); *ppConference = m_pConfObject; if(*ppConference) { (*ppConference)->AddRef(); } return S_OK; } /* O N N O T I F Y C O N F E R E N C E C R E A T E D */ /*------------------------------------------------------------------------- %%Function: OnNotifyConferenceCreated -------------------------------------------------------------------------*/ HRESULT OnNotifyConferenceCreated(IUnknown *pManagerNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pManagerNotify); ((INmManagerNotify*)pManagerNotify)->ConferenceCreated((INmConference *) pv); return S_OK; } /* O N N O T I F Y C A L L C R E A T E D */ /*------------------------------------------------------------------------- %%Function: OnNotifyCallCreated -------------------------------------------------------------------------*/ HRESULT OnNotifyCallCreated(IUnknown *pManagerNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pManagerNotify); ((INmManagerNotify*)pManagerNotify)->CallCreated((INmCall *) pv); return S_OK; } /* O N N O T I F Y C A L L S T A T E C H A N G E D */ /*------------------------------------------------------------------------- %%Function: OnNotifyCallStateChanged -------------------------------------------------------------------------*/ HRESULT OnNotifyCallStateChanged(IUnknown *pCallNotify, PVOID pv, REFIID riid) { ASSERT(NULL != pCallNotify); ((INmCallNotify*)pCallNotify)->StateChanged((NM_CALL_STATE)(DWORD_PTR)pv); return S_OK; } VOID SetBandwidth(UINT uBandwidth) { COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance(); if (NULL != pOprahNCUI) { pOprahNCUI->SetBandwidth(uBandwidth); } if (NULL != g_pH323UI) { //Inform the NAC of the connection speed g_pH323UI->SetBandwidth(uBandwidth); } } // // BOGUS LAURABU! // Do we need this HWND anymore? The hidden window is used now only to // pass to H323, which passes it to the MediaStream interfaces in the NAC, // which passes it to DirectX. // LRESULT CALLBACK COprahNCUI::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // if ms_msgChannelEvent is 0, that means that we are not initialized // RegisterWindowMessage returns MSGIds in the range 0xC000 through 0xFFFF if(CH323ChannelEvent::ms_msgChannelEvent && CH323ChannelEvent::ms_msgChannelEvent == uMsg) { COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance(); if (pOprahNCUI) { CH323ChannelEvent *pEvent = reinterpret_cast(lParam); if(pEvent) { // if we're shutting down m_hwnd will be NULL if (pOprahNCUI->m_hwnd) { pOprahNCUI->_ChannelEvent( pEvent->GetChannel(), pEvent->GetEndpoint(), pEvent->GetStatus()); } delete pEvent; } else { WARNING_OUT(("Why are we getting a NULL pEvent?")); } } return 1; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } PIUnknown NewNmManager(OBJECTDESTROYEDPROC ObjectDestroyed) { COprahNCUI *pManager = new COprahNCUI(ObjectDestroyed); if (NULL != pManager) { return (INmManager2 *) pManager; } return NULL; } VOID COprahNCUI::_ChannelEvent (ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus ) { ASSERT(pIChannel); GUID guidMedia; if (SUCCEEDED(pIChannel->GetMediaType(&guidMedia))) { if (MEDIA_TYPE_H323AUDIO == guidMedia) { OnAudioChannelStatus(pIChannel, lpConnection, dwStatus); } else if (MEDIA_TYPE_H323VIDEO == guidMedia) { OnVideoChannelStatus(pIChannel, lpConnection, dwStatus); } else if (MEDIA_TYPE_H323_T120 == guidMedia) { switch (dwStatus) { case CHANNEL_OPEN_ERROR: case CHANNEL_OPEN: case CHANNEL_CLOSED: case CHANNEL_REJECTED: case CHANNEL_NO_CAPABILITY: OnT120ChannelOpen(pIChannel, lpConnection, dwStatus); break; default: WARNING_OUT(("COprahNCUI::ChannelEvent - unrecognized T120 status")); break; } } else { WARNING_OUT(("COprahNCUI::ChannelEvent - unknown media type")); } } else { WARNING_OUT(("COprahNCUI::ChannelEvent - pIChannel->GetMediaType() failed")); } } STDMETHODIMP COprahNCUI::ChannelEvent (ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus ) { ASSERT(pIChannel); GUID guidMedia; if (SUCCEEDED(pIChannel->GetMediaType(&guidMedia))) { if (MEDIA_TYPE_H323_T120 == guidMedia) { if (NULL != m_hwnd) { CH323ChannelEvent* pEvent = new CH323ChannelEvent( pIChannel, lpConnection, dwStatus); if (pEvent) { PostMessage(m_hwnd, CH323ChannelEvent::ms_msgChannelEvent, 0, reinterpret_cast(pEvent)); return S_OK; } } } else { _ChannelEvent(pIChannel, lpConnection, dwStatus); return S_OK; } } return E_FAIL; } #ifdef DEBUG VOID TraceStatus(DWORD dwStatus) { switch(dwStatus) { case CONNECTION_DISCONNECTED: TRACE_OUT(("COprahNCUI::CallEvent: CONNECTION_DISCONNECTED")); break; case CONNECTION_CONNECTED: TRACE_OUT(("COprahNCUI::CallEvent: CONNECTION_CONNECTED")); break; case CONNECTION_RECEIVED_DISCONNECT: TRACE_OUT(( "COprahNCUI::CallEvent: RECEIVED_DISCONNECT")); break; case CONNECTION_PROCEEDING: TRACE_OUT(("COprahNCUI::CallEvent: CONNECTION_PROCEEDING")); break; case CONNECTION_REJECTED: TRACE_OUT(("COprahNCUI::CallEvent: CONNECTION_REJECTED")); break; default: TRACE_OUT(("COprahNCUI::CallEvent: dwStatus = %d", dwStatus)); break; } } #endif STDMETHODIMP COprahNCUI::CallEvent(IH323Endpoint * lpConnection, DWORD dwStatus) { DebugEntry(COprahNCUI::CallEvent); IH323CallControl * pH323CallControl = g_pH323UI->GetH323CallControl(); #ifdef DEBUG TraceStatus(dwStatus); #endif switch (dwStatus) { case CONNECTION_DISCONNECTED: OnH323Disconnected(lpConnection); break; case CONNECTION_CONNECTED: // This is currently interpreted as CONNECTION_CAPABILITIES_READY. // Lower layers are continuing to post CONNECTION_CONNECTED only after // capabilities are exchanged. note that channels may be opened while // inside OnH323Connected(); OnH323Connected(lpConnection); break; } DebugExitVOID(COprahNCUI::CallEvent); return S_OK; } STDMETHODIMP COprahNCUI::GetMediaChannel (GUID *pmediaID, BOOL bSendDirection, IMediaChannel **ppI) { // delegate to the appropriate stream provider. For the time being // there is only one provider that does both audio & video return g_pH323UI->GetMediaChannel (pmediaID, bSendDirection, ppI); }