////////////////////////////////////////////////////////////////// // // ACDUTILS.C // // Some utility functions used in ACDSMPL // ////////////////////////////////////////////////////////////////// #include #include "acdsmpl.h" extern ACDGLOBALS g; ////////////////////////////////////////////////////////////////// // // LPVOID ACDAlloc(DWORD dwSize) // ////////////////////////////////////////////////////////////////// LPVOID ACDAlloc(DWORD dwSize) { LPVOID pBuf; pBuf = GlobalAlloc(GPTR, dwSize); return pBuf; } /////////////////////////////////////////////////////////////////// // // void ACDFree(LPVOID pBuf) // /////////////////////////////////////////////////////////////////// void ACDFree(LPVOID pBuf) { if (pBuf) GlobalFree(pBuf); } /////////////////////////////////////////////////////////////////// // // LPVOID ACDReAlloc() // /////////////////////////////////////////////////////////////////// LPVOID ACDReAlloc(LPVOID pBuf, DWORD dwSize) { if (pBuf) { pBuf = GlobalReAlloc(pBuf, dwSize, GMEM_MOVEABLE); } return pBuf; } /////////////////////////////////////////////////////////////////////////////// // // BOOL InsertStruct(PGENERICSTRUCT * ppRoot, // PGENERICSTRUCT pStruct) // // Adds a structure to the end of a linked list // /////////////////////////////////////////////////////////////////////////////// BOOL InsertStruct(PGENERICSTRUCT * ppRoot, PGENERICSTRUCT pStruct) { PGENERICSTRUCT pHold = NULL; if (!*ppRoot) { *ppRoot = pStruct; } else { pHold = *ppRoot; } if (pHold) { while (pHold->pNext) { pHold = pHold->pNext; } pHold->pNext = pStruct; pStruct->pPrev = pHold; } return TRUE; } ////////////////////////////////////////////////////////////// // // BOOL DeleteStruct // Delete structure // // Delete a structure from a linked list and // frees memory associated with it. // ////////////////////////////////////////////////////////////// BOOL DeleteStruct(PGENERICSTRUCT * ppRoot, PGENERICSTRUCT pStruct) { if (pStruct->pPrev) { pStruct->pPrev->pNext = pStruct->pNext; } else { *ppRoot = pStruct->pNext; } if (pStruct->pNext) { pStruct->pNext->pPrev = pStruct->pPrev; } ACDFree(pStruct); return TRUE; } ////////////////////////////////////////////////////////////// // // PGROUP AddGroup // // Adds a group to the global group list // ////////////////////////////////////////////////////////////// PGROUP AddGroup(LPTSTR lpszName, DWORD dwDeviceID, DWORD dwAddress) { PGROUP pGroup, pHold = NULL; LONG lResult; // alloc memory pGroup = (PGROUP)ACDAlloc(sizeof(GROUP)); if (!pGroup) { return NULL; } pGroup->lpszName = (LPTSTR)ACDAlloc((lstrlen(lpszName) + 1) * sizeof(TCHAR)); // bail if there is a problem if (!pGroup->lpszName) { ACDFree(pGroup); return NULL; } // init stuff lstrcpy(pGroup->lpszName, lpszName); pGroup->dwKey = GROUPKEY; pGroup->dwSize = sizeof(GROUP); pGroup->dwDeviceID = dwDeviceID; // open the line in owner mode, so we can // get the incoming calls lResult = lineOpen(g.hLineApp, dwDeviceID, &pGroup->hLine, TAPI_CURRENT_VERSION, 0, 0, LINECALLPRIVILEGE_OWNER, LINEMEDIAMODE_INTERACTIVEVOICE, NULL); if (lResult < 0) { // LogTapiError(lResult, "lineOpen line %lu", dwDeviceID); ACDFree(pGroup->lpszName); ACDFree(pGroup); return NULL; } // insert into global list InsertStruct((PGENERICSTRUCT *)&g.pGroups, (PGENERICSTRUCT)pGroup); // increment g.dwNumGroups++; return pGroup; } ////////////////////////////////////////////////////////////// // // PAGENT AddAgent // // Adds an agent to the global agent list // // NOTE: There is a ton of verification type stuff that can // be put in here for a real implementation. For example, // might want to restrict a user to a single line, or restrict // a single line to have one person. // ////////////////////////////////////////////////////////////// PAGENT AddAgent(LPTSTR lpszName, LPTSTR lpszNumber, DWORD dwDeviceID) { PAGENT pAgent, pHold = NULL; LPLINEDEVCAPS pLDC; LPLINECALLPARAMS pLCP; LONG lResult; LPDWORD pdwProxyRequests; // alloc memory pAgent = (PAGENT)ACDAlloc(sizeof(AGENT)); if (!pAgent) { return NULL; } pAgent->lpszName = (LPTSTR)ACDAlloc((lstrlen(lpszName) + 1) * sizeof(TCHAR)); pAgent->lpszNumber = (LPTSTR)ACDAlloc((lstrlen(lpszNumber) + 1) * sizeof(TCHAR)); // bail if there is a problem if (!pAgent->lpszName || !pAgent->lpszNumber) { ACDFree(pAgent); return NULL; } // init stuff lstrcpy(pAgent->lpszName, lpszName); lstrcpy(pAgent->lpszNumber, lpszNumber); pAgent->dwKey = AGENTKEY; pAgent->dwSize = sizeof(AGENT); pAgent->dwDeviceID = dwDeviceID; pAgent->dwPermID = g.pdwPermIDs[dwDeviceID]; // insert into global agent list InsertStruct((PGENERICSTRUCT *)&g.pAgents, (PGENERICSTRUCT)pAgent); // lineOpen is where the application lets TAPI know that it is a Proxy Request handler // for this line. The LINEOPENOPTION_PROXY is added to the privileges. Also, // the dev specific portion of LINECALLPARAMS contains the proxy request constants // that indicate which requests this app can handle // This sample handles 7 types of proxy requests - all the ones that are defined // except for AGENTSPECIFIC pLCP = (LPLINECALLPARAMS)ACDAlloc(sizeof(LINECALLPARAMS) + 7*sizeof(DWORD)); pLCP->dwTotalSize = sizeof(LINECALLPARAMS) + 7*sizeof(DWORD); pLCP->dwDevSpecificOffset = sizeof(LINECALLPARAMS); pLCP->dwDevSpecificSize = sizeof(DWORD) * 7; pdwProxyRequests = (LPDWORD)((LPBYTE)pLCP + sizeof(LINECALLPARAMS)); // each constant is in a DWORD at the end of LINECALLPARAMS *pdwProxyRequests++ = LINEPROXYREQUEST_SETAGENTGROUP; *pdwProxyRequests++ = LINEPROXYREQUEST_SETAGENTSTATE; *pdwProxyRequests++ = LINEPROXYREQUEST_SETAGENTACTIVITY; *pdwProxyRequests++ = LINEPROXYREQUEST_GETAGENTSTATUS; *pdwProxyRequests++ = LINEPROXYREQUEST_GETAGENTCAPS; *pdwProxyRequests++ = LINEPROXYREQUEST_GETAGENTACTIVITYLIST; *pdwProxyRequests = LINEPROXYREQUEST_GETAGENTGROUPLIST; lResult = lineOpen(g.hLineApp, dwDeviceID, &pAgent->hLine, TAPI_CURRENT_VERSION, 0, 0, LINEOPENOPTION_PROXY | LINECALLPRIVILEGE_MONITOR, LINEMEDIAMODE_INTERACTIVEVOICE, pLCP); ACDFree(pLCP); if (lResult) { // ACDFree(pAgent->lpszName); ACDFree(pAgent); } pLDC = LineGetDevCaps(g.hLineApp, pAgent->dwDeviceID); if (!pLDC) { return FALSE; } // alloc memory for address specific info pAgent->pAddressInfo = (PADDRESSINFO)ACDAlloc(sizeof(ADDRESSINFO) * pLDC->dwNumAddresses); pAgent->dwNumAddresses = pLDC->dwNumAddresses; ACDFree(pLDC); // increment number of agents g.dwNumAgents++; return pAgent; } ////////////////////////////////////////////////////////////////////////// // // BOOL DeleteAgent(PAGENT pAgent) // // Frees all memory associated with pAgent, removes // agent from group lists, and remove pAgent from // global agent list // ////////////////////////////////////////////////////////////////////////// BOOL DeleteAgent(PAGENT pAgent) { PGROUP pGroup; lineClose(pAgent->hLine); // free name ACDFree(pAgent->lpszName); ACDFree(pAgent->lpszNumber); // free address info ACDFree(pAgent->pAddressInfo); pGroup = g.pGroups; // walk through groups and remove from // group list if in group list while (pGroup) { if (IsAgentInList(pGroup->pAgentList, pAgent)) { RemoveFromGroupList(pGroup, pAgent); } pGroup = pGroup->pNext; } // finally, remove pAgent from global list DeleteStruct((PGENERICSTRUCT *)&g.pAgents, (PGENERICSTRUCT)pAgent); return TRUE; } ////////////////////////////////////////////////////////////////////////// // // BOOL DeleteGroup(PGROUP pGroup) // // Frees memory assocated with pGroup, and removes the structure from // the global list // ////////////////////////////////////////////////////////////////////////// BOOL DeleteGroup(PGROUP pGroup) { PLISTITEM pList, pListNext; lineClose(pGroup->hLine); ACDFree(pGroup->lpszName); pList = pGroup->pAgentList; while (pList) { pListNext = pList->pNext; ACDFree(pList); pList = pListNext; } DeleteStruct((PGENERICSTRUCT *)&g.pGroups, (PGENERICSTRUCT)pGroup); return TRUE; } ////////////////////////////////////////////////////////////////////////// // // BOOL InsertIntoGroupList(PGROUP pGroup, // PAGENT pAgent) // // Insert an agent in a group // ////////////////////////////////////////////////////////////////////////// BOOL InsertIntoGroupList(PGROUP pGroup, PAGENT pAgent) { PLISTITEM pListItem; pListItem = (PLISTITEM)ACDAlloc(sizeof(LISTITEM)); pListItem->dwKey = LISTKEY; pListItem->dwSize = sizeof(LISTITEM); pListItem->pAgent = pAgent; InsertStruct((PGENERICSTRUCT *)&pGroup->pAgentList, (PGENERICSTRUCT)pListItem); return TRUE; } ////////////////////////////////////////////////////////////////////////// // // BOOL RemoveFromGroupList(PGROUP pGroup, // // remove an agent from a group's list // ////////////////////////////////////////////////////////////////////////// BOOL RemoveFromGroupList(PGROUP pGroup, PAGENT pAgent) { PLISTITEM pList; pList = pGroup->pAgentList; while (pList) { if (pList->pAgent == pAgent) { break; } pList = pList->pNext; } if (!pList) { return FALSE; } DeleteStruct((PGENERICSTRUCT *)&pGroup->pAgentList, (PGENERICSTRUCT)pList); return TRUE; } //////////////////////////////////////////////////////////////////////////////// // //PLISTITEM IsAgentInList(PLISTITEM pList, // PAGENT pAgent) // //////////////////////////////////////////////////////////////////////////////// PLISTITEM IsAgentInList(PLISTITEM pList, PAGENT pAgent) { while (pList) { if (pList->pAgent == pAgent) { return pList; } pList = pList->pNext; } return NULL; } //////////////////////////////////////////////////////////////////////////////// // // PAGENT GetAgentFromName(LPTSTR lpszName) // //////////////////////////////////////////////////////////////////////////////// PAGENT GetAgentFromName(LPTSTR lpszName) { PAGENT pHold; pHold = g.pAgents; while (pHold) { if (!lstrcmpi(pHold->lpszName, lpszName)) { return pHold; } pHold = pHold->pNext; } return NULL; } /////////////////////////////////////////////////////////////////////////////// // // PAGENT GetAgentFromhLine(HLINE hLine) // /////////////////////////////////////////////////////////////////////////////// PAGENT GetAgentFromhLine(HLINE hLine) { PAGENT pAgent; pAgent = g.pAgents; while (pAgent) { if (pAgent->hLine == hLine) { return pAgent; } pAgent = pAgent->pNext; } return NULL; } /////////////////////////////////////////////////////////////////////////////// // // DWORD GetDeviceID(DWORD dwPermID) // /////////////////////////////////////////////////////////////////////////////// DWORD GetDeviceID(DWORD dwPermID) { DWORD dwCount; for (dwCount = 0; dwCount < g.dwNumDevs; dwCount++) { if (g.pdwPermIDs[dwCount] == dwPermID) { return dwCount; } } return (DWORD)-1; } /////////////////////////////////////////////////////////////////////////////// // // **************TAPI WRAPPER FUNCTIONS************** // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // LineGetAddressCaps() // /////////////////////////////////////////////////////////////////////////////// LINEADDRESSCAPS * LineGetAddressCaps (HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAddressID) { LONG lRetVal; LINEADDRESSCAPS * pLineAddressCaps; static DWORD dwMaxNeededSize = sizeof(LINEADDRESSCAPS); // Allocate an initial block of memory for the LINEADDRESSCAPS structure, // which may or may not be big enough to hold all of the information. // pLineAddressCaps = ACDAlloc(dwMaxNeededSize); for (;;) { if (pLineAddressCaps == NULL) { return NULL; } pLineAddressCaps->dwTotalSize = dwMaxNeededSize; // Try (or retry) to get the LINEADDRESSCAPS information // lRetVal = lineGetAddressCaps(hLineApp, dwDeviceID, dwAddressID, TAPI_CURRENT_VERSION, 0, pLineAddressCaps); if (lRetVal < 0) { ACDFree((HLOCAL)pLineAddressCaps); return NULL; } // If the currently allocated LINEADDRESSCAPS memory block was big // enough, we're all done, else we need to realloc the memory block // and try again. // if (pLineAddressCaps->dwNeededSize <= dwMaxNeededSize) { return pLineAddressCaps; } else { dwMaxNeededSize = pLineAddressCaps->dwNeededSize; pLineAddressCaps = ACDReAlloc((HLOCAL)pLineAddressCaps, dwMaxNeededSize); } } } /////////////////////////////////////////////////////////////////////////////// // // LineGetCallInfo() // /////////////////////////////////////////////////////////////////////////////// LINECALLINFO * LineGetCallInfo (HCALL hCall) { LONG lRetVal; LINECALLINFO * pLineCallInfo; static DWORD dwMaxNeededSize = sizeof(LINECALLINFO); // Allocate an initial block of memory for the LINECALLINFO structure, // which may or may not be big enough to hold all of the information. // pLineCallInfo = ACDAlloc(dwMaxNeededSize); for (;;) { if (pLineCallInfo == NULL) { return NULL; } pLineCallInfo->dwTotalSize = dwMaxNeededSize; // Try (or retry) to get the LINECALLINFO information // lRetVal = lineGetCallInfo(hCall, pLineCallInfo); if (lRetVal < 0) { ACDFree((HLOCAL)pLineCallInfo); return NULL; } // If the currently allocated LINECALLINFO memory block was big // enough, we're all done, else we need to realloc the memory block // and try again. // if (pLineCallInfo->dwNeededSize <= dwMaxNeededSize) { return pLineCallInfo; } else { dwMaxNeededSize = pLineCallInfo->dwNeededSize; pLineCallInfo = ACDReAlloc((HLOCAL)pLineCallInfo, dwMaxNeededSize); } } } /////////////////////////////////////////////////////////////////////////////// // // LineGetDevCaps() // /////////////////////////////////////////////////////////////////////////////// LINEDEVCAPS * LineGetDevCaps (HLINEAPP hLineApp, DWORD dwDeviceID) { LONG lRetVal; LINEDEVCAPS * pLineDevCaps; static DWORD dwMaxNeededSize = sizeof(LINEDEVCAPS); pLineDevCaps = ACDAlloc(dwMaxNeededSize); for (;;) { if (pLineDevCaps == NULL) { return NULL; } pLineDevCaps->dwTotalSize = dwMaxNeededSize; lRetVal = lineGetDevCaps(hLineApp, dwDeviceID, TAPI_CURRENT_VERSION, 0, pLineDevCaps); if (lRetVal < 0) { ACDFree((HLOCAL)pLineDevCaps); return NULL; } if (pLineDevCaps->dwNeededSize <= dwMaxNeededSize) { return pLineDevCaps; } else { dwMaxNeededSize = pLineDevCaps->dwNeededSize; pLineDevCaps = ACDReAlloc((HLOCAL)pLineDevCaps, dwMaxNeededSize); } } } /////////////////////////////////////////////////////////////////////////////// // // LineGetID() // /////////////////////////////////////////////////////////////////////////////// VARSTRING * LineGetID (HLINE hLine, DWORD dwAddressID, HCALL hCall, DWORD dwSelect, LPCTSTR lpszDeviceClass) { LONG lRetVal; VARSTRING * pVarString; static DWORD dwMaxNeededSize = sizeof(VARSTRING); // Allocate an initial block of memory for the VARSTRING structure, // which may or may not be big enough to hold all of the information. // pVarString = ACDAlloc(dwMaxNeededSize); for (;;) { if (pVarString == NULL) { return NULL; } pVarString->dwTotalSize = dwMaxNeededSize; // Try (or retry) to get the VARSTRING information // lRetVal = lineGetID(hLine, dwAddressID, hCall, dwSelect, pVarString, lpszDeviceClass); if (lRetVal < 0) { ACDFree(pVarString); return NULL; } // If the currently allocated VARSTRING memory block was big // enough, we're all done, else we need to realloc the memory block // and try again. // if (pVarString->dwNeededSize <= dwMaxNeededSize) { return pVarString; } else { dwMaxNeededSize = pVarString->dwNeededSize; pVarString = ACDReAlloc((HLOCAL)pVarString, dwMaxNeededSize); } } } /////////////////////////////////////////////////////////////////////////////// // // LineGetCallStatus() // /////////////////////////////////////////////////////////////////////////////// LINECALLSTATUS * LineGetCallStatus (HCALL hCall) { LONG lRetVal; LINECALLSTATUS * pLineCallStatus; static DWORD dwMaxNeededSize = sizeof(LINECALLSTATUS); // Allocate an initial block of memory for the LINECALLSTATUS structure, // which may or may not be big enough to hold all of the information. // pLineCallStatus = ACDAlloc(dwMaxNeededSize); while (TRUE) { if (pLineCallStatus == NULL) { return NULL; } pLineCallStatus->dwTotalSize = dwMaxNeededSize; // Try (or retry) to get the LINECALLSTATUS information // lRetVal = lineGetCallStatus(hCall, pLineCallStatus); if (lRetVal < 0) { ACDFree((HLOCAL)pLineCallStatus); return NULL; } // If the currently allocated LINECALLSTATUS memory block was big // enough, we're all done, else we need to realloc the memory block // and try again. // if (pLineCallStatus->dwNeededSize <= dwMaxNeededSize) { return pLineCallStatus; } else { dwMaxNeededSize = pLineCallStatus->dwNeededSize; pLineCallStatus = ACDReAlloc((HLOCAL)pLineCallStatus, dwMaxNeededSize); } } }