📄 tapiline.cpp
字号:
{
TRACE0("Create Call Params fail !\n");
return FALSE;
}
// Determine which special characters the service provider
// does *not* handle so we can handle them manually.
// Keep list of unhandled characters in szFilter.
DWORD dwDevCapFlags = GetDevCapFlags(); // SP handled characters.
for (int i = 0; i < nSizeNonDialable; ++ i)
{
if ((dwDevCapFlags & g_sNonDialable[i].dwDevCapFlag) == 0)
{
strcat(szFilter, g_sNonDialable[i].szToken);
}
}
// szFilter now contains the set of tokens which delimit dialable substrings
// Setup the strings for substring dialing.
nAddressLength = strlen(lpszAddress);
lpDS = lpszDialableSubstring = (LPSTR)new TCHAR[nAddressLength + 1];
if (lpszDialableSubstring == NULL)
{
TRACE1("LocalAlloc failed: %lu\n", ::GetLastError());
CTAPIError::HandleNoMem();
bRetVal = FALSE;
goto LABEL_ERREXIT;
}
// Lets start dialing substrings!
while (nCurrentAddress < nAddressLength)
{
// LABEL_RETRYAFTERERROR:
// Find the next undialable character
i = strcspn(&lpszAddress[nCurrentAddress], szFilter);
// Was there one before the end of the Address string?
if (i + nCurrentAddress < nAddressLength)
{
// Make sure this device can handle partial dial.
if (! (lpAddressCaps->dwAddrCapFlags & LINEADDRCAPFLAGS_PARTIALDIAL))
{
::MessageBox(NULL,
"This line doesn't support partial dialing.\n",
"Warning",MB_OK);
bRetVal = FALSE;
goto LABEL_ERREXIT;
}
// Remember what the unhandled character is so we can handle it.
chUnhandledCharacter = lpszAddress[nCurrentAddress+i];
// Copy the dialable string to the Substring.
memcpy(lpszDialableSubstring, &lpszAddress[nCurrentAddress], i);
// Terminate the substring with a ';' to signify the partial dial.
lpszDialableSubstring[i] = ';';
lpszDialableSubstring[i + 1] = '\0';
// Increment the address for next iteration.
nCurrentAddress += i + 1;
}
else // No more partial dials. Dial the rest of the Address.
{
lpszDialableSubstring = (LPSTR)&lpszAddress[nCurrentAddress];
chUnhandledCharacter = 0;
nCurrentAddress = nAddressLength;
}
// do
// {
if (bFirstDial)
{
// HCALL hCall;
TRACE0("..make call !\n");
lReturn = ::lineMakeCall(m_hLine,
&m_hCall, lpszDialableSubstring,
0, lpCallParams);
TRACE0("make call **OK** !\n");
// ASSERT(hCall == m_hCall);
// ASSERT(lReturn == m_dwAsyncID);
}
else
{
lReturn = ::lineDial(m_hCall,
lpszDialableSubstring, 0);
}
/* lReturn = WaitForReply(
::lineMakeCall(m_hLine,
&m_hCall, lpszDialableSubstring,
0, lpCallParams));
else
lReturn = WaitForReply(
::lineDial(m_hCall,
lpszDialableSubstring, 0));
switch (lReturn)
{
// We should not have received these errors because of the
// prefiltering strategy, but there may be some ill-behaved
// service providers which do not correctly set their
// devcapflags. Add the character corresponding to the error
// to the filter set and retry dialing.
case LINEERR_DIALBILLING:
case LINEERR_DIALDIALTONE:
case LINEERR_DIALQUIET:
case LINEERR_DIALPROMPT:
TRACE0("Service Provider incorrectly sets dwDevCapFlags\n");
for (i = 0; i < nSizeNonDialable; ++ i)
if (lReturn == g_sNonDialable[i].lError)
{
strcat(szFilter, g_sNonDialable[i].szToken);
}
goto LABEL_RETRYAFTERERROR;
// break;
case WAITERR_WAITABORTED:
TRACE0("While Dialing, WaitForReply aborted.\n");
bRetVal = FALSE;
goto LABEL_ERREXIT;
// break;
}*/
if (lReturn < 0)
{
if (!CTAPIError::HandleLineErr(lReturn))
{
if (bFirstDial)
TRACE1("lineMakeCall unhandled error: %lx\n", lReturn);
else
TRACE1("lineDial unhandled error: %lx\n", lReturn);
bRetVal = FALSE;
goto LABEL_ERREXIT;
}
}
else
{
TRACE0("REPLY_MAKECALL\n");
m_dwAsyncID = lReturn;
m_WaitReplyType = REPLY_MAKECALL;
}
// }
// while (lReturn != TAPISUCCESS);
bFirstDial = FALSE;
// The dial was successful; now handle characters the service
// provider didn't (if any).
if (chUnhandledCharacter)
{
LPTSTR lpMsg = _T("");
// First, wait until we know we can continue dialing. While the
// last string is still pending to be dialed, we can't dial another.
while (TRUE)
{
LPLINECALLSTATUS lpLineCallStatus = I_lineGetCallStatus(m_hCall);
if (lpLineCallStatus == NULL)
{
bRetVal = FALSE;
goto LABEL_ERREXIT;
}
DWORD dwCallFeatures = lpLineCallStatus->dwCallFeatures;
delete lpLineCallStatus;
// Does CallStatus say we can dial now?
if (dwCallFeatures & LINECALLFEATURE_DIAL)
{
TRACE0("Ok to continue dialing.\n");
break;
}
// We can't dial yet, so wait for a CALLSTATE message
TRACE0("Waiting for dialing to be enabled.\n");
if (CTAPIConnection::WaitForCallState(I_LINECALLSTATE_ANY) != TAPISUCCESS)
{
bRetVal = FALSE;
goto LABEL_ERREXIT;
}
}
for (i = 0; i < nSizeNonDialable; ++ i)
if (chUnhandledCharacter == g_sNonDialable[i].szToken[0])
lpMsg = g_sNonDialable[i].szMsg;
::MessageBox(NULL, lpMsg, "Dialing Paused", MB_OK);
}
} // continue dialing until we dial all Dialable Substrings.
LABEL_ERREXIT:
if (lpDS)
delete lpDS;
if (lpCallParams != NULL)
delete lpCallParams;
if (lpAddressCaps != NULL)
delete lpAddressCaps;
return bRetVal;
}
// - There will only be one outgoing address per line.
BOOL CTAPILine::WaitCall(void)
{
if (CTAPIConnection::m_dwAnswerCallWait != (DWORD)-1)
{
TRACE1("line %d is waiting call !", CTAPIConnection::m_dwAnswerCallWait);
return FALSE;
}
if (m_WaitReplyType != REPLY_NONE)
{
TRACE0("Line is used !\n");
return FALSE;
}
// 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)
{
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;
}
CTAPIConnection::m_dwAnswerCallWait = m_dwDeviceID;
//------
delete lpLineAddressStatus;
//------
return TRUE;
}
LPCTSTR CTAPILine::GetLineName(void)
{
LPCTSTR szLineUnnamed = _T("线路无名");
LPCTSTR szLineNameEmpty = _T("线路名为空");
DWORD dwDefaultDevice = MAXDWORD;
LPCTSTR lpszLineName = _T("");
if ((m_lpLineDevCaps->dwLineNameSize) &&
(m_lpLineDevCaps->dwLineNameOffset) &&
(m_lpLineDevCaps->dwStringFormat == STRINGFORMAT_ASCII))
{
// This is the name of the device.
lpszLineName = ((LPTSTR)m_lpLineDevCaps) +
m_lpLineDevCaps->dwLineNameOffset;
if (lpszLineName[0] != '\0')
{
// Reverse indented to make this fit
// Make sure the device name is null terminated.
if (lpszLineName[m_lpLineDevCaps->dwLineNameSize - 1] != '\0')
{
// If the device name is not null terminated, null
// terminate it. Yes, this looses the end character.
// Its a bug in the service provider.
*((LPTSTR)lpszLineName + m_lpLineDevCaps->dwLineNameSize - 1) = '\0';
TRACE1("Device name for device 0x%lx is not null terminated.\n",
m_dwDeviceID);
}
}
else // Line name started with a NULL.
lpszLineName = szLineNameEmpty;
}
else // DevCaps doesn't have a valid line name. Unnamed.
lpszLineName = szLineUnnamed;
return lpszLineName;
}
LPVOID CTAPILine::CallConfigDialogEdit(HWND hMainWnd, DWORD& dwSizeDeviceConfig)
{
long lReturn;
LPVARSTRING lpVarString;
int nSizeofVarString = sizeof(VARSTRING);
while (TRUE)
{
// Allocate the VARSTRING structure
lpVarString = (LPVARSTRING)new BYTE[nSizeofVarString];
if (lpVarString == NULL)
return NULL;
lpVarString->dwTotalSize = nSizeofVarString;
lReturn = ::lineGetDevConfig(m_dwDeviceID, lpVarString,
"comm/datamodem");
if (!CTAPIError::HandleLineErr(lReturn))
{
TRACE1("lineGetDevCaps unhandled error: %lu\n", lReturn);
delete lpVarString;
return NULL;
}
if ((lpVarString->dwNeededSize) <= (lpVarString->dwTotalSize))
{
break;
}
else
{
nSizeofVarString = lpVarString->dwNeededSize;
delete lpVarString;
}
}
dwSizeDeviceConfig = lpVarString->dwStringSize;
// The extra byte allocated is in case dwStringSize is 0.
LPVOID lpDeviceConfig = (LPVOID)new BYTE[dwSizeDeviceConfig + 1];
if (lpDeviceConfig == NULL)
{
delete lpVarString;
return NULL;
}
else
{
::memcpy(lpDeviceConfig,
((LPBYTE)lpVarString + lpVarString->dwStringOffset),
dwSizeDeviceConfig);
}
delete lpVarString;
lpVarString = NULL;
// Next make the lineConfigDialogEdit call.
// Note that we determine the initial size of the VARSTRING
// structure based on the known size of the existing configuration
// information. I make the assumption that this configuration
// information is very unlikely to grow by more than 5K or by
// more than 5 times. This is a *very* conservative number.
// We do *not* want lineConfigDialogEdit to fail just because there
// wasn't enough room to stored the data. This would require the user
// to go through configuration again and that would be annoying.
nSizeofVarString = 5 * dwSizeDeviceConfig + 5000;
while (TRUE)
{
// Allocate the VARSTRING structure
lpVarString = (LPVARSTRING)new BYTE[nSizeofVarString];
if (lpVarString == NULL)
return NULL;
lpVarString->dwTotalSize = nSizeofVarString;
lReturn = ::lineConfigDialogEdit(m_dwDeviceID, hMainWnd, "comm/datamodem",
lpDeviceConfig, dwSizeDeviceConfig, lpVarString);
if (!CTAPIError::HandleLineErr(lReturn))
{
TRACE1("lineConfigDialogEdit unhandled error: %lu\n", lReturn);
delete lpVarString;
return NULL;
}
if ((lpVarString->dwNeededSize) <= (lpVarString->dwTotalSize))
{
break;
}
else
{
// We had been conservative about making sure the structure was
// big enough. Unfortunately, not conservative enough. Hopefully,
// this will not happen a second time because we are *DOUBLING*
// the NeededSize.
::MessageBox(NULL,
"Internal Error: Unable to set line configuration.\n"
"Please try again.",
"Oops", MB_OK);
nSizeofVarString = (lpVarString->dwNeededSize) * 2;
}
}
delete lpDeviceConfig;
lpDeviceConfig = NULL;
// Store the configuration information into a global structure
// so it can be set at a later time.
dwSizeDeviceConfig = lpVarString->dwStringSize;
lpDeviceConfig = (LPVOID)new BYTE[dwSizeDeviceConfig + 1];
if (lpDeviceConfig == NULL)
{
delete lpVarString;
return NULL;
}
else
{
::memcpy(lpDeviceConfig,
((LPBYTE)lpVarString + lpVarString->dwStringOffset),
dwSizeDeviceConfig);
}
delete lpVarString;
return lpDeviceConfig;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -