// File: h323cc.cpp #include "precomp.h" #include "confreg.h" #include "version.h" EXTERN_C HINSTANCE g_hInst=NULL; // global module instance IRTP *g_pIRTP = NULL; UINT g_capFlags = CAPFLAGS_AV_ALL; #ifdef DEBUG HDBGZONE ghDbgZoneCC = NULL; static PTCHAR _rgZonesCC[] = { TEXT("H323"), TEXT("Init"), TEXT("Conn"), TEXT("Channels"), TEXT("Caps"), TEXT("Member"), TEXT("unused"), TEXT("unused"), TEXT("Ref count"), TEXT("unused"), TEXT("Profile spew") }; int WINAPI CCDbgPrintf(LPTSTR lpszFormat, ... ) { va_list v1; va_start(v1, lpszFormat); DbgPrintf("H323CC", lpszFormat, v1); va_end(v1); return TRUE; } #endif /* DEBUG */ // The product ID fields are defined in the standard as an array of bytes. ASCII // characters are used regardless of local character set. // default Product ID and version ID strings static char DefaultProductID[] = H323_PRODUCTNAME_STR; static char DefaultProductVersion[] = H323_PRODUCTRELEASE_STR; extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); BOOL WINAPI DllEntryPoint( HINSTANCE hinstDLL, // handle to DLL module DWORD fdwReason, // reason for calling function LPVOID lpvReserved // reserved ) { switch(fdwReason) { case DLL_PROCESS_ATTACH: DBGINIT(&ghDbgZoneCC, _rgZonesCC); DBG_INIT_MEMORY_TRACKING(hinstDLL); DisableThreadLibraryCalls(hinstDLL); g_hInst = hinstDLL; break; case DLL_PROCESS_DETACH: DBG_CHECK_MEMORY_TRACKING(hinstDLL); DBGDEINIT(&ghDbgZoneCC); break; default: break; } return TRUE; } HRESULT WINAPI CreateH323CC(IH323CallControl ** ppCC, BOOL fForCalling, UINT capFlags) { if(!ppCC) return H323CC_E_INVALID_PARAM; DBG_SAVE_FILE_LINE *ppCC = new CH323CallControl(fForCalling, capFlags); if(!(*ppCC)) return H323CC_E_CREATE_FAILURE; return hrSuccess; } BOOL CH323CallControl::m_fGKProhibit = FALSE; RASNOTIFYPROC CH323CallControl::m_pRasNotifyProc = NULL; CH323CallControl::CH323CallControl(BOOL fForCalling, UINT capFlags) : m_uRef(1), m_fForCalling(fForCalling), m_numlines(0), m_pProcNotifyConnect(NULL), m_pCapabilityResolver(NULL), m_pListenLine(NULL), m_pLineList(NULL), m_pNextToAccept(NULL), m_pUserName(NULL), m_pLocalAliases(NULL), m_pRegistrationAliases(NULL), hrLast(hrSuccess), m_pSendAudioChannel(NULL), m_pSendVideoChannel(NULL), m_uMaximumBandwidth(0) { // // Set up caps. // if (fForCalling) { g_capFlags = capFlags; } m_VendorInfo.bCountryCode = USA_H221_COUNTRY_CODE; m_VendorInfo.bExtension = USA_H221_COUNTRY_EXTENSION; m_VendorInfo.wManufacturerCode = MICROSOFT_H_221_MFG_CODE; m_VendorInfo.pProductNumber = (PCC_OCTETSTRING)MemAlloc(sizeof(CC_OCTETSTRING) + sizeof(DefaultProductID)); if(m_VendorInfo.pProductNumber) { m_VendorInfo.pProductNumber->wOctetStringLength = sizeof(DefaultProductID); m_VendorInfo.pProductNumber->pOctetString = ((BYTE *)m_VendorInfo.pProductNumber + sizeof(CC_OCTETSTRING)); memcpy(m_VendorInfo.pProductNumber->pOctetString, DefaultProductID, sizeof(DefaultProductID)); } m_VendorInfo.pVersionNumber = (PCC_OCTETSTRING)MemAlloc(sizeof(CC_OCTETSTRING) + sizeof(DefaultProductVersion)); if(m_VendorInfo.pVersionNumber) { m_VendorInfo.pVersionNumber->wOctetStringLength = sizeof(DefaultProductVersion); m_VendorInfo.pVersionNumber->pOctetString = ((BYTE *)m_VendorInfo.pVersionNumber + sizeof(CC_OCTETSTRING)); memcpy(m_VendorInfo.pVersionNumber->pOctetString, DefaultProductVersion, sizeof(DefaultProductVersion)); } RegEntry reCC(szRegInternetPhone TEXT("\\") szRegInternetPhoneNac, HKEY_LOCAL_MACHINE, FALSE, KEY_READ); UINT uAPD = reCC.GetNumberIniStyle(TEXT ("AudioPacketDurationMs"), 0); if (uAPD) { g_AudioPacketDurationMs = uAPD; g_fRegAudioPacketDuration = TRUE; } DBG_SAVE_FILE_LINE m_pCapabilityResolver = new CapsCtl(); if (!m_pCapabilityResolver) { ERRORMESSAGE(("CH323CallControl::CH323CallControl:cannot create capability resolver\r\n")); hrLast = H323CC_E_INIT_FAILURE; } if(!m_pCapabilityResolver->Init()) { ERRORMESSAGE(("CH323CallControl::CH323CallControl cannot init capability resolver\r\n")); hrLast = H323CC_E_INIT_FAILURE; } } HRESULT CH323CallControl::Initialize(PORT *lpPort) { FX_ENTRY("CH323CallControl::Initialize"); OBJ_CPT_RESET; ASSERT(m_fForCalling); if(!HR_SUCCEEDED(LastHR())) { goto EXIT; } if(!lpPort) { SetLastHR(H323CC_E_INVALID_PARAM); goto EXIT; } if(!Init()) { goto EXIT; } else { ASSERT(m_pListenLine); hrLast = m_pListenLine->GetLocalPort(lpPort); } if (g_capFlags & CAPFLAGS_AV_STREAMS) { SetLastHR( ::CoCreateInstance(CLSID_RTP, NULL, CLSCTX_INPROC_SERVER, IID_IRTP, (void**)&g_pIRTP) ); } SHOW_OBJ_ETIME("CH323CallControl::Initialize"); EXIT: return LastHR(); } HRESULT CH323CallControl::SetMaxPPBandwidth(UINT Bandwidth) { HRESULT hr = hrSuccess; LPAPPVIDCAPPIF lpIVidAppCap = NULL; DWORD dwcFormats = 0; DWORD dwcFormatsReturned = 0; DWORD x; BASIC_VIDCAP_INFO *pvidcaps = NULL; m_uMaximumBandwidth =Bandwidth; if (g_capFlags & CAPFLAGS_AV_STREAMS) { //Set the bandwidth on every video format hr = QueryInterface(IID_IAppVidCap, (void **)&lpIVidAppCap); if (! HR_SUCCEEDED (hr)) goto EXIT; // Get the number of BASIC_VIDCAP_INFO structures available hr = lpIVidAppCap->GetNumFormats((UINT*)&dwcFormats); if (! HR_SUCCEEDED (hr)) goto EXIT; if (dwcFormats > 0) { // Allocate some memory to hold the list in if (!(pvidcaps = (BASIC_VIDCAP_INFO*)MemAlloc(dwcFormats * sizeof (BASIC_VIDCAP_INFO)))) { hr = H323CC_E_INSUFFICIENT_MEMORY; goto EXIT; } // Get the list hr=lpIVidAppCap->EnumFormats(pvidcaps, dwcFormats * sizeof (BASIC_VIDCAP_INFO), (UINT*)&dwcFormatsReturned); if (! HR_SUCCEEDED (hr)) goto EXIT; //Set the bandwidth on each format for (x=0;xApplyAppFormatPrefs(pvidcaps, dwcFormats); if (! HR_SUCCEEDED (hr)) goto EXIT; } } //Initialize the default H.323 simcaps. hr = m_pCapabilityResolver->ComputeCapabilitySets(m_uMaximumBandwidth); //if(!HR_SUCCEEDED(hr)) // goto EXIT; EXIT: // let the interface go if (lpIVidAppCap) { lpIVidAppCap->Release(); // (going out of scope) lpIVidAppCap = NULL; } if(pvidcaps) { // Free the memory, we're done MemFree(pvidcaps); } return hr; } BOOL CH323CallControl::Init() { HRESULT hResult; DEBUGMSG(ZONE_INIT,("Init: this:0x%08lX\r\n", this)); SetLastHR(hrSuccess); if (m_fForCalling) { // // Only call control code should init CC_ stuff. Codec manipulation // via audiocpl should not. // hResult = CC_Initialize(); if(!HR_SUCCEEDED(hResult)) { goto CLEANUP; } } ASSERT(m_pCapabilityResolver); // Initialize capability data using default number, but clear the saved // bandwidth number afterwards. This detects attempts to place or // accept calls before the application initializes the real bandwidth hResult = SetMaxPPBandwidth(DEF_AP_BWMAX); m_uMaximumBandwidth = 0; if(!HR_SUCCEEDED(hResult)) { goto CLEANUP; } // Create dual connection objects for listening for new connections if (m_fForCalling) { hResult = CreateConnection(&m_pListenLine,PID_H323); if(!HR_SUCCEEDED(hResult)) { goto CLEANUP; } if(!m_pListenLine) { hResult = H323CC_E_INIT_FAILURE; goto CLEANUP; } if(!(m_pListenLine->ListenOn(H323_PORT))) { hResult = H323CC_E_NETWORK_ERROR; goto CLEANUP; } } return TRUE; CLEANUP: if (m_pListenLine) { m_pListenLine->Release(); m_pListenLine = NULL; } SetLastHR(hResult); return FALSE; } CH323CallControl::~CH323CallControl() { if(m_VendorInfo.pProductNumber) MemFree(m_VendorInfo.pProductNumber); if(m_VendorInfo.pVersionNumber) MemFree(m_VendorInfo.pVersionNumber); if(m_pUserName) MemFree(m_pUserName); if(m_pLocalAliases) FreeTranslatedAliasList(m_pLocalAliases); if(m_pRegistrationAliases) FreeTranslatedAliasList(m_pRegistrationAliases); if (m_pCapabilityResolver) { m_pCapabilityResolver->Release(); m_pCapabilityResolver = NULL; } if (m_pSendAudioChannel) { ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS); m_pSendAudioChannel->Release(); m_pSendAudioChannel = NULL; } if (m_pSendVideoChannel) { ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS); m_pSendVideoChannel->Release(); m_pSendVideoChannel = NULL; } if (m_fForCalling) { // toast backward references to this in all // connection objects CConnection *pLine = m_pLineList; CConnection *pNext; while(pLine) { pNext = pLine->next; pLine->DeInit(); pLine = pNext; } // release the listening object if it exists if(m_pListenLine) m_pListenLine->Release(); // shutdown CALLCONT.DLL CC_Shutdown(); if (g_pIRTP) { ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS); g_pIRTP->Release(); g_pIRTP = NULL; } // Put capflags back g_capFlags = CAPFLAGS_AV_ALL; } else { ASSERT(!m_pLineList); ASSERT(!m_pListenLine); } } ULONG CH323CallControl::AddRef() { m_uRef++; return m_uRef; } ULONG CH323CallControl::Release() { m_uRef--; if(m_uRef == 0) { delete this; return 0; } return m_uRef; } HRESULT CH323CallControl::SetUserDisplayName(LPWSTR lpwName) { LPWSTR lpwD; ULONG ulSize; if(!lpwName) { return (MakeResult(H323CC_E_INVALID_PARAM)); } if(lpwName) { ulSize = ((lstrlenW(lpwName) +1)*sizeof(WCHAR)); lpwD = (LPWSTR)MemAlloc(ulSize); if(!lpwD) return H323CC_E_INSUFFICIENT_MEMORY; if(m_pUserName) { MemFree(m_pUserName); } m_pUserName = lpwD; memcpy(m_pUserName, lpwName, ulSize); } return (MakeResult(hrSuccess)); } // Find the most suitable alias for display. Return the first H323ID if it exists, // else return the first E.164 address PCC_ALIASITEM CH323CallControl::GetUserDisplayAlias() { WORD wC; PCC_ALIASITEM pItem, pFoundItem = NULL; if(m_pLocalAliases) { wC = m_pLocalAliases->wCount; pItem = m_pLocalAliases->pItems; while (wC--) { if(!pItem) { continue; } if(pItem->wType == CC_ALIAS_H323_ID) { if(!pItem->wDataLength || !pItem->pData) { continue; } else { pFoundItem = pItem; // done, done, done break; // I said done } } else if(pItem->wType == CC_ALIAS_H323_PHONE) { if(!pItem->wDataLength || !pItem->pData) { continue; } else { if(!pFoundItem) // if nothing at all was found so far pFoundItem = pItem; // remember this } } pItem++; } } return pFoundItem; } CREQ_RESPONSETYPE CH323CallControl::ConnectionRequest(CConnection *pConnection) { CREQ_RESPONSETYPE Response; // decide what to do internally // LOOKLOOK hardcoded acceptance Response = CRR_ACCEPT; return Response; } CREQ_RESPONSETYPE CH323CallControl::FilterConnectionRequest(CConnection *pConnection, P_APP_CALL_SETUP_DATA pAppData) { CREQ_RESPONSETYPE Response = CRR_ASYNC; ASSERT(m_uMaximumBandwidth); // run it past the notification callback (if there is one) if(m_pProcNotifyConnect) { // pass ptr to IConnection Response = (m_pProcNotifyConnect)((IH323Endpoint *)&pConnection->m_ImpConnection, pAppData); if(Response != CRR_ACCEPT) { return Response; } } return Response; } HRESULT CH323CallControl::RegisterConnectionNotify(CNOTIFYPROC pConnectRequestHandler) { // reject if there's an existing registration if (m_pProcNotifyConnect || (!pConnectRequestHandler)) { return H323CC_E_INVALID_PARAM; } m_pProcNotifyConnect = pConnectRequestHandler; return hrSuccess; } HRESULT CH323CallControl::DeregisterConnectionNotify(CNOTIFYPROC pConnectRequestHandler) { // reject if there's not an existing registration if (!m_pProcNotifyConnect) return H323CC_E_INVALID_PARAM; if (pConnectRequestHandler == m_pProcNotifyConnect) { m_pProcNotifyConnect = NULL; } else { return H323CC_E_INVALID_PARAM; } return hrSuccess; } HRESULT CH323CallControl::GetNumConnections(ULONG *lp) { ULONG ulRet = m_numlines; // hide the "listening" connection object from the client/ui/whatever if(ulRet && m_pListenLine) ulRet--; if(lp) { *lp = ulRet; } return hrSuccess; } HRESULT CH323CallControl::GetConnobjArray(CConnection **lplpArray, UINT uSize) { UINT uPublicConnections; // # of visible objects if(!lplpArray) return H323CC_E_INVALID_PARAM; uPublicConnections = m_numlines; if(m_pListenLine) uPublicConnections--; if(uSize < (sizeof(CConnection **) * uPublicConnections)) { return H323CC_E_MORE_CONNECTIONS; } CConnection *pLine = m_pLineList; CConnection *pNext; int i=0; while(pLine) { DEBUGCHK(uSize--); pNext = pLine->next; // return everything but the objects used for listening if(pLine != m_pListenLine) { lplpArray[i++] = pLine; } pLine = pNext; } return hrSuccess; }; HRESULT CH323CallControl::GetConnectionArray(IH323Endpoint * *lplpArray, UINT uSize) { UINT uPublicConnections; // # of visible objects if(!lplpArray) return H323CC_E_INVALID_PARAM; uPublicConnections = m_numlines; if(m_pListenLine) uPublicConnections--; if(uSize < (sizeof(IH323Endpoint * *) * uPublicConnections)) { return H323CC_E_MORE_CONNECTIONS; } CConnection *pLine = m_pLineList; CConnection *pNext; int i=0; while(pLine) { DEBUGCHK(uSize--); pNext = pLine->next; // return everything but the objects used for listening if(pLine != m_pListenLine) { lplpArray[i++] = (IH323Endpoint *)&pLine->m_ImpConnection; } pLine = pNext; } return hrSuccess; }; // // protocol specific CreateConnection // HRESULT CH323CallControl::CreateConnection(CConnection **lplpConnection, GUID PIDofProtocolType) { SetLastHR(hrSuccess); CConnection *lpConnection, *lpList; if(!lplpConnection) { SetLastHR(MakeResult(H323CC_E_INVALID_PARAM)); goto EXIT; } *lplpConnection = NULL; DBG_SAVE_FILE_LINE if(!(lpConnection = new CConnection)) { SetLastHR(MakeResult(H323CC_E_INSUFFICIENT_MEMORY)); goto EXIT; } hrLast = lpConnection->Init(this, PIDofProtocolType); // LOOKLOOK need to insert this connection in the connection list if(!HR_SUCCEEDED(hrSuccess)) { delete lpConnection; lpConnection = NULL; } else { *lplpConnection = lpConnection; // insert in connection list lpList = m_pLineList; m_pLineList = lpConnection; lpConnection->next =lpList; m_numlines++; } EXIT: return (LastHR()); } // // IH323CallControl->CreateConnection(), EXTERNAL create connection interface. // HRESULT CH323CallControl::CreateConnection(IH323Endpoint * *lplpLine, GUID PIDofProtocolType) { SetLastHR(hrSuccess); CConnection *lpConnection; ASSERT(m_uMaximumBandwidth); if(!m_uMaximumBandwidth) { SetLastHR(MakeResult(H323CC_E_NOT_INITIALIZED)); goto EXIT; } if(!lplpLine) { SetLastHR(MakeResult(H323CC_E_INVALID_PARAM)); goto EXIT; } *lplpLine = NULL; hrLast = CreateConnection(&lpConnection, PIDofProtocolType); if(HR_SUCCEEDED(LastHR()) && lpConnection) { *lplpLine = (IH323Endpoint *)&lpConnection->m_ImpConnection; } EXIT: return (LastHR()); } // // CreateLocalCommChannel creates the send side of a media channel outside the context // of any call. // HRESULT CH323CallControl::CreateLocalCommChannel(ICommChannel** ppCommChan, LPGUID lpMID, IMediaChannel* pMediaStream) { if(!ppCommChan || !lpMID || !pMediaStream) return H323CC_E_INVALID_PARAM; if (*lpMID == MEDIA_TYPE_H323AUDIO) { ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS); // allow only one of each media type to be created. This is an artificial // limitation. if(m_pSendAudioChannel) { hrLast = H323CC_E_CREATE_FAILURE; goto EXIT; } DBG_SAVE_FILE_LINE if(!(m_pSendAudioChannel = new ImpICommChan)) { hrLast = H323CC_E_CREATE_FAILURE; goto EXIT; } hrLast = m_pSendAudioChannel->StandbyInit(lpMID, m_pCapabilityResolver, pMediaStream); if(!HR_SUCCEEDED(hrLast)) { m_pSendAudioChannel->Release(); m_pSendAudioChannel = NULL; goto EXIT; } hrLast = m_pSendAudioChannel->QueryInterface(IID_ICommChannel, (void **)ppCommChan); if(!HR_SUCCEEDED(hrLast)) { m_pSendAudioChannel->Release(); m_pSendAudioChannel = NULL; goto EXIT; } } else if (*lpMID == MEDIA_TYPE_H323VIDEO) { ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS); // allow only one of each media type to be created. This is an artificial // limitation. if(m_pSendVideoChannel) { hrLast = H323CC_E_CREATE_FAILURE; goto EXIT; } DBG_SAVE_FILE_LINE if(!(m_pSendVideoChannel = new ImpICommChan)) { hrLast = H323CC_E_CREATE_FAILURE; goto EXIT; } hrLast = m_pSendVideoChannel->StandbyInit(lpMID, m_pCapabilityResolver, pMediaStream); if(!HR_SUCCEEDED(hrLast)) { m_pSendVideoChannel->Release(); m_pSendVideoChannel = NULL; goto EXIT; } hrLast = m_pSendVideoChannel->QueryInterface(IID_ICommChannel, (void **)ppCommChan); if(!HR_SUCCEEDED(hrLast)) { m_pSendVideoChannel->Release(); m_pSendVideoChannel = NULL; goto EXIT; } } else hrLast = H323CC_E_INVALID_PARAM; EXIT: return hrLast; } ICtrlCommChan *CH323CallControl::QueryPreviewChannel(LPGUID lpMID) { HRESULT hr; ICtrlCommChan *pCommChan = NULL; if(*lpMID == MEDIA_TYPE_H323AUDIO) { if(m_pSendAudioChannel) { hr = m_pSendAudioChannel->QueryInterface(IID_ICtrlCommChannel, (void **)&pCommChan); if(HR_SUCCEEDED(hr)) { return pCommChan; } } } else if (*lpMID == MEDIA_TYPE_H323VIDEO) { if(m_pSendVideoChannel) { hr = m_pSendVideoChannel->QueryInterface(IID_ICtrlCommChannel, (void **)&pCommChan); if(HR_SUCCEEDED(hr)) { return pCommChan; } } } // fallout to error case return NULL; } HRESULT CH323CallControl::RemoveConnection(CConnection *lpConnection) { SetLastHR(hrSuccess); CConnection *lpList; UINT nLines; if((lpConnection == NULL) || lpConnection->m_pH323CallControl != this) { SetLastHR(MakeResult(H323CC_E_INVALID_PARAM)); goto EXIT; } m_numlines--; // update count NOW // use # of lines for bug detection in list management code nLines = m_numlines; if(m_pListenLine == lpConnection) m_pListenLine = NULL; // zap the back pointer of the connection NOW - this is crucial for // implementing "asynchronous delete" of connection objects lpConnection->m_pH323CallControl = NULL; // find it in the connection list and remove it // sp. case head if(m_pLineList== lpConnection) { m_pLineList = lpConnection->next; } else { lpList = m_pLineList; while(lpList->next && nLines) { if(lpList->next == lpConnection) { lpList->next = lpConnection->next; break; } lpList = lpList->next; nLines--; } } EXIT: return (LastHR()); } STDMETHODIMP CH323CallControl::QueryInterface( REFIID iid, void ** ppvObject) { // this breaks the rules for the official COM QueryInterface because // the interfaces that are queried for are not necessarily real COM // interfaces. The reflexive property of QueryInterface would be broken in // that case. HRESULT hr = E_NOINTERFACE; if(!ppvObject) return hr; *ppvObject = 0; if ((iid == IID_IH323CC) || (iid == IID_IUnknown))// satisfy symmetric property of QI { *ppvObject = this; hr = hrSuccess; AddRef(); } else if (iid == IID_IAppAudioCap ) { hr = m_pCapabilityResolver->QueryInterface(iid, ppvObject); } else if(iid == IID_IAppVidCap ) { hr = m_pCapabilityResolver->QueryInterface(iid, ppvObject); } else if(iid == IID_IDualPubCap ) { hr = m_pCapabilityResolver->QueryInterface(iid, ppvObject); } return (hr); } // // Create a copy of the alias names in the (somewhat bogus) format that // CALLCONT expects. The destination format has a two-part string for every // entry, but the lower layers concatenate the parts. Someday H323CC and CALLCONT // will be one, and all the extraneous layers, copies of data, and redundant // validations won't be needed. // HRESULT AllocTranslatedAliasList(PCC_ALIASNAMES *ppDest, P_H323ALIASLIST pSource) { HRESULT hr = H323CC_E_INVALID_PARAM; WORD w; PCC_ALIASNAMES pNewAliases = NULL; PCC_ALIASITEM pDestItem; P_H323ALIASNAME pSrcItem; if(!ppDest || !pSource || pSource->wCount == 0) { goto ERROR_OUT; } *ppDest = NULL; pNewAliases = (PCC_ALIASNAMES)MemAlloc(sizeof(CC_ALIASNAMES)); if(!pNewAliases) { hr = H323CC_E_INSUFFICIENT_MEMORY; goto ERROR_OUT; } pNewAliases->wCount = 0; pNewAliases->pItems = (PCC_ALIASITEM)MemAlloc(pSource->wCount*sizeof(CC_ALIASITEM)); if(!pNewAliases->pItems) { hr = H323CC_E_INSUFFICIENT_MEMORY; goto ERROR_OUT; } for(w=0;wwCount;w++) { pDestItem = pNewAliases->pItems+w; pSrcItem = pSource->pItems+w; // don't tolerate empty entries - error out if any exist if(pSrcItem->wDataLength && pSrcItem->lpwData) { if(pSrcItem->aType ==AT_H323_ID) { pDestItem->wType = CC_ALIAS_H323_ID; } else if(pSrcItem->aType ==AT_H323_E164) { pDestItem->wType = CC_ALIAS_H323_PHONE; } else { // don't know how to translate this. I hope that the need for translation // goes away before new alias types are added. Adding an alias type // (H323_URL for example) requires many changes in lower layers anyway, // so that would be a good time to merge H323CC and CALLCONT. goto ERROR_OUT; // return invalid param } pDestItem->wPrefixLength = 0; // this prefix thing is bogus pDestItem->pPrefix = NULL; pDestItem->pData = (LPWSTR)MemAlloc(pSrcItem->wDataLength *sizeof(WCHAR)); if(pDestItem->pData == NULL) { hr = H323CC_E_INSUFFICIENT_MEMORY; goto ERROR_OUT; } // got good data. Copy the data, set size/length, and count it memcpy(pDestItem->pData, pSrcItem->lpwData, pSrcItem->wDataLength * sizeof(WCHAR)); pDestItem->wDataLength = pSrcItem->wDataLength; pNewAliases->wCount++; } else { goto ERROR_OUT; } } // got here, so output good data hr = hrSuccess; *ppDest = pNewAliases; //pNewAliases = NULL; // not needed if returning here instead of falling out return hr; ERROR_OUT: if(pNewAliases) // then it's an error condition needing cleanup { FreeTranslatedAliasList(pNewAliases); } return hr; } VOID FreeTranslatedAliasList(PCC_ALIASNAMES pDoomed) { WORD w; PCC_ALIASITEM pDoomedItem; if(!pDoomed) return; for(w=0;wwCount;w++) { pDoomedItem = pDoomed->pItems+w; // don't tolerate empty entries - error out if any exist if(pDoomedItem->wDataLength && pDoomedItem->pData) { MemFree(pDoomedItem->pData); } else ASSERT(0); } MemFree(pDoomed->pItems); MemFree(pDoomed); } STDMETHODIMP CH323CallControl::SetUserAliasNames(P_H323ALIASLIST pAliases) { HRESULT hr = hrSuccess; PCC_ALIASNAMES pNewAliases = NULL; PCC_ALIASITEM pItem; hr = AllocTranslatedAliasList(&pNewAliases, pAliases); if(!HR_SUCCEEDED(hr)) return hr; ASSERT(pNewAliases); if(m_pLocalAliases) FreeTranslatedAliasList(m_pLocalAliases); m_pLocalAliases = pNewAliases; return hr; } STDMETHODIMP CH323CallControl::EnableGatekeeper(BOOL bEnable, PSOCKADDR_IN pGKAddr, P_H323ALIASLIST pAliases, RASNOTIFYPROC pRasNotifyProc) { HRESULT hr = hrSuccess; PCC_ALIASNAMES pNewAliases = NULL; PCC_ALIASITEM pItem; m_pRasNotifyProc = pRasNotifyProc; if(bEnable) { if(!pRasNotifyProc || !pGKAddr || !pAliases) { return H323CC_E_INVALID_PARAM; } if((pGKAddr->sin_addr.s_addr == INADDR_NONE) || (pGKAddr->sin_addr.s_addr == INADDR_ANY)) { return H323CC_E_INVALID_PARAM; } hr = AllocTranslatedAliasList(&pNewAliases, pAliases); if(!HR_SUCCEEDED(hr)) return hr; ASSERT(pNewAliases); if(m_pRegistrationAliases) FreeTranslatedAliasList(m_pRegistrationAliases); m_pRegistrationAliases = pNewAliases; // reset "I can place calls" state m_fGKProhibit = FALSE; hr = CC_EnableGKRegistration(bEnable, pGKAddr, m_pRegistrationAliases, &m_VendorInfo, 0, // no multipoint/MC funtionality RasNotify); } else { // we are turning off knowledge of what a gatekeeper is, // so reset "I can place calls" state. m_fGKProhibit = FALSE; hr = CC_EnableGKRegistration(bEnable, NULL, NULL, NULL, 0, RasNotify); if(m_pRegistrationAliases) FreeTranslatedAliasList(m_pRegistrationAliases); m_pRegistrationAliases = NULL; } return hr; } STDMETHODIMP CH323CallControl::GetGKCallPermission() { if(m_fGKProhibit) return CONN_E_GK_NOT_REGISTERED; else return hrSuccess; } VOID CALLBACK CH323CallControl::RasNotify(DWORD dwRasEvent, HRESULT hReason) { switch(dwRasEvent) { case RAS_REG_CONFIRM: // received RCF (registration confirmed) // reset "I can place calls" state m_fGKProhibit = FALSE; break; case RAS_REG_TIMEOUT: // GK did not respond case RAS_UNREG_CONFIRM: // received UCF (unregistration confirmed) default: // do nothing. (except pass notification upward break; case RAS_REJECTED: // received RRJ (registration rejected) m_fGKProhibit = TRUE; break; case RAS_UNREG_REQ: // received URQ m_fGKProhibit = TRUE; break; } if(m_pRasNotifyProc) { (m_pRasNotifyProc)(dwRasEvent, hReason); } }