1 /*
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.
12 */
13
14
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)
18
19
20 #define _WIN32
21 #define WIN95
22 #define WIN32_LEAN_AND_MEAN
23
24 #include <windows.h>
25 #include <windowsx.h>
26 #include <tapi.h>
27
28 #include "pstypes.h"
29 #include "mono.h"
30 #include "error.h"
31 #include "winapp.h"
32 #include "xtapi.h"
33
34
35 /* The TAPI layer will interface between Descent 2 and Win32 TAPI.
36
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.
39
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.
43
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.
48
49 To dial-out. Call xtapi_device_dialout.
50
51 */
52
53 #define TAPI_VERSION 0x00010004
54
55
56
57 /*
58 * Data
59 */
60
61 struct tagTapiObj {
62 HLINEAPP hObj;
63 HWND hWnd;
64 DWORD num_devs;
65 } TapiObj = { NULL, NULL, 0 };
66
67 struct tagTapiDev {
68 BOOL valid;
69 DWORD id;
70 DWORD apiver;
71 DWORD type;
72 HLINE hLine;
73 HCALL hCall;
74 DWORD call_state;
75 BOOL connected;
76 BOOL lineReplyReceived;
77 BOOL callStateReceived;
78 DWORD asyncRequestedID;
79 LONG lineReplyResult;
80
81 } TapiDev = { FALSE, 0, 0, 0, NULL, NULL, 0, FALSE, FALSE, FALSE, 0, 0 };
82
83
84
85 /*
86 * Local function prototypes
87 */
88
89 void CALLBACK tapi_callback(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInst,
90 DWORD dw1,
91 DWORD dw2,
92 DWORD dw3);
93
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);
99
100 int xtapi_err(LONG val);
101 LONG xtapi_device_wait_for_reply(LONG reqID);
102
103
104
105 /*
106 * Functions
107 */
108
109 /* init
110 initializes the TAPI interface
111
112 returns:
113 XTAPI_NODEVICES if no devices found
114 XTAPI_BUSY if we are calling this function again for some reason
115 (non-reentrant)
116 XTAPI_APPCONFLICT TAPI is being used somewhere else, and we can't gain
117 control
118 XTAPI_INCOMPATIBLE_VERSION this interface is old or not supported
119 under current Win32.
120 */
121
xtapi_init(char * appname,int * numdevs)122 int xtapi_init(char *appname, int *numdevs)
123 {
124 LONG retval;
125 BOOL reinit;
126
127 if (TapiObj.hObj) return XTAPI_SUCCESS;
128
129 TapiObj.hWnd = GetLibraryWindow();
130
131 reinit = TRUE; // Allow for reinitialization
132
133 while (1)
134 {
135 retval = lineInitialize(&TapiObj.hObj,
136 GetWindowInstance(TapiObj.hWnd),
137 tapi_callback,
138 appname,
139 &TapiObj.num_devs);
140
141 if (!retval) {
142 break;
143 }
144 else if (retval == LINEERR_REINIT) {
145 if (reinit) {
146 timer_delay(0x50000); // delay 5 seconds
147 reinit = FALSE;
148 }
149 else {
150 return XTAPI_APPCONFLICT; // another app is using tapi resources we need
151 }
152 }
153 else if (retval == LINEERR_NODEVICE) {
154 return XTAPI_NODEVICES; // should tell user to install a modem
155 }
156 else return XTAPI_GENERAL_ERR;
157 }
158
159 *numdevs = (int)TapiObj.num_devs;
160
161 TapiDev.valid = FALSE;
162
163 return XTAPI_SUCCESS;
164 }
165
166
167 /* shutdown
168 performs a shutdown of the TAPI system
169 */
170
xtapi_shutdown()171 int xtapi_shutdown()
172 {
173 LONG retval;
174
175 if (!TapiObj.hObj) return 0;
176
177 // Close any device that may be open at this point!
178
179 // shutdown TAPI
180 retval = lineShutdown(TapiObj.hObj);
181 if (retval!=0) return xtapi_err(retval);
182
183 TapiObj.hObj = NULL;
184 TapiObj.num_devs = 0;
185 TapiObj.hWnd = NULL;
186
187 return 0;
188 }
189
190
191 /* enumdevices
192 enumerates the devices usable by TAPI. good for
193 letting the user select the device and TAPI to take over
194 */
195
xtapi_enumdevices(TapiDevice * dev,int num)196 int xtapi_enumdevices(TapiDevice *dev, int num)
197 {
198 LONG retval;
199 int i;
200
201 Assert(TapiObj.hObj != NULL);
202 Assert(num <= TapiObj.num_devs);
203
204 for (i = 0; i < num; i++)
205 {
206 LINEEXTENSIONID extid;
207 LINEDEVCAPS *caps;
208
209 caps = tapi_getdevcaps(i);
210 if (caps == NULL) return XTAPI_OUT_OF_MEMORY;
211
212 if ((caps->dwBearerModes & LINEBEARERMODE_VOICE) &&
213 (caps->dwMediaModes & LINEMEDIAMODE_DATAMODEM)) {
214 dev[i].type = XTAPI_MODEM_DEVICE;
215 }
216 else dev[i].type = 0;
217
218 retval = lineNegotiateAPIVersion(TapiObj.hObj,
219 i, TAPI_VERSION, TAPI_VERSION,
220 (DWORD *)&dev[i].apiver, &extid);
221
222 if (retval == LINEERR_INCOMPATIBLEAPIVERSION)
223 return XTAPI_INCOMPATIBLE_VERSION;
224 else if (retval != 0)
225 return xtapi_err(retval);
226
227 dev[i].id = i;
228 dev[i].min_baud = (uint)caps->dwMaxRate;
229 dev[i].max_baud = (uint)caps->dwMaxRate;
230
231 free(caps);
232 }
233
234 return XTAPI_SUCCESS;
235 }
236
237
238 /* lock
239 this function sets the specified device as the current device to be
240 used by the xtapi_device system
241 */
242
xtapi_lock(TapiDevice * dev)243 int xtapi_lock(TapiDevice *dev)
244 {
245 if (TapiDev.valid) return XTAPI_BUSY;
246
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;
258
259 return XTAPI_SUCCESS;
260 }
261
262
263 /* unlock
264 this functions just releases the device. device functions won't work
265 anymore until another lock
266 */
267
xtapi_unlock(TapiDevice * dev)268 int xtapi_unlock(TapiDevice *dev)
269 {
270 if (!TapiDev.valid) return XTAPI_NOTLOCKED;
271
272 if (TapiDev.hCall || TapiDev.hLine)
273 xtapi_device_hangup();
274
275 TapiDev.id = 0;
276 TapiDev.apiver = 0;
277 TapiDev.hLine = NULL;
278 TapiDev.hCall = NULL;
279 TapiDev.call_state = 0;
280 TapiDev.valid = FALSE;
281
282 return XTAPI_SUCCESS;
283 }
284
285
286 /* device_dial
287 this function will dialout a given number through the current
288 device.
289 */
290
xtapi_device_dialout(char * phonenum)291 int xtapi_device_dialout(char *phonenum)
292 {
293 LINEDEVCAPS *ldevcaps=NULL;
294 LINECALLPARAMS *lcallparams=NULL;
295 LONG retval;
296 int xtapi_ret = XTAPI_SUCCESS;
297
298 if (TapiDev.hLine) return XTAPI_BUSY;
299
300 // check if we can dial out
301 if (TapiDev.type != XTAPI_MODEM_DEVICE) {
302 xtapi_ret = XTAPI_NOT_SUPPORTED;
303 goto dialout_exit;
304 }
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;
309 goto dialout_exit;
310 }
311
312 // open the line!
313 retval = lineOpen(TapiObj.hObj, TapiDev.id,
314 &TapiDev.hLine,
315 TapiDev.apiver, 0, 0,
316 LINECALLPRIVILEGE_NONE,
317 LINEMEDIAMODE_DATAMODEM,
318 0);
319 if (retval != 0) {
320 xtapi_ret = xtapi_err(retval);
321 goto dialout_exit;
322 }
323
324 retval = lineSetStatusMessages(TapiDev.hLine,
325 LINEDEVSTATE_OTHER |
326 LINEDEVSTATE_RINGING | LINEDEVSTATE_CONNECTED |
327 LINEDEVSTATE_DISCONNECTED | LINEDEVSTATE_OUTOFSERVICE |
328 LINEDEVSTATE_MAINTENANCE | LINEDEVSTATE_REINIT,
329 LINEADDRESSSTATE_INUSEZERO |
330 LINEADDRESSSTATE_INUSEONE |
331 LINEADDRESSSTATE_INUSEMANY);
332
333 if (retval != 0) {
334 xtapi_ret = xtapi_err(retval);
335 goto dialout_exit;
336 }
337
338 // Setup calling parameters
339 lcallparams = (LINECALLPARAMS *)malloc(sizeof(LINECALLPARAMS)+strlen(phonenum)+1);
340 if (!lcallparams) {
341 xtapi_ret = XTAPI_OUT_OF_MEMORY;
342 goto dialout_exit;
343 }
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);
354
355 // Dial it!
356 mprintf((0, "XTAPI: dialing %s.\n", phonenum));
357 retval = xtapi_device_wait_for_reply(
358 lineMakeCall(TapiDev.hLine, &TapiDev.hCall, NULL, 0, lcallparams)
359 );
360 if (retval < 0) {
361 xtapi_ret = xtapi_err(retval);
362 goto dialout_exit;
363 }
364
365 retval = xtapi_device_wait_for_reply(
366 lineDial(TapiDev.hCall, phonenum, 0)
367 );
368 if (retval < 0) {
369 xtapi_ret = xtapi_err(retval);
370 goto dialout_exit;
371 }
372
373 dialout_exit:
374 if (lcallparams) free(lcallparams);
375 if (ldevcaps) free(ldevcaps);
376
377 return xtapi_ret;
378 }
379
380
381 /* device_dialin
382 sets up modem to wait for a call. All this function does
383 is initialize the line.
384 */
385
xtapi_device_dialin()386 int xtapi_device_dialin()
387 {
388 LONG retval;
389 int xtapi_ret = XTAPI_SUCCESS;
390
391 if (TapiDev.hLine) return XTAPI_BUSY;
392
393 // check if we can dial out
394 if (TapiDev.type != XTAPI_MODEM_DEVICE) {
395 xtapi_ret = XTAPI_NOT_SUPPORTED;
396 goto dialin_exit;
397 }
398
399 // open the line!
400 retval = lineOpen(TapiObj.hObj, TapiDev.id,
401 &TapiDev.hLine,
402 TapiDev.apiver, 0, 0,
403 LINECALLPRIVILEGE_OWNER,
404 LINEMEDIAMODE_DATAMODEM,
405 0);
406 if (retval != 0) {
407 xtapi_ret = xtapi_err(retval);
408 goto dialin_exit;
409 }
410
411 dialin_exit:
412 return xtapi_ret;
413 }
414
415
416 /* device_answer
417 the line should be open, and all this function does is grab the call
418 */
419
xtapi_device_answer()420 int xtapi_device_answer()
421 {
422 LONG retval;
423 int xtapi_ret = XTAPI_SUCCESS;
424
425 if (!TapiDev.hCall) return XTAPI_NOTOPEN;
426
427 retval = xtapi_device_wait_for_reply(
428 lineAnswer(TapiDev.hCall, NULL, 0)
429 );
430
431 if (retval < 0) {
432 xtapi_ret = xtapi_err(retval);
433 }
434
435 return xtapi_ret;
436 }
437
438
439 /* device_poll_callstate
440 we can be informed of the current state of a call made after the
441 reply from lineMakeCall
442 */
443
xtapi_device_poll_callstate(uint * state)444 int xtapi_device_poll_callstate(uint *state)
445 {
446 // perform translation from TAPI to XTAPI!
447
448 if (TapiDev.callStateReceived) {
449 switch (TapiDev.call_state)
450 {
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;
461 default:
462 mprintf((0, "call_state: %x\n", TapiDev.call_state));
463 *state = XTAPI_LINE_UNDEFINED;
464 }
465 TapiDev.callStateReceived = FALSE;
466 TapiDev.call_state = 0;
467 }
468 else *state = 0;
469
470 return XTAPI_SUCCESS;
471 }
472
473
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.
477 */
478
479 #define ASCII_XON 0x11
480 #define ASCII_XOFF 0x13
481
482
xtapi_device_create_comm_object(COMM_OBJ * commobj)483 int xtapi_device_create_comm_object(COMM_OBJ *commobj)
484 {
485 VARSTRING *varstr = NULL;
486 DWORD varstrsize;
487 HANDLE hCommHandle=NULL;
488 LINECALLINFO *lcinfo = NULL;
489 int retval;
490 int errval = XTAPI_SUCCESS;
491
492 Assert(TapiDev.connected);
493
494 varstrsize = sizeof(VARSTRING) + 1024;
495
496 while (1)
497 {
498 varstr = (VARSTRING *)realloc(varstr, varstrsize);
499 if (!varstr) {
500 errval = XTAPI_OUT_OF_MEMORY;
501 goto device_create_comm_exit;
502 }
503
504 varstr->dwTotalSize = varstrsize;
505
506 retval = lineGetID(0,0,TapiDev.hCall, LINECALLSELECT_CALL, varstr,
507 "comm/datamodem");
508 errval = xtapi_err(retval);
509
510 if (varstr->dwNeededSize > varstr->dwTotalSize) {
511 varstrsize = varstr->dwNeededSize;
512 }
513 else break;
514 }
515
516 if (errval != XTAPI_SUCCESS) return errval;
517
518 hCommHandle = *((LPHANDLE)((LPBYTE)varstr+varstr->dwStringOffset));
519
520 lcinfo = tapi_line_getcallinfo(TapiDev.hCall);
521 if (!lcinfo) {
522 errval = XTAPI_OUT_OF_MEMORY;
523 goto device_create_comm_exit;
524 }
525
526
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
530 {
531 COMMTIMEOUTS ctimeouts;
532
533 memset(commobj, 0, sizeof(COMM_OBJ));
534
535 if (GetFileType(hCommHandle) != FILE_TYPE_CHAR) {
536 errval = XTAPI_GENERAL_ERR;
537 goto device_create_comm_exit;
538 }
539
540 GetCommState(hCommHandle, &commobj->dcb);
541 GetCommTimeouts(hCommHandle, &ctimeouts);
542
543 commobj->handle = hCommHandle;
544 commobj->baud = lcinfo->dwRate;
545
546
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
562
563 // commobj->dcb.fDtrControl = DTR_CONTROL_ENABLE;// dtr=on
564 // commobj->dcb.fRtsControl = RTS_CONTROL_ENABLE;
565
566 ctimeouts.ReadIntervalTimeout = 250;
567 ctimeouts.ReadTotalTimeoutMultiplier = 0;
568 ctimeouts.ReadTotalTimeoutConstant = 0;
569 ctimeouts.WriteTotalTimeoutMultiplier = 0;
570 ctimeouts.WriteTotalTimeoutConstant = 0;
571
572 commobj->dcb.fAbortOnError = FALSE;
573
574 SetCommTimeouts(hCommHandle, &ctimeouts);
575 SetCommState(hCommHandle, &commobj->dcb);
576 }
577
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;
584 }
585 commobj->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
586 if (commobj->wov.hEvent == NULL) {
587 CloseHandle(commobj->rov.hEvent);
588 return 0;
589 }
590
591 commobj->hThread = NULL;
592 commobj->threadID = (DWORD)(-1);
593 commobj->connect = TRUE;
594
595 device_create_comm_exit:
596 if (varstr) free(varstr);
597 if (lcinfo) free(lcinfo);
598
599 return errval;
600 }
601
602
603 /* device_hangup
604 frees the call and line
605
606 damn well better assume that the COMM_OBJ allocated (if at all) is
607 closed via the comm_library.
608 */
609
xtapi_device_hangup()610 int xtapi_device_hangup()
611 {
612 LONG retval;
613
614 Assert(TapiDev.valid); // Device should be locked!
615
616 // if (!TapiDev.hCall) return XTAPI_SUCCESS;
617 // if (!TapiDev.hLine) return XTAPI_SUCCESS;
618
619 // drop any call in progress
620 if (TapiDev.hCall) {
621 LINECALLSTATUS *lcallstat = NULL;
622 MSG msg;
623 DWORD call_state;
624
625 lcallstat = tapi_line_getcallstatus(TapiDev.hCall);
626 if (!lcallstat) {
627 return XTAPI_OUT_OF_MEMORY;
628 }
629
630 mprintf((0, "XTAPI: Got linestatus.\n"));
631
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)
636 );
637
638 if (retval != XTAPI_SUCCESS) {
639 mprintf((1, "XTAPI: error when lineDrop.\n"));
640 }
641
642 mprintf((0, "XTAPI: dropped line.\n"));
643
644 // wait for IDLE
645 mprintf((0, "XTAPI: Waiting for idle.\n"));
646 while (1)
647 {
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);
653 }
654 }
655 }
656 retval = lineDeallocateCall(TapiDev.hCall);
657
658 mprintf((0, "XTAPI: deallocated call.\n"));
659
660 if (retval != 0) {
661 free(lcallstat);
662 return XTAPI_GENERAL_ERR;
663 }
664 TapiDev.hCall = NULL;
665
666 if (lcallstat) free(lcallstat);
667 }
668
669 // Free up line.
670 if (TapiDev.hLine) {
671 retval = lineClose(TapiDev.hLine);
672 if (retval != 0) {
673 return XTAPI_GENERAL_ERR;
674 }
675 TapiDev.hLine = NULL;
676 }
677
678 mprintf((0, "XTAPI: Closed line.\n"));
679
680 TapiDev.connected = FALSE;
681
682 return XTAPI_SUCCESS;
683 }
684
685
686 /* device_wait_for_reply
687 once a function is called, we wait until we have been given a reply.
688 */
xtapi_device_wait_for_reply(LONG reqID)689 LONG xtapi_device_wait_for_reply(LONG reqID)
690 {
691 if (reqID > 0) { // A valid ID. so we shall wait and see
692 MSG msg;
693
694 TapiDev.lineReplyReceived = FALSE;
695 TapiDev.asyncRequestedID = (DWORD)reqID;
696 TapiDev.lineReplyResult = LINEERR_OPERATIONFAILED;
697
698 while (!TapiDev.lineReplyReceived)
699 {
700 if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
701 TranslateMessage(&msg);
702 DispatchMessage(&msg);
703 }
704
705 // Insert code to take care of shutting down while wait.
706 }
707
708 return (LONG)TapiDev.lineReplyResult;
709 }
710
711 return reqID;
712 }
713
714
715 /* err
716 translate tapi to xtapi errors
717 */
718
xtapi_err(LONG err)719 int xtapi_err(LONG err)
720 {
721 mprintf((1, "TAPI err: %x\n", (DWORD)err));
722 switch (err)
723 {
724 case 0:
725 return XTAPI_SUCCESS;
726
727 case LINEERR_ALLOCATED:
728 return XTAPI_APPCONFLICT;
729
730 case LINEERR_NOMEM:
731 return XTAPI_OUT_OF_MEMORY;
732
733 case LINEERR_INCOMPATIBLEAPIVERSION:
734 return XTAPI_INCOMPATIBLE_VERSION;
735
736 case LINEERR_NODEVICE:
737 return XTAPI_NODEVICES;
738
739 case LINEERR_OPERATIONFAILED:
740 return XTAPI_FAIL;
741
742 case LINEERR_OPERATIONUNAVAIL:
743 return XTAPI_NOT_SUPPORTED;
744
745 case LINEERR_RESOURCEUNAVAIL:
746 return XTAPI_OUT_OF_RESOURCES;
747
748 case LINEERR_REINIT:
749 return XTAPI_BUSY;
750 }
751 return XTAPI_GENERAL_ERR;
752 }
753
754
755 /* callback
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
758 */
759
tapi_callback(DWORD hDevice,DWORD dwMsg,DWORD dwCallbackInst,DWORD dw1,DWORD dw2,DWORD dw3)760 void CALLBACK tapi_callback(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInst,
761 DWORD dw1,
762 DWORD dw2,
763 DWORD dw3)
764 {
765 switch(dwMsg)
766 {
767 case LINE_REPLY:
768 if (dw2 != 0)
769 mprintf((1, "XTAPI: LINE_REPLY err: %x.\n", dw2));
770 else
771 mprintf((1, "XTAPI: LINE_REPLY received.\n"));
772 if (TapiDev.asyncRequestedID == dw1) {
773 TapiDev.lineReplyReceived = TRUE;
774 TapiDev.lineReplyResult = (LONG)dw2;
775 }
776 break;
777
778 case LINE_CALLSTATE:
779 TapiDev.callStateReceived = TRUE;
780 TapiDev.call_state = dw1;
781
782 mprintf((0, "Call_State = %x\n", dw1));
783 switch(TapiDev.call_state)
784 {
785 case LINECALLSTATE_CONNECTED:
786 if (TapiDev.connected) break;
787 TapiDev.connected = TRUE;
788 break;
789
790 case LINECALLSTATE_OFFERING:
791 if (TapiDev.connected) {
792 mprintf((1, "TAPI: offering after connected!\n"));
793 break;
794 }
795 if (dw3 != LINECALLPRIVILEGE_OWNER) {
796 mprintf((1, "TAPI: need owner privilege to accept call!.\n"));
797 break;
798 }
799 TapiDev.hCall = (HCALL)hDevice;
800 break;
801 }
802 break;
803 }
804 }
805
806
807
808 /*
809 * TAPI functions
810 */
811
812 /* tapi_getdevcaps
813 gets device caps for specified device and returns a valid structure
814 */
815
tapi_getdevcaps(uint dev)816 LINEDEVCAPS *tapi_getdevcaps(uint dev)
817 {
818 LINEDEVCAPS *pcaps=NULL;
819 LONG retval, size;
820 DWORD apiver;
821
822 size = sizeof(LINEDEVCAPS) + 256;
823
824 while (1)
825 {
826 LINEEXTENSIONID extid;
827
828 retval = lineNegotiateAPIVersion(TapiObj.hObj,
829 dev, TAPI_VERSION, TAPI_VERSION,
830 &apiver, &extid);
831
832 if (retval != 0)
833 return NULL;
834
835 pcaps = (LINEDEVCAPS *)realloc(pcaps, size);
836 if (!pcaps) return NULL;
837
838 memset(pcaps, 0, size);
839 pcaps->dwTotalSize = size;
840
841 retval = lineGetDevCaps(TapiObj.hObj, dev,
842 apiver, 0,
843 pcaps);
844
845 if (retval!=0) {
846 free(pcaps);
847 return NULL;
848 }
849
850 if (pcaps->dwNeededSize > pcaps->dwTotalSize) {
851 size = pcaps->dwNeededSize;
852 continue;
853 }
854 else break;
855 }
856
857 return pcaps;
858 }
859
860 /* tapi_line_getaddrstatus
861 retrieves the current status of a given address on the line.
862
863 returns:
864 NULL if fail.
865 */
866
tapi_line_getaddrstatus(HLINE hLine,DWORD dwID)867 LINEADDRESSSTATUS *tapi_line_getaddrstatus(HLINE hLine, DWORD dwID)
868 {
869 LINEADDRESSSTATUS *ad=NULL;
870 LONG retval;
871 int size;
872
873 size = sizeof(LINEADDRESSSTATUS) + 256;
874
875 while (1)
876 {
877 ad = (LINEADDRESSSTATUS *)realloc(ad, size);
878 if (!ad) return NULL;
879
880 memset(ad, 0, size);
881 ad->dwTotalSize = size;
882
883 retval = lineGetAddressStatus(hLine, dwID, ad);
884
885 if (retval!=0) {
886 free(ad);
887 return NULL;
888 }
889
890 if (ad->dwNeededSize > ad->dwTotalSize) {
891 size = ad->dwNeededSize;
892 continue;
893 }
894 else break;
895 }
896
897 return ad;
898 }
899
900
901 /* tapi_line_getaddrcaps
902 retrieves the current caps of a given address on the line.
903
904 returns:
905 NULL if fail.
906 */
907
tapi_line_getaddrcaps(uint dev,DWORD addrID)908 LINEADDRESSCAPS *tapi_line_getaddrcaps(uint dev, DWORD addrID)
909 {
910 LINEADDRESSCAPS *ad=NULL;
911 LONG retval;
912 int size;
913
914 size = sizeof(LINEADDRESSCAPS) + 256;
915
916 while (1)
917 {
918 DWORD apiver;
919 LINEEXTENSIONID extid;
920
921 retval = lineNegotiateAPIVersion(TapiObj.hObj,
922 dev, TAPI_VERSION, TAPI_VERSION,
923 &apiver, &extid);
924
925 if (retval != 0)
926 return NULL;
927
928 ad = (LINEADDRESSCAPS *)realloc(ad, size);
929 if (!ad) return NULL;
930
931 memset(ad, 0, size);
932 ad->dwTotalSize = size;
933
934 retval = lineGetAddressCaps(TapiObj.hObj, dev,
935 addrID, apiver, 0,
936 ad);
937
938 if (retval!=0) {
939 free(ad);
940 return NULL;
941 }
942
943 if (ad->dwNeededSize > ad->dwTotalSize) {
944 size = ad->dwNeededSize;
945 continue;
946 }
947 else break;
948 }
949
950 return ad;
951 }
952
953
954 /* tapi_line_getcallstatus
955 retrieves the current status of a given call on the line.
956
957 returns:
958 NULL if fail.
959 */
960
tapi_line_getcallstatus(HCALL hCall)961 LINECALLSTATUS *tapi_line_getcallstatus(HCALL hCall)
962 {
963 LINECALLSTATUS *ad=NULL;
964 LONG retval;
965 int size;
966
967 size = sizeof(LINECALLSTATUS) + 256;
968
969 while (1)
970 {
971 ad = (LINECALLSTATUS *)realloc(ad, size);
972 if (!ad) return NULL;
973
974 memset(ad, 0, size);
975 ad->dwTotalSize = size;
976
977 retval = lineGetCallStatus(hCall,ad);
978
979 if (retval!=0) {
980 free(ad);
981 return NULL;
982 }
983
984 if (ad->dwNeededSize > ad->dwTotalSize) {
985 size = ad->dwNeededSize;
986 continue;
987 }
988 else break;
989 }
990
991 return ad;
992 }
993
994
995 /* tapi_line_getcallinfo
996 retrieves the current status of a given call on the line.
997
998 returns:
999 NULL if fail.
1000 */
1001
tapi_line_getcallinfo(HCALL hCall)1002 LINECALLINFO *tapi_line_getcallinfo(HCALL hCall)
1003 {
1004 LINECALLINFO *ad=NULL;
1005 LONG retval;
1006 int size;
1007
1008 size = sizeof(LINECALLINFO) + 256;
1009
1010 while (1)
1011 {
1012 ad = (LINECALLINFO *)realloc(ad, size);
1013 if (!ad) return NULL;
1014
1015 memset(ad, 0, size);
1016 ad->dwTotalSize = size;
1017
1018 retval = lineGetCallInfo(hCall,ad);
1019
1020 if (retval!=0) {
1021 free(ad);
1022 return NULL;
1023 }
1024
1025 if (ad->dwNeededSize > ad->dwTotalSize) {
1026 size = ad->dwNeededSize;
1027 continue;
1028 }
1029 else break;
1030 }
1031
1032 return ad;
1033 }
1034