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.
18 #define WIN32_LEAN_AND_MEAN
31 /* The TAPI layer will interface between Descent 2 and Win32 TAPI.
33 The application will go about using XTAPI when wanting to dial out
34 to another player (modem) or when listening for a ring in.
36 First an application will initialize the library.
37 Then one needs to find the required device id by enumerating
38 the devices and then selecting a device id.
40 Then we open this device by calling xtapi_lock. The application
41 can only use this device between lock and unlock. Also all functions
42 with the device extension will act upon this locked device.
43 When done with a device call xtapi_unlock.
45 To dial-out. Call xtapi_device_dialout.
49 #define TAPI_VERSION 0x00010004
61 } TapiObj = { NULL, NULL, 0 };
72 BOOL lineReplyReceived;
73 BOOL callStateReceived;
74 DWORD asyncRequestedID;
77 } TapiDev = { FALSE, 0, 0, 0, NULL, NULL, 0, FALSE, FALSE, FALSE, 0, 0 };
82 * Local function prototypes
85 void CALLBACK tapi_callback(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInst,
90 LINEDEVCAPS* tapi_getdevcaps(uint dev);
91 LINEADDRESSSTATUS* tapi_line_getaddrstatus(HLINE hLine, DWORD dwID);
92 LINEADDRESSCAPS* tapi_line_getaddrcaps(uint dev, DWORD addrID);
93 LINECALLSTATUS* tapi_line_getcallstatus(HCALL hCall);
94 LINECALLINFO* tapi_line_getcallinfo(HCALL hCall);
96 int xtapi_err(LONG val);
97 LONG xtapi_device_wait_for_reply(LONG reqID);
106 initializes the TAPI interface
109 XTAPI_NODEVICES if no devices found
110 XTAPI_BUSY if we are calling this function again for some reason
112 XTAPI_APPCONFLICT TAPI is being used somewhere else, and we can't gain
114 XTAPI_INCOMPATIBLE_VERSION this interface is old or not supported
118 int xtapi_init(char *appname, int *numdevs)
123 if (TapiObj.hObj) return XTAPI_SUCCESS;
125 TapiObj.hWnd = GetLibraryWindow();
127 reinit = TRUE; // Allow for reinitialization
131 retval = lineInitialize(&TapiObj.hObj,
132 GetWindowInstance(TapiObj.hWnd),
140 else if (retval == LINEERR_REINIT) {
142 timer_delay(0x50000); // delay 5 seconds
146 return XTAPI_APPCONFLICT; // another app is using tapi resources we need
149 else if (retval == LINEERR_NODEVICE) {
150 return XTAPI_NODEVICES; // should tell user to install a modem
152 else return XTAPI_GENERAL_ERR;
155 *numdevs = (int)TapiObj.num_devs;
157 TapiDev.valid = FALSE;
159 return XTAPI_SUCCESS;
164 performs a shutdown of the TAPI system
171 if (!TapiObj.hObj) return 0;
173 // Close any device that may be open at this point!
176 retval = lineShutdown(TapiObj.hObj);
177 if (retval!=0) return xtapi_err(retval);
180 TapiObj.num_devs = 0;
188 enumerates the devices usable by TAPI. good for
189 letting the user select the device and TAPI to take over
192 int xtapi_enumdevices(TapiDevice *dev, int num)
197 Assert(TapiObj.hObj != NULL);
198 Assert(num <= TapiObj.num_devs);
200 for (i = 0; i < num; i++)
202 LINEEXTENSIONID extid;
205 caps = tapi_getdevcaps(i);
206 if (caps == NULL) return XTAPI_OUT_OF_MEMORY;
208 if ((caps->dwBearerModes & LINEBEARERMODE_VOICE) &&
209 (caps->dwMediaModes & LINEMEDIAMODE_DATAMODEM)) {
210 dev[i].type = XTAPI_MODEM_DEVICE;
212 else dev[i].type = 0;
214 retval = lineNegotiateAPIVersion(TapiObj.hObj,
215 i, TAPI_VERSION, TAPI_VERSION,
216 (DWORD *)&dev[i].apiver, &extid);
218 if (retval == LINEERR_INCOMPATIBLEAPIVERSION)
219 return XTAPI_INCOMPATIBLE_VERSION;
220 else if (retval != 0)
221 return xtapi_err(retval);
224 dev[i].min_baud = (uint)caps->dwMaxRate;
225 dev[i].max_baud = (uint)caps->dwMaxRate;
230 return XTAPI_SUCCESS;
235 this function sets the specified device as the current device to be
236 used by the xtapi_device system
239 int xtapi_lock(TapiDevice *dev)
241 if (TapiDev.valid) return XTAPI_BUSY;
243 TapiDev.id = (DWORD)dev->id;
244 TapiDev.apiver = (DWORD)dev->apiver;
245 TapiDev.type = (DWORD)dev->type;
246 TapiDev.hLine = NULL;
247 TapiDev.hCall = NULL;
248 TapiDev.connected = FALSE;
249 TapiDev.call_state = 0;
250 TapiDev.lineReplyReceived = FALSE;
251 TapiDev.callStateReceived = FALSE;
252 TapiDev.lineReplyResult = 0;
253 TapiDev.valid = TRUE;
255 return XTAPI_SUCCESS;
260 this functions just releases the device. device functions won't work
261 anymore until another lock
264 int xtapi_unlock(TapiDevice *dev)
266 if (!TapiDev.valid) return XTAPI_NOTLOCKED;
268 if (TapiDev.hCall || TapiDev.hLine)
269 xtapi_device_hangup();
273 TapiDev.hLine = NULL;
274 TapiDev.hCall = NULL;
275 TapiDev.call_state = 0;
276 TapiDev.valid = FALSE;
278 return XTAPI_SUCCESS;
283 this function will dialout a given number through the current
287 int xtapi_device_dialout(char *phonenum)
289 LINEDEVCAPS *ldevcaps=NULL;
290 LINECALLPARAMS *lcallparams=NULL;
292 int xtapi_ret = XTAPI_SUCCESS;
294 if (TapiDev.hLine) return XTAPI_BUSY;
296 // check if we can dial out
297 if (TapiDev.type != XTAPI_MODEM_DEVICE) {
298 xtapi_ret = XTAPI_NOT_SUPPORTED;
301 ldevcaps = tapi_getdevcaps(TapiDev.id);
302 if (!ldevcaps) return XTAPI_OUT_OF_MEMORY;
303 if (!(ldevcaps->dwLineFeatures & LINEFEATURE_MAKECALL)) {
304 xtapi_ret = XTAPI_NOT_SUPPORTED;
309 retval = lineOpen(TapiObj.hObj, TapiDev.id,
311 TapiDev.apiver, 0, 0,
312 LINECALLPRIVILEGE_NONE,
313 LINEMEDIAMODE_DATAMODEM,
316 xtapi_ret = xtapi_err(retval);
320 retval = lineSetStatusMessages(TapiDev.hLine,
322 LINEDEVSTATE_RINGING | LINEDEVSTATE_CONNECTED |
323 LINEDEVSTATE_DISCONNECTED | LINEDEVSTATE_OUTOFSERVICE |
324 LINEDEVSTATE_MAINTENANCE | LINEDEVSTATE_REINIT,
325 LINEADDRESSSTATE_INUSEZERO |
326 LINEADDRESSSTATE_INUSEONE |
327 LINEADDRESSSTATE_INUSEMANY);
330 xtapi_ret = xtapi_err(retval);
334 // Setup calling parameters
335 lcallparams = (LINECALLPARAMS *)malloc(sizeof(LINECALLPARAMS)+strlen(phonenum)+1);
337 xtapi_ret = XTAPI_OUT_OF_MEMORY;
340 memset(lcallparams, 0, sizeof(LINECALLPARAMS)+strlen(phonenum)+1);
341 lcallparams->dwTotalSize = sizeof(LINECALLPARAMS)+strlen(phonenum)+1;
342 lcallparams->dwBearerMode = LINEBEARERMODE_VOICE;
343 lcallparams->dwMediaMode = LINEMEDIAMODE_DATAMODEM;
344 lcallparams->dwCallParamFlags = LINECALLPARAMFLAGS_IDLE;
345 lcallparams->dwAddressMode = LINEADDRESSMODE_ADDRESSID;
346 lcallparams->dwAddressID = 0;
347 lcallparams->dwDisplayableAddressOffset = sizeof(LINECALLPARAMS);
348 lcallparams->dwDisplayableAddressSize = strlen(phonenum)+1;
349 strcpy((LPSTR)lcallparams + sizeof(LINECALLPARAMS), phonenum);
352 mprintf((0, "XTAPI: dialing %s.\n", phonenum));
353 retval = xtapi_device_wait_for_reply(
354 lineMakeCall(TapiDev.hLine, &TapiDev.hCall, NULL, 0, lcallparams)
357 xtapi_ret = xtapi_err(retval);
361 retval = xtapi_device_wait_for_reply(
362 lineDial(TapiDev.hCall, phonenum, 0)
365 xtapi_ret = xtapi_err(retval);
370 if (lcallparams) free(lcallparams);
371 if (ldevcaps) free(ldevcaps);
378 sets up modem to wait for a call. All this function does
379 is initialize the line.
382 int xtapi_device_dialin()
385 int xtapi_ret = XTAPI_SUCCESS;
387 if (TapiDev.hLine) return XTAPI_BUSY;
389 // check if we can dial out
390 if (TapiDev.type != XTAPI_MODEM_DEVICE) {
391 xtapi_ret = XTAPI_NOT_SUPPORTED;
396 retval = lineOpen(TapiObj.hObj, TapiDev.id,
398 TapiDev.apiver, 0, 0,
399 LINECALLPRIVILEGE_OWNER,
400 LINEMEDIAMODE_DATAMODEM,
403 xtapi_ret = xtapi_err(retval);
413 the line should be open, and all this function does is grab the call
416 int xtapi_device_answer()
419 int xtapi_ret = XTAPI_SUCCESS;
421 if (!TapiDev.hCall) return XTAPI_NOTOPEN;
423 retval = xtapi_device_wait_for_reply(
424 lineAnswer(TapiDev.hCall, NULL, 0)
428 xtapi_ret = xtapi_err(retval);
435 /* device_poll_callstate
436 we can be informed of the current state of a call made after the
437 reply from lineMakeCall
440 int xtapi_device_poll_callstate(uint *state)
442 // perform translation from TAPI to XTAPI!
444 if (TapiDev.callStateReceived) {
445 switch (TapiDev.call_state)
447 case LINECALLSTATE_IDLE: *state = XTAPI_LINE_IDLE; break;
448 case LINECALLSTATE_DIALTONE: *state = XTAPI_LINE_DIALTONE; break;
449 case LINECALLSTATE_DIALING: *state = XTAPI_LINE_DIALING; break;
450 case LINECALLSTATE_RINGBACK: *state = XTAPI_LINE_RINGBACK; break;
451 case LINECALLSTATE_BUSY: *state = XTAPI_LINE_BUSY; break;
452 case LINECALLSTATE_SPECIALINFO: *state = XTAPI_LINE_FEEDBACK; break;
453 case LINECALLSTATE_CONNECTED: *state = XTAPI_LINE_CONNECTED; break;
454 case LINECALLSTATE_DISCONNECTED: *state = XTAPI_LINE_DISCONNECTED; break;
455 case LINECALLSTATE_PROCEEDING: *state = XTAPI_LINE_PROCEEDING; break;
456 case LINECALLSTATE_OFFERING: *state = XTAPI_LINE_RINGING; break;
458 mprintf((0, "call_state: %x\n", TapiDev.call_state));
459 *state = XTAPI_LINE_UNDEFINED;
461 TapiDev.callStateReceived = FALSE;
462 TapiDev.call_state = 0;
466 return XTAPI_SUCCESS;
470 /* device_create_comm_object
471 once we are connected, we can create a COMM_OBJ to actually send
472 and receive data through the modem.
475 #define ASCII_XON 0x11
476 #define ASCII_XOFF 0x13
479 int xtapi_device_create_comm_object(COMM_OBJ *commobj)
481 VARSTRING *varstr = NULL;
483 HANDLE hCommHandle=NULL;
484 LINECALLINFO *lcinfo = NULL;
486 int errval = XTAPI_SUCCESS;
488 Assert(TapiDev.connected);
490 varstrsize = sizeof(VARSTRING) + 1024;
494 varstr = (VARSTRING *)realloc(varstr, varstrsize);
496 errval = XTAPI_OUT_OF_MEMORY;
497 goto device_create_comm_exit;
500 varstr->dwTotalSize = varstrsize;
502 retval = lineGetID(0,0,TapiDev.hCall, LINECALLSELECT_CALL, varstr,
504 errval = xtapi_err(retval);
506 if (varstr->dwNeededSize > varstr->dwTotalSize) {
507 varstrsize = varstr->dwNeededSize;
512 if (errval != XTAPI_SUCCESS) return errval;
514 hCommHandle = *((LPHANDLE)((LPBYTE)varstr+varstr->dwStringOffset));
516 lcinfo = tapi_line_getcallinfo(TapiDev.hCall);
518 errval = XTAPI_OUT_OF_MEMORY;
519 goto device_create_comm_exit;
523 // Create the COMM compatible COMM_OBJ
524 // Most COMM settings will be set by TAPI, so this is less intensive than the
525 // COMM open connection
527 COMMTIMEOUTS ctimeouts;
529 memset(commobj, 0, sizeof(COMM_OBJ));
531 if (GetFileType(hCommHandle) != FILE_TYPE_CHAR) {
532 errval = XTAPI_GENERAL_ERR;
533 goto device_create_comm_exit;
536 GetCommState(hCommHandle, &commobj->dcb);
537 GetCommTimeouts(hCommHandle, &ctimeouts);
539 commobj->handle = hCommHandle;
540 commobj->baud = lcinfo->dwRate;
543 // commobj->dcb.BaudRate = commobj->baud;
544 // commobj->dcb.fBinary = 1;
545 // commobj->dcb.fNull = 0;
546 // commobj->dcb.ByteSize = 8;
547 // commobj->dcb.StopBits = ONESTOPBIT;
548 // commobj->dcb.fParity = FALSE;
549 // commobj->dcb.Parity = NOPARITY;
550 // commobj->dcb.XonChar = ASCII_XON;
551 // commobj->dcb.XoffChar = ASCII_XOFF;
552 // commobj->dcb.XonLim = 1024;
553 // commobj->dcb.XoffLim = 1024;
554 // commobj->dcb.EofChar = 0;
555 // commobj->dcb.EvtChar = 0;
556 // commobj->dcb.fOutxDsrFlow = FALSE;
557 // commobj->dcb.fOutxCtsFlow = FALSE; // rts/cts off
559 // commobj->dcb.fDtrControl = DTR_CONTROL_ENABLE;// dtr=on
560 // commobj->dcb.fRtsControl = RTS_CONTROL_ENABLE;
562 ctimeouts.ReadIntervalTimeout = 250;
563 ctimeouts.ReadTotalTimeoutMultiplier = 0;
564 ctimeouts.ReadTotalTimeoutConstant = 0;
565 ctimeouts.WriteTotalTimeoutMultiplier = 0;
566 ctimeouts.WriteTotalTimeoutConstant = 0;
568 commobj->dcb.fAbortOnError = FALSE;
570 SetCommTimeouts(hCommHandle, &ctimeouts);
571 SetCommState(hCommHandle, &commobj->dcb);
574 memset(&commobj->rov, 0, sizeof(OVERLAPPED));
575 memset(&commobj->wov, 0, sizeof(OVERLAPPED));
576 commobj->rov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
577 if (commobj->rov.hEvent == NULL) {
578 errval = XTAPI_GENERAL_ERR;
579 goto device_create_comm_exit;
581 commobj->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
582 if (commobj->wov.hEvent == NULL) {
583 CloseHandle(commobj->rov.hEvent);
587 commobj->hThread = NULL;
588 commobj->threadID = (DWORD)(-1);
589 commobj->connect = TRUE;
591 device_create_comm_exit:
592 if (varstr) free(varstr);
593 if (lcinfo) free(lcinfo);
600 frees the call and line
602 damn well better assume that the COMM_OBJ allocated (if at all) is
603 closed via the comm_library.
606 int xtapi_device_hangup()
610 Assert(TapiDev.valid); // Device should be locked!
612 // if (!TapiDev.hCall) return XTAPI_SUCCESS;
613 // if (!TapiDev.hLine) return XTAPI_SUCCESS;
615 // drop any call in progress
617 LINECALLSTATUS *lcallstat = NULL;
621 lcallstat = tapi_line_getcallstatus(TapiDev.hCall);
623 return XTAPI_OUT_OF_MEMORY;
626 mprintf((0, "XTAPI: Got linestatus.\n"));
628 if (!(lcallstat->dwCallState & LINECALLSTATE_IDLE)) {
629 // line not IDLE so drop it!
630 retval = xtapi_device_wait_for_reply(
631 lineDrop(TapiDev.hCall, NULL, 0)
634 if (retval != XTAPI_SUCCESS) {
635 mprintf((1, "XTAPI: error when lineDrop.\n"));
638 mprintf((0, "XTAPI: dropped line.\n"));
641 mprintf((0, "XTAPI: Waiting for idle.\n"));
644 xtapi_device_poll_callstate((uint*)&call_state);
645 if (call_state == XTAPI_LINE_IDLE) break;
646 if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
647 TranslateMessage(&msg);
648 DispatchMessage(&msg);
652 retval = lineDeallocateCall(TapiDev.hCall);
654 mprintf((0, "XTAPI: deallocated call.\n"));
658 return XTAPI_GENERAL_ERR;
660 TapiDev.hCall = NULL;
662 if (lcallstat) free(lcallstat);
667 retval = lineClose(TapiDev.hLine);
669 return XTAPI_GENERAL_ERR;
671 TapiDev.hLine = NULL;
674 mprintf((0, "XTAPI: Closed line.\n"));
676 TapiDev.connected = FALSE;
678 return XTAPI_SUCCESS;
682 /* device_wait_for_reply
683 once a function is called, we wait until we have been given a reply.
685 LONG xtapi_device_wait_for_reply(LONG reqID)
687 if (reqID > 0) { // A valid ID. so we shall wait and see
690 TapiDev.lineReplyReceived = FALSE;
691 TapiDev.asyncRequestedID = (DWORD)reqID;
692 TapiDev.lineReplyResult = LINEERR_OPERATIONFAILED;
694 while (!TapiDev.lineReplyReceived)
696 if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
697 TranslateMessage(&msg);
698 DispatchMessage(&msg);
701 // Insert code to take care of shutting down while wait.
704 return (LONG)TapiDev.lineReplyResult;
712 translate tapi to xtapi errors
715 int xtapi_err(LONG err)
717 mprintf((1, "TAPI err: %x\n", (DWORD)err));
721 return XTAPI_SUCCESS;
723 case LINEERR_ALLOCATED:
724 return XTAPI_APPCONFLICT;
727 return XTAPI_OUT_OF_MEMORY;
729 case LINEERR_INCOMPATIBLEAPIVERSION:
730 return XTAPI_INCOMPATIBLE_VERSION;
732 case LINEERR_NODEVICE:
733 return XTAPI_NODEVICES;
735 case LINEERR_OPERATIONFAILED:
738 case LINEERR_OPERATIONUNAVAIL:
739 return XTAPI_NOT_SUPPORTED;
741 case LINEERR_RESOURCEUNAVAIL:
742 return XTAPI_OUT_OF_RESOURCES;
747 return XTAPI_GENERAL_ERR;
752 this function is used by TAPI to inform us of when asynchronous
753 requests are valid and of any changes to the current call_state
756 void CALLBACK tapi_callback(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInst,
765 mprintf((1, "XTAPI: LINE_REPLY err: %x.\n", dw2));
767 mprintf((1, "XTAPI: LINE_REPLY received.\n"));
768 if (TapiDev.asyncRequestedID == dw1) {
769 TapiDev.lineReplyReceived = TRUE;
770 TapiDev.lineReplyResult = (LONG)dw2;
775 TapiDev.callStateReceived = TRUE;
776 TapiDev.call_state = dw1;
778 mprintf((0, "Call_State = %x\n", dw1));
779 switch(TapiDev.call_state)
781 case LINECALLSTATE_CONNECTED:
782 if (TapiDev.connected) break;
783 TapiDev.connected = TRUE;
786 case LINECALLSTATE_OFFERING:
787 if (TapiDev.connected) {
788 mprintf((1, "TAPI: offering after connected!\n"));
791 if (dw3 != LINECALLPRIVILEGE_OWNER) {
792 mprintf((1, "TAPI: need owner privilege to accept call!.\n"));
795 TapiDev.hCall = (HCALL)hDevice;
809 gets device caps for specified device and returns a valid structure
812 LINEDEVCAPS *tapi_getdevcaps(uint dev)
814 LINEDEVCAPS *pcaps=NULL;
818 size = sizeof(LINEDEVCAPS) + 256;
822 LINEEXTENSIONID extid;
824 retval = lineNegotiateAPIVersion(TapiObj.hObj,
825 dev, TAPI_VERSION, TAPI_VERSION,
831 pcaps = (LINEDEVCAPS *)realloc(pcaps, size);
832 if (!pcaps) return NULL;
834 memset(pcaps, 0, size);
835 pcaps->dwTotalSize = size;
837 retval = lineGetDevCaps(TapiObj.hObj, dev,
846 if (pcaps->dwNeededSize > pcaps->dwTotalSize) {
847 size = pcaps->dwNeededSize;
856 /* tapi_line_getaddrstatus
857 retrieves the current status of a given address on the line.
863 LINEADDRESSSTATUS *tapi_line_getaddrstatus(HLINE hLine, DWORD dwID)
865 LINEADDRESSSTATUS *ad=NULL;
869 size = sizeof(LINEADDRESSSTATUS) + 256;
873 ad = (LINEADDRESSSTATUS *)realloc(ad, size);
874 if (!ad) return NULL;
877 ad->dwTotalSize = size;
879 retval = lineGetAddressStatus(hLine, dwID, ad);
886 if (ad->dwNeededSize > ad->dwTotalSize) {
887 size = ad->dwNeededSize;
897 /* tapi_line_getaddrcaps
898 retrieves the current caps of a given address on the line.
904 LINEADDRESSCAPS *tapi_line_getaddrcaps(uint dev, DWORD addrID)
906 LINEADDRESSCAPS *ad=NULL;
910 size = sizeof(LINEADDRESSCAPS) + 256;
915 LINEEXTENSIONID extid;
917 retval = lineNegotiateAPIVersion(TapiObj.hObj,
918 dev, TAPI_VERSION, TAPI_VERSION,
924 ad = (LINEADDRESSCAPS *)realloc(ad, size);
925 if (!ad) return NULL;
928 ad->dwTotalSize = size;
930 retval = lineGetAddressCaps(TapiObj.hObj, dev,
939 if (ad->dwNeededSize > ad->dwTotalSize) {
940 size = ad->dwNeededSize;
950 /* tapi_line_getcallstatus
951 retrieves the current status of a given call on the line.
957 LINECALLSTATUS *tapi_line_getcallstatus(HCALL hCall)
959 LINECALLSTATUS *ad=NULL;
963 size = sizeof(LINECALLSTATUS) + 256;
967 ad = (LINECALLSTATUS *)realloc(ad, size);
968 if (!ad) return NULL;
971 ad->dwTotalSize = size;
973 retval = lineGetCallStatus(hCall,ad);
980 if (ad->dwNeededSize > ad->dwTotalSize) {
981 size = ad->dwNeededSize;
991 /* tapi_line_getcallinfo
992 retrieves the current status of a given call on the line.
998 LINECALLINFO *tapi_line_getcallinfo(HCALL hCall)
1000 LINECALLINFO *ad=NULL;
1004 size = sizeof(LINECALLINFO) + 256;
1008 ad = (LINECALLINFO *)realloc(ad, size);
1009 if (!ad) return NULL;
1011 memset(ad, 0, size);
1012 ad->dwTotalSize = size;
1014 retval = lineGetCallInfo(hCall,ad);
1021 if (ad->dwNeededSize > ad->dwTotalSize) {
1022 size = ad->dwNeededSize;