1085 lines
28 KiB
C++
1085 lines
28 KiB
C++
/*
|
|
|
|
Copyright (c) 1998-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
sdpblob.cpp
|
|
|
|
Abstract:
|
|
Implementation of CSdpConferenceBlob
|
|
|
|
Author:
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "blbgen.h"
|
|
#include "sdpblb.h"
|
|
#include "sdpblob.h"
|
|
|
|
#include "blbreg.h"
|
|
#include "addrgen.h"
|
|
#include <time.h>
|
|
#include <winsock2.h>
|
|
#include "blbtico.h"
|
|
#include "blbmeco.h"
|
|
|
|
// ZoltanS: This is the multicast address we give by default. The app must then
|
|
// go and get a real address via MDHCP and explicitly set it to a meaningful
|
|
// value.
|
|
|
|
const long DUMMY_ADDRESS = 0xe0000000; // A dummy address that qualifies as Class D.
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSdpConferenceBlob
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// definition for the critical section needed by
|
|
// CObjectSafeImpl
|
|
//
|
|
|
|
CComAutoCriticalSection CObjectSafeImpl::s_CritSection;
|
|
|
|
|
|
CCritSection g_DllLock;
|
|
|
|
const USHORT MAX_IP_ADDRESS_STRLEN = 15;
|
|
const USHORT NUM_CONF_BLOB_TEMPLATE_PARAMS = 9;
|
|
|
|
// static SDP_REG_READER gs_SdpRegReader;
|
|
|
|
// a 1-1 mapping from the index (BLOB_CHARACTER_SET) to the SDP_CHAR_SET
|
|
// ASSUMPTION: BCS_UTF8 is the last value in the enumeration BLOB_CHARACTER_SET
|
|
SDP_CHARACTER_SET const CSdpConferenceBlob::gs_SdpCharSetMapping[BCS_UTF8] =
|
|
{
|
|
CS_ASCII,
|
|
CS_UTF7,
|
|
CS_UTF8
|
|
};
|
|
|
|
CSdpConferenceBlob *
|
|
CSdpConferenceBlob::GetConfBlob(
|
|
)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CSdpConferenceBlob::WriteStartTime(
|
|
IN DWORD MinStartTime
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
int NumEntries = (int)GetTimeList().GetSize();
|
|
|
|
// set the first time entry to the MinStartTime
|
|
if ( 0 < NumEntries )
|
|
{
|
|
// need to make sure that the stop time is after the start time or unbounded (0)
|
|
HRESULT HResult = ((SDP_TIME *)GetTimeList().GetAt(0))->SetStartTime(MinStartTime);
|
|
BAIL_ON_FAILURE(HResult);
|
|
}
|
|
else // create an entry
|
|
{
|
|
// create a new entry, use vb 1 based indices
|
|
HRESULT HResult = ((MY_TIME_COLL_IMPL *)m_TimeCollection)->Create(1, MinStartTime, 0);
|
|
BAIL_ON_FAILURE(HResult);
|
|
}
|
|
|
|
// iterate through the time list and for each other time entry
|
|
// modify the start time (if the start time is before MinStartTime, change it to MinStartTime)
|
|
for(UINT i = 1; (int)i < NumEntries; i++ )
|
|
{
|
|
ULONG StartTime;
|
|
HRESULT HResult = ((SDP_TIME *)GetTimeList().GetAt(i))->GetStartTime(StartTime);
|
|
|
|
// ignore invalid values and continue
|
|
if ( FAILED(HResult) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( StartTime < MinStartTime )
|
|
{
|
|
HRESULT HResult = ((SDP_TIME *)GetTimeList().GetAt(i))->SetStartTime(MinStartTime);
|
|
|
|
// ignore invalid values and continue
|
|
if ( FAILED(HResult) )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CSdpConferenceBlob::WriteStopTime(
|
|
IN DWORD MaxStopTime
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
int NumEntries = (int)GetTimeList().GetSize();
|
|
|
|
// set the first time entry to the MaxStopTime
|
|
if ( 0 < NumEntries )
|
|
{
|
|
// need to make sure that the stop time is after the start time or unbounded (0)
|
|
((SDP_TIME *)GetTimeList().GetAt(0))->SetStopTime(MaxStopTime);
|
|
|
|
}
|
|
else // create an entry
|
|
{
|
|
// create a new entry, use vb 1 based indices
|
|
HRESULT HResult = ((MY_TIME_COLL_IMPL *)m_TimeCollection)->Create(1, 0, MaxStopTime);
|
|
BAIL_ON_FAILURE(HResult);
|
|
}
|
|
|
|
// iterate through the time list and for each other time entry
|
|
// modify the stop time (if the stop time is after MaxStopTime, change it to MaxStopTime)
|
|
for(UINT i = 1; (int)i < NumEntries; i++ )
|
|
{
|
|
ULONG StopTime;
|
|
HRESULT HResult = ((SDP_TIME *)GetTimeList().GetAt(i))->GetStopTime(StopTime);
|
|
|
|
// ignore invalid values and continue
|
|
if ( FAILED(HResult) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( StopTime > MaxStopTime )
|
|
{
|
|
((SDP_TIME *)GetTimeList().GetAt(i))->SetStopTime(MaxStopTime);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
enum RND_ADVERTISING_SCOPE // as per SDP recommendations
|
|
{
|
|
RAS_LOCAL, // ttl <=1 recommended ttl 1
|
|
RAS_SITE, // <=15 15
|
|
RAS_REGION, // <=63 63
|
|
RAS_WORLD // <=255 127
|
|
} RND_ADVERTISING_SCOPE;
|
|
|
|
modification in target action
|
|
ITConference SDP_BLOB for each connection line, the ttl is set to a max of the
|
|
recommended ttl for the new advertising scope
|
|
ITConnection CONFERENCE the SDP_BLOB component determines the max ttl and notifies the
|
|
CONFERENCE of the new advertising scope
|
|
|
|
this is similar to the way start/stop time modifications are handled.
|
|
*/
|
|
|
|
|
|
HRESULT
|
|
CSdpConferenceBlob::WriteAdvertisingScope(
|
|
IN DWORD MaxAdvertisingScope
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
// ZoltanS: bug # 191413: check for out of range advertising scopes
|
|
if ( ( MaxAdvertisingScope > RAS_WORLD ) ||
|
|
( MaxAdvertisingScope < RAS_LOCAL ) )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
BYTE MaxTtl = GetTtl((RND_ADVERTISING_SCOPE)MaxAdvertisingScope);
|
|
|
|
// set the default connection ttl to the max ttl
|
|
if ( GetConnection().GetTtl().IsValid() )
|
|
{
|
|
GetConnection().GetTtl().SetValue(MaxTtl);
|
|
}
|
|
else // hack** : using SetConnection method. instead, the ttl field should always be kept valid
|
|
{
|
|
// get the current address and the number of addresses value and use the SetConnection method
|
|
// this puts the ttl field into the array of member fields
|
|
BSTR StartAddress = NULL;
|
|
BAIL_ON_FAILURE(GetConnection().GetStartAddress().GetBstr(&StartAddress));
|
|
HRESULT HResult = GetConnection().SetConnection(
|
|
StartAddress,
|
|
GetConnection().GetNumAddresses().GetValue(),
|
|
MaxTtl
|
|
);
|
|
BAIL_ON_FAILURE(HResult);
|
|
}
|
|
|
|
// iterate through the sdp media list and for each connection entry, set the ttl
|
|
// to maxttl if its more than it
|
|
int NumEntries = (int)GetMediaList().GetSize();
|
|
for(UINT i = 1; (int)i < NumEntries; i++ )
|
|
{
|
|
SDP_CONNECTION &SdpConnection = ((SDP_MEDIA *)GetMediaList().GetAt(i))->GetConnection();
|
|
if ( SdpConnection.GetTtl().IsValid() && (SdpConnection.GetTtl().GetValue() > MaxTtl) )
|
|
{
|
|
SdpConnection.GetTtl().SetValue(MaxTtl);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::Init(
|
|
/*[in]*/ BSTR pName,
|
|
/*[in]*/ BLOB_CHARACTER_SET CharacterSet,
|
|
/*[in]*/ BSTR pBlob
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
// validate the parameters
|
|
// the name cannot be null, if no blob has been specified (if a blob is specified then the name
|
|
// is implicit in it
|
|
if ( (NULL == pName) && (NULL == pBlob) )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// initialize the sdp
|
|
if ( !SDP_BLOB::Init() )
|
|
{
|
|
return HRESULT_FROM_ERROR_CODE(GetLastError());
|
|
}
|
|
|
|
// create media/time collection, query for I*Collection i/f
|
|
CComObject<MEDIA_COLLECTION> *MediaCollection;
|
|
|
|
try
|
|
{
|
|
MediaCollection = new CComObject<MEDIA_COLLECTION>;
|
|
}
|
|
catch(...)
|
|
{
|
|
MediaCollection = NULL;
|
|
}
|
|
|
|
BAIL_IF_NULL(MediaCollection, HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA));
|
|
|
|
HRESULT HResult = MediaCollection->Init(*this, GetMediaList());
|
|
if ( FAILED(HResult) )
|
|
{
|
|
delete MediaCollection;
|
|
return HResult;
|
|
}
|
|
|
|
// inform the sdp instance that it needn't delete the media list on destruction
|
|
ClearDestroyMediaListFlag();
|
|
|
|
// query for the ITMediaCollection i/f
|
|
HResult = MediaCollection->_InternalQueryInterface(IID_ITMediaCollection, (void **)&m_MediaCollection);
|
|
if ( FAILED(HResult) )
|
|
{
|
|
delete MediaCollection;
|
|
return HResult;
|
|
}
|
|
|
|
// on failure, just delete the time collection and return
|
|
// no need to delete the media collection as well since that's taken care of by the destructor
|
|
CComObject<TIME_COLLECTION> *TimeCollection;
|
|
|
|
try
|
|
{
|
|
TimeCollection = new CComObject<TIME_COLLECTION>;
|
|
}
|
|
catch(...)
|
|
{
|
|
TimeCollection = NULL;
|
|
}
|
|
|
|
BAIL_IF_NULL(TimeCollection, HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA));
|
|
|
|
HResult = TimeCollection->Init(*this, GetTimeList());
|
|
if ( FAILED(HResult) )
|
|
{
|
|
delete TimeCollection;
|
|
return HResult;
|
|
}
|
|
|
|
// inform the sdp instance that it needn't delete the time list on destruction
|
|
ClearDestroyTimeListFlag();
|
|
|
|
// query for the ITTimeCollection i/f
|
|
HResult = TimeCollection->_InternalQueryInterface(IID_ITTimeCollection, (void **)&m_TimeCollection);
|
|
if ( FAILED(HResult) )
|
|
{
|
|
delete TimeCollection;
|
|
return HResult;
|
|
}
|
|
|
|
|
|
// check if a default sdp needs to be created, else use the sdp provided by the user
|
|
if ( NULL == pBlob )
|
|
{
|
|
BAIL_ON_FAILURE(
|
|
CreateDefault(
|
|
pName,
|
|
gs_SdpCharSetMapping[CharacterSet-1])
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// we change the Character set from the CS_UTF8
|
|
// if the blob containts the "a=charset:" attribute
|
|
CharacterSet = GetBlobCharacterSet( pBlob);
|
|
|
|
// HACK ** we don't want notifications of blob contents when the sdp blob is being passed in
|
|
// (conference directory - enumeration scenario), so the notification owner is set after the
|
|
// conference blob is processed
|
|
BAIL_ON_FAILURE(SetConferenceBlob(CharacterSet, pBlob));
|
|
|
|
// at this point, the sdp is either passed in by the non-dir-user or is obtained by enumerating
|
|
// the directory.
|
|
// clear the modified state on the sdp (parsing in an sdp sets the state to modified) so that
|
|
// only true modifications are tracked
|
|
ClearModifiedState();
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_IsModified(VARIANT_BOOL * pVal)
|
|
{
|
|
BAIL_IF_NULL(pVal, E_INVALIDARG);
|
|
|
|
CLock Lock(g_DllLock);
|
|
|
|
*pVal = ( (GetWasModified() || SDP::IsModified()) ? VARIANT_TRUE : VARIANT_FALSE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_TimeCollection(
|
|
ITTimeCollection * *ppTimeCollection
|
|
)
|
|
{
|
|
BAIL_IF_NULL(ppTimeCollection, E_INVALIDARG);
|
|
|
|
CLock Lock(g_DllLock);
|
|
|
|
ASSERT(NULL != m_TimeCollection);
|
|
if ( NULL == m_TimeCollection )
|
|
{
|
|
return HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
// increase the ref count
|
|
m_TimeCollection->AddRef();
|
|
|
|
*ppTimeCollection = m_TimeCollection;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_MediaCollection(
|
|
ITMediaCollection * *ppMediaCollection
|
|
)
|
|
{
|
|
BAIL_IF_NULL(ppMediaCollection, E_INVALIDARG);
|
|
|
|
CLock Lock(g_DllLock);
|
|
|
|
ASSERT(NULL != m_MediaCollection);
|
|
if ( NULL == m_MediaCollection )
|
|
{
|
|
return HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
// increase the ref count
|
|
m_MediaCollection->AddRef();
|
|
|
|
*ppMediaCollection = m_MediaCollection;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_IsValid(VARIANT_BOOL * pVal)
|
|
{
|
|
BAIL_IF_NULL(pVal, E_INVALIDARG);
|
|
|
|
CLock Lock(g_DllLock);
|
|
|
|
*pVal = (IsValid() ? VARIANT_TRUE : VARIANT_FALSE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_CharacterSet(BLOB_CHARACTER_SET *pCharacterSet)
|
|
{
|
|
// map the sdp character set value for SDP_BLOB to the BLOB_CHARACTER_SET
|
|
BAIL_IF_NULL(pCharacterSet, E_INVALIDARG);
|
|
|
|
CLock Lock(g_DllLock);
|
|
|
|
// check the sdp char set values corresponding to the blob character sets for a match
|
|
// if a match is found, return the index as the blob character set
|
|
// NOTE: the for loop is dependent upon the order of declaration of the BLOB_CHARACTER_SET
|
|
// enum values
|
|
for( UINT BlobCharSet = BCS_ASCII; BCS_UTF8 >= BlobCharSet; BlobCharSet++ )
|
|
{
|
|
// BCS_ASCII is 1, but the array starts with 0, so the index is BlobCharSet - 1.
|
|
if ( gs_SdpCharSetMapping[BlobCharSet -1] == SDP::GetCharacterSet() )
|
|
{
|
|
*pCharacterSet = (BLOB_CHARACTER_SET)BlobCharSet;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_ConferenceBlob(BSTR * pVal)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
return GetBstrCopy(pVal);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CSdpConferenceBlob::WriteConferenceBlob(
|
|
IN SDP_CHARACTER_SET SdpCharSet,
|
|
IN BSTR newVal
|
|
)
|
|
{
|
|
// set the character set of the SDP_BSTRING
|
|
VERIFY(SetCharacterSet(SdpCharSet));
|
|
|
|
// set the bstr to the passed in value, this is converted to the ascii representation and parsed
|
|
HRESULT HResult = SetBstr(newVal);
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
HResult = ((MEDIA_COLLECTION *)m_MediaCollection)->Init(*this, GetMediaList());
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
HResult = ((TIME_COLLECTION *)m_TimeCollection)->Init(*this, GetTimeList());
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::SetConferenceBlob(BLOB_CHARACTER_SET CharacterSet, BSTR newVal)
|
|
{
|
|
// validate the passed in character set value
|
|
// although this is an enumeration, someone may try and pass in a different value
|
|
// NOTE: Assumes BCS_ASCII is the first and BCS_UTF8 is the last enumerated value
|
|
if ( !( (BCS_ASCII <= CharacterSet) && (BCS_UTF8 >= CharacterSet) ) )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
CLock Lock(g_DllLock);
|
|
|
|
// map the BLOB_CHARACTER_SET value to the sdp character set (since the BCS value start at 1,
|
|
// subtract 1 from the blob character set to index into the array
|
|
// write the conference blob, also send notifications for any modified dependent attributes
|
|
HRESULT HResult = WriteConferenceBlob(gs_SdpCharSetMapping[CharacterSet-1], newVal);
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_ProtocolVersion(BYTE * pVal)
|
|
{
|
|
BAIL_IF_NULL(pVal, E_INVALIDARG);
|
|
|
|
CLock Lock(g_DllLock);
|
|
|
|
// cast the ulong value to a byte because vb doesn't take a ulong, this shouldn't be
|
|
// a problem until version 256
|
|
*pVal = (BYTE)GetProtocolVersion().GetVersionValue();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_SessionId(DOUBLE * pVal)
|
|
{
|
|
BAIL_IF_NULL(pVal, E_INVALIDARG);
|
|
|
|
CLock Lock(g_DllLock);
|
|
|
|
// vb doesn't take ulong - cast the ulong value to a double, the next bigger type
|
|
*pVal = (DOUBLE)GetOrigin().GetSessionId().GetValue();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_SessionVersion(DOUBLE * pVal)
|
|
{
|
|
BAIL_IF_NULL(pVal, E_INVALIDARG);
|
|
|
|
CLock Lock(g_DllLock);
|
|
|
|
// vb doesn't take ulong - cast the ulong value to a double, the next bigger type
|
|
*pVal = (DOUBLE)GetOrigin().GetSessionVersion().GetValue();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::put_SessionVersion(DOUBLE newVal)
|
|
{
|
|
// the bandwidth value must be a valid ULONG value (vb restrictions)
|
|
if ( !((0 <= newVal) && (ULONG(-1) > newVal)) )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// check if there is any fractional part, this check is valid as it is a valid ULONG value
|
|
if ( newVal != (ULONG)newVal )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
CLock Lock(g_DllLock);
|
|
|
|
GetOrigin().GetSessionVersion().SetValue((ULONG)newVal);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_MachineAddress(BSTR * pVal)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
return GetOrigin().GetAddress().GetBstrCopy(pVal);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::put_MachineAddress(BSTR newVal)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
return GetOrigin().GetAddress().SetBstr(newVal);
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_Name(BSTR * pVal)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
return GetSessionName().GetBstrCopy(pVal);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::put_Name(BSTR newVal)
|
|
{
|
|
// write the new session name
|
|
// acquire lock inside
|
|
return WriteName(newVal);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_Description(BSTR * pVal)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
return GetSessionTitle().GetBstrCopy(pVal);
|
|
}
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::put_Description(BSTR newVal)
|
|
{
|
|
// write the new session title / description
|
|
// acquire lock inside
|
|
HRESULT HResult = WriteSessionTitle(newVal);
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_Url(BSTR * pVal)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
return GetUri().GetBstrCopy(pVal);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::put_Url(BSTR newVal)
|
|
{
|
|
// write the new Url
|
|
// acquire lock inside
|
|
HRESULT HResult = WriteUrl(newVal);
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::GetEmailNames(
|
|
VARIANT /*SAFEARRAY(BSTR)*/ *Addresses, VARIANT /*SAFEARRAY(BSTR)*/ *Names
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
return GetEmailList().GetSafeArray(Addresses, Names);
|
|
}
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::SetEmailNames(
|
|
VARIANT /*SAFEARRAY(BSTR)*/ Addresses, VARIANT /*SAFEARRAY(BSTR)*/ Names
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
return GetEmailList().SetSafeArray(Addresses, Names);
|
|
}
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::GetPhoneNumbers(
|
|
VARIANT /*SAFEARRAY(BSTR)*/ *Numbers, VARIANT /*SAFEARRAY(BSTR)*/ *Names
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
return GetPhoneList().GetSafeArray(Numbers, Names);
|
|
}
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::SetPhoneNumbers(
|
|
VARIANT /*SAFEARRAY(BSTR)*/ Numbers, VARIANT /*SAFEARRAY(BSTR)*/ Names
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
return GetPhoneList().SetSafeArray(Numbers, Names);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::get_Originator(BSTR * pVal)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
return GetOrigin().GetUserName().GetBstrCopy(pVal);
|
|
}
|
|
|
|
STDMETHODIMP CSdpConferenceBlob::put_Originator(BSTR newVal)
|
|
{
|
|
// write the new user name
|
|
// acquire lock inside
|
|
HRESULT HResult = WriteOriginator(newVal);
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
inline WORD
|
|
GetEvenValue(
|
|
IN WORD Value
|
|
)
|
|
{
|
|
return (0 == (Value % 2))? Value : (Value - 1);
|
|
}
|
|
|
|
|
|
TCHAR *
|
|
CSdpConferenceBlob::GenerateSdpBlob(
|
|
IN BSTR Name,
|
|
IN SDP_CHARACTER_SET CharacterSet
|
|
)
|
|
{
|
|
ASSERT(NULL != Name);
|
|
|
|
//
|
|
// Get multicast ports. We don't set addresses; that's the app's
|
|
// responsibility via MDHCP.
|
|
//
|
|
|
|
MSA_PORT_GROUP PortGroup;
|
|
PortGroup.PortType = VIDEO_PORT;
|
|
|
|
WORD FirstVideoPort;
|
|
|
|
// allocate video port
|
|
if ( !MSAAllocatePorts(&PortGroup, FALSE, 2, &FirstVideoPort) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
PortGroup.PortType = AUDIO_PORT;
|
|
|
|
WORD FirstAudioPort;
|
|
|
|
// allocate audio port
|
|
if ( !MSAAllocatePorts(&PortGroup, FALSE, 2, &FirstAudioPort) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// convert the returned ports to even values for RTP compliance
|
|
// ASSUMPTION : the sdp template read from the registry uses RTP as the transport
|
|
FirstAudioPort = GetEvenValue(FirstAudioPort);
|
|
FirstVideoPort = GetEvenValue(FirstVideoPort);
|
|
|
|
IP_ADDRESS AudioIpAddress(DUMMY_ADDRESS);
|
|
IP_ADDRESS VideoIpAddress(DUMMY_ADDRESS);
|
|
|
|
const DWORD MAX_USER_NAME_LEN = 100;
|
|
DWORD OriginatorBufLen = MAX_USER_NAME_LEN+1;
|
|
TCHAR Originator[MAX_USER_NAME_LEN+1];
|
|
|
|
if ( !GetUserName(Originator, &OriginatorBufLen) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// altconv.h - requires this declaration for W2T to work
|
|
USES_CONVERSION;
|
|
|
|
// convert the provided name to a tchar; the returned tchar string is
|
|
// allocated on the stack - no need to delete it
|
|
TCHAR *TcharName = W2T(Name);
|
|
BAIL_IF_NULL(TcharName, NULL);
|
|
|
|
// allocate enough memory for the sdp blob
|
|
TCHAR *SdpBlob;
|
|
|
|
try
|
|
{
|
|
SdpBlob = new TCHAR[
|
|
SDP_REG_READER::GetConfBlobTemplateLen() +
|
|
lstrlen(Originator) +
|
|
lstrlen(TcharName) +
|
|
MAXHOSTNAME +
|
|
3*MAX_NTP_TIME_STRLEN +
|
|
2*MAX_IP_ADDRESS_STRLEN +
|
|
2*MAX_PORT_STRLEN -
|
|
2*NUM_CONF_BLOB_TEMPLATE_PARAMS
|
|
];
|
|
}
|
|
catch(...)
|
|
{
|
|
SdpBlob = NULL;
|
|
}
|
|
|
|
if ( NULL == SdpBlob )
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// ZoltanS: get the local host name (replaces all this IP address nonsense)
|
|
//
|
|
|
|
char szLocalHostName[MAXHOSTNAME + 1];
|
|
char * pszHost;
|
|
int WsockErrorCode;
|
|
|
|
WsockErrorCode = gethostname(szLocalHostName, MAXHOSTNAME);
|
|
|
|
if ( 0 == WsockErrorCode )
|
|
{
|
|
struct hostent *hostp = gethostbyname(szLocalHostName);
|
|
|
|
if ( hostp )
|
|
{
|
|
pszHost = hostp->h_name;
|
|
}
|
|
else
|
|
{
|
|
// if we can't resolve our own hostname (yuck!) then we can
|
|
// still do *something* (but it may be bad for l2tp scenarios).
|
|
|
|
pszHost = SDP_REG_READER::GetHostIpAddress();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if we can't get a hostname (yuck!) then we can still do
|
|
// *something* (but it may be bad for l2tp scenarios).
|
|
|
|
pszHost = SDP_REG_READER::GetHostIpAddress();
|
|
}
|
|
|
|
// stprintf the string to create the conference blob
|
|
// check if the stprintf operation succeeded
|
|
|
|
CHAR* szCharacterSet = (CHAR*)UTF8_STRING;
|
|
switch( CharacterSet )
|
|
{
|
|
case CS_ASCII:
|
|
szCharacterSet = (CHAR*)ASCII_STRING;
|
|
break;
|
|
case CS_UTF7:
|
|
szCharacterSet = (CHAR*)UTF7_STRING;
|
|
break;
|
|
}
|
|
|
|
if ( 0 == _stprintf(SdpBlob,
|
|
SDP_REG_READER::GetConfBlobTemplate(),
|
|
Originator,
|
|
GetCurrentNtpTime(),
|
|
pszHost, // ZoltanS was: SDP_REG_READER::GetHostIpAddress(), // local machine ip address string,
|
|
TcharName,
|
|
AudioIpAddress.GetTstr(), // common c field
|
|
GetCurrentNtpTime() + SDP_REG_READER::GetStartTimeOffset(), // start time - current time + start offset,
|
|
GetCurrentNtpTime() + SDP_REG_READER::GetStopTimeOffset(), // stop time - current time + stop offset
|
|
szCharacterSet,
|
|
FirstAudioPort,
|
|
FirstVideoPort,
|
|
VideoIpAddress.GetTstr()
|
|
) )
|
|
{
|
|
delete SdpBlob;
|
|
return NULL;
|
|
}
|
|
|
|
return SdpBlob;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CSdpConferenceBlob::CreateDefault(
|
|
IN BSTR Name,
|
|
IN SDP_CHARACTER_SET CharacterSet
|
|
)
|
|
{
|
|
BAIL_IF_NULL(Name, E_INVALIDARG);
|
|
|
|
// check if the registry entries were read without errors
|
|
if ( !SDP_REG_READER::IsValid() )
|
|
{
|
|
return HRESULT_FROM_ERROR_CODE(SDP_REG_READER::GetErrorCode());
|
|
}
|
|
|
|
// check if a valid conference blob already exists, return error
|
|
if ( SDP_BLOB::IsValid() )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
// use the registry values to generate the default sdp
|
|
CHAR *SdpBlob = GenerateSdpBlob(Name, CharacterSet);
|
|
BAIL_IF_NULL(SdpBlob, HRESULT_FROM_ERROR_CODE(GetLastError()));
|
|
|
|
ASSERT(NULL != SdpBlob);
|
|
|
|
// parse in the sdp
|
|
HRESULT HResult = SetTstr(SdpBlob);
|
|
delete SdpBlob;
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
HResult = ((MEDIA_COLLECTION *)m_MediaCollection)->Init(*this, GetMediaList());
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
HResult = ((TIME_COLLECTION *)m_TimeCollection)->Init(*this, GetTimeList());
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
typedef IDispatchImpl<ITConferenceBlobVtbl<CSdpConferenceBlob>, &IID_ITConferenceBlob, &LIBID_SDPBLBLib> CTConferenceBlob;
|
|
typedef IDispatchImpl<ITSdpVtbl<CSdpConferenceBlob>, &IID_ITSdp, &LIBID_SDPBLBLib> CTSdp;
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CSdpConferenceBlob::GetIDsOfNames
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP CSdpConferenceBlob::GetIDsOfNames(REFIID riid,
|
|
LPOLESTR* rgszNames,
|
|
UINT cNames,
|
|
LCID lcid,
|
|
DISPID* rgdispid
|
|
)
|
|
{
|
|
HRESULT hr = DISP_E_UNKNOWNNAME;
|
|
|
|
|
|
|
|
//
|
|
// See if the requsted method belongs to the default interface
|
|
//
|
|
|
|
hr = CTConferenceBlob::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
rgdispid[0] |= IDISPCONFBLOB;
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// If not, then try the ITSdp base class
|
|
//
|
|
|
|
hr = CTSdp::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
rgdispid[0] |= IDISPSDP;
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// If not, then try the ITConnection base class
|
|
//
|
|
|
|
hr = ITConnectionImpl::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
rgdispid[0] |= IDISPCONNECTION;
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// If not, then try the ITAttributeList base class
|
|
//
|
|
|
|
hr = ITAttributeListImpl::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
rgdispid[0] |= IDISPATTRLIST;
|
|
return hr;
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CSdpConferenceBlob::Invoke
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP CSdpConferenceBlob::Invoke(DISPID dispidMember,
|
|
REFIID riid,
|
|
LCID lcid,
|
|
WORD wFlags,
|
|
DISPPARAMS* pdispparams,
|
|
VARIANT* pvarResult,
|
|
EXCEPINFO* pexcepinfo,
|
|
UINT* puArgErr
|
|
)
|
|
{
|
|
HRESULT hr = DISP_E_MEMBERNOTFOUND;
|
|
DWORD dwInterface = (dispidMember & INTERFACEMASK);
|
|
|
|
|
|
//
|
|
// Call invoke for the required interface
|
|
//
|
|
|
|
switch (dwInterface)
|
|
{
|
|
case IDISPCONFBLOB:
|
|
{
|
|
hr = CTConferenceBlob::Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case IDISPSDP:
|
|
{
|
|
hr = CTSdp::Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case IDISPCONNECTION:
|
|
{
|
|
hr = ITConnectionImpl::Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case IDISPATTRLIST:
|
|
{
|
|
hr = ITAttributeListImpl::Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
} // end switch (dwInterface)
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
BLOB_CHARACTER_SET CSdpConferenceBlob::GetBlobCharacterSet(
|
|
IN BSTR bstrBlob
|
|
)
|
|
{
|
|
BLOB_CHARACTER_SET CharSet = BCS_ASCII;
|
|
const WCHAR szCharacterSet[] = L"a=charset:";
|
|
|
|
WCHAR* szCharacterSetAttribute = wcsstr( bstrBlob, szCharacterSet);
|
|
|
|
if( szCharacterSetAttribute == NULL)
|
|
{
|
|
//We don't have the attribute
|
|
//We consider, for backward compability the default ASCII
|
|
|
|
return CharSet;
|
|
}
|
|
|
|
// We have an attribute entry
|
|
szCharacterSetAttribute += wcslen( szCharacterSet );
|
|
if( wcsstr( szCharacterSetAttribute, L"unicode-1-1-utf8"))
|
|
{
|
|
CharSet = BCS_UTF8;
|
|
}
|
|
else if (wcsstr( szCharacterSetAttribute, L"unicode-1-1-utf7"))
|
|
{
|
|
CharSet = BCS_UTF7;
|
|
}
|
|
else if (wcsstr( szCharacterSetAttribute, L"ascii"))
|
|
{
|
|
CharSet = BCS_ASCII;
|
|
}
|
|
|
|
return CharSet;
|
|
}
|