Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2738 lines
73 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. tapi.c
  5. Abstract:
  6. This module wraps all of the TAPI calls.
  7. Author:
  8. Wesley Witt (wesw) 22-Jan-1996
  9. Revision History:
  10. --*/
  11. #include "faxsvc.h"
  12. #pragma hdrstop
  13. //
  14. // globals
  15. //
  16. HLINEAPP hLineApp; // application line handle
  17. DWORD TapiApiVersion; //
  18. HANDLE TapiCompletionPort; //
  19. DWORD DeviceInstalled; //
  20. CRITICAL_SECTION CsLine; // critical section for accessing tapi lines
  21. DWORD TapiDevices; // number of tapi devices
  22. DWORD DeviceCount; // number of devices in the TapiLinesListHead
  23. LIST_ENTRY TapiLinesListHead; // linked list of tapi lines
  24. LPBYTE AdaptiveFileBuffer; // list of approved adaptive answer modems
  25. extern LONG ConnectionCount;
  26. #include "modem.c"
  27. BOOL
  28. AddNewDevice(
  29. DWORD DeviceId,
  30. LPLINEDEVCAPS LineDevCaps,
  31. BOOL InitDevice
  32. );
  33. DWORD
  34. InitializeTapiLine(
  35. DWORD DeviceId,
  36. LPLINEDEVCAPS LineDevCaps,
  37. DWORD Priority,
  38. DWORD Rings,
  39. DWORD Flags,
  40. LPTSTR Csid,
  41. LPTSTR Tsid
  42. );
  43. LPTSTR
  44. FixupDeviceName(
  45. LPTSTR OrigDeviceName
  46. )
  47. {
  48. LPTSTR NewDeviceName;
  49. LPTSTR p;
  50. NewDeviceName = StringDup( OrigDeviceName );
  51. if (!NewDeviceName) {
  52. return NULL;
  53. }
  54. p = _tcschr( NewDeviceName, TEXT(',') );
  55. if (!p) {
  56. return NewDeviceName;
  57. }
  58. p = NewDeviceName;
  59. while( p ) {
  60. p = _tcschr( p, TEXT(',') );
  61. if (p) {
  62. *p = TEXT('_');
  63. }
  64. }
  65. return NewDeviceName;
  66. }
  67. VOID
  68. FreeTapiLine(
  69. PLINE_INFO LineInfo
  70. )
  71. {
  72. HLINE hLine = 0;
  73. if (!LineInfo) {
  74. return;
  75. }
  76. if (LineInfo->hLine) {
  77. hLine = LineInfo->hLine;
  78. LineInfo->hLine = 0;
  79. }
  80. MemFree( LineInfo->DeviceName );
  81. MemFree( LineInfo->Tsid );
  82. MemFree( LineInfo );
  83. if (hLine) {
  84. lineClose( hLine );
  85. }
  86. }
  87. int
  88. __cdecl
  89. DevicePriorityCompare(
  90. const void *arg1,
  91. const void *arg2
  92. )
  93. {
  94. if (((PDEVICE_SORT)arg1)->Priority < ((PDEVICE_SORT)arg2)->Priority) {
  95. return -1;
  96. }
  97. if (((PDEVICE_SORT)arg1)->Priority > ((PDEVICE_SORT)arg2)->Priority) {
  98. return 1;
  99. }
  100. return 0;
  101. }
  102. BOOL
  103. SortDevicePriorities(
  104. VOID
  105. )
  106. {
  107. PLIST_ENTRY Next;
  108. PLINE_INFO LineInfo;
  109. PDEVICE_SORT DeviceSort;
  110. DWORD i = 0;
  111. EnterCriticalSection( &CsLine );
  112. Next = TapiLinesListHead.Flink;
  113. if (Next == NULL) {
  114. LeaveCriticalSection( &CsLine );
  115. return FALSE;
  116. }
  117. DeviceSort = (PDEVICE_SORT) MemAlloc( DeviceCount * sizeof(DEVICE_SORT) );
  118. if (DeviceSort == NULL) {
  119. LeaveCriticalSection( &CsLine );
  120. return FALSE;
  121. }
  122. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  123. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  124. Next = LineInfo->ListEntry.Flink;
  125. DeviceSort[i].Priority = LineInfo->Priority;
  126. DeviceSort[i].LineInfo = LineInfo;
  127. i += 1;
  128. }
  129. qsort(
  130. (PVOID)DeviceSort,
  131. (int)DeviceCount,
  132. sizeof(DEVICE_SORT),
  133. DevicePriorityCompare
  134. );
  135. InitializeListHead( &TapiLinesListHead );
  136. for (i=0; i<DeviceCount; i++) {
  137. DeviceSort[i].LineInfo->Priority = i + 1;
  138. DeviceSort[i].LineInfo->ListEntry.Flink = NULL;
  139. DeviceSort[i].LineInfo->ListEntry.Blink = NULL;
  140. InsertTailList( &TapiLinesListHead, &DeviceSort[i].LineInfo->ListEntry );
  141. }
  142. LeaveCriticalSection( &CsLine );
  143. MemFree( DeviceSort );
  144. return TRUE;
  145. }
  146. DWORD GetFaxDeviceCount(
  147. VOID
  148. )
  149. /*++
  150. Routine Description:
  151. counts the number of installed fax devices
  152. Arguments:
  153. NONE.
  154. Return Value:
  155. number of devices
  156. --*/
  157. {
  158. DWORD FaxDevices = 0;
  159. PLIST_ENTRY Next;
  160. PLINE_INFO LineInfo;
  161. __try {
  162. EnterCriticalSection(&CsLine);
  163. Next = TapiLinesListHead.Flink;
  164. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  165. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  166. Next = LineInfo->ListEntry.Flink;
  167. if (LineInfo->PermanentLineID && LineInfo->DeviceName) {
  168. FaxDevices += 1;
  169. }
  170. }
  171. LeaveCriticalSection(&CsLine);
  172. } __except (EXCEPTION_EXECUTE_HANDLER) {
  173. LeaveCriticalSection(&CsLine);
  174. }
  175. return FaxDevices;
  176. }
  177. BOOL GetDeviceTypeCount(
  178. LPDWORD SendDevices,
  179. LPDWORD ReceiveDevices
  180. )
  181. /*++
  182. Routine Description:
  183. counts the number of devices with receive enabled, number with send enabled
  184. Arguments:
  185. SendDevices - receives number of send devices
  186. ReceiveDevices - receives number of receive devices
  187. Return Value:
  188. number of devices
  189. --*/
  190. {
  191. DWORD Rx = 0, Tx = 0;
  192. PLIST_ENTRY Next;
  193. PLINE_INFO LineInfo;
  194. __try {
  195. EnterCriticalSection(&CsLine);
  196. Next = TapiLinesListHead.Flink;
  197. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  198. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  199. Next = LineInfo->ListEntry.Flink;
  200. if (LineInfo->PermanentLineID && LineInfo->DeviceName) {
  201. if ((LineInfo->Flags & FPF_SEND) == FPF_SEND) {
  202. Tx++;
  203. }
  204. if ((LineInfo->Flags & FPF_RECEIVE) == FPF_RECEIVE) {
  205. Rx++;
  206. }
  207. }
  208. }
  209. LeaveCriticalSection(&CsLine);
  210. } __except (EXCEPTION_EXECUTE_HANDLER) {
  211. LeaveCriticalSection(&CsLine);
  212. }
  213. if (SendDevices) {
  214. *SendDevices = Tx;
  215. }
  216. if (ReceiveDevices) {
  217. *ReceiveDevices = Rx;
  218. }
  219. return TRUE;
  220. }
  221. BOOL
  222. CommitDeviceChanges(
  223. VOID
  224. )
  225. /*++
  226. Routine Description:
  227. commit device changes to registry.
  228. note that we commit all devices to registry since priority may have changed
  229. Arguments:
  230. NONE.
  231. Return Value:
  232. TRUE for success.
  233. --*/
  234. {
  235. PLIST_ENTRY Next;
  236. PLINE_INFO LineInfo;
  237. __try {
  238. EnterCriticalSection(&CsLine);
  239. Next = TapiLinesListHead.Flink;
  240. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  241. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  242. Next = LineInfo->ListEntry.Flink;
  243. if (LineInfo->PermanentLineID && LineInfo->DeviceName) {
  244. RegAddNewFaxDevice(
  245. LineInfo->DeviceName,
  246. LineInfo->Provider->ProviderName,
  247. LineInfo->Csid,
  248. LineInfo->Tsid,
  249. LineInfo->Priority,
  250. LineInfo->PermanentLineID,
  251. LineInfo->Flags & 0x0fffffff,
  252. LineInfo->RingsForAnswer,
  253. -1,
  254. NULL,
  255. NULL,
  256. NULL
  257. );
  258. }
  259. }
  260. LeaveCriticalSection(&CsLine);
  261. } __except (EXCEPTION_EXECUTE_HANDLER) {
  262. LeaveCriticalSection(&CsLine);
  263. }
  264. return TRUE;
  265. }
  266. ULONG
  267. TapiWorkerThread(
  268. LPVOID UnUsed
  269. )
  270. /*++
  271. Routine Description:
  272. This is worker thread for the FAX service. All queued
  273. requests are processed here.
  274. Arguments:
  275. None.
  276. Return Value:
  277. Thread return value.
  278. --*/
  279. {
  280. PLINE_INFO LineInfo;
  281. BOOL Rval;
  282. DWORD Bytes;
  283. ULONG_PTR CompletionKey;
  284. LPLINEMESSAGE LineMsg = NULL;
  285. while( TRUE ) {
  286. if (LineMsg) {
  287. LocalFree( LineMsg );
  288. }
  289. Rval = GetQueuedCompletionStatus(
  290. TapiCompletionPort,
  291. &Bytes,
  292. &CompletionKey,
  293. (LPOVERLAPPED*) &LineMsg,
  294. INFINITE
  295. );
  296. if (!Rval) {
  297. Rval = GetLastError();
  298. LineMsg = NULL;
  299. DebugPrint(( TEXT("GetQueuedCompletionStatus() failed, ec=0x%08x"), Rval ));
  300. continue;
  301. }
  302. SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
  303. if (CompletionKey == FAXDEV_EVENT_KEY) {
  304. //
  305. // this is an event from a fax service provider
  306. // that has enumerated virtual device(s)
  307. //
  308. // the LINEMESSAGE structure must be filled out
  309. // as follows:
  310. //
  311. // LineMsg->hDevice == DeviceId from FaxDevStartJob()
  312. // LineMsg->dwMessageID == 0
  313. // LineMsg->dwCallbackInstance == 0
  314. // LineMsg->dwParam1 == LINEDEVSTATE_RINGING
  315. // LineMsg->dwParam2 == 0
  316. // LineMsg->dwParam3 == 0
  317. //
  318. EnterCriticalSection( &CsJob );
  319. EnterCriticalSection( &CsLine );
  320. LineInfo = GetTapiLineFromDeviceId( (DWORD) LineMsg->hDevice );
  321. if (!LineInfo) {
  322. goto next_event;
  323. }
  324. if (LineMsg->dwParam1 == LINEDEVSTATE_RINGING) {
  325. LineInfo->RingCount += 1;
  326. CreateFaxEvent( LineInfo->PermanentLineID, FEI_RINGING, 0xffffffff );
  327. if ((LineInfo->Flags & FPF_RECEIVE) && (LineInfo->State == FPS_AVAILABLE)) {
  328. PJOB_ENTRY JobEntry;
  329. TCHAR FileName[MAX_PATH];
  330. //
  331. // start a fax job
  332. //
  333. JobEntry = StartJob( LineInfo->PermanentLineID, JT_RECEIVE, NULL );
  334. if (JobEntry) {
  335. //
  336. // receive the fax
  337. //
  338. StartFaxReceive(
  339. JobEntry,
  340. 0,
  341. LineInfo,
  342. FileName,
  343. sizeof(FileName)
  344. );
  345. } else {
  346. DebugPrint(( TEXT("StartJob() failed, cannot receive incoming fax") ));
  347. }
  348. }
  349. }
  350. goto next_event;
  351. }
  352. LineInfo = (PLINE_INFO) LineMsg->dwCallbackInstance;
  353. ShowLineEvent(
  354. (HLINE) LineMsg->hDevice,
  355. (HCALL) LineMsg->hDevice,
  356. LineInfo == NULL ? TEXT("*NULL LineInfo*") : (LineInfo->JobEntry == NULL) ? TEXT("*NULL Job*") : NULL,
  357. LineMsg->dwCallbackInstance,
  358. LineMsg->dwMessageID,
  359. LineMsg->dwParam1,
  360. LineMsg->dwParam2,
  361. LineMsg->dwParam3
  362. );
  363. EnterCriticalSection( &CsJob );
  364. EnterCriticalSection( &CsLine );
  365. __try {
  366. switch( LineMsg->dwMessageID ) {
  367. case LINE_ADDRESSSTATE:
  368. if (LineMsg->dwParam2 == LINEADDRESSSTATE_INUSEONE ||
  369. LineMsg->dwParam2 == LINEADDRESSSTATE_INUSEMANY) {
  370. //
  371. // the port is now unavailable
  372. //
  373. LineInfo->State = FPS_AVAILABLE;
  374. }
  375. if (LineMsg->dwParam2 == LINEADDRESSSTATE_INUSEZERO) {
  376. //
  377. // the port is now available
  378. //
  379. LineInfo->State = FPS_UNAVAILABLE;
  380. }
  381. break;
  382. case LINE_CALLINFO:
  383. break;
  384. case LINE_CALLSTATE:
  385. if (LineMsg->dwParam3 == LINECALLPRIVILEGE_OWNER && LineInfo->JobEntry && LineInfo->JobEntry->HandoffJob) {
  386. //
  387. // call was just handed off to us
  388. //
  389. if (LineInfo->JobEntry && LineInfo->JobEntry->HandoffJob) {
  390. LineInfo->HandoffCallHandle = (HCALL) LineMsg->hDevice;
  391. SetEvent( LineInfo->JobEntry->hCallHandleEvent );
  392. }
  393. else {
  394. lineDeallocateCall( (HCALL) LineMsg->hDevice );
  395. }
  396. }
  397. if (LineMsg->dwParam1 == LINECALLSTATE_IDLE) {
  398. ReleaseTapiLine( LineInfo, (HCALL) LineMsg->hDevice );
  399. LineInfo->NewCall = FALSE;
  400. CreateFaxEvent( LineInfo->PermanentLineID, FEI_IDLE, 0xffffffff );
  401. }
  402. if (LineInfo->NewCall && LineMsg->dwParam1 != LINECALLSTATE_OFFERING && LineInfo->State == FPS_AVAILABLE) {
  403. LineInfo->State = FPS_NOT_FAX_CALL;
  404. LineInfo->NewCall = FALSE;
  405. }
  406. break;
  407. case LINE_CLOSE:
  408. //
  409. // this usually happens when something bad happens to the modem device. before we go off and scare the
  410. // user with a popup, let's try to revive the device once. Then we can let them know that the device is
  411. // messed up or powered off.
  412. //
  413. DebugPrint(( TEXT("Received a LINE_CLOSE message for device %x [%s]."),
  414. LineInfo->DeviceId,
  415. LineInfo->DeviceName ));
  416. if (OpenTapiLine( LineInfo )) {
  417. DebugPrint(( TEXT("Device [%s] was revived"), LineInfo->DeviceName ));
  418. LineInfo->Flags &= ~FPF_POWERED_OFF;
  419. LineInfo->State = 0;
  420. if (LineInfo->Flags & FPF_RECEIVE_OK) {
  421. LineInfo->Flags |= FPF_RECEIVE;
  422. LineInfo->Flags &= ~FPF_RECEIVE_OK;
  423. }
  424. } else {
  425. //
  426. // the modem is really messed up or powered off, so it's ok to scare the user. :)
  427. //
  428. if (LineInfo->Flags & FPF_RECEIVE) {
  429. LineInfo->Flags &= ~FPF_RECEIVE;
  430. LineInfo->Flags |= FPF_RECEIVE_OK;
  431. }
  432. LineInfo->Flags |= FPF_POWERED_OFF;
  433. LineInfo->State = FPS_OFFLINE;
  434. LineInfo->hLine = 0;
  435. CreateFaxEvent( LineInfo->PermanentLineID, FEI_MODEM_POWERED_OFF, 0xffffffff );
  436. //
  437. // put a popup on the currently active desktop
  438. // we only allow 1 popup per device at a time
  439. // and we only present the popup twice
  440. //
  441. if (!LineInfo->ModemInUse &&
  442. LineInfo->ModemPopupActive &&
  443. LineInfo->ModemPopUps < MAX_MODEM_POPUPS)
  444. {
  445. LineInfo->ModemPopupActive = 0;
  446. LineInfo->ModemPopUps += 1;
  447. ServiceMessageBox(
  448. GetString( IDS_POWERED_OFF_MODEM ),
  449. MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND,
  450. TRUE,
  451. &LineInfo->ModemPopupActive
  452. );
  453. }
  454. }
  455. //
  456. // if we were waiting for a handoff, give up on it!
  457. //
  458. if (LineInfo->JobEntry && LineInfo->JobEntry->HandoffJob) {
  459. LineInfo->HandoffCallHandle = 0;
  460. SetEvent(LineInfo->JobEntry->hCallHandleEvent);
  461. }
  462. break;
  463. case LINE_DEVSPECIFIC:
  464. break;
  465. case LINE_DEVSPECIFICFEATURE:
  466. break;
  467. case LINE_GATHERDIGITS:
  468. break;
  469. case LINE_GENERATE:
  470. break;
  471. case LINE_LINEDEVSTATE:
  472. if (LineMsg->dwParam1 == LINEDEVSTATE_RINGING) {
  473. LineInfo->RingCount = (DWORD)LineMsg->dwParam3 + 1;
  474. CreateFaxEvent( LineInfo->PermanentLineID, FEI_RINGING, 0xffffffff );
  475. //
  476. // Pick up the line only if the last inbound job has completed
  477. //
  478. if (LineInfo->State != FPS_AVAILABLE) {
  479. break;
  480. }
  481. if ((LineInfo->Flags & FPF_RECEIVE) && (LineInfo->State == FPS_AVAILABLE)) {
  482. if (LineInfo->LineMsgOffering.hDevice == 0) {
  483. //
  484. // wait for the offering message
  485. //
  486. break;
  487. }
  488. if ((LineInfo->RingCount > LineInfo->RingsForAnswer) && !LineInfo->JobEntry) {
  489. PJOB_ENTRY JobEntry;
  490. TCHAR FileName[MAX_PATH];
  491. //
  492. // start a fax job
  493. //
  494. JobEntry = StartJob( LineInfo->PermanentLineID, JT_RECEIVE, NULL );
  495. if (JobEntry) {
  496. //
  497. // receive the fax
  498. //
  499. StartFaxReceive(
  500. JobEntry,
  501. (HCALL) LineInfo->LineMsgOffering.hDevice,
  502. LineInfo,
  503. FileName,
  504. sizeof(FileName)
  505. );
  506. } else {
  507. DebugPrint(( TEXT("StartJob() failed, cannot receive incoming fax") ));
  508. }
  509. }
  510. } else {
  511. //
  512. // we are not supposed to answer the call, so give it to ras
  513. //
  514. HandoffCallToRas( LineInfo, (HCALL) LineInfo->LineMsgOffering.hDevice );
  515. }
  516. }
  517. break;
  518. case LINE_MONITORDIGITS:
  519. break;
  520. case LINE_MONITORMEDIA:
  521. break;
  522. case LINE_MONITORTONE:
  523. break;
  524. case LINE_REPLY:
  525. if (LineInfo->InitEvent && LineInfo->RequestId == LineMsg->dwParam1) {
  526. LineInfo->Result = (DWORD)LineMsg->dwParam2;
  527. SetEvent( LineInfo->InitEvent );
  528. }
  529. break;
  530. case LINE_REQUEST:
  531. break;
  532. case PHONE_BUTTON:
  533. break;
  534. case PHONE_CLOSE:
  535. break;
  536. case PHONE_DEVSPECIFIC:
  537. break;
  538. case PHONE_REPLY:
  539. break;
  540. case PHONE_STATE:
  541. break;
  542. case LINE_CREATE:
  543. {
  544. LPLINEDEVCAPS LineDevCaps;
  545. LINEEXTENSIONID lineExtensionID;
  546. DWORD LocalTapiApiVersion;
  547. DWORD Rslt;
  548. DWORD DeviceId;
  549. DeviceId = (DWORD)LineMsg->dwParam1;
  550. Rslt = lineNegotiateAPIVersion(
  551. hLineApp,
  552. DeviceId,
  553. 0x00010003,
  554. TapiApiVersion,
  555. &LocalTapiApiVersion,
  556. &lineExtensionID
  557. );
  558. if (Rslt == 0) {
  559. LineDevCaps = MyLineGetDevCaps( DeviceId );
  560. if (LineDevCaps) {
  561. AddNewDevice( DeviceId, LineDevCaps, TRUE );
  562. MemFree( LineDevCaps );
  563. }
  564. }
  565. }
  566. break;
  567. case PHONE_CREATE:
  568. break;
  569. case LINE_AGENTSPECIFIC:
  570. break;
  571. case LINE_AGENTSTATUS:
  572. break;
  573. case LINE_APPNEWCALL:
  574. LineInfo->NewCall = TRUE;
  575. break;
  576. case LINE_PROXYREQUEST:
  577. break;
  578. case LINE_REMOVE:
  579. break;
  580. case PHONE_REMOVE:
  581. break;
  582. }
  583. if (LineInfo && ((!LineInfo->Provider) || (!LineInfo->Provider->FaxDevCallback))) {
  584. DebugPrint(( TEXT("Unhandled tapi callback event") ));
  585. goto next_event;
  586. }
  587. //
  588. // call the device provider's line callback function
  589. //
  590. __try {
  591. if (LineInfo && LineInfo->JobEntry) {
  592. LineInfo->Provider->FaxDevCallback(
  593. LineInfo->JobEntry ? (HANDLE) LineInfo->JobEntry->InstanceData : NULL,
  594. LineMsg->hDevice,
  595. LineMsg->dwMessageID,
  596. LineMsg->dwCallbackInstance,
  597. LineMsg->dwParam1,
  598. LineMsg->dwParam2,
  599. LineMsg->dwParam3
  600. );
  601. }
  602. } __except (EXCEPTION_EXECUTE_HANDLER) {
  603. DebugPrint(( TEXT("Device provider tapi callback crashed: 0x%08x"), GetExceptionCode() ));
  604. }
  605. if (LineMsg->dwMessageID == LINE_CALLSTATE && LineMsg->dwParam1 == LINECALLSTATE_OFFERING) {
  606. // we'll get a LINE_LINEDEVSTATE (RINGING) event, so we'll post the ring event there or we'll get a duplicate event
  607. //CreateFaxEvent( LineInfo->PermanentLineID, FEI_RINGING, 0xffffffff );
  608. LineInfo->NewCall = FALSE;
  609. if ((LineInfo->Flags & FPF_RECEIVE) && (LineInfo->State == FPS_AVAILABLE)) {
  610. if ((LineInfo->RingCount > LineInfo->RingsForAnswer) && !LineInfo->JobEntry) {
  611. PJOB_ENTRY JobEntry;
  612. TCHAR FileName[MAX_PATH];
  613. //
  614. // start a fax job
  615. //
  616. JobEntry = StartJob( LineInfo->PermanentLineID, JT_RECEIVE, NULL );
  617. if (JobEntry) {
  618. //
  619. // receive the fax
  620. //
  621. StartFaxReceive(
  622. JobEntry,
  623. (HCALL) LineMsg->hDevice,
  624. LineInfo,
  625. FileName,
  626. sizeof(FileName)
  627. );
  628. } else {
  629. DebugPrint(( TEXT("StartJob() failed, cannot receive incoming fax") ));
  630. }
  631. } else {
  632. //
  633. // save the line msg
  634. //
  635. CopyMemory( &LineInfo->LineMsgOffering, LineMsg, sizeof(LINEMESSAGE) );
  636. }
  637. } else {
  638. //
  639. // we are not supposed to answer the call, so give it to ras
  640. //
  641. HandoffCallToRas( LineInfo, (HCALL) LineMsg->hDevice );
  642. }
  643. }
  644. } __except (EXCEPTION_EXECUTE_HANDLER) {
  645. DebugPrint(( TEXT("TapiWorkerThread() crashed: 0x%08x"), GetExceptionCode() ));
  646. }
  647. next_event:
  648. LeaveCriticalSection( &CsLine );
  649. LeaveCriticalSection( &CsJob );
  650. SetThreadExecutionState(ES_CONTINUOUS);
  651. }
  652. return 0;
  653. }
  654. BOOL
  655. HandoffCallToRas(
  656. PLINE_INFO LineInfo,
  657. HCALL hCall
  658. )
  659. /*++
  660. Routine Description:
  661. This function will try to hand a call of to RAS.
  662. We do this under 2 circumstances:
  663. 1) we've answered an incoming call and
  664. determined that the call is NOT a fax call
  665. 2) the configuration for the line that is
  666. ringing is not configured for receiving faxes
  667. If the handoff fails and we have an open job for the
  668. line, then we have to call the device provider so that
  669. the line can be put on hook.
  670. Arguments:
  671. LineInfo - LineInfo structure for the line this call is on
  672. hCall - TAPI call handle
  673. Return Value:
  674. TRUE for success
  675. FALSE for failure
  676. --*/
  677. {
  678. LONG Rval;
  679. //
  680. // need to hand the call off to RAS
  681. //
  682. Rval = lineHandoff(
  683. hCall,
  684. RAS_MODULE_NAME,
  685. LINEMEDIAMODE_DATAMODEM
  686. );
  687. if (Rval != 0 && LineInfo && LineInfo->JobEntry) {
  688. DebugPrint(( TEXT("lineHandoff() failed, ec=0x%08x"), Rval ));
  689. //
  690. // since the handoff failed we must notify
  691. // the fsp so that the call can be put onhook
  692. //
  693. __try {
  694. LineInfo->Provider->FaxDevAbortOperation(
  695. (HANDLE) LineInfo->JobEntry->InstanceData
  696. );
  697. } __except (EXCEPTION_EXECUTE_HANDLER) {
  698. DebugPrint(( TEXT("FaxDevAbortOperation() failed: 0x%08x"), GetExceptionCode() ));
  699. }
  700. } else {
  701. DebugPrint(( TEXT("call handed off to RAS") ));
  702. }
  703. return Rval == 0;
  704. }
  705. PLINE_INFO
  706. GetTapiLineFromDeviceId(
  707. DWORD DeviceId
  708. )
  709. {
  710. PLIST_ENTRY Next;
  711. PLINE_INFO LineInfo;
  712. Next = TapiLinesListHead.Flink;
  713. if (!Next) {
  714. return NULL;
  715. }
  716. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  717. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  718. Next = LineInfo->ListEntry.Flink;
  719. if (LineInfo->PermanentLineID == DeviceId) {
  720. return LineInfo;
  721. }
  722. }
  723. return NULL;
  724. }
  725. PLINE_INFO
  726. GetTapiLineForFaxOperation(
  727. DWORD DeviceId,
  728. DWORD JobType,
  729. LPWSTR FaxNumber,
  730. BOOL Handoff
  731. )
  732. /*++
  733. Routine Description:
  734. Locates an avaliable TAPI device for use in a
  735. FAX operation. The selection is based on the
  736. available devices and their assigned priority.
  737. Arguments:
  738. DeviceId - device for operation
  739. JobType - send or receive job
  740. FaxNumber - the number for a send
  741. Handoff - will this be a handoff job?
  742. Return Value:
  743. Pointer to a LINE_INFO structure or NULL is the
  744. function fails.
  745. --*/
  746. {
  747. static NoDevicePopupCount = 0;
  748. PLIST_ENTRY Next;
  749. PLINE_INFO LineInfo;
  750. PLINE_INFO SelectedLine = NULL;
  751. EnterCriticalSection( &CsLine );
  752. Next = TapiLinesListHead.Flink;
  753. //
  754. // only makes sense for a send job
  755. //
  756. if (Next && (JobType == JT_SEND) && FaxNumber) {
  757. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  758. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  759. Next = LineInfo->ListEntry.Flink;
  760. //
  761. // prevent a race condition?
  762. //
  763. if (LineInfo->JobEntry && LineInfo->JobEntry->PhoneNumber[0]) {
  764. if (_wcsicmp( LineInfo->JobEntry->PhoneNumber, FaxNumber ) == 0) {
  765. LeaveCriticalSection( &CsLine );
  766. return NULL;
  767. }
  768. }
  769. }
  770. }
  771. Next = TapiLinesListHead.Flink;
  772. if (Next) {
  773. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  774. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  775. Next = LineInfo->ListEntry.Flink;
  776. if (DeviceId != USE_SERVER_DEVICE) {
  777. // find the specified device
  778. if (LineInfo->PermanentLineID == DeviceId) {
  779. if (Handoff) {
  780. if (JobType!= JT_SEND) {
  781. break;
  782. }
  783. SelectedLine = LineInfo;
  784. // LineInfo->State = FPS_???;
  785. break;
  786. }
  787. if ((LineInfo->State == FPS_AVAILABLE) &&
  788. ((JobType == JT_SEND && (LineInfo->Flags & FPF_SEND)) ||
  789. (JobType == JT_RECEIVE && (LineInfo->Flags & FPF_RECEIVE))))
  790. {
  791. LineInfo->State = 0;
  792. SelectedLine = LineInfo;
  793. break;
  794. } else if (LineInfo->UnimodemDevice && (LineInfo->Flags & FPF_POWERED_OFF)) {
  795. //
  796. // see if we can revive the device
  797. //
  798. if (OpenTapiLine( LineInfo )) {
  799. DebugPrint(( TEXT("Device [%s] is now powered on"), LineInfo->DeviceName ));
  800. LineInfo->Flags &= ~FPF_POWERED_OFF;
  801. LineInfo->State = 0;
  802. if (LineInfo->Flags & FPF_RECEIVE_OK) {
  803. LineInfo->Flags |= FPF_RECEIVE;
  804. LineInfo->Flags &= ~FPF_RECEIVE_OK;
  805. }
  806. CreateFaxEvent( LineInfo->PermanentLineID, FEI_MODEM_POWERED_ON, 0xffffffff );
  807. SelectedLine = LineInfo;
  808. }
  809. }
  810. break;
  811. }
  812. } else {
  813. Assert( JobType != JT_RECEIVE );
  814. if ((LineInfo->State == FPS_AVAILABLE) &&
  815. ((JobType == JT_SEND && (LineInfo->Flags & FPF_SEND)) ||
  816. (JobType == JT_RECEIVE && (LineInfo->Flags & FPF_RECEIVE))))
  817. {
  818. LineInfo->State = 0;
  819. SelectedLine = LineInfo;
  820. break;
  821. }
  822. }
  823. }
  824. }
  825. LeaveCriticalSection( &CsLine );
  826. if (SelectedLine) {
  827. DebugPrint((
  828. TEXT("Line selected for FAX operation: %d, %d"),
  829. SelectedLine->DeviceId,
  830. SelectedLine->PermanentLineID
  831. ));
  832. } else if (JobType == JT_SEND) {
  833. DWORD SendDevices;
  834. GetDeviceTypeCount(&SendDevices,NULL);
  835. if (SendDevices == 0 && NoDevicePopupCount < 2 ) {
  836. //
  837. // no devices configured to send faxes
  838. //
  839. ServiceMessageBox(GetString(IDS_NO_SEND_DEVICES),MB_OK|MB_ICONEXCLAMATION, TRUE,NULL);
  840. NoDevicePopupCount++;
  841. }
  842. }
  843. return SelectedLine;
  844. }
  845. BOOL
  846. ReleaseTapiLine(
  847. PLINE_INFO LineInfo,
  848. HCALL hCall
  849. )
  850. /*++
  851. Routine Description:
  852. Releases the specified TAPI line back into
  853. the list as an available device.
  854. Arguments:
  855. LineInfo - Pointer to the TAPI line to be released
  856. Return Value:
  857. TRUE - The line is release.
  858. FALSE - The line is not released.
  859. --*/
  860. {
  861. LONG rVal;
  862. HLINE hLine;
  863. if (!LineInfo) {
  864. return FALSE;
  865. }
  866. EnterCriticalSection( &CsLine );
  867. LineInfo->State = FPS_AVAILABLE;
  868. LineInfo->RingCount = 0;
  869. ZeroMemory( &LineInfo->LineMsgOffering, sizeof(LINEMESSAGE) );
  870. if ((!(LineInfo->Flags & FPF_RECEIVE)) && LineInfo->hLine) {
  871. hLine = LineInfo->hLine;
  872. LineInfo->hLine = 0;
  873. lineClose( hLine );
  874. DebugPrint(( TEXT("ReleaseTapiLine(): lineClose on hLine=%08x "), hLine ));
  875. }
  876. if (hCall) {
  877. rVal = lineDeallocateCall( hCall );
  878. if (rVal != 0) {
  879. DebugPrint(( TEXT("ReleaseTapiLine(): lineDeallocateCall() failed, ec=0x%08x, hCall=%08x"),
  880. rVal, hCall ));
  881. } else {
  882. if (LineInfo->JobEntry && LineInfo->JobEntry->CallHandle == hCall) {
  883. LineInfo->JobEntry->CallHandle = 0;
  884. }
  885. }
  886. } else {
  887. DebugPrint(( TEXT("ReleaseTapiLine(): cannot deallocate call, NULL call handle") ));
  888. }
  889. LeaveCriticalSection( &CsLine );
  890. return TRUE;
  891. }
  892. LPLINEDEVCAPS
  893. MyLineGetDevCaps(
  894. DWORD DeviceId
  895. )
  896. {
  897. DWORD LineDevCapsSize;
  898. LPLINEDEVCAPS LineDevCaps = NULL;
  899. LONG Rslt = ERROR_SUCCESS;
  900. //
  901. // allocate the initial linedevcaps structure
  902. //
  903. LineDevCapsSize = sizeof(LINEDEVCAPS) + 4096;
  904. LineDevCaps = (LPLINEDEVCAPS) MemAlloc( LineDevCapsSize );
  905. if (!LineDevCaps) {
  906. return NULL;
  907. }
  908. LineDevCaps->dwTotalSize = LineDevCapsSize;
  909. Rslt = lineGetDevCaps(
  910. hLineApp,
  911. DeviceId,
  912. TapiApiVersion,
  913. 0,
  914. LineDevCaps
  915. );
  916. if (Rslt != 0) {
  917. //
  918. // lineGetDevCaps() can fail with error code 0x8000004b
  919. // if a device has been deleted and tapi has not been
  920. // cycled. this is caused by the fact that tapi leaves
  921. // a phantom device in it's device list. the error is
  922. // benign and the device can safely be ignored.
  923. //
  924. if (Rslt != LINEERR_INCOMPATIBLEAPIVERSION) {
  925. DebugPrint(( TEXT("lineGetDevCaps() failed, ec=0x%08x"), Rslt ));
  926. }
  927. goto exit;
  928. }
  929. if (LineDevCaps->dwNeededSize > LineDevCaps->dwTotalSize) {
  930. //
  931. // re-allocate the linedevcaps structure
  932. //
  933. LineDevCapsSize = LineDevCaps->dwNeededSize;
  934. MemFree( LineDevCaps );
  935. LineDevCaps = (LPLINEDEVCAPS) MemAlloc( LineDevCapsSize );
  936. if (!LineDevCaps) {
  937. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  938. goto exit;
  939. }
  940. Rslt = lineGetDevCaps(
  941. hLineApp,
  942. DeviceId,
  943. TapiApiVersion,
  944. 0,
  945. LineDevCaps
  946. );
  947. if (Rslt != 0) {
  948. DebugPrint(( TEXT("lineGetDevCaps() failed, ec=0x%08x"), Rslt ));
  949. goto exit;
  950. }
  951. }
  952. exit:
  953. if (Rslt != ERROR_SUCCESS) {
  954. MemFree( LineDevCaps );
  955. LineDevCaps = NULL;
  956. }
  957. return LineDevCaps;
  958. }
  959. LPLINEDEVSTATUS
  960. MyLineGetLineDevStatus(
  961. HLINE hLine
  962. )
  963. {
  964. DWORD LineDevStatusSize;
  965. LPLINEDEVSTATUS LineDevStatus = NULL;
  966. LONG Rslt = ERROR_SUCCESS;
  967. //
  968. // allocate the initial linedevstatus structure
  969. //
  970. LineDevStatusSize = sizeof(LINEDEVSTATUS) + 4096;
  971. LineDevStatus = (LPLINEDEVSTATUS) MemAlloc( LineDevStatusSize );
  972. if (!LineDevStatus) {
  973. return NULL;
  974. }
  975. LineDevStatus->dwTotalSize = LineDevStatusSize;
  976. Rslt = lineGetLineDevStatus(
  977. hLine,
  978. LineDevStatus
  979. );
  980. if (Rslt != 0) {
  981. DebugPrint(( TEXT("lineGetLineDevStatus() failed, ec=0x%08x"), Rslt ));
  982. goto exit;
  983. }
  984. if (LineDevStatus->dwNeededSize > LineDevStatus->dwTotalSize) {
  985. //
  986. // re-allocate the LineDevStatus structure
  987. //
  988. LineDevStatusSize = LineDevStatus->dwNeededSize;
  989. MemFree( LineDevStatus );
  990. LineDevStatus = (LPLINEDEVSTATUS) MemAlloc( LineDevStatusSize );
  991. if (!LineDevStatus) {
  992. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  993. goto exit;
  994. }
  995. Rslt = lineGetLineDevStatus(
  996. hLine,
  997. LineDevStatus
  998. );
  999. if (Rslt != 0) {
  1000. DebugPrint(( TEXT("lineGetLineDevStatus() failed, ec=0x%08x"), Rslt ));
  1001. goto exit;
  1002. }
  1003. }
  1004. exit:
  1005. if (Rslt != ERROR_SUCCESS) {
  1006. MemFree( LineDevStatus );
  1007. LineDevStatus = NULL;
  1008. }
  1009. return LineDevStatus;
  1010. }
  1011. LONG
  1012. MyLineGetTransCaps(
  1013. LPLINETRANSLATECAPS *LineTransCaps
  1014. )
  1015. {
  1016. DWORD LineTransCapsSize;
  1017. LONG Rslt = ERROR_SUCCESS;
  1018. //
  1019. // allocate the initial linetranscaps structure
  1020. //
  1021. LineTransCapsSize = sizeof(LINETRANSLATECAPS) + 4096;
  1022. *LineTransCaps = (LPLINETRANSLATECAPS) MemAlloc( LineTransCapsSize );
  1023. if (!*LineTransCaps) {
  1024. DebugPrint(( TEXT("MemAlloc() failed, sz=0x%08x"), LineTransCapsSize ));
  1025. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  1026. goto exit;
  1027. }
  1028. (*LineTransCaps)->dwTotalSize = LineTransCapsSize;
  1029. Rslt = lineGetTranslateCaps(
  1030. hLineApp,
  1031. TapiApiVersion,
  1032. *LineTransCaps
  1033. );
  1034. if (Rslt != 0) {
  1035. DebugPrint(( TEXT("lineGetTranslateCaps() failed, ec=0x%08x"), Rslt ));
  1036. goto exit;
  1037. }
  1038. if ((*LineTransCaps)->dwNeededSize > (*LineTransCaps)->dwTotalSize) {
  1039. //
  1040. // re-allocate the LineTransCaps structure
  1041. //
  1042. LineTransCapsSize = (*LineTransCaps)->dwNeededSize;
  1043. MemFree( *LineTransCaps );
  1044. *LineTransCaps = (LPLINETRANSLATECAPS) MemAlloc( LineTransCapsSize );
  1045. if (!*LineTransCaps) {
  1046. DebugPrint(( TEXT("MemAlloc() failed, sz=0x%08x"), LineTransCapsSize ));
  1047. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  1048. goto exit;
  1049. }
  1050. (*LineTransCaps)->dwTotalSize = LineTransCapsSize;
  1051. Rslt = lineGetTranslateCaps(
  1052. hLineApp,
  1053. TapiApiVersion,
  1054. *LineTransCaps
  1055. );
  1056. if (Rslt != 0) {
  1057. DebugPrint(( TEXT("lineGetTranslateCaps() failed, ec=0x%08x"), Rslt ));
  1058. goto exit;
  1059. }
  1060. }
  1061. exit:
  1062. if (Rslt != ERROR_SUCCESS) {
  1063. MemFree( *LineTransCaps );
  1064. *LineTransCaps = NULL;
  1065. }
  1066. return Rslt;
  1067. }
  1068. LONG
  1069. MyLineTranslateAddress(
  1070. LPTSTR Address,
  1071. DWORD DeviceId,
  1072. LPLINETRANSLATEOUTPUT *TranslateOutput
  1073. )
  1074. {
  1075. DWORD LineTransOutSize;
  1076. LONG Rslt = ERROR_SUCCESS;
  1077. //
  1078. // allocate the initial linetranscaps structure
  1079. //
  1080. LineTransOutSize = sizeof(LINETRANSLATEOUTPUT) + 4096;
  1081. *TranslateOutput = (LPLINETRANSLATEOUTPUT) MemAlloc( LineTransOutSize );
  1082. if (!*TranslateOutput) {
  1083. DebugPrint(( TEXT("MemAlloc() failed, sz=0x%08x"), LineTransOutSize ));
  1084. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  1085. goto exit;
  1086. }
  1087. (*TranslateOutput)->dwTotalSize = LineTransOutSize;
  1088. Rslt = lineTranslateAddress(
  1089. hLineApp,
  1090. DeviceId,
  1091. TapiApiVersion,
  1092. Address,
  1093. 0,
  1094. 0,
  1095. *TranslateOutput
  1096. );
  1097. if (Rslt != 0) {
  1098. DebugPrint(( TEXT("lineGetTranslateAddress() failed, ec=0x%08x"), Rslt ));
  1099. goto exit;
  1100. }
  1101. if ((*TranslateOutput)->dwNeededSize > (*TranslateOutput)->dwTotalSize) {
  1102. //
  1103. // re-allocate the LineTransCaps structure
  1104. //
  1105. LineTransOutSize = (*TranslateOutput)->dwNeededSize;
  1106. MemFree( *TranslateOutput );
  1107. *TranslateOutput = (LPLINETRANSLATEOUTPUT) MemAlloc( LineTransOutSize );
  1108. if (!*TranslateOutput) {
  1109. DebugPrint(( TEXT("MemAlloc() failed, sz=0x%08x"), LineTransOutSize ));
  1110. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  1111. goto exit;
  1112. }
  1113. (*TranslateOutput)->dwTotalSize = LineTransOutSize;
  1114. Rslt = lineTranslateAddress(
  1115. hLineApp,
  1116. DeviceId,
  1117. TapiApiVersion,
  1118. Address,
  1119. 0,
  1120. 0,
  1121. *TranslateOutput
  1122. );
  1123. if (Rslt != 0) {
  1124. DebugPrint(( TEXT("lineGetTranslateAddress() failed, ec=0x%08x"), Rslt ));
  1125. goto exit;
  1126. }
  1127. }
  1128. exit:
  1129. if (Rslt != ERROR_SUCCESS) {
  1130. MemFree( *TranslateOutput );
  1131. *TranslateOutput = NULL;
  1132. }
  1133. return Rslt;
  1134. }
  1135. BOOL
  1136. OpenTapiLine(
  1137. PLINE_INFO LineInfo
  1138. )
  1139. {
  1140. LONG Rslt = ERROR_SUCCESS;
  1141. HLINE hLine;
  1142. DWORD LineStates = 0;
  1143. DWORD AddressStates = 0;
  1144. EnterCriticalSection( &CsLine );
  1145. if (LineInfo->UnimodemDevice) {
  1146. Rslt = lineOpen(
  1147. hLineApp,
  1148. LineInfo->DeviceId,
  1149. &hLine,
  1150. TapiApiVersion,
  1151. 0,
  1152. (DWORD_PTR) LineInfo,
  1153. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  1154. LINEMEDIAMODE_DATAMODEM | LINEMEDIAMODE_UNKNOWN,
  1155. NULL
  1156. );
  1157. if (Rslt != 0) {
  1158. Rslt = lineOpen(
  1159. hLineApp,
  1160. LineInfo->DeviceId,
  1161. &hLine,
  1162. TapiApiVersion,
  1163. 0,
  1164. (DWORD_PTR) LineInfo,
  1165. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  1166. LINEMEDIAMODE_DATAMODEM,
  1167. NULL
  1168. );
  1169. }
  1170. } else {
  1171. Rslt = lineOpen(
  1172. hLineApp,
  1173. LineInfo->DeviceId,
  1174. &hLine,
  1175. TapiApiVersion,
  1176. 0,
  1177. (DWORD_PTR) LineInfo,
  1178. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  1179. LINEMEDIAMODE_G3FAX,
  1180. NULL
  1181. );
  1182. }
  1183. if (Rslt != 0) {
  1184. DebugPrint(( TEXT("Device %s FAILED to initialize, ec=%08x"), LineInfo->DeviceName, Rslt ));
  1185. } else {
  1186. LineInfo->hLine = hLine;
  1187. //
  1188. // set the line status that we need
  1189. //
  1190. LineStates |= LineInfo->LineStates & LINEDEVSTATE_OPEN ? LINEDEVSTATE_OPEN : 0;
  1191. LineStates |= LineInfo->LineStates & LINEDEVSTATE_CLOSE ? LINEDEVSTATE_CLOSE : 0;
  1192. LineStates |= LineInfo->LineStates & LINEDEVSTATE_RINGING ? LINEDEVSTATE_RINGING : 0;
  1193. LineStates |= LineInfo->LineStates & LINEDEVSTATE_NUMCALLS ? LINEDEVSTATE_NUMCALLS : 0;
  1194. LineStates |= LineInfo->LineStates & LINEDEVSTATE_REMOVED ? LINEDEVSTATE_REMOVED : 0;
  1195. AddressStates = LINEADDRESSSTATE_INUSEZERO | LINEADDRESSSTATE_INUSEONE |
  1196. LINEADDRESSSTATE_INUSEMANY | LINEADDRESSSTATE_NUMCALLS;
  1197. Rslt = lineSetStatusMessages( hLine, LineStates, AddressStates );
  1198. if (Rslt != 0) {
  1199. DebugPrint(( TEXT("lineSetStatusMessages() failed, [0x%08x:0x%08x], ec=0x%08x"), LineStates, AddressStates, Rslt ));
  1200. Rslt = ERROR_SUCCESS;
  1201. }
  1202. }
  1203. LeaveCriticalSection( &CsLine );
  1204. return Rslt == ERROR_SUCCESS;
  1205. }
  1206. BOOL
  1207. IsDeviceModem(
  1208. LPLINEDEVCAPS LineDevCaps
  1209. )
  1210. {
  1211. LPTSTR DeviceClassList;
  1212. BOOL UnimodemDevice = FALSE;
  1213. if (LineDevCaps->dwDeviceClassesSize && LineDevCaps->dwDeviceClassesOffset) {
  1214. DeviceClassList = (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwDeviceClassesOffset);
  1215. while (*DeviceClassList) {
  1216. if (_tcscmp(DeviceClassList,TEXT("comm/datamodem")) == 0) {
  1217. UnimodemDevice = TRUE;
  1218. break;
  1219. }
  1220. DeviceClassList += (_tcslen(DeviceClassList) + 1);
  1221. }
  1222. }
  1223. if ((!(LineDevCaps->dwBearerModes & LINEBEARERMODE_VOICE)) ||
  1224. (!(LineDevCaps->dwBearerModes & LINEBEARERMODE_PASSTHROUGH))) {
  1225. //
  1226. // unacceptable modem device type
  1227. //
  1228. UnimodemDevice = FALSE;
  1229. }
  1230. //
  1231. // modem fsp only works with unimodem TSP
  1232. //
  1233. if (wcscmp((LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwProviderInfoOffset),
  1234. GetString(IDS_MODEM_PROVIDER_NAME)) != 0) {
  1235. UnimodemDevice = FALSE;
  1236. }
  1237. return UnimodemDevice;
  1238. }
  1239. BOOL CALLBACK
  1240. NewDeviceRoutingMethodEnumerator(
  1241. PROUTING_METHOD RoutingMethod,
  1242. DWORD DeviceId
  1243. )
  1244. {
  1245. BOOL Rslt = FALSE;
  1246. __try {
  1247. Rslt = RoutingMethod->RoutingExtension->FaxRouteDeviceChangeNotification( DeviceId, TRUE );
  1248. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1249. DebugPrint(( TEXT("FaxRouteDeviceChangeNotification() crashed: 0x%08x"), GetExceptionCode() ));
  1250. }
  1251. return Rslt;
  1252. }
  1253. BOOL
  1254. CloseDevicesMatch(
  1255. LPWSTR DeviceName,
  1256. LPWSTR CacheName
  1257. )
  1258. {
  1259. //
  1260. // deal with the fact that the device name might have changed slightly (add #1 to end, etc.)
  1261. // assumption: devices are for same TSP
  1262. //
  1263. DWORD len;
  1264. BOOL rVal = FALSE;
  1265. LPTSTR NewCacheName;
  1266. LPTSTR NewDeviceName;
  1267. if (!DeviceName || !CacheName) {
  1268. return FALSE;
  1269. }
  1270. //
  1271. // check if one is a shorted version of the other name
  1272. //
  1273. len = min( wcslen(CacheName), wcslen(DeviceName) );
  1274. if (_wcsnicmp( CacheName, DeviceName, len ) == 0 ) {
  1275. return TRUE;
  1276. }
  1277. //
  1278. // check if we have different numbered devices that are similar
  1279. //
  1280. NewDeviceName = wcsrchr(DeviceName,L'#');
  1281. if (NewDeviceName) *NewDeviceName = (WCHAR)0;
  1282. NewCacheName = wcsrchr(CacheName,L'#');
  1283. if (NewCacheName) *NewCacheName = (WCHAR)0;
  1284. len = min( wcslen(CacheName), wcslen(DeviceName) );
  1285. if (_wcsnicmp( CacheName, DeviceName, len ) == 0) {
  1286. rVal = TRUE;
  1287. }
  1288. //
  1289. // put back the device name to normal
  1290. //
  1291. if (NewDeviceName) *NewDeviceName = (WCHAR) L'#';
  1292. if (NewCacheName) *NewCacheName = (WCHAR) L'#';
  1293. return rVal;
  1294. }
  1295. BOOL
  1296. AddNewDevice(
  1297. DWORD DeviceId,
  1298. LPLINEDEVCAPS LineDevCaps,
  1299. BOOL InitDevice
  1300. )
  1301. {
  1302. BOOL rVal = FALSE;
  1303. BOOL UnimodemDevice = FALSE;
  1304. PMDM_DEVSPEC MdmDevSpec = NULL;
  1305. LPSTR ModemKey = NULL;
  1306. DWORD Flags;
  1307. DWORD Priority = 1;
  1308. LPTSTR DeviceName = NULL;
  1309. REG_SETUP RegSetup;
  1310. PREG_FAX_DEVICES_CACHE RegDevicesCache;
  1311. DWORD i;
  1312. DWORD CloseMatchIndex = -1, UseIndex = -1;
  1313. if (IsSmallBiz() && DeviceCount >= 4) {
  1314. return FALSE;
  1315. } else if (!IsCommServer() && DeviceCount >= 2) {
  1316. return FALSE;
  1317. }
  1318. //
  1319. // only add devices that support fax
  1320. //
  1321. if (! ( ((LineDevCaps->dwMediaModes & LINEMEDIAMODE_DATAMODEM) &&
  1322. (UnimodemDevice = IsDeviceModem( LineDevCaps ) )) ||
  1323. (LineDevCaps->dwMediaModes & LINEMEDIAMODE_G3FAX) )) {
  1324. return FALSE;
  1325. }
  1326. //
  1327. // we have a fax capable device to be added, so let's retreive configuration
  1328. // data about fax devices on the system to decide how to configure this
  1329. // device
  1330. //
  1331. if (!GetOrigSetupData( &RegSetup ) || !(RegDevicesCache = GetFaxDevicesCacheRegistry()) ) {
  1332. return FALSE;
  1333. }
  1334. if (UnimodemDevice) {
  1335. Flags = FPF_SEND;
  1336. if (ForceReceive) {
  1337. Flags |= FPF_RECEIVE;
  1338. }
  1339. } else {
  1340. Flags = FPF_RECEIVE | FPF_SEND;
  1341. }
  1342. if (Flags & FPF_RECEIVE) {
  1343. InterlockedIncrement( &ConnectionCount );
  1344. }
  1345. DeviceName = FixupDeviceName( (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwLineNameOffset) );
  1346. //
  1347. // check in the device cache for an old instantiation of this device
  1348. //
  1349. for (i=0; i<RegDevicesCache->DeviceCount ; i++ ) {
  1350. if (RegDevicesCache->Devices[i].Provider &&
  1351. RegDevicesCache->Devices[i].Name &&
  1352. (wcscmp((LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwProviderInfoOffset),
  1353. RegDevicesCache->Devices[i].Provider) == 0)) {
  1354. if (wcscmp(DeviceName,RegDevicesCache->Devices[i].Name) == 0) {
  1355. //
  1356. // exact match, use it
  1357. //
  1358. UseIndex = i;
  1359. break;
  1360. } else if (CloseDevicesMatch(DeviceName,RegDevicesCache->Devices[i].Name)) {
  1361. CloseMatchIndex = i;
  1362. }
  1363. }
  1364. }
  1365. if (UseIndex == (DWORD) -1) {
  1366. UseIndex = CloseMatchIndex;
  1367. } else {
  1368. CloseMatchIndex = -1;
  1369. }
  1370. if (UseIndex != (DWORD) -1) {
  1371. Priority = RegAddNewFaxDevice(
  1372. DeviceName,
  1373. RegDevicesCache->Devices[UseIndex].Provider,
  1374. RegDevicesCache->Devices[UseIndex].Csid,
  1375. RegDevicesCache->Devices[UseIndex].Tsid,
  1376. -1, // BugBug what priority ???
  1377. LineDevCaps->dwPermanentLineID,
  1378. Flags,
  1379. RegDevicesCache->Devices[UseIndex].Rings,
  1380. RegDevicesCache->Devices[UseIndex].RoutingMask,
  1381. RegDevicesCache->Devices[UseIndex].Printer,
  1382. RegDevicesCache->Devices[UseIndex].StoreDir,
  1383. RegDevicesCache->Devices[UseIndex].Profile
  1384. );
  1385. //
  1386. // get rid of the cached entry
  1387. //
  1388. if (CloseMatchIndex == -1) {
  1389. DeleteCachedFaxDevice( RegDevicesCache->Devices[UseIndex].Name );
  1390. }
  1391. } else {
  1392. Priority = RegAddNewFaxDevice(
  1393. DeviceName,
  1394. (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwProviderInfoOffset),
  1395. RegSetup.Csid,
  1396. RegSetup.Tsid,
  1397. -1,
  1398. LineDevCaps->dwPermanentLineID,
  1399. Flags,
  1400. RegSetup.Rings,
  1401. RegSetup.Mask,
  1402. RegSetup.Printer,
  1403. RegSetup.StoreDir,
  1404. RegSetup.Profile
  1405. );
  1406. }
  1407. if (InitDevice) {
  1408. DeviceCount += 1;
  1409. InitializeTapiLine(
  1410. DeviceId,
  1411. LineDevCaps,
  1412. Priority,
  1413. RegSetup.Rings,
  1414. Flags,
  1415. RegSetup.Csid,
  1416. RegSetup.Tsid
  1417. );
  1418. }
  1419. rVal = TRUE;
  1420. if (DeviceName) {
  1421. MemFree( DeviceName );
  1422. }
  1423. FreeFaxDevicesCacheRegistry( RegDevicesCache );
  1424. FreeOrigSetupData( &RegSetup );
  1425. EnumerateRoutingMethods( (PFAXROUTEMETHODENUM)NewDeviceRoutingMethodEnumerator, (LPVOID)LineDevCaps->dwPermanentLineID );
  1426. return rVal;
  1427. }
  1428. DWORD
  1429. InitializeTapiLine(
  1430. DWORD DeviceId,
  1431. LPLINEDEVCAPS LineDevCaps,
  1432. DWORD Priority,
  1433. DWORD Rings,
  1434. DWORD Flags,
  1435. LPTSTR Csid,
  1436. LPTSTR Tsid
  1437. )
  1438. {
  1439. PLINE_INFO LineInfo = NULL;
  1440. LONG Rslt = ERROR_SUCCESS;
  1441. DWORD len;
  1442. PDEVICE_PROVIDER Provider;
  1443. BOOL UnimodemDevice;
  1444. HLINE hLine = 0;
  1445. LPTSTR ProviderName = NULL;
  1446. LPTSTR DeviceName = NULL;
  1447. BOOL NewDevice = TRUE;
  1448. DWORD LineStates = 0;
  1449. DWORD AddressStates = 0;
  1450. LPLINEDEVSTATUS LineDevStatus;
  1451. //
  1452. // allocate the LINE_INFO structure
  1453. //
  1454. LineInfo = (PLINE_INFO) MemAlloc( sizeof(LINE_INFO) );
  1455. if (!LineInfo) {
  1456. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  1457. goto exit;
  1458. }
  1459. //
  1460. // get the provider name
  1461. //
  1462. len = _tcslen( (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwProviderInfoOffset) );
  1463. ProviderName = MemAlloc( (len + 1) * sizeof(TCHAR) );
  1464. if (!ProviderName) {
  1465. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  1466. goto exit;
  1467. }
  1468. _tcscpy( ProviderName, (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwProviderInfoOffset) );
  1469. //
  1470. // get the device name
  1471. //
  1472. DeviceName = FixupDeviceName( (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwLineNameOffset) );
  1473. if (!DeviceName) {
  1474. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  1475. goto exit;
  1476. }
  1477. //
  1478. // verify that the line id is good
  1479. //
  1480. if (LineDevCaps->dwPermanentLineID == 0) {
  1481. DebugPrint((
  1482. TEXT("TAPI lines must have a non-zero line id [%s]"),
  1483. DeviceName
  1484. ));
  1485. Rslt = ERROR_BAD_DEVICE;
  1486. goto exit;
  1487. }
  1488. //
  1489. // check for a modem device
  1490. //
  1491. UnimodemDevice = IsDeviceModem( LineDevCaps );
  1492. //
  1493. // assign the device provider
  1494. //
  1495. Provider = FindDeviceProvider( ProviderName );
  1496. if (!Provider) {
  1497. DebugPrint(( TEXT("Could not find a valid device provider for device: %s"), DeviceName ));
  1498. Rslt = ERROR_BAD_PROVIDER;
  1499. goto exit;
  1500. }
  1501. //
  1502. // open the line
  1503. //
  1504. if (UnimodemDevice) {
  1505. Rslt = lineOpen(
  1506. hLineApp,
  1507. DeviceId,
  1508. &hLine,
  1509. TapiApiVersion,
  1510. 0,
  1511. (DWORD_PTR) LineInfo,
  1512. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  1513. LINEMEDIAMODE_DATAMODEM | LINEMEDIAMODE_UNKNOWN,
  1514. NULL
  1515. );
  1516. if (Rslt != 0) {
  1517. Rslt = lineOpen(
  1518. hLineApp,
  1519. DeviceId,
  1520. &hLine,
  1521. TapiApiVersion,
  1522. 0,
  1523. (DWORD_PTR) LineInfo,
  1524. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  1525. LINEMEDIAMODE_DATAMODEM,
  1526. NULL
  1527. );
  1528. }
  1529. } else {
  1530. Rslt = lineOpen(
  1531. hLineApp,
  1532. DeviceId,
  1533. &hLine,
  1534. TapiApiVersion,
  1535. 0,
  1536. (DWORD_PTR) LineInfo,
  1537. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  1538. LINEMEDIAMODE_G3FAX,
  1539. NULL
  1540. );
  1541. }
  1542. if (Rslt != 0) {
  1543. DebugPrint(( TEXT("Device %s FAILED to initialize, ec=%08x"), DeviceName, Rslt ));
  1544. goto exit;
  1545. }
  1546. //
  1547. // set the line status that we need
  1548. //
  1549. LineStates |= LineDevCaps->dwLineStates & LINEDEVSTATE_OPEN ? LINEDEVSTATE_OPEN : 0;
  1550. LineStates |= LineDevCaps->dwLineStates & LINEDEVSTATE_CLOSE ? LINEDEVSTATE_CLOSE : 0;
  1551. LineStates |= LineDevCaps->dwLineStates & LINEDEVSTATE_RINGING ? LINEDEVSTATE_RINGING : 0;
  1552. LineStates |= LineDevCaps->dwLineStates & LINEDEVSTATE_NUMCALLS ? LINEDEVSTATE_NUMCALLS : 0;
  1553. LineStates |= LineDevCaps->dwLineStates & LINEDEVSTATE_REMOVED ? LINEDEVSTATE_REMOVED : 0;
  1554. AddressStates = LINEADDRESSSTATE_INUSEZERO | LINEADDRESSSTATE_INUSEONE |
  1555. LINEADDRESSSTATE_INUSEMANY | LINEADDRESSSTATE_NUMCALLS;
  1556. Rslt = lineSetStatusMessages( hLine, LineStates, AddressStates );
  1557. if (Rslt != 0) {
  1558. DebugPrint(( TEXT("lineSetStatusMessages() failed, [0x%08x:0x%08x], ec=0x%08x"), LineStates, AddressStates, Rslt ));
  1559. if (Rslt == LINEERR_INVALLINEHANDLE) {
  1560. hLine = 0;
  1561. }
  1562. Rslt = 0;
  1563. }
  1564. //
  1565. // now assign the necessary values to the line info struct
  1566. //
  1567. LineInfo->Signature = LINE_SIGNATURE;
  1568. LineInfo->DeviceId = DeviceId;
  1569. LineInfo->PermanentLineID = LineDevCaps->dwPermanentLineID;
  1570. LineInfo->hLine = hLine;
  1571. LineInfo->Provider = Provider;
  1572. LineInfo->DeviceName = StringDup( DeviceName );
  1573. LineInfo->UnimodemDevice = UnimodemDevice;
  1574. LineInfo->State = FPS_AVAILABLE;
  1575. LineInfo->Csid = StringDup( Csid );
  1576. LineInfo->Tsid = StringDup( Tsid );
  1577. LineInfo->Priority = Priority;
  1578. LineInfo->RingsForAnswer = (LineDevCaps->dwLineStates & LINEDEVSTATE_RINGING) ? Rings : 0;
  1579. LineInfo->Flags = Flags;
  1580. LineInfo->RingCount = 0;
  1581. LineInfo->ModemPopUps = 0;
  1582. LineInfo->ModemPopupActive = 1;
  1583. LineInfo->LineStates = LineDevCaps->dwLineStates;
  1584. if (LineInfo->Flags & FPF_RECEIVE) {
  1585. InterlockedIncrement( &ConnectionCount );
  1586. }
  1587. if (hLine) {
  1588. //
  1589. // check to see if the line is in use
  1590. //
  1591. LineDevStatus = MyLineGetLineDevStatus( hLine );
  1592. if (LineDevStatus) {
  1593. if (LineDevStatus->dwNumOpens > 0 && LineDevStatus->dwNumActiveCalls > 0) {
  1594. LineInfo->ModemInUse = TRUE;
  1595. }
  1596. MemFree( LineDevStatus );
  1597. }
  1598. } else {
  1599. //
  1600. // if we don't have a line handle at this time then the
  1601. // device must be powered off
  1602. //
  1603. DebugPrint(( TEXT("Device %s is powered off or disconnected"), DeviceName ));
  1604. if (LineInfo->Flags & FPF_RECEIVE) {
  1605. LineInfo->Flags &= ~FPF_RECEIVE;
  1606. LineInfo->Flags |= FPF_RECEIVE_OK;
  1607. }
  1608. LineInfo->Flags |= FPF_POWERED_OFF;
  1609. LineInfo->State = FPS_OFFLINE;
  1610. }
  1611. exit:
  1612. MemFree( DeviceName );
  1613. MemFree( ProviderName );
  1614. if (Rslt == ERROR_SUCCESS) {
  1615. InsertTailList( &TapiLinesListHead, &LineInfo->ListEntry );
  1616. } else {
  1617. FreeTapiLine( LineInfo );
  1618. }
  1619. return Rslt;
  1620. }
  1621. BOOL MoveToDeviceCache(
  1622. PREG_DEVICE FaxDevice
  1623. )
  1624. {
  1625. PREG_ROUTING_INFO pRouting = RegGetRoutingInfo( FaxDevice->PermanentLineID );
  1626. if (!pRouting) {
  1627. return FALSE;
  1628. }
  1629. if (!RegAddNewFaxDeviceCache(
  1630. FaxDevice->Name,
  1631. FaxDevice->Provider,
  1632. FaxDevice->Csid,
  1633. FaxDevice->Tsid,
  1634. FaxDevice->PermanentLineID,
  1635. FaxDevice->Flags,
  1636. FaxDevice->Rings,
  1637. pRouting->RoutingMask,
  1638. pRouting->Printer,
  1639. pRouting->StoreDir,
  1640. pRouting->Profile
  1641. ) ) {
  1642. DebugPrint(( TEXT("Couldn't RegAddNewFaxDeviceCache(%s), ec = %d\n"),
  1643. FaxDevice->Name,
  1644. GetLastError() ));
  1645. return FALSE;
  1646. }
  1647. FreeRegRoutingInfo( pRouting );
  1648. return DeleteFaxDevice( FaxDevice->PermanentLineID );
  1649. }
  1650. BOOL
  1651. IsVirtualDevice(
  1652. PLINE_INFO LineInfo
  1653. )
  1654. {
  1655. if (!LineInfo) {
  1656. return FALSE;
  1657. }
  1658. return (LineInfo->Provider->FaxDevVirtualDeviceCreation) ? TRUE : FALSE;
  1659. }
  1660. VOID
  1661. UpdateVirtualDevices(
  1662. VOID
  1663. )
  1664. {
  1665. PLIST_ENTRY Next;
  1666. PLINE_INFO LineInfo = NULL;
  1667. EnterCriticalSection( &CsLine );
  1668. Next = TapiLinesListHead.Flink;
  1669. if (Next == NULL) {
  1670. LeaveCriticalSection( &CsLine );
  1671. return;
  1672. }
  1673. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  1674. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  1675. Next = LineInfo->ListEntry.Flink;
  1676. if (IsVirtualDevice(LineInfo) && LineInfo->Provider->FaxDevCallback) {
  1677. __try {
  1678. LineInfo->Provider->FaxDevCallback( NULL,
  1679. LineInfo->PermanentLineID,
  1680. LINE_DEVSPECIFIC,
  1681. 0,
  1682. (LineInfo->Flags & FPF_RECEIVE),
  1683. (LineInfo->Flags & FPF_SEND),
  1684. 0
  1685. );
  1686. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1687. DebugPrint(( TEXT("Exception in FaxDevCallback, ec = %d\n"),GetExceptionCode() ));
  1688. }
  1689. }
  1690. }
  1691. LeaveCriticalSection( &CsLine );
  1692. }
  1693. DWORD
  1694. CreateVirtualDevices(
  1695. PREG_FAX_SERVICE FaxReg
  1696. )
  1697. {
  1698. extern LIST_ENTRY DeviceProviders;
  1699. PLIST_ENTRY Next;
  1700. PDEVICE_PROVIDER Provider;
  1701. DWORD VirtualDeviceCount;
  1702. WCHAR DevicePrefix[128];
  1703. DWORD DeviceIdPrefix;
  1704. LPWSTR DeviceName;
  1705. DWORD i,j;
  1706. PLINE_INFO LineInfo = NULL;
  1707. PREG_DEVICE FaxDevice = NULL;
  1708. PREG_FAX_DEVICES FaxDevices = NULL;
  1709. BOOL NewDevice;
  1710. DWORD DeviceCount = 0;
  1711. REG_SETUP RegSetup;
  1712. Next = DeviceProviders.Flink;
  1713. if (!Next) {
  1714. return DeviceCount;
  1715. }
  1716. if (!GetOrigSetupData( &RegSetup )) {
  1717. return DeviceCount;
  1718. }
  1719. while ((ULONG_PTR)Next != (ULONG_PTR)&DeviceProviders) {
  1720. Provider = CONTAINING_RECORD( Next, DEVICE_PROVIDER, ListEntry );
  1721. Next = Provider->ListEntry.Flink;
  1722. if (Provider->FaxDevVirtualDeviceCreation) {
  1723. __try {
  1724. VirtualDeviceCount = 0;
  1725. ZeroMemory(DevicePrefix, sizeof(DevicePrefix));
  1726. DeviceIdPrefix = 0;
  1727. if (Provider->FaxDevVirtualDeviceCreation(
  1728. &VirtualDeviceCount,
  1729. DevicePrefix,
  1730. &DeviceIdPrefix,
  1731. TapiCompletionPort,
  1732. FAXDEV_EVENT_KEY
  1733. ))
  1734. {
  1735. for (i=0; i<VirtualDeviceCount; i++) {
  1736. //
  1737. // create the device name
  1738. //
  1739. DeviceName = (LPWSTR) MemAlloc( StringSize(DevicePrefix) + 16 );
  1740. if (!DeviceName) {
  1741. goto InitializationFailure;
  1742. }
  1743. swprintf( DeviceName, L"%s%d", DevicePrefix, i );
  1744. //
  1745. // find the registry information for this device
  1746. //
  1747. for (j=0,FaxDevice=NULL; j<FaxReg->DeviceCount; j++) {
  1748. if (FaxReg->Devices[j].PermanentLineID == DeviceIdPrefix+i) {
  1749. FaxDevice = &FaxReg->Devices[j];
  1750. break;
  1751. }
  1752. }
  1753. //
  1754. // if the device is new then add it to the registry
  1755. //
  1756. if (!FaxDevice) {
  1757. RegAddNewFaxDevice(
  1758. DeviceName,
  1759. Provider->ProviderName,
  1760. RegSetup.Csid,
  1761. RegSetup.Tsid,
  1762. 1, // priority
  1763. DeviceIdPrefix + i,
  1764. FPF_SEND | FPF_VIRTUAL,
  1765. RegSetup.Rings,
  1766. RegSetup.Mask,
  1767. RegSetup.Printer,
  1768. RegSetup.StoreDir,
  1769. RegSetup.Profile
  1770. );
  1771. NewDevice = TRUE;
  1772. } else {
  1773. NewDevice = FALSE;
  1774. }
  1775. //
  1776. // allocate the LINE_INFO structure
  1777. //
  1778. LineInfo = (PLINE_INFO) MemAlloc( sizeof(LINE_INFO) );
  1779. if (!LineInfo) {
  1780. goto InitializationFailure;
  1781. }
  1782. //
  1783. // now assign the necessary values to the line info struct
  1784. //
  1785. LineInfo->Signature = LINE_SIGNATURE;
  1786. LineInfo->DeviceId = i;
  1787. LineInfo->PermanentLineID = DeviceIdPrefix + i;
  1788. LineInfo->hLine = 0;
  1789. LineInfo->Provider = Provider;
  1790. LineInfo->DeviceName = DeviceName;
  1791. LineInfo->UnimodemDevice = FALSE;
  1792. LineInfo->State = FPS_AVAILABLE;
  1793. LineInfo->Csid = StringDup( FaxDevice ? FaxDevice->Csid : RegSetup.Csid );
  1794. LineInfo->Tsid = StringDup( FaxDevice ? FaxDevice->Tsid : RegSetup.Tsid );
  1795. LineInfo->Priority = FaxDevice ? FaxDevice->Priority : 1;
  1796. LineInfo->RingsForAnswer = 0;
  1797. LineInfo->Flags = FaxDevice ? FaxDevice->Flags : FPF_SEND | FPF_VIRTUAL;
  1798. LineInfo->RingCount = 0;
  1799. LineInfo->ModemPopUps = 0;
  1800. LineInfo->ModemPopupActive = 1;
  1801. LineInfo->LineStates = 0;
  1802. InsertTailList( &TapiLinesListHead, &LineInfo->ListEntry );
  1803. if (LineInfo->Flags & FPF_RECEIVE) {
  1804. InterlockedIncrement( &ConnectionCount );
  1805. }
  1806. DeviceCount += 1;
  1807. if (NewDevice) {
  1808. FreeFaxDevicesRegistry( FaxDevices );
  1809. }
  1810. }
  1811. }
  1812. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1813. DebugPrint(( TEXT("FaxDevVirtualDeviceCreation() crashed: 0x%08x"), GetExceptionCode() ));
  1814. goto InitializationFailure;
  1815. }
  1816. }
  1817. goto next;
  1818. InitializationFailure:
  1819. FaxLog(
  1820. FAXLOG_CATEGORY_INIT,
  1821. FAXLOG_LEVEL_NONE,
  1822. 1,
  1823. MSG_VIRTUAL_DEVICE_INIT_FAILED,
  1824. Provider->FriendlyName
  1825. );
  1826. next:
  1827. ;
  1828. }
  1829. DebugPrint(( TEXT("Virtual devices initialized, devices=%d"), DeviceCount ));
  1830. FreeOrigSetupData( &RegSetup );
  1831. return DeviceCount;
  1832. }
  1833. DWORD
  1834. TapiInitialize(
  1835. PREG_FAX_SERVICE FaxReg
  1836. )
  1837. /*++
  1838. Routine Description:
  1839. This function performs all necessary TAPI initialization.
  1840. This includes device enumeration, message pump creation,
  1841. device capabilities caputure, etc. It is required that
  1842. the device provider initialization is completed before
  1843. calling this function.
  1844. Arguments:
  1845. None.
  1846. Return Value:
  1847. Error code.
  1848. --*/
  1849. {
  1850. extern CRITICAL_SECTION CsRouting;
  1851. LONG Rslt;
  1852. DWORD i,j;
  1853. HANDLE hThread;
  1854. DWORD ThreadId;
  1855. PLIST_ENTRY Next;
  1856. PLINE_INFO LineInfo;
  1857. LPLINEDEVCAPS LineDevCaps = NULL;
  1858. PREG_FAX_DEVICES FaxDevices = NULL;
  1859. HLINE hLine;
  1860. LINEINITIALIZEEXPARAMS LineInitializeExParams;
  1861. TCHAR FaxSvcName[MAX_PATH*2];
  1862. TCHAR Fname[_MAX_FNAME];
  1863. TCHAR Ext[_MAX_EXT];
  1864. DWORD LocalTapiApiVersion;
  1865. LINEEXTENSIONID lineExtensionID;
  1866. LPTSTR AdaptiveFileName;
  1867. HANDLE AdaptiveFileHandle;
  1868. BOOL Found = FALSE;
  1869. DWORD DeviceLimit;
  1870. InitializeListHead( &TapiLinesListHead );
  1871. InitializeCriticalSection( &CsLine );
  1872. InitializeCriticalSection( &CsRouting );
  1873. //
  1874. // we need to hold onto this cs until tapi is up and ready to serve
  1875. //
  1876. EnterCriticalSection( &CsLine );
  1877. //
  1878. // set the device limit
  1879. //
  1880. if (IsSmallBiz()) {
  1881. DeviceLimit = 4;
  1882. } else if (IsCommServer()) {
  1883. DeviceLimit = 0xFFFFFFFF;
  1884. } else {
  1885. DeviceLimit = 2;
  1886. }
  1887. //
  1888. // open faxadapt.lst file to decide on enabling rx
  1889. //
  1890. AdaptiveFileName = ExpandEnvironmentString( TEXT("%systemroot%\\system32\\faxadapt.lst") );
  1891. if (AdaptiveFileName) {
  1892. AdaptiveFileHandle = CreateFile(
  1893. AdaptiveFileName,
  1894. GENERIC_READ,
  1895. FILE_SHARE_READ,
  1896. NULL,
  1897. OPEN_EXISTING,
  1898. 0,
  1899. NULL
  1900. );
  1901. if (AdaptiveFileHandle == INVALID_HANDLE_VALUE ) {
  1902. DebugPrint(( TEXT("Could not open adaptive file [%s], ec=0x%08x"), _tcslwr(AdaptiveFileName), GetLastError() ));
  1903. } else {
  1904. i = GetFileSize( AdaptiveFileHandle, NULL );
  1905. if (i != 0xffffffff) {
  1906. AdaptiveFileBuffer = MemAlloc( i + 16 );
  1907. if (AdaptiveFileBuffer) {
  1908. if (!ReadFile( AdaptiveFileHandle, AdaptiveFileBuffer, i, &j, NULL ) ) {
  1909. DebugPrint(( TEXT("Could not read adaptive file [%s], ec=0x%08x"), _tcslwr(AdaptiveFileName), GetLastError() ));
  1910. MemFree( AdaptiveFileBuffer );
  1911. AdaptiveFileBuffer = NULL;
  1912. } else {
  1913. AdaptiveFileBuffer[j] = 0; // need a string
  1914. }
  1915. }
  1916. }
  1917. CloseHandle( AdaptiveFileHandle );
  1918. }
  1919. }
  1920. //
  1921. // initialize tapi
  1922. //
  1923. TapiCompletionPort = CreateIoCompletionPort(
  1924. INVALID_HANDLE_VALUE,
  1925. NULL,
  1926. 0,
  1927. 1
  1928. );
  1929. if (!TapiCompletionPort) {
  1930. DebugPrint(( TEXT("CreateIoCompletionPort() failed, ec=0x%08x"), GetLastError() ));
  1931. goto no_devices_exit;
  1932. }
  1933. LineInitializeExParams.dwTotalSize = sizeof(LINEINITIALIZEEXPARAMS);
  1934. LineInitializeExParams.dwNeededSize = 0;
  1935. LineInitializeExParams.dwUsedSize = 0;
  1936. LineInitializeExParams.dwOptions = LINEINITIALIZEEXOPTION_USECOMPLETIONPORT;
  1937. LineInitializeExParams.Handles.hCompletionPort = TapiCompletionPort;
  1938. LineInitializeExParams.dwCompletionKey = TAPI_COMPLETION_KEY;
  1939. LocalTapiApiVersion = TapiApiVersion = 0x00020000;
  1940. Rslt = lineInitializeEx(
  1941. &hLineApp,
  1942. GetModuleHandle(NULL),
  1943. NULL,
  1944. FAX_DISPLAY_NAME,
  1945. &TapiDevices,
  1946. &LocalTapiApiVersion,
  1947. &LineInitializeExParams
  1948. );
  1949. if (Rslt != 0 || LocalTapiApiVersion < 0x00020000) {
  1950. DebugPrint(( TEXT("lineInitializeEx() failed, ec=0x%08x, devices=%d"), Rslt, TapiDevices ));
  1951. goto no_devices_exit;
  1952. }
  1953. //
  1954. // add any new devices to the registry
  1955. //
  1956. for (i=0; i<TapiDevices; i++) {
  1957. Rslt = lineNegotiateAPIVersion(
  1958. hLineApp,
  1959. i,
  1960. 0x00010003,
  1961. TapiApiVersion,
  1962. &LocalTapiApiVersion,
  1963. &lineExtensionID
  1964. );
  1965. if (Rslt == 0) {
  1966. LineDevCaps = MyLineGetDevCaps( i );
  1967. if (LineDevCaps) {
  1968. for (j=0; j<FaxReg->DeviceCount; j++) {
  1969. if (FaxReg->Devices[j].PermanentLineID == LineDevCaps->dwPermanentLineID) {
  1970. MemFree( LineDevCaps );
  1971. FaxReg->Devices[j].DeviceInstalled = TRUE;
  1972. goto next_device;
  1973. }
  1974. }
  1975. AddNewDevice( i, LineDevCaps, FALSE );
  1976. MemFree( LineDevCaps );
  1977. }
  1978. } else {
  1979. DebugPrint(( TEXT("lineNegotiateAPIVersion() failed, ec=0x%08x"), Rslt ));
  1980. }
  1981. next_device:;
  1982. }
  1983. //
  1984. // move any devices that aren't current installed into the device cache
  1985. // don't cache virtual devices!
  1986. //
  1987. for (j=0; j<FaxReg->DeviceCount; j++) {
  1988. if (!FaxReg->Devices[j].DeviceInstalled && !(FaxReg->Devices[j].Flags & FPF_VIRTUAL)) {
  1989. MoveToDeviceCache(&FaxReg->Devices[j]);
  1990. }
  1991. }
  1992. //
  1993. // get a current list of valid devices
  1994. //
  1995. FaxDevices = GetFaxDevicesRegistry();
  1996. if (!FaxDevices) {
  1997. goto no_devices_exit;
  1998. }
  1999. //
  2000. // create the virtual devices
  2001. //
  2002. DeviceCount += CreateVirtualDevices( FaxReg );
  2003. if (GetModuleFileName( NULL, FaxSvcName, sizeof(FaxSvcName) )) {
  2004. _tsplitpath( FaxSvcName, NULL, NULL, Fname, Ext );
  2005. _stprintf( FaxSvcName, TEXT("%s%s"), Fname, Ext );
  2006. Rslt = lineSetAppPriority(
  2007. FaxSvcName,
  2008. LINEMEDIAMODE_UNKNOWN,
  2009. 0,
  2010. 0,
  2011. NULL,
  2012. 1
  2013. );
  2014. Rslt = lineSetAppPriority(
  2015. FaxSvcName,
  2016. LINEMEDIAMODE_DATAMODEM,
  2017. 0,
  2018. 0,
  2019. NULL,
  2020. 1
  2021. );
  2022. if (Rslt != 0) {
  2023. DebugPrint(( TEXT("lineSetAppPriority() failed, ec=0x%08x"), Rslt ));
  2024. }
  2025. }
  2026. if (DeviceCount == 0 && FaxDevices->DeviceCount == 0) {
  2027. goto no_devices_exit;
  2028. }
  2029. //
  2030. // create a thread to service the tapi callback events
  2031. //
  2032. hThread = CreateThread(
  2033. NULL,
  2034. 0,
  2035. (LPTHREAD_START_ROUTINE) TapiWorkerThread,
  2036. NULL,
  2037. 0,
  2038. &ThreadId
  2039. );
  2040. if (!hThread) {
  2041. Rslt = GetLastError();
  2042. DebugPrint(( TEXT("Could not start a FAX worker thread, ec=0x%08x"), Rslt ));
  2043. } else {
  2044. CloseHandle( hThread );
  2045. }
  2046. //
  2047. // enumerate and initialize all of the tapi devices
  2048. //
  2049. for (i=0; (i<TapiDevices) && (DeviceCount < DeviceLimit) ; i++) {
  2050. Rslt = lineNegotiateAPIVersion(
  2051. hLineApp,
  2052. i,
  2053. 0x00010003,
  2054. TapiApiVersion,
  2055. &LocalTapiApiVersion,
  2056. &lineExtensionID
  2057. );
  2058. if (Rslt != 0) {
  2059. DebugPrint(( TEXT("lineNegotiateAPIVersion() failed, ec=0x%08x"), Rslt ));
  2060. }
  2061. LineDevCaps = MyLineGetDevCaps( i );
  2062. if (LineDevCaps) {
  2063. for (j=0; j<FaxDevices->DeviceCount; j++) {
  2064. if (FaxDevices->Devices[j].PermanentLineID == LineDevCaps->dwPermanentLineID) {
  2065. Rslt = InitializeTapiLine(
  2066. i,
  2067. LineDevCaps,
  2068. FaxDevices->Devices[j].Priority,
  2069. FaxDevices->Devices[j].Rings,
  2070. FaxDevices->Devices[j].Flags,
  2071. FaxDevices->Devices[j].Csid,
  2072. FaxDevices->Devices[j].Tsid
  2073. );
  2074. if (Rslt != 0) {
  2075. DebugPrint(( TEXT("InitializeTapiLine() failed, ec=0x%08x"), Rslt ));
  2076. } else {
  2077. DeviceCount += 1;
  2078. }
  2079. }
  2080. }
  2081. MemFree( LineDevCaps );
  2082. }
  2083. }
  2084. FreeFaxDevicesRegistry( FaxDevices );
  2085. //
  2086. // loop thru the devices and close the line handles
  2087. // for all devices that are NOT set to receive
  2088. //
  2089. Next = TapiLinesListHead.Flink;
  2090. if (Next) {
  2091. while ((ULONG_PTR)Next != (ULONG_PTR)&TapiLinesListHead) {
  2092. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  2093. Next = LineInfo->ListEntry.Flink;
  2094. if (LineInfo->Flags & FPF_RECEIVE) {
  2095. TerminationDelay = (DWORD)-1;
  2096. } else {
  2097. if (LineInfo->hLine) {
  2098. hLine = LineInfo->hLine;
  2099. LineInfo->hLine = 0;
  2100. lineClose( hLine );
  2101. }
  2102. }
  2103. }
  2104. }
  2105. SortDevicePriorities();
  2106. LeaveCriticalSection( &CsLine );
  2107. return 0;
  2108. no_devices_exit:
  2109. FaxLog(
  2110. FAXLOG_CATEGORY_INIT,
  2111. FAXLOG_LEVEL_NONE,
  2112. 0,
  2113. MSG_NO_FAX_DEVICES
  2114. );
  2115. ReportServiceStatus( SERVICE_STOPPED, 0, 0 );
  2116. FaxLog(
  2117. FAXLOG_CATEGORY_INIT,
  2118. FAXLOG_LEVEL_NONE,
  2119. 0,
  2120. MSG_SERVICE_STOPPED
  2121. );
  2122. ExitProcess(0);
  2123. return 0;
  2124. }