www.pudn.com > TAPI会议系统.rar > tapiline.cpp
// ----------------------------------------------------------------------------
// IP Office SDK (c) Avaya 2001. All rights reserved.
//
// PROJECT: TapiSample
// FILE: tapiline.cpp
// CREATED: Geoff Froud, based on previous work by Carl Muller
//
// See tapisample.h for an explanation of this program.
//
// This is the implementation file for the tapi support classes.
// See tapiline.h for the definition of this class
//
// ----------------------------------------------------------------------------
#include "stdafx.h"
#include "tapisample.h"
#include "tapisampleDlg.h"
#include "tapidescribe.h"
// ============================================================================
// Static functions
// ============================================================================
// ----------------------------------------------------------------------------
// Get a string from a TAPI structure
void getTapiString(CString& result, void *ptr, DWORD Size, DWORD Offset)
{
if (Size > 0)
{
char *buffer = result.GetBufferSetLength(Size + 1);
memcpy(buffer, &((BYTE *) ptr)[Offset], Size);
buffer[Size] = 0;
result.ReleaseBuffer();
}
else
result.Empty();
}
// ----------------------------------------------------------------------------
// Get device capabilities information from TAPI
// Note: The calling function must delete the info structure later on!
HRESULT loopLineGetDevCaps(HLINEAPP hLineApp, DWORD DeviceID,
DWORD APIVersion, DWORD ExtVersion, LINEDEVCAPS*& pLineDevCaps)
{
size_t CurrentSize = 512; // Starting value - usually big enough
HRESULT hr;
for (;;)
{
// Allocate some memory for the call
pLineDevCaps = (LINEDEVCAPS *) new BYTE[CurrentSize];
ZeroMemory(&pLineDevCaps[0], CurrentSize);
pLineDevCaps->dwTotalSize = CurrentSize;
// Ask TAPI for some information
hr = ::lineGetDevCaps(hLineApp, DeviceID, APIVersion, ExtVersion, pLineDevCaps);
// Cope with variable length structures
if (hr == LINEERR_STRUCTURETOOSMALL)
{
if (pLineDevCaps->dwNeededSize <= 0)
break;
CurrentSize = pLineDevCaps->dwNeededSize;
delete [] pLineDevCaps;
pLineDevCaps = NULL;
}
else
break;
}
return hr;
}
// ----------------------------------------------------------------------------
// Get call information from TAPI
// Note: The calling function must delete the info structure later on!
HRESULT loopLineGetCallInfo(HCALL hCall, LINECALLINFO*& pCallInfo)
{
size_t CurrentSize = 512; // Starting value - usually big enough
HRESULT hr;
for (;;)
{
// Allocate some memory for the call
pCallInfo = (LINECALLINFO *) new BYTE[CurrentSize];
ZeroMemory(&pCallInfo[0], CurrentSize);
pCallInfo->dwTotalSize = CurrentSize;
// Ask TAPI for some information
hr = ::lineGetCallInfo(hCall, pCallInfo);
// Cope with variable length structures
if (hr == LINEERR_STRUCTURETOOSMALL)
{
if (pCallInfo->dwNeededSize <= 0)
break;
CurrentSize = pCallInfo->dwNeededSize;
delete [] pCallInfo;
pCallInfo = NULL;
}
else
break;
}
return hr;
}
// ----------------------------------------------------------------------------
// Get identification information from TAPI
HRESULT loopLineGetID(DWORD& result, HLINE hLine, DWORD AddressID,
HCALL hCall, DWORD Select, LPCSTR pszDeviceClass)
{
VARSTRING* pVarString = NULL;
result = 0xffffffff;
size_t CurrentSize = 512; // Starting value - usually big enough
HRESULT hr;
for (;;)
{
// Allocate some memory for the call
pVarString = (VARSTRING *) new BYTE[CurrentSize];
ZeroMemory(&pVarString[0], CurrentSize);
pVarString->dwTotalSize = CurrentSize;
// Ask TAPI for some information
hr = ::lineGetID(hLine, AddressID, hCall, Select, pVarString, pszDeviceClass);
// Cope with variable length structures
if (hr == LINEERR_STRUCTURETOOSMALL)
{
if (pVarString->dwNeededSize <= 0)
break;
CurrentSize = pVarString->dwNeededSize;
delete [] pVarString;
pVarString = NULL;
}
else
break;
}
if (hr == S_OK)
result = ((DWORD *) (((BYTE *) pVarString) + pVarString->dwStringOffset))[0];
delete [] pVarString;
return hr;
}
// ----------------------------------------------------------------------------
// Get address capabilities information from TAPI
HRESULT loopLineGetAddressCaps(HLINEAPP hLineApp, DWORD DeviceID, DWORD AddressID,
DWORD APIVersion, DWORD ExtVersion, LINEADDRESSCAPS*& pAddressCaps)
{
size_t CurrentSize = 512; // Starting value - usually big enough
HRESULT hr;
for (;;)
{
// Allocate some memory for the call
pAddressCaps = (LINEADDRESSCAPS *) new BYTE[CurrentSize];
ZeroMemory(&pAddressCaps[0], CurrentSize);
pAddressCaps->dwTotalSize = CurrentSize;
// Ask TAPI for some information
hr = ::lineGetAddressCaps(hLineApp, DeviceID, AddressID, APIVersion,
ExtVersion, pAddressCaps);
// Cope with variable length structures
if (hr == LINEERR_STRUCTURETOOSMALL)
{
if (pAddressCaps->dwNeededSize <= 0)
break;
CurrentSize = pAddressCaps->dwNeededSize;
delete [] pAddressCaps;
pAddressCaps = NULL;
}
else
break;
}
return hr;
}
// Get address capabilities information from TAPI
HRESULT loopLineGetAddressStatus(HLINE hLine, DWORD AddressID,
LINEADDRESSSTATUS*& pAddressStatus)
{
size_t CurrentSize = 512; // Starting value - usually big enough
HRESULT hr;
for (;;)
{
// Allocate some memory for the call
pAddressStatus = (LINEADDRESSSTATUS *) new BYTE[CurrentSize];
ZeroMemory(&pAddressStatus[0], CurrentSize);
pAddressStatus->dwTotalSize = CurrentSize;
// Ask TAPI for some information
hr = ::lineGetAddressStatus(hLine, AddressID, pAddressStatus);
// Cope with variable length structures
if (hr == LINEERR_STRUCTURETOOSMALL)
{
if (pAddressStatus->dwNeededSize <= 0)
break;
CurrentSize = pAddressStatus->dwNeededSize;
delete [] pAddressStatus;
pAddressStatus = NULL;
}
else
break;
}
return hr;
}
// ----------------------------------------------------------------------------
// Get call status information from TAPI
HRESULT loopLineGetCallStatus(HCALL hCall, LINECALLSTATUS*& pCallStatus)
{
size_t CurrentSize = 512; // Starting value - usually big enough
HRESULT hr;
for (;;)
{
// Allocate some memory for the call
pCallStatus = (LINECALLSTATUS *) new BYTE[CurrentSize];
ZeroMemory(&pCallStatus[0], CurrentSize);
pCallStatus->dwTotalSize = CurrentSize;
// Ask TAPI for some information
hr = ::lineGetCallStatus(hCall, pCallStatus);
// Cope with variable length structures
if (hr == LINEERR_STRUCTURETOOSMALL)
{
if (pCallStatus->dwNeededSize <= 0)
break;
CurrentSize = pCallStatus->dwNeededSize;
delete [] pCallStatus;
pCallStatus = NULL;
}
else
break;
}
return hr;
}
// ----------------------------------------------------------------------------
// Line Event Handling
static void CALLBACK TapiLineCallback(
DWORD dwDevice,
DWORD nMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2,
DWORD dwParam3)
{
switch( nMsg )
{
case LINE_CREATE:
// We have been asked to create a line. We can't do this, the number
// of lines is dictated by the IP Office Telephony Service Provider, so
// we'll ignore this request.
break;
case LINE_REQUEST:
// We have received an assisted telephony request. This application
// doesn't handle assisted telephony requests, so we'll ignore it.
break;
default:
// We have received an event relevant to an existing line
TapiLine* pLine = (TapiLine*) dwInstance;
if (pLine)
pLine->OnEvent(dwDevice, nMsg, dwParam1, dwParam2, dwParam3);
break;
}
}
// ============================================================================
// TAPI line class
// ============================================================================
// ----------------------------------------------------------------------------
// Create a TAPI line wrapper object
TapiLine::TapiLine(TapiApplication &Parent) :
m_Parent(Parent)
{
m_LineID = 0;
m_hLine = 0;
m_hConnectedCall = 0;
m_hWaitingCall = 0;
m_hHeldCall = 0;
m_hPendingCall = 0;
m_hConferenceCall = 0;
m_hConsultationCall = 0;
}
// ----------------------------------------------------------------------------
// Destroy a TAPI line wrapper object
TapiLine::~TapiLine()
{
if (m_hLine)
::lineClose(m_hLine);
m_hLine = 0;
}
// ----------------------------------------------------------------------------
// Ask TAPI to make a call - only works if we are not on a call.
void TapiLine::MakeCall(LPCTSTR pszAddress)
{
if ((m_hConnectedCall == 0) && (m_hWaitingCall == 0)) // No currently active call
{
// Calculate the size of the parameter structure, and allocate it.
size_t cbDestAddress = strlen(pszAddress) + 1;
size_t cbCallParams = sizeof(LINECALLPARAMS) + cbDestAddress;
LINECALLPARAMS* pCallParams = (LINECALLPARAMS*)(new BYTE[cbCallParams]);
// Setup the parameters
if (pCallParams)
{
ZeroMemory(pCallParams, cbCallParams);
pCallParams->dwTotalSize = cbCallParams;
pCallParams->dwBearerMode = LINEBEARERMODE_VOICE;
pCallParams->dwMinRate = 0; // Use device default
pCallParams->dwMaxRate = 0; // Use device default
pCallParams->dwMediaMode = LINEMEDIAMODE_INTERACTIVEVOICE;
pCallParams->dwCallParamFlags = 0; // No flags
pCallParams->dwAddressMode = LINEADDRESSMODE_ADDRESSID;
pCallParams->dwAddressID = 0; // Use the main (and only) line address
// Variable length strings
pCallParams->dwDisplayableAddressSize = cbDestAddress;
pCallParams->dwDisplayableAddressOffset = sizeof(LINECALLPARAMS);
char* pszDisplayableAddress = (char*)((BYTE*)pCallParams + sizeof(LINECALLPARAMS));
strcpy(pszDisplayableAddress, pszAddress);
}
// Ask TAPI to make the call
HRESULT tr = ::lineMakeCall(m_hLine, &m_hWaitingCall, pszAddress, 0, pCallParams);
delete[] pCallParams;
if (tr > 0)
{
// Store the request details so that we can match up the
// asynchronous reply from TAPI.
REQUEST_INFO ri = { "MakeCall", m_hWaitingCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "MakeCall");
}
else
m_Parent.m_Dlg.AddText("Error(MakeCall: There is already an Active call)");
}
// ----------------------------------------------------------------------------
// Drop the line - only works if a call is connected or an outgoing call is
// alerting
void TapiLine::DropCall()
{
if (m_hWaitingCall) // Outgoing call
{
HRESULT tr = ::lineDrop(m_hWaitingCall, NULL, 0);
if (tr > 0)
{
// Store the request details so that we can match up the
// asynchronous reply from TAPI.
REQUEST_INFO ri = { "DropCall", m_hWaitingCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "DropCall");
}
else if (m_hConnectedCall) // Active call
{
HRESULT tr = ::lineDrop(m_hConnectedCall, NULL, 0);
if (tr > 0)
{
// Store the request details so that we can match up the
// asynchronous reply from TAPI.
REQUEST_INFO ri = { "DropCall", m_hConnectedCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "DropCall");
}
else
m_Parent.m_Dlg.AddText("Error(DropCall: No Active Call)");
}
// ----------------------------------------------------------------------------
// Hold the current call - only works if call is currently pending
void TapiLine::AnswerCall()
{
if (m_hPendingCall)
{
HRESULT tr = ::lineAnswer(m_hPendingCall, NULL, 0);
if (tr > 0)
{
REQUEST_INFO ri = { "AnswerCall", m_hPendingCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "AnswerCall");
}
else
m_Parent.m_Dlg.AddText("Error(AnswerCall: No Pending Call)");
}
// ----------------------------------------------------------------------------
// Hold the current call - only works if call is connected
void TapiLine::HoldCall()
{
if (m_hConnectedCall)
{
HRESULT tr = ::lineHold(m_hConnectedCall);
if (tr > 0)
{
REQUEST_INFO ri = { "HoldCall", m_hConnectedCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "HoldCall");
}
else
m_Parent.m_Dlg.AddText("Error(HoldCall: No Active Call)");
}
// ----------------------------------------------------------------------------
// Retrieve the call from hold - only works if call is currently proceeding
void TapiLine::UnholdCall()
{
if (m_hHeldCall)
{
HRESULT tr = ::lineUnhold(m_hHeldCall);
if (tr > 0)
{
REQUEST_INFO ri = { "UnholdCall", m_hHeldCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "UnholdCall");
}
else
m_Parent.m_Dlg.AddText("Error(UnholdCall: No Held Call)");
}
// ----------------------------------------------------------------------------
// Conference the current call with the call on hold - only works if call
// is currently connected and there is a call on hold.
void TapiLine::ConferenceCall()
{
if (m_hConnectedCall && m_hHeldCall)
{
HRESULT tr = ::lineCompleteTransfer(m_hHeldCall, m_hConnectedCall, &m_hConferenceCall,
LINETRANSFERMODE_CONFERENCE);
if (tr > 0)
{
REQUEST_INFO ri = { "ConferenceCall", m_hConferenceCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "ConferenceCall");
if (m_hConferenceCall == 0)
m_Parent.m_Dlg.AddText("Error(ConferenceCall: No Conference Call Handle returned)");
}
else
{
if (!m_hConnectedCall)
m_Parent.m_Dlg.AddText("Error(ConferenceCall: No Active Call)");
if (!m_hHeldCall)
m_Parent.m_Dlg.AddText("Error(ConferenceCall: No Held Call)");
}
}
// ----------------------------------------------------------------------------
// Transfer the call on hold to the current call
// - only works if call is currently connected
void TapiLine::BlindTransferCall(LPCTSTR pszAddress)
{
if (m_hConnectedCall)
{
HRESULT tr = ::lineBlindTransfer(m_hConnectedCall, pszAddress, 0);
if (tr > 0)
{
REQUEST_INFO ri = { "BlindTransferCall", m_hConnectedCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "BlindTransferCall");
}
else
m_Parent.m_Dlg.AddText("Error(BlindTransferCall: No Active Call)");
}
// ----------------------------------------------------------------------------
// If the current call is connected, then lineSetupTransfer will put the call
// on hold and create a new consultation call. If the current call is already
// on hold, then lineSetupTransfer will just create a new consultation call.
void TapiLine::SetupTransfer()
{
if (m_hConnectedCall)
{
HRESULT tr = ::lineSetupTransfer(m_hConnectedCall, &m_hConsultationCall, 0);
if (tr > 0)
{
REQUEST_INFO ri = { "SetupTransfer", m_hConnectedCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "SetupTransfer");
}
else if (m_hHeldCall)
{
HRESULT tr = ::lineSetupTransfer(m_hHeldCall, &m_hConsultationCall, 0);
if (tr > 0)
{
REQUEST_INFO ri = { "SetupTransfer", m_hHeldCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "SetupTransfer");
}
else
m_Parent.m_Dlg.AddText("Error(lineSetupTransfer: No Active or Held Call)");
}
// ----------------------------------------------------------------------------
// Dial will dial the given number on the currently active call, where the call
// has been created using lineSetupTransfer.
void TapiLine::Dial(LPCTSTR pszAddress)
{
if (!m_hHeldCall)
m_Parent.m_Dlg.AddText("Error(lineSetupTransfer: No Held Call)");
else if (!m_hConsultationCall)
m_Parent.m_Dlg.AddText("Error(lineSetupTransfer: No Consultation Call)");
else
{
HRESULT tr = ::lineDial(m_hConsultationCall, pszAddress, 0);
if (tr > 0)
{
REQUEST_INFO ri = { "Dial", m_hConnectedCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "Dial");
}
}
// ----------------------------------------------------------------------------
// CompleteTransfer will transfer the held call to the currently connected call
void TapiLine::CompleteTransfer()
{
if (!m_hHeldCall)
m_Parent.m_Dlg.AddText("Error(lineCompleteTransfer: No Held Call)");
else
if (!m_hConsultationCall)
{
if(!m_hConnectedCall)
{
m_Parent.m_Dlg.AddText("Error(lineSetupTransfer: No Consultation Call)");
return;
}
else m_hConsultationCall = m_hConnectedCall;
}
HRESULT tr = ::lineCompleteTransfer(m_hHeldCall, m_hConsultationCall, NULL, LINETRANSFERMODE_TRANSFER);
if (tr > 0)
{
REQUEST_INFO ri = { "CompleteTransfer", m_hConnectedCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "CompleteTransfer");
}
// ----------------------------------------------------------------------------
// SwapHold puts the currently active call on hold and retrieves the held call.
void TapiLine::SwapHold()
{
if (!m_hHeldCall)
m_Parent.m_Dlg.AddText("Error(lineSwapHold: No Held Call)");
else if (!m_hConnectedCall)
m_Parent.m_Dlg.AddText("Error(lineSwapHold: No Active Call)");
else
{
HRESULT tr = ::lineSwapHold(m_hConnectedCall, m_hHeldCall);
if (tr > 0)
{
REQUEST_INFO ri = { "SwapHold", m_hConnectedCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "SwapHold");
}
}
// ----------------------------------------------------------------------------
// Park will park a call. Note that only a directed park will succeed on
// IP Office
void TapiLine::Park(LPCTSTR pszAddress)
{
if (!m_hConnectedCall)
m_Parent.m_Dlg.AddText("Error(linePark: No Active Call)");
else
{
HRESULT tr = 0;
if (pszAddress)
tr = ::linePark(m_hConnectedCall, LINEPARKMODE_DIRECTED, pszAddress, NULL);
else
{
DWORD size = 512;
VARSTRING* pAddress = (VARSTRING*) new char[size]; // This should be big enough
ZeroMemory(&pAddress[0], size);
pAddress->dwTotalSize = size;
tr = ::linePark(m_hConnectedCall, LINEPARKMODE_NONDIRECTED, NULL, pAddress);
}
if (tr > 0)
{
REQUEST_INFO ri = { "Park", m_hConnectedCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "Park");
}
}
// ----------------------------------------------------------------------------
// Unpark retrieves a parked call from the given park address
void TapiLine::Unpark(LPCTSTR pszAddress)
{
HRESULT tr = ::lineUnpark(m_hLine, 0, &m_hConnectedCall, pszAddress);
if (tr > 0)
{
REQUEST_INFO ri = { "Unpark", m_hConnectedCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "Unpark");
}
// ----------------------------------------------------------------------------
// This function redirects an alerting call to the given extension
void TapiLine::Redirect(LPCTSTR pszAddress)
{
if (!m_hPendingCall)
m_Parent.m_Dlg.AddText("Error(linePark: No Offering Call)");
else
{
HRESULT tr = ::lineRedirect(m_hPendingCall, pszAddress, 0);
if (tr > 0)
{
REQUEST_INFO ri = { "Redirect", m_hPendingCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "Redirect");
}
}
// ----------------------------------------------------------------------------
// AddToConference adds the connected call to a held conference
void TapiLine::AddToConference()
{
if (m_hConnectedCall && m_hHeldCall)//m_hConferenceCall)
{
HRESULT tr = ::lineAddToConference(m_hHeldCall/*m_hConferenceCall*/, m_hConnectedCall);
if (tr > 0)
{
REQUEST_INFO ri = { "AddToConference", m_hConferenceCall };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "AddToConference");
m_hLastCallIntoConf = m_hConnectedCall;
}
else
{
if (!m_hConnectedCall)
m_Parent.m_Dlg.AddText("Error(lineAddToConference: No Active Call)");
if (!m_hConferenceCall)
m_Parent.m_Dlg.AddText("Error(lineAddToConference: No Conference Call)");
}
}
// ----------------------------------------------------------------------------
// RemoveFromConference removes the last call added to the conference
void TapiLine::RemoveFromConference()
{
if (m_hLastCallIntoConf)
{
HRESULT tr = ::lineRemoveFromConference(m_hLastCallIntoConf);
if (tr > 0)
{
REQUEST_INFO ri = { "RemoveFromConference", m_hLastCallIntoConf };
m_Requests.SetAt(tr, ri);
}
m_Parent.CheckError(tr, "RemoveFromConference");
}
else
{
if (!m_hLastCallIntoConf)
m_Parent.m_Dlg.AddText("Error(lineRemoveFromConference: No Active Call)");
}
}
// ----------------------------------------------------------------------------
// Retrieves the address status for the TAPI line (IP Office lines only have
// one address) and displays the details.
void TapiLine::AddressStatus()
{
LINEADDRESSSTATUS* pAddressStatus = NULL;
loopLineGetAddressStatus(m_hLine, 0, pAddressStatus);
if (pAddressStatus)
{
CString txt;
txt.Format("lineAddressStatus: NumInUse<%d> NumActiveCalls<%d> NumOnHoldCalls<%d> NumOnHoldPendCalls<%d> NumRingsNoAnswer<%d>",
pAddressStatus->dwNumInUse, pAddressStatus->dwNumActiveCalls,
pAddressStatus->dwNumOnHoldCalls, pAddressStatus->dwNumOnHoldPendCalls,
pAddressStatus->dwNumRingsNoAnswer);
m_Parent.m_Dlg.AddText(txt);
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_FORWARD)
m_Parent.m_Dlg.AddText("lineAddressStatus: The address can be forwarded.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_MAKECALL)
m_Parent.m_Dlg.AddText("lineAddressStatus: An outgoing call can be placed on the address.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_PICKUP)
m_Parent.m_Dlg.AddText("lineAddressStatus: A call can be picked up at the address.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_PICKUPDIRECT)
m_Parent.m_Dlg.AddText("lineAddressStatus: The linePickup function can be used to pick up a call on a specific address.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_PICKUPGROUP)
m_Parent.m_Dlg.AddText("lineAddressStatus: The linePickup function can be used to pick up a call in the group.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_PICKUPHELD)
m_Parent.m_Dlg.AddText("lineAddressStatus: The linePickup function (with a null destination address) can be used to pick up a call that is held on the address.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_PICKUPWAITING)
m_Parent.m_Dlg.AddText("lineAddressStatus: The linePickup function (with a null destination address) can be used to pick up a call waiting call.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_SETMEDIACONTROL)
m_Parent.m_Dlg.AddText("lineAddressStatus: Media control can be set on this address.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_SETTERMINAL)
m_Parent.m_Dlg.AddText("lineAddressStatus: The terminal modes for this address can be set.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_SETUPCONF)
m_Parent.m_Dlg.AddText("lineAddressStatus: A conference call with a NULL initial call can be set up at this address.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_UNCOMPLETECALL)
m_Parent.m_Dlg.AddText("lineAddressStatus: Call completion requests can be canceled at this address.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_UNPARK)
m_Parent.m_Dlg.AddText("lineAddressStatus: Calls can be unparked using this address.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_FORWARDDND)
m_Parent.m_Dlg.AddText("lineAddressStatus: The lineForward function (with an empty destination address) can be used to turn on the Do Not Disturb feature on the address. LINEADDRFEATURE_FORWARD will also be set.");
if (pAddressStatus->dwAddressFeatures & LINEADDRFEATURE_FORWARDFWD)
m_Parent.m_Dlg.AddText("lineAddressStatus: The lineForward function can be used to forward calls on the address to other numbers.");
}
delete [] pAddressStatus;
}
// ----------------------------------------------------------------------------
// Retrieves call info for one of the call handles (see the order below) and
// displays the details.
void TapiLine::GetCallInfo()
{
HCALL hCall = NULL;
if (m_hConnectedCall)
hCall = m_hConnectedCall;
else if (m_hWaitingCall)
hCall = m_hWaitingCall;
else if (m_hHeldCall)
hCall = m_hHeldCall;
else if (m_hPendingCall)
hCall = m_hPendingCall;
else if (m_hConferenceCall)
hCall = m_hConferenceCall;
else if (m_hConsultationCall)
hCall = m_hConsultationCall;
if (hCall)
{
OnCallInfo(hCall, 0);
}
}
// ----------------------------------------------------------------------------
// Open a specified TAPI line
HRESULT TapiLine::Open(DWORD LineID, DWORD CallPrivilege, DWORD MediaModes)
{
// Reset the line
ASSERT(m_hLine == 0);
m_hLine = 0;
// Ask TAPI for a new line
HLINE hNewLine;
HRESULT tr = ::lineOpen(m_Parent.m_hLineApp, LineID,
&hNewLine, m_Parent.m_ApiVersions[LineID],
0, (DWORD)this, CallPrivilege, MediaModes, 0);
m_Parent.CheckError(tr, "Open");
if (S_OK == tr)
{
// Use the results
m_hLine = hNewLine;
m_LineID = LineID;
ASSERT(m_hLine);
// Set all status messages
tr = ::lineSetStatusMessages(m_hLine, LINEDEVSTATE_ALL, LINEADDRESSSTATE_ALL);
m_Parent.CheckError(tr, "SetStatusMessages");
}
return tr;
}
// ----------------------------------------------------------------------------
// Retrieve the status of one of the calls (see order below) and display the
// details.
void TapiLine::GetCallStatus()
{
LINECALLSTATUS* pCallStatus;
HCALL hCall = 0;
if (m_hConnectedCall)
hCall = m_hConnectedCall;
if (m_hWaitingCall)
hCall = m_hWaitingCall;
if (m_hHeldCall)
hCall = m_hHeldCall;
if (m_hPendingCall)
hCall = m_hPendingCall;
if (m_hConferenceCall)
hCall = m_hConferenceCall;
if (hCall)
{
HRESULT tr = loopLineGetCallStatus(hCall, pCallStatus);
if (tr < 0)
m_Parent.CheckError(tr, "lineGetCallStatus");
else
{
CString state;
DescribeCallState(state, pCallStatus->dwCallState);
CString txt;
txt.Format("Call Status: %s", (LPCTSTR)state);
m_Parent.m_Dlg.AddText(txt);
delete [] pCallStatus;
}
}
}
// ----------------------------------------------------------------------------
// Log On an extension
void TapiLine::LogOn(LPCTSTR pszAddress)
{
TCHAR buffer[10];
buffer[0] = 8;
UINT length = strlen(pszAddress);
for (UINT i=0; i < length; i++)
{
buffer[i + 1] = pszAddress[i];
}
buffer[length + 1] = 0; // NULL terminate
HRESULT tr = ::lineDevSpecific(m_hLine,0,NULL,buffer,length + 2);
m_Parent.CheckError(tr, "LogOn");
}
// ----------------------------------------------------------------------------
// Log Off an extension
void TapiLine::LogOff()
{
TCHAR buffer[3];
buffer[0] = 9;
buffer[1] = 47;
buffer[2] = 0; // NULL terminate
HRESULT tr = ::lineDevSpecific(m_hLine,0,NULL,buffer,3);
m_Parent.CheckError(tr, "LogOff");
}
// ----------------------------------------------------------------------------
// Display the IP Office TAPI Config Dialog
void TapiLine::ConfigDialog()
{
HRESULT tr = ::lineConfigDialog(m_LineID, m_Parent.m_Dlg.m_hWnd, NULL);
m_Parent.CheckError(tr, "ConfigDialog");
}
// ----------------------------------------------------------------------------
// Set the divert destination
void TapiLine::DivertDestination(LPCTSTR pszAddress)
{
TCHAR buffer[10];
buffer[0] = 9;
buffer[1] = 6;
UINT length = strlen(pszAddress);
for (UINT i=0; i < length; i++)
{
buffer[i + 2] = pszAddress[i];
}
buffer[length + 2] = 0; // NULL terminate
HRESULT tr = ::lineDevSpecific(m_hLine,0,NULL,buffer,length + 3);
m_Parent.CheckError(tr, "DivertDestination");
}
// ----------------------------------------------------------------------------
// Set the divert settings, i.e. forwarding or Do Not Disturb
void TapiLine::SetDivertSettings(BOOL FwdAll, BOOL FwdBusy, BOOL FwdNoAnsw, BOOL DND)
{
// Call lineDevSpecific for each of the four divert settings
TCHAR buffer[3];
// The first and last byte are the same for all four
buffer[0] = 9;
buffer[2] = 0; // NULL terminate
// Forward All
buffer[1] = (char)((FwdAll) ? 0 : 1);
HRESULT tr = ::lineDevSpecific(m_hLine,0,NULL,buffer,3);
m_Parent.CheckError(tr, "SetDivertSettings");
// Forward Busy
buffer[1] = (char)((FwdBusy) ? 2 : 3);
tr = ::lineDevSpecific(m_hLine,0,NULL,buffer,3);
m_Parent.CheckError(tr, "SetDivertSettings");
// Forward No Answer
buffer[1] = (char)((FwdNoAnsw) ? 4 : 5);
tr = ::lineDevSpecific(m_hLine,0,NULL,buffer,3);
m_Parent.CheckError(tr, "SetDivertSettings");
// Do Not Disturb
buffer[1] = (char)((DND) ? 7 : 8);
tr = ::lineDevSpecific(m_hLine,0,NULL,buffer,3);
m_Parent.CheckError(tr, "SetDivertSettings");
}
// ----------------------------------------------------------------------------
// Retrieve and display the Divert Settings
void TapiLine::GetDivertSettings()
{
TCHAR buffer[sizeof(LINEDEVSTATUS) + 100];
LPLINEDEVSTATUS lpLineDevStatus = reinterpret_cast(buffer);
lpLineDevStatus->dwTotalSize = sizeof(LINEDEVSTATUS) + 100;
HRESULT tr = ::lineGetLineDevStatus(m_hLine, lpLineDevStatus);
m_Parent.CheckError(tr, "GetDivertSettings");
// Set the pointer to the start of the dev specific data
TCHAR* pDevSpecific = (TCHAR*)lpLineDevStatus + lpLineDevStatus->dwDevSpecificOffset;
CString txt;
CString phoneExt(pDevSpecific);
txt = CString("Divert Settings: Phone Ext(") + phoneExt + CString(")");
// Move the pointer past the phone number
pDevSpecific += phoneExt.GetLength() + 1;
if (pDevSpecific[0]) // Forward On Busy
txt += CString(", Fwd On Busy(On)");
else
txt += CString(", Fwd On Busy(Off)");
if (pDevSpecific[1]) // Forward On No Answer
txt += CString(", Fwd On No Answer(On)");
else
txt += CString(", Fwd On No Answer(Off)");
if (pDevSpecific[2]) // Forward All
txt += CString(", Fwd All(On)");
else
txt += CString(", Fwd All(Off)");
if (pDevSpecific[4]) // Do Not Disturb
txt += CString(", DND(On)");
else
txt += CString(", DND(Off)");
pDevSpecific += 26; // Move past the forward settings and other reserved data
CString userExt(pDevSpecific);
txt += CString(", User Ext(") + userExt + CString(")");
// Move the pointer past the user number
pDevSpecific += userExt.GetLength() + 1;
CString locale(pDevSpecific);
txt += CString(", Locale(") + locale + CString(")");
// Move the pointer past the locale
pDevSpecific += locale.GetLength() + 1;
CString divertDestination(pDevSpecific);
txt += CString(", Divert Dest(") + divertDestination + CString(")");
m_Parent.m_Dlg.AddText(txt);
}
// ----------------------------------------------------------------------------
// Set the App Specific value for a call. See below for the order in which the
// call is selected.
void TapiLine::SetAppSpecific(DWORD num)
{
HCALL hCall = NULL;
if (m_hConnectedCall)
hCall = m_hConnectedCall;
else if (m_hWaitingCall)
hCall = m_hWaitingCall;
else if (m_hHeldCall)
hCall = m_hHeldCall;
else if (m_hPendingCall)
hCall = m_hPendingCall;
else if (m_hConferenceCall)
hCall = m_hConferenceCall;
else if (m_hConsultationCall)
hCall = m_hConsultationCall;
if (hCall)
{
HRESULT tr = ::lineSetAppSpecific(hCall, num);
m_Parent.CheckError(tr, "GetDivertSettings");
}
else
{
m_Parent.m_Dlg.AddText("SetAppSpecific: No call");
}
}
void TapiLine::SetMsgWaitLamp(DWORD num)
{
TCHAR buffer[50];
buffer[0] = 9;
buffer[1] = 73; // DisplayMsg
strcpy(&(buffer[2]),";Mailbox Msgs=");
buffer[16] = num + '0';
buffer[17] = 0; // NULL terminate
// Set Message Waiting Lamp
HRESULT tr = ::lineDevSpecific(m_hLine,0,NULL,buffer,18);
m_Parent.CheckError(tr, "lineDevSpecific");
}
void TapiLine::SetInGroup(LPCTSTR pszGroup)
{
TCHAR buffer[50];
DWORD len = 3;
buffer[0] = 9;
buffer[1] = 76; // HuntGroupEnable
// if ((pszGroup[0] == '0') || (pszGroup[0] == 0))
buffer[2] = 0; // NULL terminate
// else
// {
// strcpy(&(buffer[2]),pszGroup);
// buffer[2 + strlen(pszGroup)] = 0; // NULL terminate
// len = 2 + _tcslen(pszGroup);
// }
// Set In Group status
HRESULT tr = ::lineDevSpecific(m_hLine,0,NULL,buffer,len);
m_Parent.CheckError(tr, "lineDevSpecific");
}
void TapiLine::SetOutGroup(LPCTSTR pszGroup)
{
TCHAR buffer[50];
DWORD len = 3;
buffer[0] = 9;
buffer[1] = 77; // HuntGroupDisable
// if ((pszGroup[0] == '0') || (pszGroup[0] == 0))
buffer[2] = 0; // NULL terminate
// else
// {
// strcpy(&(buffer[2]),pszGroup);
// buffer[2 + strlen(pszGroup)] = 0; // NULL terminate
// len = 2 + _tcslen(pszGroup);
// }
// Set In Group status
HRESULT tr = ::lineDevSpecific(m_hLine,0,NULL,buffer,len);
m_Parent.CheckError(tr, "lineDevSpecific");
}
void TapiLine::SetCallData(LPCTSTR pszData)
{
HCALL hCall = NULL;
if (m_hConnectedCall)
hCall = m_hConnectedCall;
else if (m_hWaitingCall)
hCall = m_hWaitingCall;
else if (m_hHeldCall)
hCall = m_hHeldCall;
else if (m_hPendingCall)
hCall = m_hPendingCall;
else if (m_hConferenceCall)
hCall = m_hConferenceCall;
else if (m_hConsultationCall)
hCall = m_hConsultationCall;
if (hCall)
{
HRESULT tr = ::lineSetCallData(hCall,(void*)pszData,_tcslen(pszData));
m_Parent.CheckError(tr, "SetCallData");
}
else
{
m_Parent.m_Dlg.AddText("SetCallData: No call");
}
}
// ----------------------------------------------------------------------------
// Handle messages from TAPI
void TapiLine::OnEvent(
DWORD Device,
DWORD Msg,
DWORD Param1,
DWORD Param2,
DWORD Param3)
{
switch (Msg)
{
case LINE_REPLY: // Reply to an asynchronous TAPI function
OnReply(Param1, Param2);
break;
case LINE_CLOSE: // A line has closed
OnClose();
break;
case LINE_ADDRESSSTATE: // The address state has changed
ASSERT(m_hLine == (HLINE) Device);
OnAddressState(Param1, Param2);
break;
case LINE_CALLINFO: // The call info has changed
OnCallInfo((HCALL) Device, Param1);
break;
case LINE_CALLSTATE: // The call state has changed
OnCallState((HCALL) Device, Param1, Param2, Param3);
GetCallStatus();
break;
case LINE_LINEDEVSTATE: // The device state has changed
ASSERT(m_hLine == (HLINE) Device);
OnLineDevState(Param1, Param2, Param3);
break;
case LINE_APPNEWCALL: // There is a new incoming call
OnNewCall(Param1, (HCALL) Param2, Param3);
// The following demonstrates screen pop!!!
m_Parent.m_Dlg.ShowWindow(SW_SHOWNORMAL);
break;
case LINE_DEVSPECIFIC: // The device specific data has changed
case LINE_DEVSPECIFICFEATURE: // The device specific features have changed
TRACE("Device Specific Event\n");
break;
case LINE_GATHERDIGITS: // A digit has been received
TRACE("Gather Digits Event\n");
break;
case LINE_GENERATE: // A tone has been generated
TRACE("Generate Event\n");
break;
case LINE_MONITORDIGITS: // A digit has been received
TRACE("Monitor Digits Event\n");
break;
case LINE_MONITORMEDIA:
TRACE("Monitor Media Event\n");
break;
case LINE_MONITORTONE: // A tone has been detected
TRACE("Monitor Tone Event\n");
break;
case LINE_REQUEST:
TRACE("Assisted Telephony Request Event\n");
break;
case PHONE_BUTTON: // Phone events are not supported
case PHONE_CLOSE:
case PHONE_DEVSPECIFIC:
case PHONE_REPLY:
case PHONE_STATE:
case PHONE_CREATE:
case PHONE_REMOVE:
TRACE("Phone Event\n");
break;
case LINE_CREATE: // Not supported
TRACE("Line Create Event\n");
break;
case LINE_AGENTSPECIFIC: // Not Supported
case LINE_AGENTSTATUS: // Not supported
TRACE("Agent Event\n");
break;
case LINE_PROXYREQUEST: // Not supported
TRACE("Proxy Request Event\n");
break;
case LINE_REMOVE: // Not supported
TRACE("Line Remove Event\n");
break;
default:
ASSERT(FALSE);
break;
}
}
// ----------------------------------------------------------------------------
// Handle a LINE_REPLY message from TAPI
void TapiLine::OnReply(LONG RequestID, HRESULT Result)
{
CString info;
REQUEST_INFO ri = { "Unknown", 0 };
if (m_Requests.Lookup(RequestID, ri))
m_Requests.RemoveKey(RequestID);
if (Result == 0)
info.Format("Reply(%s: OK)", ri.Name);
else
{
// Describe the error message returned from TAPI
info.Format("Reply(%s: 0x%08lx = %s)", ri.Name,
Result, DescribeError(Result));
}
m_Parent.m_Dlg.AddText(info);
}
// ----------------------------------------------------------------------------
// Handle a LINE_CLOSE message from TAPI
void TapiLine::OnClose()
{
// This line (us) has been closed down
m_hLine = 0;
// Describe this event
CString info;
info.Format("Close()");
m_Parent.m_Dlg.AddText(info);
}
// ----------------------------------------------------------------------------
// Handle a LINE_ADDRESSSTATE message from TAPI
void TapiLine::OnAddressState(DWORD AddressID, DWORD AddressState)
{
CString state;
CString info;
info.Format("Address(%d, %s)", AddressID,
DescribeAddressStatus(state, AddressState));
m_Parent.m_Dlg.AddText(info);
// Get further information about the address change
LINEADDRESSSTATUS AddressStatus = { sizeof(LINEADDRESSSTATUS) };
HRESULT hr = ::lineGetAddressStatus(m_hLine, AddressID, &AddressStatus);
m_Parent.CheckError(hr, "GetAddressStatus");
info.Format("[NumInUse=%d, NumActiveCalls=%d, NumOnHoldCalls=%d, "
"NumOnHoldPendCalls=%d]",
AddressStatus.dwNumInUse, AddressStatus.dwNumActiveCalls,
AddressStatus.dwNumOnHoldCalls, AddressStatus.dwNumOnHoldPendCalls);
m_Parent.m_Dlg.AddText(info);
}
// ----------------------------------------------------------------------------
// Handle a LINE_CALLINFO message from TAPI
void TapiLine::OnCallInfo(HCALL hCall, DWORD CallInfoState)
{
CString state, which, info;
// Which call is this information about?
which.Format("%d/", hCall);
if (hCall == m_hConnectedCall) which += "Active";
else if (hCall == m_hWaitingCall) which += "Waiting";
else if (hCall == m_hHeldCall) which += "Held";
else if (hCall == m_hPendingCall) which += "Pending";
else if (hCall == m_hConferenceCall) which += "Conference";
else which += "Unknown";
// Put the information into the dialog box
info.Format("CallInfo(%s: %s)", LPCTSTR(which), DescribeCallInfo(state, CallInfoState));
m_Parent.m_Dlg.AddText(info);
// Get further information about the call info
CString s1, s2, Trunk, CallerID, CalledID, ConnectedID, RedirectingID, RedirectionID, CallData;
LINECALLINFO* pCallInfo = NULL;
/*HRESULT hr = */loopLineGetCallInfo(hCall, pCallInfo);
if (pCallInfo->dwTrunk == 0xffffffff)
Trunk = "Unknown";
else
Trunk.Format("%ld", pCallInfo->dwTrunk);
getTapiString(CallerID, pCallInfo, pCallInfo->dwCallerIDSize, pCallInfo->dwCallerIDOffset);
getTapiString(CalledID, pCallInfo, pCallInfo->dwCalledIDSize, pCallInfo->dwCalledIDOffset);
getTapiString(ConnectedID, pCallInfo, pCallInfo->dwConnectedIDSize, pCallInfo->dwConnectedIDOffset);
getTapiString(RedirectingID, pCallInfo, pCallInfo->dwRedirectingIDSize, pCallInfo->dwRedirectingIDOffset);
getTapiString(RedirectionID, pCallInfo, pCallInfo->dwRedirectionIDSize, pCallInfo->dwRedirectionIDOffset);
getTapiString(CallData, pCallInfo, pCallInfo->dwCallDataSize, pCallInfo->dwCallDataOffset);
info.Format("[AddressID=%d, Origin=%s, Reason=%s, Trunk=%s, "
"CallerID=%s, CalledID=%s, ConnectedID=%s, RedirectingID=%s, RedirectionID=%s, CallData=%s]",
pCallInfo->dwAddressID,
DescribeCallOrigin(s1, pCallInfo->dwOrigin),
DescribeCallReason(s2, pCallInfo->dwReason),
LPCTSTR(Trunk), LPCTSTR(CallerID), LPCTSTR(CalledID), LPCTSTR(ConnectedID),
LPCTSTR(RedirectingID), LPCTSTR(RedirectionID),
LPCTSTR(CallData));
m_Parent.m_Dlg.AddText(info);
delete [] pCallInfo;
}
// ----------------------------------------------------------------------------
// Handle a LINE_CALLSTATE message from TAPI
void TapiLine::OnCallState(HCALL hCall, DWORD CallState, DWORD CallStateDetail, DWORD CallPrivilege)
{
CString info, which, s1, s2;
// Which call is this information about?
which.Format("%d/", hCall);
if (hCall == m_hConnectedCall) which += "Active";
else if (hCall == m_hWaitingCall) which += "Waiting";
else if (hCall == m_hHeldCall) which += "Held";
else if (hCall == m_hPendingCall) which += "Pending";
else if (hCall == m_hConferenceCall) which += "Conference";
else if (hCall == m_hConsultationCall) which += "Consultation";
else which += "Unknown";
// Describe the event to the dialog box
info.Format("CallState(%s: %s, %s, %s)",
LPCTSTR(which),
DescribeCallState(s1, CallState),
DescribeCallStateDetail(CallState, CallStateDetail),
DescribePrivilege(s2, CallPrivilege));
m_Parent.m_Dlg.AddText(info);
// Handle releasing resources when they go idle
// This is necessary to allow another call to be made!
if (CallState & LINECALLSTATE_DISCONNECTED)
// DropCall(); // This seems to hang up the wrong call!!!
;
else if (CallState & LINECALLSTATE_IDLE)
{
HRESULT Result = ::lineDeallocateCall(hCall);
// Describe the error message returned from TAPI
if (Result)
{
info.Format("LineDeallocate(0x%08lx = %s)",
Result, DescribeError(Result));
m_Parent.m_Dlg.AddText(info);
}
else
{
if (hCall == m_hConnectedCall) m_hConnectedCall = 0;
else if (hCall == m_hWaitingCall) m_hWaitingCall = 0;
else if (hCall == m_hHeldCall) m_hHeldCall = 0;
else if (hCall == m_hPendingCall) m_hPendingCall = 0;
else if (hCall == m_hConferenceCall) m_hConferenceCall = 0;
}
}
// Has a call been answered / retrieved?
else if (CallState & LINECALLSTATE_CONNECTED)
{
if (hCall == m_hWaitingCall) m_hWaitingCall = 0;
if (hCall == m_hPendingCall) m_hPendingCall = 0;
if (hCall == m_hHeldCall) m_hHeldCall = 0;
if (hCall == m_hConferenceCall) m_hConferenceCall = 0;
m_hConnectedCall = hCall;
}
// Has a call been put on hold?
else if (CallState & (LINECALLSTATE_ONHOLDPENDTRANSFER | LINECALLSTATE_ONHOLD
| LINECALLSTATE_ONHOLDPENDCONF))
{
if (hCall == m_hConnectedCall) m_hConnectedCall = m_hHeldCall;
m_hHeldCall = hCall;
}
// Is a call proceeding?
else if (CallState & (LINECALLSTATE_DIALING | LINECALLSTATE_PROCEEDING))
{
m_hWaitingCall = hCall;
}
m_Parent.m_Dlg.CheckButtons();
}
// ----------------------------------------------------------------------------
// Handle a LINE_APPNEWCALL message from TAPI
void TapiLine::OnNewCall(DWORD AddressID, HCALL hCall, DWORD CallPrivilege)
{
// We can answer this if we want
m_hPendingCall = hCall;
m_Parent.m_Dlg.CheckButtons();
// Mention the new call
CString info, s1;
info.Format("NewCall(%d, %s)", AddressID, DescribePrivilege(s1, CallPrivilege));
m_Parent.m_Dlg.AddText(info);
// Get further information about the address change
LINEADDRESSSTATUS AddressStatus = { sizeof(LINEADDRESSSTATUS) };
HRESULT hr = ::lineGetAddressStatus(m_hLine, AddressID, &AddressStatus);
m_Parent.CheckError(hr, "GetAddressStatus");
info.Format("[NumInUse=%d, NumActiveCalls=%d, NumOnHoldCalls=%d, "
"NumOnHoldPendCalls=%d]",
AddressStatus.dwNumInUse, AddressStatus.dwNumActiveCalls,
AddressStatus.dwNumOnHoldCalls, AddressStatus.dwNumOnHoldPendCalls);
m_Parent.m_Dlg.AddText(info);
}
// ----------------------------------------------------------------------------
// Handle a LINE_LINEDEVSTATE message from TAPI
void TapiLine::OnLineDevState(DWORD DeviceState, DWORD DeviceStateDetail1, DWORD DeviceStateDetail2)
{
CString state;
CString info;
info.Format("DeviceState(%s, %d, %d)",
DescribeDeviceStatus(state, DeviceState),
DeviceStateDetail1, DeviceStateDetail2);
m_Parent.m_Dlg.AddText(info);
}
// ============================================================================
// TAPI application class
// ============================================================================
// ----------------------------------------------------------------------------
// Create a TAPI application interface class
TapiApplication::TapiApplication(CTapisampleDlg& Dlg) :
m_Dlg(Dlg)
{
m_extension = 0;
m_hLineApp = 0;
m_NumDevs = 0;
m_ApiVersions = 0;
m_CurrentLine = -1;
}
// ----------------------------------------------------------------------------
// Destroy a TAPI application interface class
TapiApplication::~TapiApplication()
{
if (m_ApiVersions)
delete [] m_ApiVersions;
}
// ----------------------------------------------------------------------------
// Shutdown our channel to TAPI
void TapiApplication::ShutdownTAPI()
{
if (m_pLines)
{
DWORD LineID;
for (LineID = 0; LineID < m_NumDevs; LineID++)
{
delete m_pLines[LineID];
}
delete [] m_pLines;
m_pLines = NULL;
}
if (m_hLineApp )
{
::lineShutdown(m_hLineApp);
m_hLineApp = 0;
}
}
// ----------------------------------------------------------------------------
// Initialise TAPI
void TapiApplication::InitialiseTAPI()
{
const DWORD dwLoVersion = 0x00020000; // TAPI v2.0
const DWORD dwHiVersion = TAPI_CURRENT_VERSION;
HLINEAPP hLineApp;
DWORD dwAPIVersion = dwHiVersion;
LINEINITIALIZEEXPARAMS params = { sizeof(LINEINITIALIZEEXPARAMS) };
params.dwOptions = LINEINITIALIZEEXOPTION_USEHIDDENWINDOW;
HINSTANCE hInst = ::AfxGetInstanceHandle();
LPCTSTR pszAppName = ::AfxGetAppName();
HRESULT tr = ::lineInitializeEx( &hLineApp,
hInst,
TapiLineCallback,
pszAppName,
&m_NumDevs,
&dwAPIVersion,
¶ms );
if (S_OK == tr)
{
// Save the handle
m_hLineApp = hLineApp;
// Negotiate the API versions
// (Necessary to get proper notifications)
TRACE("Number of devices: %d\n", m_NumDevs);
if (m_NumDevs > 0)
{
m_ApiVersions = new DWORD[m_NumDevs];
if (m_ApiVersions)
{
LINEEXTENSIONID dummy;
for (DWORD LineID = 0; LineID < m_NumDevs; LineID++)
{
if (S_OK != ::lineNegotiateAPIVersion( m_hLineApp,
LineID,
dwLoVersion,
dwHiVersion,
&m_ApiVersions[LineID],
&dummy) )
{
m_ApiVersions[LineID] = 0;
}
//TRACE("API Ver: %X\n", m_ApiVersions[LineID]);
}
}
}
}
}
// ----------------------------------------------------------------------------
// Open valid TAPI lines
void TapiApplication::OpenValidLines()
{
// Get and open valid lines
DWORD nLines = m_NumDevs;
DWORD nOpenedLines = 0;
m_pLines = new PTAPILINE[nLines];
if (m_pLines != NULL)
{
memset(m_pLines, 0, nLines * sizeof(PTAPILINE));
for (DWORD LineID = 0; LineID < nLines; LineID++ )
{
LINEDEVCAPS *pDevCaps = NULL;
HRESULT tr = loopLineGetDevCaps(m_hLineApp, LineID,
m_ApiVersions[LineID], 0, pDevCaps);
// This is how you are supposed to select TAPI lines,
// i.e. according to the line's capabilities
if( (S_OK == tr) &&
(pDevCaps->dwBearerModes & LINEBEARERMODE_VOICE) &&
(pDevCaps->dwMediaModes & LINEMEDIAMODE_INTERACTIVEVOICE) &&
(pDevCaps->dwLineFeatures & LINEFEATURE_MAKECALL) )
{
// Retrieve the name of the TAPI service provider
CString info, s1, s2;
getTapiString(s1, pDevCaps, pDevCaps->dwProviderInfoSize,
pDevCaps->dwProviderInfoOffset);
info.Format("[Provider = %s]", LPCTSTR(s1));
// Skip TSPs that we are not interested in by looking for the
// Provider name of the IP Office TAPI driver
if (s1 != CString("Avaya"))
continue;
TRACE(info);
TRACE("API version: %X\n", m_ApiVersions[LineID]);
// m_Dlg.AddText(info);
getTapiString(s1, pDevCaps, pDevCaps->dwLineNameSize,
pDevCaps->dwLineNameOffset);
TRACE("[Line Name = %s]\n", LPCTSTR(s1));
// Instantiate a TapiLine class for every line that we open
m_pLines[LineID] = new TapiLine(*this);
if (m_pLines[LineID])
{
tr = m_pLines[LineID]->Open(LineID,
LINECALLPRIVILEGE_OWNER,
LINEMEDIAMODE_INTERACTIVEVOICE /*| LINEMEDIAMODE_UNKNOWN*/);
if (S_OK == tr)
{
nOpenedLines++;
// The following code looks up and displays the line ID
// However, this is the same as the LineID variable
//DWORD id;
//loopLineGetID(id, m_pLines[LineID]->m_hLine, 0, 0,
// LINECALLSELECT_LINE, "tapi/line");
//info.Format("[Line ID = %ld]", id);
//m_Dlg.AddText(info);
LINEADDRESSSTATUS* pAddressStatus = NULL;
loopLineGetAddressStatus(m_pLines[LineID]->m_hLine, 0, pAddressStatus);
// Tell the user about the capabilities of this line
info.Format("[Supported Line States = %s]",
DescribeDeviceStatus(s1, pDevCaps->dwLineStates));
// m_Dlg.AddText(info);
// Find out about each address
for (DWORD AddressID = 0; AddressID < pDevCaps->dwNumAddresses;
AddressID++)
{
// Find out its capabilities
LINEADDRESSCAPS *pAddressCaps = NULL;
tr = loopLineGetAddressCaps(m_hLineApp,
LineID, AddressID,
m_ApiVersions[LineID], 0, pAddressCaps);
// Find and use the name of the extension we control
getTapiString(s1, pAddressCaps, pAddressCaps->dwAddressSize, pAddressCaps->dwAddressOffset);
info.Format("[Extn ID = %s]", s1);
TRACE("[Extn ID = %s]\n",s1);
//* m_Dlg.AddText(info);
DWORD ext = atoi(s1);
m_pLines[LineID]->m_extension = ext;
if (m_CurrentLine == -1)
{
m_CurrentLine = LineID;
m_extension = ext;
m_Dlg.SetExtension(s1);
}
// Tell the user about the capabilities of this address
/* info.Format("[MaxNumActive = %d, MaxNumOnHold = %d, "
"MaxNumOnHoldPending = %d, MaxNumConference = %d, "
"MaxNumTransConf = %d]",
pAddressCaps->dwMaxNumActiveCalls,
pAddressCaps->dwMaxNumOnHoldCalls,
pAddressCaps->dwMaxNumOnHoldPendingCalls,
pAddressCaps->dwMaxNumConference,
pAddressCaps->dwMaxNumTransConf);
m_Dlg.AddText(info);
info.Format("[Supported Address() = %s]",
DescribeAddressStatus(s1, pAddressCaps->dwAddressStates));
m_Dlg.AddText(info);
info.Format("[Supported CallState() = %s]",
DescribeCallState(s1, pAddressCaps->dwCallStates));
m_Dlg.AddText(info);
info.Format("[Supported CallInfo() = %s]",
DescribeCallInfo(s1, pAddressCaps->dwCallInfoStates));
m_Dlg.AddText(info);
info.Format("[Call Completion Capabilities = %s]",
DescribeCallCompletion(s1, pAddressCaps->dwCallCompletionModes));
m_Dlg.AddText(info);
info.Format("[Call Features = %s %s]",
DescribeCallFeatures(s1, pAddressCaps->dwCallFeatures),
DescribeCallFeatures2(s2, pAddressCaps->dwCallFeatures2) );
m_Dlg.AddText(info);
info.Format("[Address Capabilities = %s]",
DescribeAddressCapabilities(s1, pAddressCaps->dwAddrCapFlags));
m_Dlg.AddText(info);*/
delete [] pAddressCaps;
}
}
else
{
delete m_pLines[LineID]; m_pLines[LineID] = NULL;
}
}
}
delete [] pDevCaps;
}
}
TRACE("Number of Open Lines: %d\n", nOpenedLines);
if( !nOpenedLines )
{
delete[] m_pLines;
m_pLines = NULL;
}
m_Dlg.CheckButtons();
}
// ----------------------------------------------------------------------------
// Note an immediate error message
void TapiApplication::CheckError(HRESULT hr, LPCTSTR pszCommand)
{
if (hr < 0)
{
CString info;
info.Format("Error(%s:0x%lx)", pszCommand, hr);
m_Dlg.AddText(info);
}
}