Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1778 lines
39 KiB

#include "precomp.h"
// NetMeeting stuff
#include "AtlExeModule.h"
#include "ConfUtil.h"
#include "NmLdap.h"
#include "call.h"
#include "common.h"
#include "ConfMan.h"
#include "cmd.h"
#include "conf.h"
#include "iAppLdr.h"
#include "confroom.h"
#include "ConfPolicies.h"
#include "cmd.h"
#include "ConfWnd.h"
#include "Taskbar.h"
#include "certui.h"
// NetMeeting SDK includes
#include "NmEnum.h"
#include "NmManager.h"
#include "NmConference.h"
#include "NmCall.h"
#include "SDKWindow.h"
#include "dlgCall2.h"
bool g_bSDKPostNotifications;
extern BOOL g_fLoggedOn;
extern INmSysInfo2 * g_pNmSysInfo;
extern GUID g_csguidSecurity;
//static
CSimpleArray<CNmManagerObj*>* CNmManagerObj::ms_pManagerObjList = NULL;
bool g_bOfficeModeSuspendNotifications = false;
DWORD CNmManagerObj::ms_dwID = 1;
BOOL InitAppletSDK(void);
void CleanupAppletSDK(void);
///////////////////////////////////////////////
// Construction\Destruction
///////////////////////////////////////////////
CNmManagerObj::CNmManagerObj()
: m_bInitialized(false),
m_chCaps(NMCH_NONE),
m_bNmActive(false),
m_bSentConferenceCreated(false),
m_dwID(0),
m_dwSysInfoID(0),
m_uOptions(0)
{
DBGENTRY(CNmManagerObj::CNmManagerObj);
CNmManagerObj* p = const_cast<CNmManagerObj*>(this);
ms_pManagerObjList->Add(p);
DBGEXIT(CNmManagerObj::CNmManagerObj);
}
CNmManagerObj::~CNmManagerObj()
{
DBGENTRY(CNmManagerObj::~CNmManagerObj);
CNmManagerObj* p = const_cast<CNmManagerObj*>(this);
ms_pManagerObjList->Remove(p);
// Free our conferencing objects
while(m_SDKConferenceObjs.GetSize())
{
CComPtr<INmConference> sp = m_SDKConferenceObjs[0];
m_SDKConferenceObjs.RemoveAt(0);
sp.p->Release();
}
// Free our conferencing objects
while(m_SDKCallObjs.GetSize())
{
CComPtr<INmCall> sp = m_SDKCallObjs[0];
m_SDKCallObjs.RemoveAt(0);
sp.p->Release();
}
m_spInternalNmManager = NULL;
DBGEXIT(CNmManagerObj::~CNmManagerObj);
}
HRESULT CNmManagerObj::FinalConstruct()
{
DBGENTRY(CNmManagerObj::FinalContstruct);
HRESULT hr = S_OK;
m_bInitialized = false;
m_dwInternalNmManagerAdvise = 0;
DBGEXIT_HR(CNmManagerObj::FinalContstruct,hr);
return hr;
}
ULONG CNmManagerObj::InternalRelease()
{
ATLASSERT(m_dwRef > 0);
--m_dwRef;
if((1 == m_dwRef) && m_dwInternalNmManagerAdvise)
{
++m_dwRef;
DWORD dwAdvise = m_dwInternalNmManagerAdvise;
m_dwInternalNmManagerAdvise = 0;
AtlUnadvise(m_spInternalNmManager, IID_INmManagerNotify, dwAdvise);
--m_dwRef;
}
return m_dwRef;
}
void CNmManagerObj::FinalRelease()
{
DBGENTRY(CNmManagerObj::FinalRelease);
if(m_bInitialized)
{
switch(m_uOptions)
{
case NM_INIT_CONTROL:
// Even though we have the NM_INIT_CONTROL flag set here
// We may not me in INIT_CONTROL mode. NetMeeting may have
// already been up when we initialized. In that case the UI is active
if(_Module.InitControlMode())
{
// If we are the last NmManager object with NM_INIT_CONTROL, then
// we should switch the UI mode away from InitControl
if((GetManagerCount(NM_INIT_CONTROL) == 1))
{
if(!_Module.IsSDKCallerRTC())
{
_Module.SetInitControlMode(FALSE);
::AddTaskbarIcon(::GetHiddenWindow());
}
}
}
break;
case NM_INIT_OBJECT:
// Check to see if this is the last "office" client
if (GetManagerCount(NM_INIT_OBJECT) == 1)
{
CConfMan::AllowAV(TRUE);
}
break;
default:
break;
}
}
DBGEXIT(CNmManagerObj::FinalRelease);
}
/*static*/ HRESULT CNmManagerObj::InitSDK()
{
DBGENTRY(CNmManagerObj::InitSDK);
HRESULT hr = S_OK;
g_bSDKPostNotifications = false;
ms_pManagerObjList = new CSimpleArray<CNmManagerObj*>;
if(!ms_pManagerObjList)
{
hr = E_OUTOFMEMORY;
}
::InitAppletSDK();
InitPluggableTransportSDK();
DBGEXIT_HR(CNmManagerObj::InitSDK,hr);
return hr;
}
/*static*/void CNmManagerObj::CleanupSDK()
{
DBGENTRY(CNmManagerObj::CleanupSDK);
::CleanupAppletSDK();
CleanupPluggableTransportSDK();
delete ms_pManagerObjList;
DBGEXIT(CNmManagerObj::CleanupSDK);
}
///////////////////////////////////////////////
// INmManager methods
///////////////////////////////////////////////
STDMETHODIMP CNmManagerObj::Initialize( ULONG * puOptions, ULONG *puchCaps)
{
DBGENTRY(CNmManagerObj::Initialize);
HRESULT hr = S_OK;
// If the remote control service is running, this will bring up a dialog
// that the user can choose weather or not to kill the remote control session
// If they do want to kill the session then the mananger object will initialize properly
if(!CheckRemoteControlService())
{
return E_FAIL;
}
m_uOptions = puOptions ? *puOptions : NM_INIT_NORMAL;
if(puOptions && (*puOptions > NM_INIT_BACKGROUND))
{
hr = E_INVALIDARG;
goto end;
}
if(!m_bInitialized)
{
bool bStartedNetMeeting = false;
if(!g_pInternalNmManager)
{
if(NM_INIT_NO_LAUNCH == m_uOptions)
{
// We don't launch NetMeeting in this case...
m_bNmActive = false;
goto end;
}
if (NM_INIT_CONTROL == m_uOptions)
{
_Module.SetInitControlMode(TRUE);
}
hr = InitConfExe(NM_INIT_NORMAL == m_uOptions);
bStartedNetMeeting = SUCCEEDED(hr);
}
if(SUCCEEDED(hr))
{
if(NM_INIT_OBJECT == m_uOptions)
{
if (!_Module.IsUIVisible())
{
CConfMan::AllowAV(FALSE);
}
}
m_bNmActive = true;
CFt::EnsureLoadFtApplet();
m_spInternalNmManager = g_pInternalNmManager;
// The old NetMeeting ignored this param...
// for the time being, we are ignoring it too.
//m_chCaps = puchCaps ? *puchCaps : NMCH_ALL;
m_chCaps = NMCH_ALL;
hr = AtlAdvise(m_spInternalNmManager,GetUnknown(),IID_INmManagerNotify, &m_dwInternalNmManagerAdvise);
}
}
else
{
hr = E_FAIL;
}
end:
m_bInitialized = SUCCEEDED(hr);
if(m_bInitialized)
{
INmConference2* pConf = ::GetActiveConference();
if(pConf)
{
ConferenceCreated(pConf);
// If there is no manager notify hooked in, we simply
// sync up with the Internal conference object state
IConnectionPointImpl<CNmManagerObj, &IID_INmManagerNotify, CComDynamicUnkArray>* pCP = this;
if((0 == pCP->m_vec.GetSize()) && !m_bSentConferenceCreated)
{
// It must be the first conference, because we are newly-initialized
ASSERT(m_SDKConferenceObjs[0]);
// Sinc up the channels, etc.
com_cast<IInternalConferenceObj>(m_SDKConferenceObjs[0])->FireNotificationsToSyncToInternalObject();
}
}
}
DBGEXIT_HR(CNmManagerObj::Initialize,hr);
return hr;
}
// This is not guarenteed to work if called from conf.exe's process!!!
STDMETHODIMP CNmManagerObj::GetSysInfo(INmSysInfo **ppSysInfo)
{
DBGENTRY(CNmManagerObj::GetSysInfo);
HRESULT hr = S_OK;
hr = CoCreateInstance(CLSID_NmSysInfo, NULL, CLSCTX_ALL, IID_INmSysInfo, reinterpret_cast<void**>(ppSysInfo));
if(*ppSysInfo)
{
m_dwID = ++ms_dwID;
com_cast<IInternalSysInfoObj>(*ppSysInfo)->SetID(m_dwID);
}
DBGEXIT_HR(CNmManagerObj::GetSysInfo,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::CreateConference(INmConference **ppConference, BSTR bstrName, BSTR bstrPassword, ULONG uchCaps)
{
DBGENTRY(CNmManagerObj::CreateConference);
HRESULT hr = S_OK;
if(m_bInitialized)
{
if(m_bNmActive)
{
if(ppConference)
{
if(m_spInternalNmManager)
{
switch(ConfPolicies::GetSecurityLevel())
{
case REQUIRED_POL_SECURITY:
m_chCaps = uchCaps | NMCH_SECURE;
break;
case DISABLED_POL_SECURITY:
m_chCaps = uchCaps & ~NMCH_SECURE;
break;
default:
m_chCaps = uchCaps;
break;
}
if(OfficeMode()) g_bOfficeModeSuspendNotifications = true;
CComPtr<INmConference> spInternalINmConference;
hr = m_spInternalNmManager->CreateConference(&spInternalINmConference, bstrName, bstrPassword, m_chCaps);
if(SUCCEEDED(hr))
{
// This was created by the previous call
*ppConference = GetSDKConferenceFromInternalConference(spInternalINmConference);
if(*ppConference)
{
(*ppConference)->AddRef();
}
else
{
hr = E_UNEXPECTED;
}
}
if(OfficeMode()) g_bOfficeModeSuspendNotifications = false;
}
else
{
hr = E_UNEXPECTED;
}
}
else
{
hr = E_POINTER;
}
}
else
{
hr = NM_E_NOT_ACTIVE;
}
}
else
{
hr = NM_E_NOT_INITIALIZED;
}
DBGEXIT_HR(CNmManagerObj::CreateConference,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::EnumConference(IEnumNmConference **ppEnum)
{
DBGENTRY(CNmManagerObj::EnumConference);
HRESULT hr = S_OK;
if(m_bInitialized)
{
if(m_bNmActive)
{
hr = CreateEnumFromSimpleAryOfInterface<IEnumNmConference, INmConference>(m_SDKConferenceObjs, ppEnum);
}
else
{
hr = NM_E_NOT_ACTIVE;
}
}
else
{
hr = NM_E_NOT_INITIALIZED;
}
DBGEXIT_HR(CNmManagerObj::EnumConference,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::CreateCall(INmCall **ppCall, NM_CALL_TYPE callType, NM_ADDR_TYPE addrType, BSTR bstrAddr, INmConference *pConference)
{
DBGENTRY(CNmManagerObj::CreateCall);
HRESULT hr = S_OK;
if(!m_bInitialized)
{
hr = NM_E_NOT_INITIALIZED;
goto end;
}
if(!m_bNmActive)
{
hr = NM_E_NOT_ACTIVE;
goto end;
}
if(m_spInternalNmManager)
{
if(!pConference)
{ // Get the active conference
pConference = _GetActiveConference();
if(!pConference)
{ // There is no active conf, so create a new one
CComPtr<INmConference> spInternalINmConference;
// TODO: What about NMCH_SECURE?
ULONG ulCaps = NMCH_AUDIO | NMCH_VIDEO | NMCH_DATA | NMCH_SHARE | NMCH_FT;
CCalltoParams params;
bool bSecure = FALSE;
LPTSTR szName;
hr = BSTR_to_LPTSTR (&szName, bstrAddr);
if (SUCCEEDED(hr))
{
params.SetParams(szName);
bSecure = params.GetBooleanParam("secure",bSecure);
delete (szName);
}
if(ConfPolicies::OutgoingSecurityPreferred() || bSecure)
{
ulCaps |= NMCH_SECURE;
}
hr = m_spInternalNmManager->CreateConference(&spInternalINmConference, NULL, NULL, ulCaps);
if(SUCCEEDED(hr))
{
// the above call to CreateConference generates a callback, so we have this object now!
pConference = GetSDKConferenceFromInternalConference(spInternalINmConference);
}
}
}
CComPtr<INmCall> spInternalINmCall;
if(SUCCEEDED(hr))
{
if(addrType == NM_ADDR_CALLTO)
{
ASSERT( g_pCCallto != NULL );
if(NM_CALL_DEFAULT == callType)
{
LPTSTR szName;
hr = BSTR_to_LPTSTR (&szName, bstrAddr);
if (SUCCEEDED(hr))
{
hr = g_pCCallto->Callto(szName, // pointer to the callto url to try to place the call with...
NULL, // pointer to the display name to use...
NM_ADDR_CALLTO, // callto type to resolve this callto as...
false, // the pszCallto parameter is to be interpreted as a pre-unescaped addressing component vs a full callto...
NULL, // security preference, NULL for none. must be "compatible" with secure param if present...
false, // whether or not save in mru...
false, // whether or not to perform user interaction on errors...
NULL, // if bUIEnabled is true this is the window to parent error/status windows to...
&spInternalINmCall ); // out pointer to INmCall * to receive INmCall * generated by placing call...
delete (szName);
}
else
{
goto end;
}
}
else
{
hr = E_INVALIDARG;
goto end;
}
}
else
{
hr = SdkPlaceCall(callType, addrType, bstrAddr, NULL, NULL, &spInternalINmCall);
}
if(SUCCEEDED(hr))
{
CallCreated(spInternalINmCall);
if(ppCall)
{
*ppCall = GetSDKCallFromInternalCall(spInternalINmCall);
if(*ppCall)
{
(*ppCall)->AddRef();
}
}
}
}
}
else
{
hr = E_UNEXPECTED;
ERROR_OUT(("Why don't we have a manager object"));
}
end:
DBGEXIT_HR(CNmManagerObj::CreateCall,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::CallConference(INmCall **ppCall, NM_CALL_TYPE callType, NM_ADDR_TYPE addrType, BSTR bstrAddr, BSTR bstrConferenceName, BSTR bstrPassword)
{
DBGENTRY(CNmManagerObj::CallConference);
HRESULT hr = S_OK;
if(!m_bInitialized)
{
hr = NM_E_NOT_INITIALIZED;
goto end;
}
if(!m_bNmActive)
{
hr = NM_E_NOT_ACTIVE;
goto end;
}
{
CComPtr<INmCall> spInternalINmCall;
hr = SdkPlaceCall(callType, addrType, bstrAddr, bstrConferenceName, bstrPassword, &spInternalINmCall);
if(SUCCEEDED(hr))
{
CallCreated(spInternalINmCall);
*ppCall = GetSDKCallFromInternalCall(spInternalINmCall);
if(*ppCall)
{
(*ppCall)->AddRef();
}
}
}
end:
DBGEXIT_HR(CNmManagerObj::CallConference,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::EnumCall(IEnumNmCall **ppEnum)
{
DBGENTRY(CNmManagerObj::EnumCall);
HRESULT hr = S_OK;
if(m_bInitialized)
{
if(m_bNmActive)
{
hr = CreateEnumFromSimpleAryOfInterface<IEnumNmCall, INmCall>(m_SDKCallObjs, ppEnum);
}
else
{
hr = NM_E_NOT_ACTIVE;
}
}
else
{
hr = NM_E_NOT_INITIALIZED;
}
DBGEXIT_HR(CNmManagerObj::EnumCall,hr);
return hr;
}
///////////////////////////////////////////////
// INmObject methods
///////////////////////////////////////////////
STDMETHODIMP CNmManagerObj::CallDialog(long hwnd, int cdOptions)
{
DBGENTRY(CNmManagerObj::CallDialog);
HRESULT hr = S_OK;
CFindSomeone::findSomeone(GetConfRoom());
g_bSDKPostNotifications = true;
if(OfficeMode() && !m_bSentConferenceCreated)
{
Fire_ConferenceCreated(m_SDKConferenceObjs[0]);
}
g_bSDKPostNotifications = false;
DBGEXIT_HR(CNmManagerObj::CallDialog,hr);
return hr;
}
extern "C" { BOOL WINAPI StartStopOldWB(LPCTSTR lpsz); }
STDMETHODIMP CNmManagerObj::ShowLocal(NM_APPID id)
{
if(!m_bInitialized)
{
return NM_E_NOT_INITIALIZED;
}
if(!m_bNmActive)
{
return NM_E_NOT_ACTIVE;
}
switch (id)
{
case NM_APPID_WHITEBOARD:
StartStopOldWB(NULL);
return S_OK;
case NM_APPID_T126_WHITEBOARD:
return (T120_NO_ERROR == ::T120_LoadApplet(APPLET_ID_WB, TRUE , 0, FALSE, NULL)) ? S_OK : E_FAIL;
case NM_APPID_CHAT:
return (T120_NO_ERROR == T120_LoadApplet(APPLET_ID_CHAT, TRUE , 0, FALSE, NULL)) ? S_OK : E_FAIL;
case NM_APPID_FILE_TRANSFER:
return CFt::ShowFtUI();
case NM_APPID_APPSHARING:
if(g_pConfRoom && g_pConfRoom->IsSharingAllowed())
{
g_pConfRoom->CmdShowSharing();
return S_OK;
}
return NM_E_SHARING_NOT_AVAILABLE;
default:
ERROR_OUT(("Unknown flag passed to ShowLocal"));
break;
}
return E_INVALIDARG;
}
STDMETHODIMP CNmManagerObj::VerifyUserInfo(UINT_PTR hwnd, NM_VUI options)
{
ASSERT(0);
return E_UNEXPECTED;
}
////////////////////////////////////////////////////////////
// IInternalConfExe
////////////////////////////////////////////////////////////
STDMETHODIMP CNmManagerObj::LoggedIn()
{
DBGENTRY(STDMETHODIMP CNmManagerObj::LoggedIn);
HRESULT hr = g_fLoggedOn ? S_OK : S_FALSE;
DBGEXIT_HR(STDMETHODIMP CNmManagerObj::LoggedIn,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::IsRunning()
{
DBGENTRY(STDMETHODIMP CNmManagerObj::IsRunning);
HRESULT hr = g_pInternalNmManager ? S_OK : S_FALSE;
DBGEXIT_HR(STDMETHODIMP CNmManagerObj::IsRunning,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::InConference()
{
DBGENTRY(STDMETHODIMP CNmManagerObj::InConference);
HRESULT hr = ::FIsConferenceActive() ? S_OK : S_FALSE;
DBGEXIT_HR(STDMETHODIMP CNmManagerObj::InConference,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::LDAPLogon(BOOL bLogon)
{
DBGENTRY(STDMETHODIMP CNmManagerObj::LDAPLogon);
HRESULT hr = S_OK;
if(g_pLDAP)
{
hr = bLogon ? g_pLDAP->LogonAsync() : g_pLDAP->Logoff();
}
else
{
hr = E_FAIL;
}
DBGEXIT_HR(STDMETHODIMP CNmManagerObj::LDAPLogon,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::GetLocalCaps(DWORD* pdwLocalCaps)
{
DBGENTRY(STDMETHODIMP CNmManagerObj::);
HRESULT hr = S_OK;
*pdwLocalCaps = g_uMediaCaps;
DBGEXIT_HR(STDMETHODIMP CNmManagerObj::,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::IsNetMeetingRunning()
{
return g_pInternalNmManager ? S_OK : S_FALSE;
}
STDMETHODIMP CNmManagerObj::GetActiveConference(INmConference** ppConf)
{
if(ppConf && ms_pManagerObjList && m_dwSysInfoID)
{
for(int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
if((*ms_pManagerObjList)[i]->m_dwID == m_dwSysInfoID)
{
if((*ms_pManagerObjList)[i]->m_SDKConferenceObjs.GetSize() != 0)
{
*ppConf = (*ms_pManagerObjList)[i]->m_SDKConferenceObjs[0];
(*ppConf)->AddRef();
return S_OK;
}
}
}
}
return E_FAIL;
}
//--------------------------------------------------------------------------//
// CNmManagerObj::ShellCalltoProtocolHandler. //
//--------------------------------------------------------------------------//
STDMETHODIMP
CNmManagerObj::ShellCalltoProtocolHandler
(
BSTR url,
BOOL bStrict
){
ASSERT( g_pCCallto != NULL );
HRESULT result = S_OK;
if(!g_pInternalNmManager)
{
if(!CheckRemoteControlService())
{
return E_FAIL;
}
result = InitConfExe();
}
if( SUCCEEDED( result ) )
{
LPTSTR szName;
result = BSTR_to_LPTSTR (&szName, url);
if (SUCCEEDED(result))
{
if(CCallto::DoUserValidation(szName))
{
result = g_pCCallto->Callto(szName, // pointer to the callto url to try to place the call with...
NULL, // pointer to the display name to use...
NM_ADDR_CALLTO, // callto type to resolve this callto as...
false, // the pszCallto parameter is to be interpreted as a pre-unescaped addressing component vs a full callto...
NULL, // security preference, NULL for none. must be "compatible" with secure param if present...
false, // whether or not save in mru...
true, // whether or not to perform user interaction on errors...
NULL, // if bUIEnabled is true this is the window to parent error/status windows to...
NULL ); // out pointer to INmCall * to receive INmCall * generated by placing call...
}
delete (szName);
}
}
return( result );
} // End of CNmManagerObj::ShellCalltoProtocolHandler.
//--------------------------------------------------------------------------//
// CNmManagerObj::Launch. //
//--------------------------------------------------------------------------//
STDMETHODIMP
CNmManagerObj::Launch()
{
if(_Module.InitControlMode())
{
return E_FAIL;
}
else
{
if(!g_pInternalNmManager)
{
if(!CheckRemoteControlService())
{
return E_FAIL;
}
InitConfExe();
}
else
{
::CreateConfRoomWindow();
}
}
return S_OK;
} // End of CNmManagerObj::Launch.
LPTSTR StripDoubleQuotes(LPTSTR sz)
{
BOOL fSkippedQuote = FALSE;
if (sz)
{
int cchLength;
// Skip past first quote
if (fSkippedQuote = (*sz == '"'))
sz++;
cchLength = lstrlen(sz);
//
// NOTE:
// There may be DBCS implications with this. Hence we check to see
// if we skipped the first quote; we assume that if the file name
// starts with a quote it must end with one also. But we need to check
// it out.
//
// Strip last quote
if (fSkippedQuote && (cchLength > 0) && (sz[cchLength - 1] == '"'))
{
BYTE * pLastQuote = (BYTE *)&sz[cchLength - 1];
*pLastQuote = '\0';
}
}
return sz;
}
STDMETHODIMP CNmManagerObj::LaunchApplet(NM_APPID appid, BSTR strCmdLine)
{
if(!g_pInternalNmManager)
{
if(!CheckRemoteControlService())
{
return E_FAIL;
}
InitConfExe();
}
LPTSTR szName = NULL;
BSTR_to_LPTSTR (&szName, strCmdLine);
switch(appid)
{
case NM_APPID_WHITEBOARD:
CmdShowOldWhiteboard(strCmdLine ? StripDoubleQuotes(szName) : NULL);
break;
case NM_APPID_T126_WHITEBOARD:
::CmdShowNewWhiteboard(strCmdLine ? StripDoubleQuotes(szName) : NULL);
break;
case NM_APPID_CHAT:
CmdShowChat();
break;
}
if(szName)
{
delete (szName);
}
return S_OK;
}
STDMETHODIMP CNmManagerObj::GetUserData(REFGUID rguid, BYTE **ppb, ULONG *pcb)
{
if(g_pNmSysInfo)
{
return g_pNmSysInfo->GetUserData(rguid, ppb, pcb);
}
return NM_E_NOT_ACTIVE;
}
STDMETHODIMP CNmManagerObj::SetUserData(REFGUID rguid, BYTE *pb, ULONG cb)
{
//
// Special case this guid to allow changing cert via SetUserData
//
if ( g_csguidSecurity == rguid )
{
return SetCertFromCertInfo ( (PCERT_INFO) pb );
}
if(g_pNmSysInfo)
{
return g_pNmSysInfo->SetUserData(rguid, pb, cb);
}
return NM_E_NOT_ACTIVE;
}
STDMETHODIMP CNmManagerObj::DisableH323(BOOL bDisableH323)
{
if(!g_pInternalNmManager)
{
_Module.SetSDKDisableH323(bDisableH323);
return S_OK;
}
return NM_E_ALREADY_RUNNING;
}
STDMETHODIMP CNmManagerObj::SetCallerIsRTC (BOOL bCallerIsRTC)
{
if(!g_pInternalNmManager)
{
_Module.SetSDKCallerIsRTC(bCallerIsRTC);
return S_OK;
}
return NM_E_ALREADY_RUNNING;
}
STDMETHODIMP CNmManagerObj::DisableInitialILSLogon(BOOL bDisable)
{
if(!g_pInternalNmManager)
{
_Module.SetSDKDisableInitialILSLogon(bDisable);
return S_OK;
}
return NM_E_ALREADY_RUNNING;
}
///////////////////////////////////////////////
// INmManagerNotify methods:
///////////////////////////////////////////////
STDMETHODIMP CNmManagerObj::NmUI(CONFN uNotify)
{
DBGENTRY(CNmManagerObj::NmUI);
HRESULT hr = S_OK;
// We should not be sending other notifactions
ASSERT(CONFN_NM_STARTED == uNotify);
hr = Fire_NmUI(uNotify);
DBGEXIT_HR(CNmManagerObj::NmUI,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::ConferenceCreated(INmConference *pInternalConference)
{
DBGENTRY(CNmManagerOebj::ConferenceCreated);
HRESULT hr = S_OK;
CComPtr<INmConference> spConf;
hr = CNmConferenceObj::CreateInstance(this, pInternalConference, &spConf);
if(SUCCEEDED(hr))
{
spConf.p->AddRef();
m_SDKConferenceObjs.Add(spConf.p);
Fire_ConferenceCreated(spConf);
if(!CFt::IsFtActive() && FileTransferNotifications())
{
CFt::StartNewConferenceSession();
}
}
DBGEXIT_HR(CNmManagerObj::ConferenceCreated,hr);
return hr;
}
STDMETHODIMP CNmManagerObj::CallCreated(INmCall *pInternalCall)
{
DBGENTRY(CNmManagerObj::CallCreated);
HRESULT hr = S_OK;
if(m_bInitialized)
{
if(NULL == GetSDKCallFromInternalCall(pInternalCall))
{
// First we make sure that we don't have the call object yet
CComPtr<INmCall> spCall;
hr = CNmCallObj::CreateInstance(this, pInternalCall, &spCall);
if(SUCCEEDED(hr))
{
spCall.p->AddRef();
m_SDKCallObjs.Add(spCall.p);
Fire_CallCreated(spCall);
}
}
}
DBGEXIT_HR(CNmManagerObj::CallCreated,hr);
return hr;
}
///////////////////////////////////////////////
// Notifications
///////////////////////////////////////////////
HRESULT CNmManagerObj::Fire_ConferenceCreated(INmConference *pConference)
{
DBGENTRY(CNmManagerObj::Fire_ConferenceCreated);
HRESULT hr = S_OK;
// Som SDK clients need this to come in at a specific time....
if(m_bSentConferenceCreated || OfficeMode() && g_bOfficeModeSuspendNotifications)
{
// We don't have to notify anyone at all...
return S_OK;
}
if(!g_bSDKPostNotifications)
{
IConnectionPointImpl<CNmManagerObj, &IID_INmManagerNotify, CComDynamicUnkArray>* pCP = this;
for(int i = 0; i < pCP->m_vec.GetSize(); ++i )
{
m_bSentConferenceCreated = true;
INmManagerNotify* pNotify = reinterpret_cast<INmManagerNotify*>(pCP->m_vec.GetAt(i));
if(pNotify)
{
pNotify->ConferenceCreated(pConference);
// Sinc up the channels, etc.
com_cast<IInternalConferenceObj>(pConference)->FireNotificationsToSyncToInternalObject();
}
}
}
else
{
hr = CSDKWindow::PostConferenceCreated(this, pConference);
}
DBGEXIT_HR(CNmManagerObj::Fire_ConferenceCreated,hr);
return hr;
}
HRESULT CNmManagerObj::Fire_CallCreated(INmCall* pCall)
{
DBGENTRY(CNmManagerObj::Fire_CallCreated);
HRESULT hr = S_OK;
// Always send Outgoing call notifications
// Only send incoming call notifications to INIT CONTROL clients.
if((S_OK != pCall->IsIncoming()) || _Module.InitControlMode())
{
if(!g_bSDKPostNotifications)
{
IConnectionPointImpl<CNmManagerObj, &IID_INmManagerNotify, CComDynamicUnkArray>* pCP = this;
for(int i = 0; i < pCP->m_vec.GetSize(); ++i )
{
INmManagerNotify* pNotify = reinterpret_cast<INmManagerNotify*>(pCP->m_vec.GetAt(i));
if(pNotify)
{
pNotify->CallCreated(pCall);
}
}
}
else
{
hr = CSDKWindow::PostCallCreated(this, pCall);
}
}
DBGEXIT_HR(CNmManagerObj::Fire_CallCreated,hr);
return hr;
}
HRESULT CNmManagerObj::Fire_NmUI(CONFN uNotify)
{
DBGENTRY(CNmManagerObj::Fire_NmUI);
HRESULT hr = S_OK;
// notice the InSendMessage statement.
// The problem is that we can get this notificaiton in
// response to the taskbar icon being clicked. In that case
// an inter-thread SendMessage is occuring. If we try to make
// the NmUi call, we will get RPC_E_CANTCALLOUT_INPUTSYNCCALL
if(!g_bSDKPostNotifications && !InSendMessage())
{
IConnectionPointImpl<CNmManagerObj, &IID_INmManagerNotify, CComDynamicUnkArray>* pCP = this;
for(int i = 0; i < pCP->m_vec.GetSize(); ++i )
{
INmManagerNotify* pNotify = reinterpret_cast<INmManagerNotify*>(pCP->m_vec.GetAt(i));
if(pNotify)
{
pNotify->NmUI(uNotify);
}
}
}
else
{
hr = CSDKWindow::PostManagerNmUI(this, uNotify);
}
DBGEXIT_HR(CNmManagerObj::Fire_NmUI,hr);
return hr;
}
///////////////////////////////////////////////
// Helper Fns
///////////////////////////////////////////////
INmConference* CNmManagerObj::_GetActiveConference()
{
INmConference* pConf = NULL;
if(m_SDKConferenceObjs.GetSize())
{
pConf = m_SDKConferenceObjs[0];
}
return pConf;
}
INmCall* CNmManagerObj::GetSDKCallFromInternalCall(INmCall* pInternalCall)
{
INmCall* pRet = NULL;
for( int i = 0; i < m_SDKCallObjs.GetSize(); ++i)
{
CComQIPtr<IInternalCallObj> spInternal = m_SDKCallObjs[i];
ASSERT(spInternal);
CComPtr<INmCall> spCall;
if(SUCCEEDED(spInternal->GetInternalINmCall(&spCall)))
{
if(spCall.IsEqualObject(pInternalCall))
{
pRet = m_SDKCallObjs[i];
break;
}
}
}
return pRet;
}
INmConference* CNmManagerObj::GetSDKConferenceFromInternalConference(INmConference* pInternalConference)
{
INmConference* pRet = NULL;
for( int i = 0; i < m_SDKConferenceObjs.GetSize(); ++i)
{
CComQIPtr<IInternalConferenceObj> spInternal = m_SDKConferenceObjs[i];
ASSERT(spInternal);
CComPtr<INmConference> spConference;
if(SUCCEEDED(spInternal->GetInternalINmConference(&spConference)))
{
if(spConference.IsEqualObject(pInternalConference))
{
pRet = m_SDKConferenceObjs[i];
break;
}
}
}
return pRet;
}
HRESULT CNmManagerObj::RemoveCall(INmCall* pSDKCallObj)
{
HRESULT hr = S_OK;
for(int i = 0; i < m_SDKCallObjs.GetSize(); ++i)
{
CComPtr<INmCall> spSDKCallObj = m_SDKCallObjs[i];
if(spSDKCallObj.IsEqualObject(pSDKCallObj))
{
m_SDKCallObjs.RemoveAt(i);
spSDKCallObj.p->Release();
}
}
return hr;
}
HRESULT CNmManagerObj::RemoveConference(INmConference* pSDKConferenceObj)
{
HRESULT hr = S_OK;
for(int i = 0; i < m_SDKConferenceObjs.GetSize(); ++i)
{
CComPtr<INmConference> spSDKConferenceObj = m_SDKConferenceObjs[i];
if(spSDKConferenceObj.IsEqualObject(pSDKConferenceObj))
{
m_SDKConferenceObjs.RemoveAt(i);
spSDKConferenceObj.p->Release();
}
}
return hr;
}
bool CNmManagerObj::AudioNotifications()
{
return m_bInitialized && (m_chCaps & NMCH_AUDIO);
}
bool CNmManagerObj::VideoNotifications()
{
return m_bInitialized && (m_chCaps & NMCH_VIDEO);
}
bool CNmManagerObj::DataNotifications()
{
return m_bInitialized && (m_chCaps & NMCH_DATA);
}
bool CNmManagerObj::FileTransferNotifications()
{
return m_bInitialized && (m_chCaps & NMCH_FT);
}
bool CNmManagerObj::AppSharingNotifications()
{
return m_bInitialized && (m_chCaps & NMCH_SHARE);
}
//static
void CNmManagerObj::NetMeetingLaunched()
{
ASSERT(ms_pManagerObjList);
if(ms_pManagerObjList)
{
for( int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
(*ms_pManagerObjList)[i]->Fire_NmUI(CONFN_NM_STARTED);
}
}
}
//static
void CNmManagerObj::SharableAppStateChanged(HWND hWnd, NM_SHAPP_STATE state)
{
if(ms_pManagerObjList)
{
for( int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
(*ms_pManagerObjList)[i]->_SharableAppStateChanged(hWnd, state);
}
}
}
void CNmManagerObj::_SharableAppStateChanged(HWND hWnd, NM_SHAPP_STATE state)
{
// Free our conferencing objects
for(int i = 0; i < m_SDKConferenceObjs.GetSize(); ++i)
{
com_cast<IInternalConferenceObj>(m_SDKConferenceObjs[i])->SharableAppStateChanged(hWnd, state);
}
}
//static
void CNmManagerObj::AppSharingChannelChanged()
{
if(ms_pManagerObjList)
{
for( int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
(*ms_pManagerObjList)[i]->_AppSharingChannelChanged();
}
}
}
void CNmManagerObj::_AppSharingChannelChanged()
{
// Free our conferencing objects
for(int i = 0; i < m_SDKConferenceObjs.GetSize(); ++i)
{
com_cast<IInternalConferenceObj>(m_SDKConferenceObjs[i])->AppSharingChannelChanged();
}
}
//static
void CNmManagerObj::AppSharingChannelActiveStateChanged(bool bActive)
{
if(ms_pManagerObjList)
{
for( int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
(*ms_pManagerObjList)[i]->_AppSharingChannelActiveStateChanged(bActive);
}
}
}
void CNmManagerObj::_AppSharingChannelActiveStateChanged(bool bActive)
{
// Free our conferencing objects
for(int i = 0; i < m_SDKConferenceObjs.GetSize(); ++i)
{
com_cast<IInternalConferenceObj>(m_SDKConferenceObjs[i])->AppSharingStateChanged(bActive);
}
}
//static
void CNmManagerObj::ASLocalMemberChanged()
{
if(ms_pManagerObjList)
{
for( int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
(*ms_pManagerObjList)[i]->_ASLocalMemberChanged();
}
}
}
void CNmManagerObj::_ASLocalMemberChanged()
{
// notify our conferencing objects
for(int i = 0; i < m_SDKConferenceObjs.GetSize(); ++i)
{
com_cast<IInternalConferenceObj>(m_SDKConferenceObjs[i])->ASLocalMemberChanged();
}
}
//static
void CNmManagerObj::ASMemberChanged(UINT gccID)
{
if(ms_pManagerObjList)
{
for( int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
(*ms_pManagerObjList)[i]->_ASMemberChanged(gccID);
}
}
}
void CNmManagerObj::_ASMemberChanged(UINT gccID)
{
// notify our conferencing objects
for(int i = 0; i < m_SDKConferenceObjs.GetSize(); ++i)
{
com_cast<IInternalConferenceObj>(m_SDKConferenceObjs[i])->ASMemberChanged(gccID);
}
}
// static
void CNmManagerObj::AudioChannelActiveState(BOOL bActive, BOOL bIsIncoming)
{
if(ms_pManagerObjList)
{
for( int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
(*ms_pManagerObjList)[i]->_AudioChannelActiveState(bActive, bIsIncoming);
}
}
}
void CNmManagerObj::_AudioChannelActiveState(BOOL bActive, BOOL bIsIncoming)
{
// notify our conferencing objects
for(int i = 0; i < m_SDKConferenceObjs.GetSize(); ++i)
{
com_cast<IInternalConferenceObj>(m_SDKConferenceObjs[i])->AudioChannelActiveState(bActive ? TRUE : FALSE, bIsIncoming);
}
}
// static
void CNmManagerObj::VideoChannelActiveState(BOOL bActive, BOOL bIsIncoming)
{
if(ms_pManagerObjList)
{
for( int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
(*ms_pManagerObjList)[i]->_VideoChannelActiveState(bActive, bIsIncoming);
}
}
}
void CNmManagerObj::_VideoChannelActiveState(BOOL bActive, BOOL bIsIncoming)
{
// notify our conferencing objects
for(int i = 0; i < m_SDKConferenceObjs.GetSize(); ++i)
{
com_cast<IInternalConferenceObj>(m_SDKConferenceObjs[i])->VideoChannelActiveState(bActive ? TRUE : FALSE, bIsIncoming);
}
}
// static
void CNmManagerObj::VideoPropChanged(DWORD dwProp, BOOL bIsIncoming)
{
if(ms_pManagerObjList)
{
for( int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
(*ms_pManagerObjList)[i]->_VideoPropChanged(dwProp, bIsIncoming);
}
}
}
void CNmManagerObj::_VideoPropChanged(DWORD dwProp, BOOL bIsIncoming)
{
// notify our conferencing objects
for(int i = 0; i < m_SDKConferenceObjs.GetSize(); ++i)
{
com_cast<IInternalConferenceObj>(m_SDKConferenceObjs[i])->VideoChannelPropChanged(dwProp, bIsIncoming);
}
}
// static
void CNmManagerObj::VideoChannelStateChanged(NM_VIDEO_STATE uState, BOOL bIsIncoming)
{
if(ms_pManagerObjList)
{
for( int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
(*ms_pManagerObjList)[i]->_VideoChannelStateChanged(uState, bIsIncoming);
}
}
}
void CNmManagerObj::_VideoChannelStateChanged(NM_VIDEO_STATE uState, BOOL bIsIncoming)
{
// notify our conferencing objects
for(int i = 0; i < m_SDKConferenceObjs.GetSize(); ++i)
{
com_cast<IInternalConferenceObj>(m_SDKConferenceObjs[i])->VideoChannelStateChanged(uState, bIsIncoming);
}
}
UINT CNmManagerObj::GetManagerCount(ULONG uOption)
{
UINT nMgrs = 0;
for(int i = 0; i < ms_pManagerObjList->GetSize(); ++i)
{
if(uOption == (*ms_pManagerObjList)[i]->m_uOptions)
{
nMgrs++;
}
}
return nMgrs;
}
void CNmManagerObj::OnShowUI(BOOL fShow)
{
_Module.SetUIVisible(fShow);
if (fShow)
{
CConfMan::AllowAV(TRUE);
}
else
{
if(0 != GetManagerCount(NM_INIT_OBJECT))
{
CConfMan::AllowAV(FALSE);
}
}
}
HRESULT CNmManagerObj::SdkPlaceCall(NM_CALL_TYPE callType,
NM_ADDR_TYPE addrType,
BSTR bstrAddr,
BSTR bstrConf,
BSTR bstrPw,
INmCall **ppInternalCall)
{
HRESULT hr;
LPTSTR szAddr = NULL;
LPTSTR szConf = NULL;
LPTSTR szPw = NULL;
DWORD dwFlags = MapNmCallTypeToCallFlags(callType, addrType, g_uMediaCaps);
if (0 == dwFlags)
{
hr = NM_CALLERR_MEDIA;
goto end;
}
{
BSTR_to_LPTSTR (&szAddr, bstrAddr);
if(NM_ADDR_T120_TRANSPORT == addrType)
{
//
// Check if "+secure=true" parameter was passed
//
CCalltoParams params;
bool bSecure = FALSE;
params.SetParams(szAddr);
bSecure = params.GetBooleanParam("secure",bSecure);
//
// Yes it was in the parameters.
// Now make sure to remove it
// The addre now is like "111.222.333.444+secure=true"
// The call will only work if we pass the ip address only
//
if(bSecure)
{
// Get the syze of the bstr
int cch = lstrlen(szAddr);
BYTE *pByte = (BYTE *) szAddr;
for(int i = 0; i < cch;i++)
{
// Null terminate the string
if(*pByte == '+')
{
*pByte = '\0';
break;
}
pByte++;
}
dwFlags |= CRPCF_SECURE;
}
}
CCallResolver CallResolver(szAddr, addrType);
hr = CallResolver.Resolve();
if (FAILED(hr))
{
goto end;
}
CCall* pCall = new CCall(CallResolver.GetPszAddr(), szAddr, NM_ADDR_CALLTO, FALSE, FALSE);
if(NULL == pCall)
{
goto end;
}
pCall->AddRef();
switch(CallResolver.GetAddrType())
{
case NM_ADDR_ULS:
case NM_ADDR_IP:
case NM_ADDR_MACHINENAME:
case NM_ADDR_H323_GATEWAY:
ASSERT(FIpAddress(CallResolver.GetPszAddrIP()));
/////////////////////////////////////////////
// !!!!! HEY RYAN, WERE FALLING THROUGH !!!!!
/////////////////////////////////////////////
case NM_ADDR_T120_TRANSPORT:
BSTR_to_LPTSTR (&szConf, bstrConf);
BSTR_to_LPTSTR (&szPw, bstrPw);
hr = pCall->PlaceCall(
dwFlags, // dwFlags
CallResolver.GetAddrType(), // addrType
NULL, // szSetup
(NM_ADDR_T120_TRANSPORT == CallResolver.GetAddrType()) ?
CallResolver.GetPszAddr() :
CallResolver.GetPszAddrIP(), // szDestination
CallResolver.GetPszAddr(),// szAlias
NULL, // szURL
(szConf), // szConference
(szPw), // szPassword
NULL); // szUserData
break;
default:
ERROR_OUT(("Don't know this call type"));
ASSERT(0);
break;
}
if( FAILED(hr) && (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 && SUCCEEDED(hr))
{
*ppInternalCall = pCall->GetINmCall();
(*ppInternalCall)->AddRef();
}
pCall->Release();
}
end:
if( FAILED( hr ) && _Module.IsUIActive() )
{
DisplayCallError( hr, szAddr );
}
delete szAddr;
delete szConf;
delete szPw;
return hr;
}
DWORD CNmManagerObj::MapNmCallTypeToCallFlags(NM_CALL_TYPE callType, NM_ADDR_TYPE addrType, UINT uCaps)
{
DWORD dwFlags = 0;
BOOL fForceSecure = FALSE;
// Check global conference status
if (INmConference *pConf = ::GetActiveConference())
{
// We are in a conference. Use the conference security setting.
DWORD dwCaps;
if ((S_OK == pConf->GetNmchCaps(&dwCaps)) &&
(NMCH_SECURE & dwCaps))
{
fForceSecure = TRUE;
}
}
else
{
fForceSecure = (REQUIRED_POL_SECURITY == ConfPolicies::GetSecurityLevel());
}
switch(addrType)
{
case NM_ADDR_T120_TRANSPORT:
dwFlags = CRPCF_T120 | CRPCF_DATA;
if(ConfPolicies::OutgoingSecurityPreferred() || fForceSecure)
{
dwFlags |= CRPCF_SECURE;
}
break;
default:
switch (callType)
{
case NM_CALL_T120:
if (fForceSecure)
{
dwFlags = CRPCF_T120 | CRPCF_DATA | CRPCF_SECURE;
}
else
{
dwFlags = CRPCF_T120 | CRPCF_DATA;
}
break;
case NM_CALL_H323:
if (!fForceSecure)
{
dwFlags = CRPCF_H323CC;
if (uCaps & (CAPFLAG_RECV_AUDIO | CAPFLAG_SEND_AUDIO))
dwFlags |= CRPCF_AUDIO;
if (uCaps & (CAPFLAG_RECV_VIDEO | CAPFLAG_SEND_VIDEO))
dwFlags |= CRPCF_VIDEO;
}
break;
case NM_CALL_DEFAULT:
if (fForceSecure)
{
dwFlags = CRPCF_T120 | CRPCF_DATA | CRPCF_SECURE;
}
else
{
dwFlags = CRPCF_DEFAULT;
// strip AV if policies prohibit
if((uCaps & (CAPFLAG_RECV_AUDIO |CAPFLAG_SEND_AUDIO)) == 0)
{
dwFlags &= ~CRPCF_AUDIO;
}
if((uCaps & (CAPFLAG_RECV_VIDEO |CAPFLAG_SEND_VIDEO)) == 0)
{
dwFlags &= ~CRPCF_VIDEO;
}
}
break;
default:
dwFlags = 0;
break;
}
}
return dwFlags;
}