2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
15 #pragma off (unreferenced)
16 static char rcsid[] = "$Id: xtapi.c,v 1.1.1.1 2001-01-19 03:30:15 bradleyb Exp $";
17 #pragma on (unreferenced)
22 #define WIN32_LEAN_AND_MEAN
35 /* The TAPI layer will interface between Descent 2 and Win32 TAPI.
37 The application will go about using XTAPI when wanting to dial out
38 to another player (modem) or when listening for a ring in.
40 First an application will initialize the library.
41 Then one needs to find the required device id by enumerating
42 the devices and then selecting a device id.
44 Then we open this device by calling xtapi_lock. The application
45 can only use this device between lock and unlock. Also all functions
46 with the device extension will act upon this locked device.
47 When done with a device call xtapi_unlock.
49 To dial-out. Call xtapi_device_dialout.
53 #define TAPI_VERSION 0x00010004
65 } TapiObj = { NULL, NULL, 0 };
76 BOOL lineReplyReceived;
77 BOOL callStateReceived;
78 DWORD asyncRequestedID;
81 } TapiDev = { FALSE, 0, 0, 0, NULL, NULL, 0, FALSE, FALSE, FALSE, 0, 0 };
86 * Local function prototypes
89 void CALLBACK tapi_callback(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInst,
94 LINEDEVCAPS* tapi_getdevcaps(uint dev);
95 LINEADDRESSSTATUS* tapi_line_getaddrstatus(HLINE hLine, DWORD dwID);
96 LINEADDRESSCAPS* tapi_line_getaddrcaps(uint dev, DWORD addrID);
97 LINECALLSTATUS* tapi_line_getcallstatus(HCALL hCall);
98 LINECALLINFO* tapi_line_getcallinfo(HCALL hCall);
100 int xtapi_err(LONG val);
101 LONG xtapi_device_wait_for_reply(LONG reqID);
110 initializes the TAPI interface
113 XTAPI_NODEVICES if no devices found
114 XTAPI_BUSY if we are calling this function again for some reason
116 XTAPI_APPCONFLICT TAPI is being used somewhere else, and we can't gain
118 XTAPI_INCOMPATIBLE_VERSION this interface is old or not supported
122 int xtapi_init(char *appname, int *numdevs)
127 if (TapiObj.hObj) return XTAPI_SUCCESS;
129 TapiObj.hWnd = GetLibraryWindow();
131 reinit = TRUE; // Allow for reinitialization
135 retval = lineInitialize(&TapiObj.hObj,
136 GetWindowInstance(TapiObj.hWnd),
144 else if (retval == LINEERR_REINIT) {
146 timer_delay(0x50000); // delay 5 seconds
150 return XTAPI_APPCONFLICT; // another app is using tapi resources we need
153 else if (retval == LINEERR_NODEVICE) {
154 return XTAPI_NODEVICES; // should tell user to install a modem
156 else return XTAPI_GENERAL_ERR;
159 *numdevs = (int)TapiObj.num_devs;
161 TapiDev.valid = FALSE;
163 return XTAPI_SUCCESS;
168 performs a shutdown of the TAPI system
175 if (!TapiObj.hObj) return 0;
177 // Close any device that may be open at this point!
180 retval = lineShutdown(TapiObj.hObj);
181 if (retval!=0) return xtapi_err(retval);
184 TapiObj.num_devs = 0;
192 enumerates the devices usable by TAPI. good for
193 letting the user select the device and TAPI to take over
196 int xtapi_enumdevices(TapiDevice *dev, int num)
201 Assert(TapiObj.hObj != NULL);
202 Assert(num <= TapiObj.num_devs);
204 for (i = 0; i < num; i++)
206 LINEEXTENSIONID extid;
209 caps = tapi_getdevcaps(i);
210 if (caps == NULL) return XTAPI_OUT_OF_MEMORY;
212 if ((caps->dwBearerModes & LINEBEARERMODE_VOICE) &&
213 (caps->dwMediaModes & LINEMEDIAMODE_DATAMODEM)) {
214 dev[i].type = XTAPI_MODEM_DEVICE;
216 else dev[i].type = 0;
218 retval = lineNegotiateAPIVersion(TapiObj.hObj,
219 i, TAPI_VERSION, TAPI_VERSION,
220 (DWORD *)&dev[i].apiver, &extid);
222 if (retval == LINEERR_INCOMPATIBLEAPIVERSION)
223 return XTAPI_INCOMPATIBLE_VERSION;
224 else if (retval != 0)
225 return xtapi_err(retval);
228 dev[i].min_baud = (uint)caps->dwMaxRate;
229 dev[i].max_baud = (uint)caps->dwMaxRate;
234 return XTAPI_SUCCESS;
239 this function sets the specified device as the current device to be
240 used by the xtapi_device system
243 int xtapi_lock(TapiDevice *dev)
245 if (TapiDev.valid) return XTAPI_BUSY;
247 TapiDev.id = (DWORD)dev->id;
248 TapiDev.apiver = (DWORD)dev->apiver;
249 TapiDev.type = (DWORD)dev->type;
250 TapiDev.hLine = NULL;
251 TapiDev.hCall = NULL;
252 TapiDev.connected = FALSE;
253 TapiDev.call_state = 0;
254 TapiDev.lineReplyReceived = FALSE;
255 TapiDev.callStateReceived = FALSE;
256 TapiDev.lineReplyResult = 0;
257 TapiDev.valid = TRUE;
259 return XTAPI_SUCCESS;
264 this functions just releases the device. device functions won't work
265 anymore until another lock
268 int xtapi_unlock(TapiDevice *dev)
270 if (!TapiDev.valid) return XTAPI_NOTLOCKED;
272 if (TapiDev.hCall || TapiDev.hLine)
273 xtapi_device_hangup();
277 TapiDev.hLine = NULL;
278 TapiDev.hCall = NULL;
279 TapiDev.call_state = 0;
280 TapiDev.valid = FALSE;
282 return XTAPI_SUCCESS;
287 this function will dialout a given number through the current
291 int xtapi_device_dialout(char *phonenum)
293 LINEDEVCAPS *ldevcaps=NULL;
294 LINECALLPARAMS *lcallparams=NULL;
296 int xtapi_ret = XTAPI_SUCCESS;
298 if (TapiDev.hLine) return XTAPI_BUSY;
300 // check if we can dial out
301 if (TapiDev.type != XTAPI_MODEM_DEVICE) {
302 xtapi_ret = XTAPI_NOT_SUPPORTED;
305 ldevcaps = tapi_getdevcaps(TapiDev.id);
306 if (!ldevcaps) return XTAPI_OUT_OF_MEMORY;
307 if (!(ldevcaps->dwLineFeatures & LINEFEATURE_MAKECALL)) {
308 xtapi_ret = XTAPI_NOT_SUPPORTED;
313 retval = lineOpen(TapiObj.hObj, TapiDev.id,
315 TapiDev.apiver, 0, 0,
316 LINECALLPRIVILEGE_NONE,
317 LINEMEDIAMODE_DATAMODEM,
320 xtapi_ret = xtapi_err(retval);
324 retval = lineSetStatusMessages(TapiDev.hLine,
326 LINEDEVSTATE_RINGING | LINEDEVSTATE_CONNECTED |
327 LINEDEVSTATE_DISCONNECTED | LINEDEVSTATE_OUTOFSERVICE |
328 LINEDEVSTATE_MAINTENANCE | LINEDEVSTATE_REINIT,
329 LINEADDRESSSTATE_INUSEZERO |
330 LINEADDRESSSTATE_INUSEONE |
331 LINEADDRESSSTATE_INUSEMANY);
334 xtapi_ret = xtapi_err(retval);
338 // Setup calling parameters
339 lcallparams = (LINECALLPARAMS *)malloc(sizeof(LINECALLPARAMS)+strlen(phonenum)+1);
341 xtapi_ret = XTAPI_OUT_OF_MEMORY;
344 memset(lcallparams, 0, sizeof(LINECALLPARAMS)+strlen(phonenum)+1);
345 lcallparams->dwTotalSize = sizeof(LINECALLPARAMS)+strlen(phonenum)+1;
346 lcallparams->dwBearerMode = LINEBEARERMODE_VOICE;
347 lcallparams->dwMediaMode = LINEMEDIAMODE_DATAMODEM;
348 lcallparams->dwCallParamFlags = LINECALLPARAMFLAGS_IDLE;
349 lcallparams->dwAddressMode = LINEADDRESSMODE_ADDRESSID;
350 lcallparams->dwAddressID = 0;
351 lcallparams->dwDisplayableAddressOffset = sizeof(LINECALLPARAMS);
352 lcallparams->dwDisplayableAddressSize = strlen(phonenum)+1;
353 strcpy((LPSTR)lcallparams + sizeof(LINECALLPARAMS), phonenum);
356 mprintf((0, "XTAPI: dialing %s.\n", phonenum));
357 retval = xtapi_device_wait_for_reply(
358 lineMakeCall(TapiDev.hLine, &TapiDev.hCall, NULL, 0, lcallparams)
361 xtapi_ret = xtapi_err(retval);
365 retval = xtapi_device_wait_for_reply(
366 lineDial(TapiDev.hCall, phonenum, 0)
369 xtapi_ret = xtapi_err(retval);
374 if (lcallparams) free(lcallparams);
375 if (ldevcaps) free(ldevcaps);
382 sets up modem to wait for a call. All this function does
383 is initialize the line.
386 int xtapi_device_dialin()
389 int xtapi_ret = XTAPI_SUCCESS;
391 if (TapiDev.hLine) return XTAPI_BUSY;
393 // check if we can dial out
394 if (TapiDev.type != XTAPI_MODEM_DEVICE) {
395 xtapi_ret = XTAPI_NOT_SUPPORTED;
400 retval = lineOpen(TapiObj.hObj, TapiDev.id,
402 TapiDev.apiver, 0, 0,
403 LINECALLPRIVILEGE_OWNER,
404 LINEMEDIAMODE_DATAMODEM,
407 xtapi_ret = xtapi_err(retval);
417 the line should be open, and all this function does is grab the call
420 int xtapi_device_answer()
423 int xtapi_ret = XTAPI_SUCCESS;
425 if (!TapiDev.hCall) return XTAPI_NOTOPEN;
427 retval = xtapi_device_wait_for_reply(
428 lineAnswer(TapiDev.hCall, NULL, 0)
432 xtapi_ret = xtapi_err(retval);
439 /* device_poll_callstate
440 we can be informed of the current state of a call made after the
441 reply from lineMakeCall
444 int xtapi_device_poll_callstate(uint *state)
446 // perform translation from TAPI to XTAPI!
448 if (TapiDev.callStateReceived) {
449 switch (TapiDev.call_state)
451 case LINECALLSTATE_IDLE: *state = XTAPI_LINE_IDLE; break;
452 case LINECALLSTATE_DIALTONE: *state = XTAPI_LINE_DIALTONE; break;
453 case LINECALLSTATE_DIALING: *state = XTAPI_LINE_DIALING; break;
454 case LINECALLSTATE_RINGBACK: *state = XTAPI_LINE_RINGBACK; break;
455 case LINECALLSTATE_BUSY: *state = XTAPI_LINE_BUSY; break;
456 case LINECALLSTATE_SPECIALINFO: *state = XTAPI_LINE_FEEDBACK; break;
457 case LINECALLSTATE_CONNECTED: *state = XTAPI_LINE_CONNECTED; break;
458 case LINECALLSTATE_DISCONNECTED: *state = XTAPI_LINE_DISCONNECTED; break;
459 case LINECALLSTATE_PROCEEDING: *state = XTAPI_LINE_PROCEEDING; break;
460 case LINECALLSTATE_OFFERING: *state = XTAPI_LINE_RINGING; break;
462 mprintf((0, "call_state: %x\n", TapiDev.call_state));
463 *state = XTAPI_LINE_UNDEFINED;
465 TapiDev.callStateReceived = FALSE;
466 TapiDev.call_state = 0;
470 return XTAPI_SUCCESS;
474 /* device_create_comm_object
475 once we are connected, we can create a COMM_OBJ to actually send
476 and receive data through the modem.
479 #define ASCII_XON 0x11
480 #define ASCII_XOFF 0x13
483 int xtapi_device_create_comm_object(COMM_OBJ *commobj)
485 VARSTRING *varstr = NULL;
487 HANDLE hCommHandle=NULL;
488 LINECALLINFO *lcinfo = NULL;
490 int errval = XTAPI_SUCCESS;
492 Assert(TapiDev.connected);
494 varstrsize = sizeof(VARSTRING) + 1024;
498 varstr = (VARSTRING *)realloc(varstr, varstrsize);
500 errval = XTAPI_OUT_OF_MEMORY;
501 goto device_create_comm_exit;
504 varstr->dwTotalSize = varstrsize;
506 retval = lineGetID(0,0,TapiDev.hCall, LINECALLSELECT_CALL, varstr,
508 errval = xtapi_err(retval);
510 if (varstr->dwNeededSize > varstr->dwTotalSize) {
511 varstrsize = varstr->dwNeededSize;
516 if (errval != XTAPI_SUCCESS) return errval;
518 hCommHandle = *((LPHANDLE)((LPBYTE)varstr+varstr->dwStringOffset));
520 lcinfo = tapi_line_getcallinfo(TapiDev.hCall);
522 errval = XTAPI_OUT_OF_MEMORY;
523 goto device_create_comm_exit;
527 // Create the COMM compatible COMM_OBJ
528 // Most COMM settings will be set by TAPI, so this is less intensive than the
529 // COMM open connection
531 COMMTIMEOUTS ctimeouts;
533 memset(commobj, 0, sizeof(COMM_OBJ));
535 if (GetFileType(hCommHandle) != FILE_TYPE_CHAR) {
536 errval = XTAPI_GENERAL_ERR;
537 goto device_create_comm_exit;
540 GetCommState(hCommHandle, &commobj->dcb);
541 GetCommTimeouts(hCommHandle, &ctimeouts);
543 commobj->handle = hCommHandle;
544 commobj->baud = lcinfo->dwRate;
547 // commobj->dcb.BaudRate = commobj->baud;
548 // commobj->dcb.fBinary = 1;
549 // commobj->dcb.fNull = 0;
550 // commobj->dcb.ByteSize = 8;
551 // commobj->dcb.StopBits = ONESTOPBIT;
552 // commobj->dcb.fParity = FALSE;
553 // commobj->dcb.Parity = NOPARITY;
554 // commobj->dcb.XonChar = ASCII_XON;
555 // commobj->dcb.XoffChar = ASCII_XOFF;
556 // commobj->dcb.XonLim = 1024;
557 // commobj->dcb.XoffLim = 1024;
558 // commobj->dcb.EofChar = 0;
559 // commobj->dcb.EvtChar = 0;
560 // commobj->dcb.fOutxDsrFlow = FALSE;
561 // commobj->dcb.fOutxCtsFlow = FALSE; // rts/cts off
563 // commobj->dcb.fDtrControl = DTR_CONTROL_ENABLE;// dtr=on
564 // commobj->dcb.fRtsControl = RTS_CONTROL_ENABLE;
566 ctimeouts.ReadIntervalTimeout = 250;
567 ctimeouts.ReadTotalTimeoutMultiplier = 0;
568 ctimeouts.ReadTotalTimeoutConstant = 0;
569 ctimeouts.WriteTotalTimeoutMultiplier = 0;
570 ctimeouts.WriteTotalTimeoutConstant = 0;
572 commobj->dcb.fAbortOnError = FALSE;
574 SetCommTimeouts(hCommHandle, &ctimeouts);
575 SetCommState(hCommHandle, &commobj->dcb);
578 memset(&commobj->rov, 0, sizeof(OVERLAPPED));
579 memset(&commobj->wov, 0, sizeof(OVERLAPPED));
580 commobj->rov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
581 if (commobj->rov.hEvent == NULL) {
582 errval = XTAPI_GENERAL_ERR;
583 goto device_create_comm_exit;
585 commobj->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
586 if (commobj->wov.hEvent == NULL) {
587 CloseHandle(commobj->rov.hEvent);
591 commobj->hThread = NULL;
592 commobj->threadID = (DWORD)(-1);
593 commobj->connect = TRUE;
595 device_create_comm_exit:
596 if (varstr) free(varstr);
597 if (lcinfo) free(lcinfo);
604 frees the call and line
606 damn well better assume that the COMM_OBJ allocated (if at all) is
607 closed via the comm_library.
610 int xtapi_device_hangup()
614 Assert(TapiDev.valid); // Device should be locked!
616 // if (!TapiDev.hCall) return XTAPI_SUCCESS;
617 // if (!TapiDev.hLine) return XTAPI_SUCCESS;
619 // drop any call in progress
621 LINECALLSTATUS *lcallstat = NULL;
625 lcallstat = tapi_line_getcallstatus(TapiDev.hCall);
627 return XTAPI_OUT_OF_MEMORY;
630 mprintf((0, "XTAPI: Got linestatus.\n"));
632 if (!(lcallstat->dwCallState & LINECALLSTATE_IDLE)) {
633 // line not IDLE so drop it!
634 retval = xtapi_device_wait_for_reply(
635 lineDrop(TapiDev.hCall, NULL, 0)
638 if (retval != XTAPI_SUCCESS) {
639 mprintf((1, "XTAPI: error when lineDrop.\n"));
642 mprintf((0, "XTAPI: dropped line.\n"));
645 mprintf((0, "XTAPI: Waiting for idle.\n"));
648 xtapi_device_poll_callstate((uint*)&call_state);
649 if (call_state == XTAPI_LINE_IDLE) break;
650 if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
651 TranslateMessage(&msg);
652 DispatchMessage(&msg);
656 retval = lineDeallocateCall(TapiDev.hCall);
658 mprintf((0, "XTAPI: deallocated call.\n"));
662 return XTAPI_GENERAL_ERR;
664 TapiDev.hCall = NULL;
666 if (lcallstat) free(lcallstat);
671 retval = lineClose(TapiDev.hLine);
673 return XTAPI_GENERAL_ERR;
675 TapiDev.hLine = NULL;
678 mprintf((0, "XTAPI: Closed line.\n"));
680 TapiDev.connected = FALSE;
682 return XTAPI_SUCCESS;
686 /* device_wait_for_reply
687 once a function is called, we wait until we have been given a reply.
689 LONG xtapi_device_wait_for_reply(LONG reqID)
691 if (reqID > 0) { // A valid ID. so we shall wait and see
694 TapiDev.lineReplyReceived = FALSE;
695 TapiDev.asyncRequestedID = (DWORD)reqID;
696 TapiDev.lineReplyResult = LINEERR_OPERATIONFAILED;
698 while (!TapiDev.lineReplyReceived)
700 if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
701 TranslateMessage(&msg);
702 DispatchMessage(&msg);
705 // Insert code to take care of shutting down while wait.
708 return (LONG)TapiDev.lineReplyResult;
716 translate tapi to xtapi errors
719 int xtapi_err(LONG err)
721 mprintf((1, "TAPI err: %x\n", (DWORD)err));
725 return XTAPI_SUCCESS;
727 case LINEERR_ALLOCATED:
728 return XTAPI_APPCONFLICT;
731 return XTAPI_OUT_OF_MEMORY;
733 case LINEERR_INCOMPATIBLEAPIVERSION:
734 return XTAPI_INCOMPATIBLE_VERSION;
736 case LINEERR_NODEVICE:
737 return XTAPI_NODEVICES;
739 case LINEERR_OPERATIONFAILED:
742 case LINEERR_OPERATIONUNAVAIL:
743 return XTAPI_NOT_SUPPORTED;
745 case LINEERR_RESOURCEUNAVAIL:
746 return XTAPI_OUT_OF_RESOURCES;
751 return XTAPI_GENERAL_ERR;
756 this function is used by TAPI to inform us of when asynchronous
757 requests are valid and of any changes to the current call_state
760 void CALLBACK tapi_callback(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInst,
769 mprintf((1, "XTAPI: LINE_REPLY err: %x.\n", dw2));
771 mprintf((1, "XTAPI: LINE_REPLY received.\n"));
772 if (TapiDev.asyncRequestedID == dw1) {
773 TapiDev.lineReplyReceived = TRUE;
774 TapiDev.lineReplyResult = (LONG)dw2;
779 TapiDev.callStateReceived = TRUE;
780 TapiDev.call_state = dw1;
782 mprintf((0, "Call_State = %x\n", dw1));
783 switch(TapiDev.call_state)
785 case LINECALLSTATE_CONNECTED:
786 if (TapiDev.connected) break;
787 TapiDev.connected = TRUE;
790 case LINECALLSTATE_OFFERING:
791 if (TapiDev.connected) {
792 mprintf((1, "TAPI: offering after connected!\n"));
795 if (dw3 != LINECALLPRIVILEGE_OWNER) {
796 mprintf((1, "TAPI: need owner privilege to accept call!.\n"));
799 TapiDev.hCall = (HCALL)hDevice;
813 gets device caps for specified device and returns a valid structure
816 LINEDEVCAPS *tapi_getdevcaps(uint dev)
818 LINEDEVCAPS *pcaps=NULL;
822 size = sizeof(LINEDEVCAPS) + 256;
826 LINEEXTENSIONID extid;
828 retval = lineNegotiateAPIVersion(TapiObj.hObj,
829 dev, TAPI_VERSION, TAPI_VERSION,
835 pcaps = (LINEDEVCAPS *)realloc(pcaps, size);
836 if (!pcaps) return NULL;
838 memset(pcaps, 0, size);
839 pcaps->dwTotalSize = size;
841 retval = lineGetDevCaps(TapiObj.hObj, dev,
850 if (pcaps->dwNeededSize > pcaps->dwTotalSize) {
851 size = pcaps->dwNeededSize;
860 /* tapi_line_getaddrstatus
861 retrieves the current status of a given address on the line.
867 LINEADDRESSSTATUS *tapi_line_getaddrstatus(HLINE hLine, DWORD dwID)
869 LINEADDRESSSTATUS *ad=NULL;
873 size = sizeof(LINEADDRESSSTATUS) + 256;
877 ad = (LINEADDRESSSTATUS *)realloc(ad, size);
878 if (!ad) return NULL;
881 ad->dwTotalSize = size;
883 retval = lineGetAddressStatus(hLine, dwID, ad);
890 if (ad->dwNeededSize > ad->dwTotalSize) {
891 size = ad->dwNeededSize;
901 /* tapi_line_getaddrcaps
902 retrieves the current caps of a given address on the line.
908 LINEADDRESSCAPS *tapi_line_getaddrcaps(uint dev, DWORD addrID)
910 LINEADDRESSCAPS *ad=NULL;
914 size = sizeof(LINEADDRESSCAPS) + 256;
919 LINEEXTENSIONID extid;
921 retval = lineNegotiateAPIVersion(TapiObj.hObj,
922 dev, TAPI_VERSION, TAPI_VERSION,
928 ad = (LINEADDRESSCAPS *)realloc(ad, size);
929 if (!ad) return NULL;
932 ad->dwTotalSize = size;
934 retval = lineGetAddressCaps(TapiObj.hObj, dev,
943 if (ad->dwNeededSize > ad->dwTotalSize) {
944 size = ad->dwNeededSize;
954 /* tapi_line_getcallstatus
955 retrieves the current status of a given call on the line.
961 LINECALLSTATUS *tapi_line_getcallstatus(HCALL hCall)
963 LINECALLSTATUS *ad=NULL;
967 size = sizeof(LINECALLSTATUS) + 256;
971 ad = (LINECALLSTATUS *)realloc(ad, size);
972 if (!ad) return NULL;
975 ad->dwTotalSize = size;
977 retval = lineGetCallStatus(hCall,ad);
984 if (ad->dwNeededSize > ad->dwTotalSize) {
985 size = ad->dwNeededSize;
995 /* tapi_line_getcallinfo
996 retrieves the current status of a given call on the line.
1002 LINECALLINFO *tapi_line_getcallinfo(HCALL hCall)
1004 LINECALLINFO *ad=NULL;
1008 size = sizeof(LINECALLINFO) + 256;
1012 ad = (LINECALLINFO *)realloc(ad, size);
1013 if (!ad) return NULL;
1015 memset(ad, 0, size);
1016 ad->dwTotalSize = size;
1018 retval = lineGetCallInfo(hCall,ad);
1025 if (ad->dwNeededSize > ad->dwTotalSize) {
1026 size = ad->dwNeededSize;