dxx-rebirth/unused/win95/xtapi.c
2006-03-20 17:12:09 +00:00

1034 lines
22 KiB
C
Executable file

/*
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
*/
#pragma off (unreferenced)
static char rcsid[] = "$Id: xtapi.c,v 1.1.1.1 2006/03/17 20:00:36 zicodxx Exp $";
#pragma on (unreferenced)
#define _WIN32
#define WIN95
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <tapi.h>
#include "pstypes.h"
#include "mono.h"
#include "error.h"
#include "winapp.h"
#include "xtapi.h"
/* The TAPI layer will interface between Descent 2 and Win32 TAPI.
The application will go about using XTAPI when wanting to dial out
to another player (modem) or when listening for a ring in.
First an application will initialize the library.
Then one needs to find the required device id by enumerating
the devices and then selecting a device id.
Then we open this device by calling xtapi_lock. The application
can only use this device between lock and unlock. Also all functions
with the device extension will act upon this locked device.
When done with a device call xtapi_unlock.
To dial-out. Call xtapi_device_dialout.
*/
#define TAPI_VERSION 0x00010004
/*
* Data
*/
struct tagTapiObj {
HLINEAPP hObj;
HWND hWnd;
DWORD num_devs;
} TapiObj = { NULL, NULL, 0 };
struct tagTapiDev {
BOOL valid;
DWORD id;
DWORD apiver;
DWORD type;
HLINE hLine;
HCALL hCall;
DWORD call_state;
BOOL connected;
BOOL lineReplyReceived;
BOOL callStateReceived;
DWORD asyncRequestedID;
LONG lineReplyResult;
} TapiDev = { FALSE, 0, 0, 0, NULL, NULL, 0, FALSE, FALSE, FALSE, 0, 0 };
/*
* Local function prototypes
*/
void CALLBACK tapi_callback(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInst,
DWORD dw1,
DWORD dw2,
DWORD dw3);
LINEDEVCAPS* tapi_getdevcaps(uint dev);
LINEADDRESSSTATUS* tapi_line_getaddrstatus(HLINE hLine, DWORD dwID);
LINEADDRESSCAPS* tapi_line_getaddrcaps(uint dev, DWORD addrID);
LINECALLSTATUS* tapi_line_getcallstatus(HCALL hCall);
LINECALLINFO* tapi_line_getcallinfo(HCALL hCall);
int xtapi_err(LONG val);
LONG xtapi_device_wait_for_reply(LONG reqID);
/*
* Functions
*/
/* init
initializes the TAPI interface
returns:
XTAPI_NODEVICES if no devices found
XTAPI_BUSY if we are calling this function again for some reason
(non-reentrant)
XTAPI_APPCONFLICT TAPI is being used somewhere else, and we can't gain
control
XTAPI_INCOMPATIBLE_VERSION this interface is old or not supported
under current Win32.
*/
int xtapi_init(char *appname, int *numdevs)
{
LONG retval;
BOOL reinit;
if (TapiObj.hObj) return XTAPI_SUCCESS;
TapiObj.hWnd = GetLibraryWindow();
reinit = TRUE; // Allow for reinitialization
while (1)
{
retval = lineInitialize(&TapiObj.hObj,
GetWindowInstance(TapiObj.hWnd),
tapi_callback,
appname,
&TapiObj.num_devs);
if (!retval) {
break;
}
else if (retval == LINEERR_REINIT) {
if (reinit) {
timer_delay(0x50000); // delay 5 seconds
reinit = FALSE;
}
else {
return XTAPI_APPCONFLICT; // another app is using tapi resources we need
}
}
else if (retval == LINEERR_NODEVICE) {
return XTAPI_NODEVICES; // should tell user to install a modem
}
else return XTAPI_GENERAL_ERR;
}
*numdevs = (int)TapiObj.num_devs;
TapiDev.valid = FALSE;
return XTAPI_SUCCESS;
}
/* shutdown
performs a shutdown of the TAPI system
*/
int xtapi_shutdown()
{
LONG retval;
if (!TapiObj.hObj) return 0;
// Close any device that may be open at this point!
// shutdown TAPI
retval = lineShutdown(TapiObj.hObj);
if (retval!=0) return xtapi_err(retval);
TapiObj.hObj = NULL;
TapiObj.num_devs = 0;
TapiObj.hWnd = NULL;
return 0;
}
/* enumdevices
enumerates the devices usable by TAPI. good for
letting the user select the device and TAPI to take over
*/
int xtapi_enumdevices(TapiDevice *dev, int num)
{
LONG retval;
int i;
Assert(TapiObj.hObj != NULL);
Assert(num <= TapiObj.num_devs);
for (i = 0; i < num; i++)
{
LINEEXTENSIONID extid;
LINEDEVCAPS *caps;
caps = tapi_getdevcaps(i);
if (caps == NULL) return XTAPI_OUT_OF_MEMORY;
if ((caps->dwBearerModes & LINEBEARERMODE_VOICE) &&
(caps->dwMediaModes & LINEMEDIAMODE_DATAMODEM)) {
dev[i].type = XTAPI_MODEM_DEVICE;
}
else dev[i].type = 0;
retval = lineNegotiateAPIVersion(TapiObj.hObj,
i, TAPI_VERSION, TAPI_VERSION,
(DWORD *)&dev[i].apiver, &extid);
if (retval == LINEERR_INCOMPATIBLEAPIVERSION)
return XTAPI_INCOMPATIBLE_VERSION;
else if (retval != 0)
return xtapi_err(retval);
dev[i].id = i;
dev[i].min_baud = (uint)caps->dwMaxRate;
dev[i].max_baud = (uint)caps->dwMaxRate;
free(caps);
}
return XTAPI_SUCCESS;
}
/* lock
this function sets the specified device as the current device to be
used by the xtapi_device system
*/
int xtapi_lock(TapiDevice *dev)
{
if (TapiDev.valid) return XTAPI_BUSY;
TapiDev.id = (DWORD)dev->id;
TapiDev.apiver = (DWORD)dev->apiver;
TapiDev.type = (DWORD)dev->type;
TapiDev.hLine = NULL;
TapiDev.hCall = NULL;
TapiDev.connected = FALSE;
TapiDev.call_state = 0;
TapiDev.lineReplyReceived = FALSE;
TapiDev.callStateReceived = FALSE;
TapiDev.lineReplyResult = 0;
TapiDev.valid = TRUE;
return XTAPI_SUCCESS;
}
/* unlock
this functions just releases the device. device functions won't work
anymore until another lock
*/
int xtapi_unlock(TapiDevice *dev)
{
if (!TapiDev.valid) return XTAPI_NOTLOCKED;
if (TapiDev.hCall || TapiDev.hLine)
xtapi_device_hangup();
TapiDev.id = 0;
TapiDev.apiver = 0;
TapiDev.hLine = NULL;
TapiDev.hCall = NULL;
TapiDev.call_state = 0;
TapiDev.valid = FALSE;
return XTAPI_SUCCESS;
}
/* device_dial
this function will dialout a given number through the current
device.
*/
int xtapi_device_dialout(char *phonenum)
{
LINEDEVCAPS *ldevcaps=NULL;
LINECALLPARAMS *lcallparams=NULL;
LONG retval;
int xtapi_ret = XTAPI_SUCCESS;
if (TapiDev.hLine) return XTAPI_BUSY;
// check if we can dial out
if (TapiDev.type != XTAPI_MODEM_DEVICE) {
xtapi_ret = XTAPI_NOT_SUPPORTED;
goto dialout_exit;
}
ldevcaps = tapi_getdevcaps(TapiDev.id);
if (!ldevcaps) return XTAPI_OUT_OF_MEMORY;
if (!(ldevcaps->dwLineFeatures & LINEFEATURE_MAKECALL)) {
xtapi_ret = XTAPI_NOT_SUPPORTED;
goto dialout_exit;
}
// open the line!
retval = lineOpen(TapiObj.hObj, TapiDev.id,
&TapiDev.hLine,
TapiDev.apiver, 0, 0,
LINECALLPRIVILEGE_NONE,
LINEMEDIAMODE_DATAMODEM,
0);
if (retval != 0) {
xtapi_ret = xtapi_err(retval);
goto dialout_exit;
}
retval = lineSetStatusMessages(TapiDev.hLine,
LINEDEVSTATE_OTHER |
LINEDEVSTATE_RINGING | LINEDEVSTATE_CONNECTED |
LINEDEVSTATE_DISCONNECTED | LINEDEVSTATE_OUTOFSERVICE |
LINEDEVSTATE_MAINTENANCE | LINEDEVSTATE_REINIT,
LINEADDRESSSTATE_INUSEZERO |
LINEADDRESSSTATE_INUSEONE |
LINEADDRESSSTATE_INUSEMANY);
if (retval != 0) {
xtapi_ret = xtapi_err(retval);
goto dialout_exit;
}
// Setup calling parameters
lcallparams = (LINECALLPARAMS *)malloc(sizeof(LINECALLPARAMS)+strlen(phonenum)+1);
if (!lcallparams) {
xtapi_ret = XTAPI_OUT_OF_MEMORY;
goto dialout_exit;
}
memset(lcallparams, 0, sizeof(LINECALLPARAMS)+strlen(phonenum)+1);
lcallparams->dwTotalSize = sizeof(LINECALLPARAMS)+strlen(phonenum)+1;
lcallparams->dwBearerMode = LINEBEARERMODE_VOICE;
lcallparams->dwMediaMode = LINEMEDIAMODE_DATAMODEM;
lcallparams->dwCallParamFlags = LINECALLPARAMFLAGS_IDLE;
lcallparams->dwAddressMode = LINEADDRESSMODE_ADDRESSID;
lcallparams->dwAddressID = 0;
lcallparams->dwDisplayableAddressOffset = sizeof(LINECALLPARAMS);
lcallparams->dwDisplayableAddressSize = strlen(phonenum)+1;
strcpy((LPSTR)lcallparams + sizeof(LINECALLPARAMS), phonenum);
// Dial it!
mprintf((0, "XTAPI: dialing %s.\n", phonenum));
retval = xtapi_device_wait_for_reply(
lineMakeCall(TapiDev.hLine, &TapiDev.hCall, NULL, 0, lcallparams)
);
if (retval < 0) {
xtapi_ret = xtapi_err(retval);
goto dialout_exit;
}
retval = xtapi_device_wait_for_reply(
lineDial(TapiDev.hCall, phonenum, 0)
);
if (retval < 0) {
xtapi_ret = xtapi_err(retval);
goto dialout_exit;
}
dialout_exit:
if (lcallparams) free(lcallparams);
if (ldevcaps) free(ldevcaps);
return xtapi_ret;
}
/* device_dialin
sets up modem to wait for a call. All this function does
is initialize the line.
*/
int xtapi_device_dialin()
{
LONG retval;
int xtapi_ret = XTAPI_SUCCESS;
if (TapiDev.hLine) return XTAPI_BUSY;
// check if we can dial out
if (TapiDev.type != XTAPI_MODEM_DEVICE) {
xtapi_ret = XTAPI_NOT_SUPPORTED;
goto dialin_exit;
}
// open the line!
retval = lineOpen(TapiObj.hObj, TapiDev.id,
&TapiDev.hLine,
TapiDev.apiver, 0, 0,
LINECALLPRIVILEGE_OWNER,
LINEMEDIAMODE_DATAMODEM,
0);
if (retval != 0) {
xtapi_ret = xtapi_err(retval);
goto dialin_exit;
}
dialin_exit:
return xtapi_ret;
}
/* device_answer
the line should be open, and all this function does is grab the call
*/
int xtapi_device_answer()
{
LONG retval;
int xtapi_ret = XTAPI_SUCCESS;
if (!TapiDev.hCall) return XTAPI_NOTOPEN;
retval = xtapi_device_wait_for_reply(
lineAnswer(TapiDev.hCall, NULL, 0)
);
if (retval < 0) {
xtapi_ret = xtapi_err(retval);
}
return xtapi_ret;
}
/* device_poll_callstate
we can be informed of the current state of a call made after the
reply from lineMakeCall
*/
int xtapi_device_poll_callstate(uint *state)
{
// perform translation from TAPI to XTAPI!
if (TapiDev.callStateReceived) {
switch (TapiDev.call_state)
{
case LINECALLSTATE_IDLE: *state = XTAPI_LINE_IDLE; break;
case LINECALLSTATE_DIALTONE: *state = XTAPI_LINE_DIALTONE; break;
case LINECALLSTATE_DIALING: *state = XTAPI_LINE_DIALING; break;
case LINECALLSTATE_RINGBACK: *state = XTAPI_LINE_RINGBACK; break;
case LINECALLSTATE_BUSY: *state = XTAPI_LINE_BUSY; break;
case LINECALLSTATE_SPECIALINFO: *state = XTAPI_LINE_FEEDBACK; break;
case LINECALLSTATE_CONNECTED: *state = XTAPI_LINE_CONNECTED; break;
case LINECALLSTATE_DISCONNECTED: *state = XTAPI_LINE_DISCONNECTED; break;
case LINECALLSTATE_PROCEEDING: *state = XTAPI_LINE_PROCEEDING; break;
case LINECALLSTATE_OFFERING: *state = XTAPI_LINE_RINGING; break;
default:
mprintf((0, "call_state: %x\n", TapiDev.call_state));
*state = XTAPI_LINE_UNDEFINED;
}
TapiDev.callStateReceived = FALSE;
TapiDev.call_state = 0;
}
else *state = 0;
return XTAPI_SUCCESS;
}
/* device_create_comm_object
once we are connected, we can create a COMM_OBJ to actually send
and receive data through the modem.
*/
#define ASCII_XON 0x11
#define ASCII_XOFF 0x13
int xtapi_device_create_comm_object(COMM_OBJ *commobj)
{
VARSTRING *varstr = NULL;
DWORD varstrsize;
HANDLE hCommHandle=NULL;
LINECALLINFO *lcinfo = NULL;
int retval;
int errval = XTAPI_SUCCESS;
Assert(TapiDev.connected);
varstrsize = sizeof(VARSTRING) + 1024;
while (1)
{
varstr = (VARSTRING *)realloc(varstr, varstrsize);
if (!varstr) {
errval = XTAPI_OUT_OF_MEMORY;
goto device_create_comm_exit;
}
varstr->dwTotalSize = varstrsize;
retval = lineGetID(0,0,TapiDev.hCall, LINECALLSELECT_CALL, varstr,
"comm/datamodem");
errval = xtapi_err(retval);
if (varstr->dwNeededSize > varstr->dwTotalSize) {
varstrsize = varstr->dwNeededSize;
}
else break;
}
if (errval != XTAPI_SUCCESS) return errval;
hCommHandle = *((LPHANDLE)((LPBYTE)varstr+varstr->dwStringOffset));
lcinfo = tapi_line_getcallinfo(TapiDev.hCall);
if (!lcinfo) {
errval = XTAPI_OUT_OF_MEMORY;
goto device_create_comm_exit;
}
// Create the COMM compatible COMM_OBJ
// Most COMM settings will be set by TAPI, so this is less intensive than the
// COMM open connection
{
COMMTIMEOUTS ctimeouts;
memset(commobj, 0, sizeof(COMM_OBJ));
if (GetFileType(hCommHandle) != FILE_TYPE_CHAR) {
errval = XTAPI_GENERAL_ERR;
goto device_create_comm_exit;
}
GetCommState(hCommHandle, &commobj->dcb);
GetCommTimeouts(hCommHandle, &ctimeouts);
commobj->handle = hCommHandle;
commobj->baud = lcinfo->dwRate;
// commobj->dcb.BaudRate = commobj->baud;
// commobj->dcb.fBinary = 1;
// commobj->dcb.fNull = 0;
// commobj->dcb.ByteSize = 8;
// commobj->dcb.StopBits = ONESTOPBIT;
// commobj->dcb.fParity = FALSE;
// commobj->dcb.Parity = NOPARITY;
// commobj->dcb.XonChar = ASCII_XON;
// commobj->dcb.XoffChar = ASCII_XOFF;
// commobj->dcb.XonLim = 1024;
// commobj->dcb.XoffLim = 1024;
// commobj->dcb.EofChar = 0;
// commobj->dcb.EvtChar = 0;
// commobj->dcb.fOutxDsrFlow = FALSE;
// commobj->dcb.fOutxCtsFlow = FALSE; // rts/cts off
// commobj->dcb.fDtrControl = DTR_CONTROL_ENABLE;// dtr=on
// commobj->dcb.fRtsControl = RTS_CONTROL_ENABLE;
ctimeouts.ReadIntervalTimeout = 250;
ctimeouts.ReadTotalTimeoutMultiplier = 0;
ctimeouts.ReadTotalTimeoutConstant = 0;
ctimeouts.WriteTotalTimeoutMultiplier = 0;
ctimeouts.WriteTotalTimeoutConstant = 0;
commobj->dcb.fAbortOnError = FALSE;
SetCommTimeouts(hCommHandle, &ctimeouts);
SetCommState(hCommHandle, &commobj->dcb);
}
memset(&commobj->rov, 0, sizeof(OVERLAPPED));
memset(&commobj->wov, 0, sizeof(OVERLAPPED));
commobj->rov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (commobj->rov.hEvent == NULL) {
errval = XTAPI_GENERAL_ERR;
goto device_create_comm_exit;
}
commobj->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (commobj->wov.hEvent == NULL) {
CloseHandle(commobj->rov.hEvent);
return 0;
}
commobj->hThread = NULL;
commobj->threadID = (DWORD)(-1);
commobj->connect = TRUE;
device_create_comm_exit:
if (varstr) free(varstr);
if (lcinfo) free(lcinfo);
return errval;
}
/* device_hangup
frees the call and line
damn well better assume that the COMM_OBJ allocated (if at all) is
closed via the comm_library.
*/
int xtapi_device_hangup()
{
LONG retval;
Assert(TapiDev.valid); // Device should be locked!
// if (!TapiDev.hCall) return XTAPI_SUCCESS;
// if (!TapiDev.hLine) return XTAPI_SUCCESS;
// drop any call in progress
if (TapiDev.hCall) {
LINECALLSTATUS *lcallstat = NULL;
MSG msg;
DWORD call_state;
lcallstat = tapi_line_getcallstatus(TapiDev.hCall);
if (!lcallstat) {
return XTAPI_OUT_OF_MEMORY;
}
mprintf((0, "XTAPI: Got linestatus.\n"));
if (!(lcallstat->dwCallState & LINECALLSTATE_IDLE)) {
// line not IDLE so drop it!
retval = xtapi_device_wait_for_reply(
lineDrop(TapiDev.hCall, NULL, 0)
);
if (retval != XTAPI_SUCCESS) {
mprintf((1, "XTAPI: error when lineDrop.\n"));
}
mprintf((0, "XTAPI: dropped line.\n"));
// wait for IDLE
mprintf((0, "XTAPI: Waiting for idle.\n"));
while (1)
{
xtapi_device_poll_callstate((uint*)&call_state);
if (call_state == XTAPI_LINE_IDLE) break;
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
retval = lineDeallocateCall(TapiDev.hCall);
mprintf((0, "XTAPI: deallocated call.\n"));
if (retval != 0) {
free(lcallstat);
return XTAPI_GENERAL_ERR;
}
TapiDev.hCall = NULL;
if (lcallstat) free(lcallstat);
}
// Free up line.
if (TapiDev.hLine) {
retval = lineClose(TapiDev.hLine);
if (retval != 0) {
return XTAPI_GENERAL_ERR;
}
TapiDev.hLine = NULL;
}
mprintf((0, "XTAPI: Closed line.\n"));
TapiDev.connected = FALSE;
return XTAPI_SUCCESS;
}
/* device_wait_for_reply
once a function is called, we wait until we have been given a reply.
*/
LONG xtapi_device_wait_for_reply(LONG reqID)
{
if (reqID > 0) { // A valid ID. so we shall wait and see
MSG msg;
TapiDev.lineReplyReceived = FALSE;
TapiDev.asyncRequestedID = (DWORD)reqID;
TapiDev.lineReplyResult = LINEERR_OPERATIONFAILED;
while (!TapiDev.lineReplyReceived)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Insert code to take care of shutting down while wait.
}
return (LONG)TapiDev.lineReplyResult;
}
return reqID;
}
/* err
translate tapi to xtapi errors
*/
int xtapi_err(LONG err)
{
mprintf((1, "TAPI err: %x\n", (DWORD)err));
switch (err)
{
case 0:
return XTAPI_SUCCESS;
case LINEERR_ALLOCATED:
return XTAPI_APPCONFLICT;
case LINEERR_NOMEM:
return XTAPI_OUT_OF_MEMORY;
case LINEERR_INCOMPATIBLEAPIVERSION:
return XTAPI_INCOMPATIBLE_VERSION;
case LINEERR_NODEVICE:
return XTAPI_NODEVICES;
case LINEERR_OPERATIONFAILED:
return XTAPI_FAIL;
case LINEERR_OPERATIONUNAVAIL:
return XTAPI_NOT_SUPPORTED;
case LINEERR_RESOURCEUNAVAIL:
return XTAPI_OUT_OF_RESOURCES;
case LINEERR_REINIT:
return XTAPI_BUSY;
}
return XTAPI_GENERAL_ERR;
}
/* callback
this function is used by TAPI to inform us of when asynchronous
requests are valid and of any changes to the current call_state
*/
void CALLBACK tapi_callback(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInst,
DWORD dw1,
DWORD dw2,
DWORD dw3)
{
switch(dwMsg)
{
case LINE_REPLY:
if (dw2 != 0)
mprintf((1, "XTAPI: LINE_REPLY err: %x.\n", dw2));
else
mprintf((1, "XTAPI: LINE_REPLY received.\n"));
if (TapiDev.asyncRequestedID == dw1) {
TapiDev.lineReplyReceived = TRUE;
TapiDev.lineReplyResult = (LONG)dw2;
}
break;
case LINE_CALLSTATE:
TapiDev.callStateReceived = TRUE;
TapiDev.call_state = dw1;
mprintf((0, "Call_State = %x\n", dw1));
switch(TapiDev.call_state)
{
case LINECALLSTATE_CONNECTED:
if (TapiDev.connected) break;
TapiDev.connected = TRUE;
break;
case LINECALLSTATE_OFFERING:
if (TapiDev.connected) {
mprintf((1, "TAPI: offering after connected!\n"));
break;
}
if (dw3 != LINECALLPRIVILEGE_OWNER) {
mprintf((1, "TAPI: need owner privilege to accept call!.\n"));
break;
}
TapiDev.hCall = (HCALL)hDevice;
break;
}
break;
}
}
/*
* TAPI functions
*/
/* tapi_getdevcaps
gets device caps for specified device and returns a valid structure
*/
LINEDEVCAPS *tapi_getdevcaps(uint dev)
{
LINEDEVCAPS *pcaps=NULL;
LONG retval, size;
DWORD apiver;
size = sizeof(LINEDEVCAPS) + 256;
while (1)
{
LINEEXTENSIONID extid;
retval = lineNegotiateAPIVersion(TapiObj.hObj,
dev, TAPI_VERSION, TAPI_VERSION,
&apiver, &extid);
if (retval != 0)
return NULL;
pcaps = (LINEDEVCAPS *)realloc(pcaps, size);
if (!pcaps) return NULL;
memset(pcaps, 0, size);
pcaps->dwTotalSize = size;
retval = lineGetDevCaps(TapiObj.hObj, dev,
apiver, 0,
pcaps);
if (retval!=0) {
free(pcaps);
return NULL;
}
if (pcaps->dwNeededSize > pcaps->dwTotalSize) {
size = pcaps->dwNeededSize;
continue;
}
else break;
}
return pcaps;
}
/* tapi_line_getaddrstatus
retrieves the current status of a given address on the line.
returns:
NULL if fail.
*/
LINEADDRESSSTATUS *tapi_line_getaddrstatus(HLINE hLine, DWORD dwID)
{
LINEADDRESSSTATUS *ad=NULL;
LONG retval;
int size;
size = sizeof(LINEADDRESSSTATUS) + 256;
while (1)
{
ad = (LINEADDRESSSTATUS *)realloc(ad, size);
if (!ad) return NULL;
memset(ad, 0, size);
ad->dwTotalSize = size;
retval = lineGetAddressStatus(hLine, dwID, ad);
if (retval!=0) {
free(ad);
return NULL;
}
if (ad->dwNeededSize > ad->dwTotalSize) {
size = ad->dwNeededSize;
continue;
}
else break;
}
return ad;
}
/* tapi_line_getaddrcaps
retrieves the current caps of a given address on the line.
returns:
NULL if fail.
*/
LINEADDRESSCAPS *tapi_line_getaddrcaps(uint dev, DWORD addrID)
{
LINEADDRESSCAPS *ad=NULL;
LONG retval;
int size;
size = sizeof(LINEADDRESSCAPS) + 256;
while (1)
{
DWORD apiver;
LINEEXTENSIONID extid;
retval = lineNegotiateAPIVersion(TapiObj.hObj,
dev, TAPI_VERSION, TAPI_VERSION,
&apiver, &extid);
if (retval != 0)
return NULL;
ad = (LINEADDRESSCAPS *)realloc(ad, size);
if (!ad) return NULL;
memset(ad, 0, size);
ad->dwTotalSize = size;
retval = lineGetAddressCaps(TapiObj.hObj, dev,
addrID, apiver, 0,
ad);
if (retval!=0) {
free(ad);
return NULL;
}
if (ad->dwNeededSize > ad->dwTotalSize) {
size = ad->dwNeededSize;
continue;
}
else break;
}
return ad;
}
/* tapi_line_getcallstatus
retrieves the current status of a given call on the line.
returns:
NULL if fail.
*/
LINECALLSTATUS *tapi_line_getcallstatus(HCALL hCall)
{
LINECALLSTATUS *ad=NULL;
LONG retval;
int size;
size = sizeof(LINECALLSTATUS) + 256;
while (1)
{
ad = (LINECALLSTATUS *)realloc(ad, size);
if (!ad) return NULL;
memset(ad, 0, size);
ad->dwTotalSize = size;
retval = lineGetCallStatus(hCall,ad);
if (retval!=0) {
free(ad);
return NULL;
}
if (ad->dwNeededSize > ad->dwTotalSize) {
size = ad->dwNeededSize;
continue;
}
else break;
}
return ad;
}
/* tapi_line_getcallinfo
retrieves the current status of a given call on the line.
returns:
NULL if fail.
*/
LINECALLINFO *tapi_line_getcallinfo(HCALL hCall)
{
LINECALLINFO *ad=NULL;
LONG retval;
int size;
size = sizeof(LINECALLINFO) + 256;
while (1)
{
ad = (LINECALLINFO *)realloc(ad, size);
if (!ad) return NULL;
memset(ad, 0, size);
ad->dwTotalSize = size;
retval = lineGetCallInfo(hCall,ad);
if (retval!=0) {
free(ad);
return NULL;
}
if (ad->dwNeededSize > ad->dwTotalSize) {
size = ad->dwNeededSize;
continue;
}
else break;
}
return ad;
}