📄 tapiline.cpp
字号:
// If the buffer was big enough, then succeed.
if ((lpLineAddressCaps->dwNeededSize) <=
(lpLineAddressCaps->dwTotalSize))
{
return lpLineAddressCaps;
}
else
{
// Buffer wasn't big enough. Make it bigger and try again.
nSizeLineAddressCaps = lpLineAddressCaps->dwNeededSize;
delete lpLineAddressCaps;
}
}
}
// Retrieve a LINECALLSTATUS structure for the specified line.
// This function is a wrapper around lineGetTranslateOutput to make it
// easy to handle the variable sized structure and any errors received.
LPLINETRANSLATEOUTPUT CTAPILine::I_lineTranslateAddress(LPCTSTR lpszDialAddress)
{
int nSizeLineTranslateOutput = sizeof(LINETRANSLATEOUTPUT) + 1024;
long lReturn;
// Continue this loop until the structure is big enough.
while (TRUE)
{
// Make sure the buffer exists, is valid and big enough.
LPLINETRANSLATEOUTPUT lpLineTranslateOutput =
(LPLINETRANSLATEOUTPUT)new BYTE[nSizeLineTranslateOutput];
if (lpLineTranslateOutput == NULL)
return NULL;
lpLineTranslateOutput->dwTotalSize = nSizeLineTranslateOutput;
// Make the call to fill the structure.
do
{
// Note that CALLWAITING is disabled
// (assuming the service provider can disable it)
lReturn = ::lineTranslateAddress(CTAPIConnection::m_hLineApp,
m_dwDeviceID, m_dwAPIVersion,
lpszDialAddress, 0,
LINETRANSLATEOPTION_CANCELCALLWAITING,
lpLineTranslateOutput);
// If the address isn't translatable, notify the user.
if (lReturn == LINEERR_INVALADDRESS)
::MessageBox(NULL, "Unable to translate phone number", "Warning", MB_OK);
if (!CTAPIError::HandleLineErr(lReturn))
{
TRACE1("lineTranslateOutput unhandled error: %lx\n", lReturn);
delete lpLineTranslateOutput;
return NULL;
}
}
while (lReturn != TAPISUCCESS);
// If the buffer was big enough, then succeed.
if ((lpLineTranslateOutput->dwNeededSize) <=
(lpLineTranslateOutput->dwTotalSize))
{
return lpLineTranslateOutput;
}
else
{
// Buffer wasn't big enough. Make it bigger and try again.
nSizeLineTranslateOutput = lpLineTranslateOutput->dwNeededSize;
delete lpLineTranslateOutput;
}
}
}
// Get Comm File Handle to used by Comm API
HANDLE CTAPILine::GetCommHandle(void)
{
ASSERT(m_hCall != (HCALL)-1);
LPVARSTRING lpVarString = NULL;
int nSizeofVarString = sizeof(VARSTRING) + 1024;
// Get the handle to the comm port from the driver so we can start
// communicating. This is returned in a LPVARSTRING structure.
long lReturn;
while (TRUE)
{
// Allocate the VARSTRING structure
lpVarString = (LPVARSTRING)new BYTE[nSizeofVarString];
if (lpVarString == NULL)
{
TRACE0("Error alloc LPVARSTRING !\n");
return INVALID_HANDLE_VALUE;
}
lpVarString->dwTotalSize = nSizeofVarString;
// Fill the VARSTRING structure
lReturn = ::lineGetID(0, 0, m_hCall, LINECALLSELECT_CALL,
lpVarString, "comm/datamodem");
if (!CTAPIError::HandleLineErr(lReturn))
{
TRACE1("lineGetID unhandled error: %lu\n", lReturn);
delete lpVarString;
return INVALID_HANDLE_VALUE;
}
// If the VARSTRING wasn't big enough, loop again.
if ((lpVarString->dwNeededSize) <= (lpVarString->dwTotalSize))
{
break;
}
else
{
nSizeofVarString = lpVarString->dwNeededSize;
delete lpVarString;
}
}
// Again, the handle to the comm port is contained in a
// LPVARSTRING structure. Thus, the handle is the very first
// thing after the end of the structure. Note that the name of
// the comm port is right after the handle, but I don't want it.
HANDLE hCommFile = *((LPHANDLE)((LPBYTE)lpVarString + lpVarString->dwStringOffset));
if (lpVarString != NULL)
delete lpVarString;
return hCommFile;
}
// Hangup the call in progress if it exists.
// If HangupCall fails, then its likely either a problem
// with the service provider (and might require a system
// reboot to correct) or the application ran out of memory.
BOOL CTAPILine::HangupCall(void)
{
LPLINECALLSTATUS pLineCallStatus = NULL;
long lReturn;
// If Tapi is not being used right now, then the call is hung up.
if (m_WaitReplyType != REPLY_NONE)
return FALSE;
TRACE0("Stopping Call in progress\n");
// Stop any data communications on the comm port.
if (m_pComm)
{
delete m_pComm;
m_pComm = NULL;
}
// If there is a call in progress, drop and deallocate it.
if (m_hCall != (HCALL)-1)
{
if ((pLineCallStatus = I_lineGetCallStatus(m_hCall)) == NULL)
{
// ShutdownTAPI();
return FALSE;
}
// Only drop the call when the line is not IDLE.
if (!((pLineCallStatus->dwCallState) & LINECALLSTATE_IDLE))
{
do
{
lReturn = ::lineDrop(m_hCall, NULL, 0);
if (lReturn < 0)
{
if (!CTAPIError::HandleLineErr(lReturn))
{
TRACE1("lineDrop unhandled error: %lu\n", lReturn);
}
}
else
{
// believe it or not, lineDrop is returning 0 syncronously with Unimodem!
if (!lReturn)
{
// do what Unimodem should be doing
CTAPIConnection::DoLineCallState((DWORD)m_hCall, LINE_CALLSTATE,
0, LINECALLSTATE_IDLE, 0, 0);
}
m_dwAsyncID = lReturn;
m_WaitReplyType = REPLY_DROPCALL;
break;
}
}
while (lReturn != TAPISUCCESS);
// Wait for the dropped call to go IDLE before continuing.
lReturn = CTAPIConnection::WaitForCallState(LINECALLSTATE_IDLE);
switch (lReturn)
{
case WAITERR_WAITTIMEDOUT:
TRACE0("Call timed out waiting for IDLE state.\n");
break;
case WAITERR_WAITABORTED:
TRACE0("WAITERR_WAITABORTED while waiting for IDLE state.\n");
break;
}
TRACE0("Call Dropped.\n");
}
// The call is now idle. Deallocate it!
do
{
lReturn = ::lineDeallocateCall(m_hCall);
if (!CTAPIError::HandleLineErr(lReturn))
{
TRACE1("lineDeallocateCall unhandled error: %lu\n", lReturn);
break;
}
}
while (lReturn != TAPISUCCESS);
TRACE0("Call Deallocated.\n");
}
Close();
m_hCall = (HCALL)-1;
m_bConnected = FALSE;
TRACE0("Call stopped\n");
PostHangupCall();
CTAPIConnection::m_dwAnswerCallWait=(DWORD)-1;
// Send UI message
// "Ready to make a call."
// Need to free LocalAlloc()d buffer returned from I_lineGetCallStatus
if (pLineCallStatus != NULL)
delete pLineCallStatus;
return TRUE;
}
// Posts a message to the main TAPI thread to hangup the call.
// TAPI is thread specific, meaning that only the thread that does the
// lineInitialize can get asynchronous messages through the callback.
// Since the HangupCall can potentially go into a loop waiting for
// specific events, any other threads that call HangupCall can cause
// timing confusion. Best to just have other threads 'ask' the main thread
// to hangup the call.
void CTAPILine::PostHangupCall()
{
TRACE0("Post Hangup Call !\n");
if (CTAPIConnection::m_pNotifyWnd != NULL)
{
CTAPIConnection::m_pNotifyWnd->PostMessage(WM_COMMAND,
CTAPIConnection::m_dwCommBaseCommandID + IDM_HANGUPCALL,
/*CTAPIConnection::m_dwAnswerCallWait*/0);
}
else
{
// avoid MainWnd is NULL
if (::AfxGetApp()->m_pMainWnd != NULL)
{
::AfxGetApp()->m_pMainWnd->PostMessage(WM_COMMAND,
CTAPIConnection::m_dwCommBaseCommandID + IDM_HANGUPCALL,
/*CTAPIConnection::m_dwAnswerCallWait*/0);
}
}
}
// - There will only be one outgoing address per line.
BOOL CTAPILine::DialCall(LPCTSTR lpDialNumber, LPCTSTR lpszDisplayableAddress)
{
// If TAPI isn't initialized, its either because we couldn't initialize
// at startup (and this might have been corrected by now), or because
// a REINIT event was received. In either case, try to init now.
if (!CTAPIConnection::m_hLineApp)
{
if (!CTAPIConnection::Create(CTAPIConnection::m_pNotifyWnd,
CTAPIConnection::m_dwAPILowVersion,
CTAPIConnection::m_dwAPIHighVersion,
CTAPIConnection::m_dwCommBaseCommandID,
CTAPIConnection::m_pReadBuf,
CTAPIConnection::m_nReadBufLen))
return FALSE;
}
if (m_bConnected || (m_WaitReplyType != REPLY_NONE && m_WaitReplyType != REPLY_DROPCALL))
{
TRACE0("---");
return FALSE;
}
// Send Message to UI, Enable
// If there are no line devices installed on the machine, lets give
// the user the opportunity to install one.
if (CTAPIConnection::GetNumDevs() < 1)
{
if (!CTAPIError::HandleNoDevicesInstalled())
return FALSE;
}
// Need to check the DevCaps to make sure this line is usable.
if (!IsSupportVoice())
{
::MessageBox(NULL,
"Error on Requested line",
"The selected line doesn't support VOICE capabilities",
MB_OK);
return FALSE;
}
if (!IsSupportDataModem())
{
::MessageBox(NULL,
"Error on Requested line",
"The selected line doesn't support DATAMODEM capabilities",
MB_OK);
return FALSE;
}
// Does this line have the capability to make calls?
// It is possible that some lines can't make outbound calls.
if (!IsSupportMakeCall())
{
::MessageBox(NULL,
"Error on Requested line",
"The selected line doesn't support MAKECALL capabilities",
MB_OK);
return FALSE;
}
if (!Open())
{
TRACE0("Open fail !\n");
return FALSE;
}
// Get LineAddressStatus so we can make sure the line
// isn't already in use by a TAPI application.
LPLINEADDRESSSTATUS lpLineAddressStatus = I_lineGetAddressStatus(0);
if (lpLineAddressStatus == NULL)
{
::MessageBox(NULL,
"Error on Requested line",
"Unable to Use Line",MB_OK);
if (lpLineAddressStatus != NULL)
delete lpLineAddressStatus;
return FALSE;
}
// MAKECALL will be set if there are any available call appearances
if (!((lpLineAddressStatus->dwAddressFeatures) & LINEADDRFEATURE_MAKECALL))
{
TRACE0("This line is not available to place a call.\n");
::MessageBox(NULL,
"Requested line is already in use",
"Unable to Use Line", MB_OK);
if (lpLineAddressStatus != NULL)
delete lpLineAddressStatus;
return FALSE;
}
// Start dialing the number
if (DialCallInParts(lpDialNumber,
lpszDisplayableAddress))
{
TRACE0("DialCallInParts succeeded.\n");
}
else
{
TRACE0("DialCallInParts failed.\n");
if (lpLineAddressStatus != NULL)
delete lpLineAddressStatus;
return FALSE;
}
if (lpLineAddressStatus != NULL)
delete lpLineAddressStatus;
// Send Message UI
return TRUE;
}
// Structures needed to handle special non-dialable characters.
struct NONDIALTOKENS
{
LONG lError;
DWORD dwDevCapFlag;
LPSTR szToken;
LPSTR szMsg;
};
NONDIALTOKENS g_sNonDialable[] =
{
{
LINEERR_DIALBILLING,
LINEDEVCAPFLAGS_DIALBILLING,
"$",
"Wait for the credit card bong tone"
},
{
LINEERR_DIALDIALTONE,
LINEDEVCAPFLAGS_DIALDIALTONE,
"W",
"Wait for the second dial tone"
},
{
LINEERR_DIALDIALTONE,
LINEDEVCAPFLAGS_DIALDIALTONE,
"w",
"Wait for the second dial tone"
},
{
LINEERR_DIALQUIET,
LINEDEVCAPFLAGS_DIALQUIET,
"@",
"Wait for the remote end to answer"
},
{
LINEERR_DIALPROMPT,
0,
"?",
"Press OK when you are ready to continue dialing"
},
};
const int nSizeNonDialable = sizeof(g_sNonDialable) / sizeof(g_sNonDialable[0]);
// Dials the call, handling special characters.
// This function dials the Address and handles any
// special characters in the address that the service provider
// can't handle. It requires input from the user to handle
// these characters; this can cause problems for fully automated
// dialing.
//
// Note that we can return TRUE, even if we don't reach a
// CONNECTED state. DIalCallInParts returns as soon as the
// Address is fully dialed or when an error occurs.
BOOL CTAPILine::DialCallInParts(LPCSTR lpszAddress,
LPCSTR lpszDisplayableAddress)
{
/*
if (CTAPIConnection::m_dwMakeCallWait != (DWORD)-1)
{
TRACE1("line %d is Making call !", CTAPIConnection::m_dwMakeCallWait);
return FALSE;
}*/
if (m_WaitReplyType != REPLY_NONE)
{
TRACE0("Line is used !\n");
return FALSE;
}
// CTAPIConnection::m_dwMakeCallWait = m_dwDeviceID;
// CTAPIConnection::m_dwAnswerCallWait = m_dwDeviceID;
BOOL bRetVal = TRUE;
long lReturn;
char szFilter[sizeof(g_sNonDialable) + 1] = "";
BOOL bFirstDial = TRUE;
// Variables to handle Dialable Substring dialing.
LPSTR lpDS; // This is just so we can free lpszDialableSubstring later.
LPSTR lpszDialableSubstring;
int nAddressLength = 0;
int nCurrentAddress = 0;
char chUnhandledCharacter;
// Get the capabilities for the line device we're going to use.
LPLINEADDRESSCAPS lpAddressCaps = I_lineGetAddressCaps(0);
if (lpAddressCaps == NULL)
{
TRACE0("Get Address Caps fail !\n");
return FALSE;
}
// Setup our CallParams for DATAMODEM settings.
LPLINECALLPARAMS lpCallParams = CreateCallParams(lpszDisplayableAddress);
if (lpCallParams == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -