windows-nt/Source/XPSP1/NT/net/tapi/skywalker/sdpblb/sdpblob.cpp
2020-09-26 16:20:57 +08:00

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;
}