Leaked source code of windows server 2003
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.

5012 lines
151 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. #include <vector>
  14. using namespace std;
  15. #include "tapiCountry.h"
  16. //
  17. // globals
  18. //
  19. HLINEAPP g_hLineApp; // application line handle
  20. HANDLE g_TapiCompletionPort; //
  21. HANDLE g_hTapiWorkerThread; // holds the TapiWorkerThread handle
  22. CFaxCriticalSection g_CsLine; // critical section for accessing tapi lines
  23. DWORD g_dwDeviceCount; // number of devices in the g_TapiLinesListHead
  24. LIST_ENTRY g_TapiLinesListHead; // linked list of tapi lines
  25. LIST_ENTRY g_RemovedTapiLinesListHead; // linked list of removed tapi lines
  26. LPBYTE g_pAdaptiveFileBuffer; // list of approved adaptive answer modems
  27. DWORD g_dwManualAnswerDeviceId; // Id of (one and only) device capable of manual answering (protected by g_CsLine)
  28. DWORD g_dwDeviceEnabledLimit; // Total number of devices
  29. DWORD g_dwDeviceEnabledCount; // Device limt by SKU
  30. static BOOL LoadAdaptiveFileBuffer();
  31. static BOOL CreateLegacyVirtualDevices(
  32. PREG_FAX_SERVICE FaxReg,
  33. const REG_SETUP * lpRegSetup,
  34. DEVICE_PROVIDER * lpcProvider,
  35. LPDWORD lpdwDeviceCount);
  36. DWORD g_dwMaxLineCloseTime; // Wait interval in sec before trying to resend a powered off device
  37. BOOL
  38. AddNewDevice(
  39. DWORD DeviceId,
  40. LPLINEDEVCAPS LineDevCaps,
  41. BOOL fServerInitialization,
  42. PREG_FAX_DEVICES pInputFaxReg
  43. );
  44. DWORD
  45. InitializeTapiLine(
  46. DWORD DeviceId,
  47. DWORD dwUniqueLineId,
  48. LPLINEDEVCAPS LineDevCaps,
  49. DWORD Rings,
  50. DWORD Flags,
  51. LPTSTR Csid,
  52. LPTSTR Tsid,
  53. LPTSTR lptstrDescription,
  54. BOOL fCheckDeviceLimit,
  55. DWORD dwDeviceType
  56. );
  57. BOOL
  58. RemoveTapiDevice(
  59. DWORD dwTapiDeviceId
  60. );
  61. void
  62. ResetDeviceFlags(
  63. PLINE_INFO pLineInfo
  64. )
  65. {
  66. DWORD dwRes;
  67. DEBUG_FUNCTION_NAME(TEXT("ResetDeviceFlags"));
  68. Assert (pLineInfo);
  69. pLineInfo->Flags = (pLineInfo->Flags & FPF_VIRTUAL) ? FPF_VIRTUAL : 0; // send/receive disabled
  70. dwRes = RegSetFaxDeviceFlags( pLineInfo->PermanentLineID,
  71. pLineInfo->Flags);
  72. if (ERROR_SUCCESS != dwRes)
  73. {
  74. DebugPrintEx(
  75. DEBUG_ERR,
  76. TEXT("RegSetFaxDeviceFlags() (ec: %ld)"),
  77. dwRes);
  78. }
  79. if (pLineInfo->PermanentLineID == g_dwManualAnswerDeviceId)
  80. {
  81. g_dwManualAnswerDeviceId = 0; // Disable manual receive
  82. dwRes = WriteManualAnswerDeviceId (g_dwManualAnswerDeviceId);
  83. if (ERROR_SUCCESS != dwRes)
  84. {
  85. DebugPrintEx(
  86. DEBUG_ERR,
  87. TEXT("WriteManualAnswerDeviceId(0) (ec: %lc)"),
  88. dwRes);
  89. }
  90. }
  91. }
  92. LPTSTR
  93. FixupDeviceName(
  94. LPTSTR OrigDeviceName
  95. )
  96. {
  97. LPTSTR NewDeviceName;
  98. LPTSTR p;
  99. NewDeviceName = StringDup( OrigDeviceName );
  100. if (!NewDeviceName) {
  101. return NULL;
  102. }
  103. p = _tcschr( NewDeviceName, TEXT(',') );
  104. if (!p) {
  105. return NewDeviceName;
  106. }
  107. p = NewDeviceName;
  108. while( p ) {
  109. p = _tcschr( p, TEXT(',') );
  110. if (p) {
  111. *p = TEXT('_');
  112. }
  113. }
  114. return NewDeviceName;
  115. }
  116. void
  117. FreeTapiLines(
  118. void
  119. )
  120. {
  121. PLIST_ENTRY pNext;
  122. PLINE_INFO pLineInfo;
  123. pNext = g_TapiLinesListHead.Flink;
  124. while ((ULONG_PTR)pNext != (ULONG_PTR)&g_TapiLinesListHead)
  125. {
  126. pLineInfo = CONTAINING_RECORD( pNext, LINE_INFO, ListEntry );
  127. pNext = pLineInfo->ListEntry.Flink;
  128. RemoveEntryList(&pLineInfo->ListEntry);
  129. FreeTapiLine(pLineInfo);
  130. }
  131. pNext = g_RemovedTapiLinesListHead.Flink;
  132. while ((ULONG_PTR)pNext != (ULONG_PTR)&g_RemovedTapiLinesListHead)
  133. {
  134. pLineInfo = CONTAINING_RECORD( pNext, LINE_INFO, ListEntry );
  135. pNext = pLineInfo->ListEntry.Flink;
  136. RemoveEntryList(&pLineInfo->ListEntry);
  137. FreeTapiLine(pLineInfo);
  138. }
  139. }
  140. VOID
  141. FreeTapiLine(
  142. PLINE_INFO LineInfo
  143. )
  144. {
  145. HLINE hLine = NULL;
  146. if (!LineInfo)
  147. {
  148. return;
  149. }
  150. if (LineInfo->hLine)
  151. {
  152. hLine = LineInfo->hLine;
  153. LineInfo->hLine = NULL;
  154. }
  155. MemFree( LineInfo->DeviceName );
  156. MemFree( LineInfo->Tsid );
  157. MemFree( LineInfo->Csid );
  158. MemFree( LineInfo->lptstrDescription );
  159. MemFree( LineInfo );
  160. if (hLine)
  161. {
  162. lineClose( hLine );
  163. }
  164. }
  165. int
  166. __cdecl
  167. DevicePriorityCompare(
  168. const void *arg1,
  169. const void *arg2
  170. )
  171. {
  172. if (((PDEVICE_SORT)arg1)->Priority < ((PDEVICE_SORT)arg2)->Priority) {
  173. return -1;
  174. }
  175. if (((PDEVICE_SORT)arg1)->Priority > ((PDEVICE_SORT)arg2)->Priority) {
  176. return 1;
  177. }
  178. return 0;
  179. }
  180. DWORD GetFaxDeviceCount(
  181. VOID
  182. )
  183. /*++
  184. Routine Description:
  185. counts the number of installed fax devices
  186. Arguments:
  187. NONE.
  188. Return Value:
  189. number of devices
  190. --*/
  191. {
  192. DWORD FaxDevices = 0;
  193. PLIST_ENTRY Next;
  194. PLINE_INFO LineInfo;
  195. EnterCriticalSection(&g_CsLine);
  196. Next = g_TapiLinesListHead.Flink;
  197. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  198. {
  199. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  200. Next = LineInfo->ListEntry.Flink;
  201. if (LineInfo->PermanentLineID && LineInfo->DeviceName)
  202. {
  203. FaxDevices += 1;
  204. }
  205. }
  206. LeaveCriticalSection(&g_CsLine);
  207. return FaxDevices;
  208. }
  209. BOOL GetDeviceTypeCount(
  210. LPDWORD SendDevices,
  211. LPDWORD ReceiveDevices
  212. )
  213. /*++
  214. Routine Description:
  215. counts the number of devices with receive enabled, number with send enabled
  216. Arguments:
  217. SendDevices - receives number of send devices
  218. ReceiveDevices - receives number of receive devices
  219. Return Value:
  220. number of devices
  221. --*/
  222. {
  223. DWORD Rx = 0, Tx = 0;
  224. PLIST_ENTRY Next;
  225. PLINE_INFO LineInfo;
  226. EnterCriticalSection(&g_CsLine);
  227. Next = g_TapiLinesListHead.Flink;
  228. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  229. {
  230. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  231. Next = LineInfo->ListEntry.Flink;
  232. if (LineInfo->PermanentLineID && LineInfo->DeviceName)
  233. {
  234. if ((LineInfo->Flags & FPF_SEND) == FPF_SEND)
  235. {
  236. Tx++;
  237. }
  238. if ((LineInfo->Flags & FPF_RECEIVE) == FPF_RECEIVE)
  239. {
  240. Rx++;
  241. }
  242. }
  243. }
  244. LeaveCriticalSection(&g_CsLine);
  245. if (SendDevices)
  246. {
  247. *SendDevices = Tx;
  248. }
  249. if (ReceiveDevices)
  250. {
  251. *ReceiveDevices = Rx;
  252. }
  253. return TRUE;
  254. }
  255. BOOL
  256. CommitDeviceChanges(
  257. PLINE_INFO LineInfo
  258. )
  259. /*++
  260. Routine Description:
  261. commit device changes to registry.
  262. Arguments:
  263. LineInfo - Pointer to the LINE_INFO describing the device to be commited.
  264. Return Value:
  265. TRUE for success.
  266. --*/
  267. {
  268. EnterCriticalSection(&g_CsLine);
  269. RegAddNewFaxDevice(
  270. &g_dwLastUniqueLineId,
  271. &LineInfo->PermanentLineID, // Do not create new device. Update it.
  272. LineInfo->DeviceName,
  273. LineInfo->Provider->ProviderName,
  274. LineInfo->Provider->szGUID,
  275. LineInfo->Csid,
  276. LineInfo->Tsid,
  277. LineInfo->TapiPermanentLineId,
  278. LineInfo->Flags & 0x0fffffff,
  279. LineInfo->RingsForAnswer);
  280. LeaveCriticalSection(&g_CsLine);
  281. return TRUE;
  282. }
  283. BOOL
  284. SendIncomingCallEvent(
  285. PLINE_INFO LineInfo,
  286. LPLINEMESSAGE LineMsg,
  287. HCALL hCall
  288. )
  289. /*++
  290. Routine Description:
  291. This function posts FAX_EVENT_EX of
  292. FAX_EVENT_INCOMING_CALL type.
  293. Arguments:
  294. LineInfo - pointer to LINE_INFO structure
  295. LineMsg - pointer to LINEMESSAGE structure
  296. hCall - call handle to set into message
  297. Return Values:
  298. TRUE for success
  299. FALSE for failure
  300. --*/
  301. {
  302. BOOL success = FALSE;
  303. DWORD dwEventSize;
  304. DWORD dwResult;
  305. PFAX_EVENT_EX pEvent = NULL;
  306. TCHAR CallerID[512];
  307. DEBUG_FUNCTION_NAME(TEXT("SendIncomingCallEvent"));
  308. //
  309. // save the line msg so we could verify hCall later
  310. //
  311. CopyMemory( &LineInfo->LineMsgOffering, LineMsg, sizeof(LINEMESSAGE) );
  312. //
  313. // allocate event structure, including caller ID info, if any
  314. //
  315. dwEventSize = sizeof(FAX_EVENT_EX);
  316. CallerID[0] = TEXT('\0');
  317. if(GetCallerIDFromCall(LineMsg->hDevice, CallerID, ARR_SIZE(CallerID)))
  318. {
  319. dwEventSize += (lstrlen(CallerID) + 1) * sizeof(TCHAR);
  320. }
  321. pEvent = (PFAX_EVENT_EX)MemAlloc(dwEventSize);
  322. if(!pEvent)
  323. {
  324. DebugPrintEx(
  325. DEBUG_ERR,
  326. TEXT("Failed to notify clients of incoming call. Error allocating FAX_EVENT_EX"));
  327. goto Cleanup;
  328. }
  329. //
  330. // fill in event structure
  331. //
  332. ZeroMemory(pEvent, dwEventSize);
  333. pEvent->dwSizeOfStruct = sizeof(FAX_EVENT_EX);
  334. GetSystemTimeAsFileTime( &(pEvent->TimeStamp) );
  335. pEvent->EventType = FAX_EVENT_TYPE_NEW_CALL;
  336. pEvent->EventInfo.NewCall.hCall = hCall;
  337. pEvent->EventInfo.NewCall.dwDeviceId = LineInfo->PermanentLineID;
  338. //
  339. // copy caller ID info, if available
  340. //
  341. if(CallerID[0] != TEXT('\0'))
  342. {
  343. pEvent->EventInfo.NewCall.lptstrCallerId = (LPTSTR) sizeof(FAX_EVENT_EX);
  344. lstrcpy((LPTSTR)((BYTE *)pEvent + sizeof(FAX_EVENT_EX)), CallerID);
  345. }
  346. //
  347. // post extended event to any clients
  348. //
  349. dwResult = PostFaxEventEx(pEvent, dwEventSize, NULL);
  350. if(dwResult != ERROR_SUCCESS)
  351. {
  352. DebugPrintEx(
  353. DEBUG_ERR,
  354. TEXT("Failed to notify clients of incoming call. PostFaxEventEx() returned %x"),
  355. dwResult);
  356. goto Cleanup;
  357. }
  358. success = TRUE;
  359. Cleanup:
  360. if (NULL != pEvent)
  361. {
  362. MemFree(pEvent);
  363. }
  364. return success;
  365. }
  366. ULONG
  367. TapiWorkerThread(
  368. LPVOID UnUsed
  369. )
  370. /*++
  371. Routine Description:
  372. This is worker thread for the FAX service. All queued
  373. requests are processed here.
  374. Arguments:
  375. None.
  376. Return Value:
  377. Thread return value.
  378. --*/
  379. {
  380. PLINE_INFO LineInfo;
  381. BOOL Rval;
  382. DWORD Bytes;
  383. ULONG_PTR CompletionKey;
  384. LPLINEMESSAGE LineMsg = NULL;
  385. DWORD dwQueueState;
  386. BOOL fWakeupJobQueueThread;
  387. static BOOL fServiceIsDownSemaphoreWasReleased = FALSE;
  388. DEBUG_FUNCTION_NAME(TEXT("TapiWorkerThread"));
  389. while( TRUE )
  390. {
  391. fWakeupJobQueueThread = FALSE; // We want to wake up the JobQueueThread if a new devce was added.
  392. if (LineMsg)
  393. {
  394. LocalFree( LineMsg );
  395. }
  396. Rval = GetQueuedCompletionStatus(
  397. g_TapiCompletionPort,
  398. &Bytes,
  399. &CompletionKey,
  400. (LPOVERLAPPED*) &LineMsg,
  401. INFINITE
  402. );
  403. if (!Rval)
  404. {
  405. Rval = GetLastError();
  406. LineMsg = NULL;
  407. DebugPrintEx(DEBUG_ERR, TEXT("GetQueuedCompletionStatus() failed, ec=0x%08x"), Rval);
  408. continue;
  409. }
  410. if (SERVICE_SHUT_DOWN_KEY == CompletionKey)
  411. {
  412. //
  413. // Service is shutting down
  414. //
  415. DebugPrintEx(
  416. DEBUG_MSG,
  417. TEXT("Service is shutting down"));
  418. break;
  419. }
  420. if(CompletionKey == ANSWERNOW_EVENT_KEY)
  421. {
  422. //
  423. // this is an event posted by FAX_AnswerCall
  424. //
  425. // the LINEMESSAGE structure must be filled out
  426. // as follows:
  427. //
  428. // LineMsg->hDevice == 0
  429. // LineMsg->dwMessageID == 0
  430. // LineMsg->dwCallbackInstance == 0
  431. // LineMsg->dwParam1 == Permanent device Id
  432. // LineMsg->dwParam2 == 0
  433. // LineMsg->dwParam3 == 0
  434. //
  435. PJOB_ENTRY pJobEntry;
  436. TCHAR FileName[MAX_PATH];
  437. DWORD dwOldFlags;
  438. EnterCriticalSection( &g_CsJob );
  439. EnterCriticalSection( &g_CsLine );
  440. if (TRUE == g_bServiceIsDown)
  441. {
  442. //
  443. // Notify EndFaxSvc that we read the shutdown flag
  444. //
  445. if (FALSE == fServiceIsDownSemaphoreWasReleased)
  446. {
  447. if (!ReleaseSemaphore(
  448. g_hServiceIsDownSemaphore, // handle to semaphore
  449. 1, // count increment amount
  450. NULL // previous count
  451. ))
  452. {
  453. DebugPrintEx(
  454. DEBUG_ERR,
  455. TEXT("ReleaseSemaphore() failed, (ec = %ld)"),
  456. GetLastError());
  457. }
  458. else
  459. {
  460. fServiceIsDownSemaphoreWasReleased = TRUE;
  461. }
  462. }
  463. //
  464. // don't process event - from now on TapiWorkerThread is in-active
  465. // and only sends notifications to FSP
  466. //
  467. goto next_event;
  468. }
  469. //
  470. // Get LineInfo from permanent device ID
  471. //
  472. LineInfo = GetTapiLineFromDeviceId( (DWORD) LineMsg->dwParam1, FALSE );
  473. if(!LineInfo)
  474. {
  475. DebugPrintEx(DEBUG_ERR,
  476. TEXT("Line %ld not found"),
  477. LineMsg->dwParam1);
  478. goto next_event;
  479. }
  480. //
  481. // See if the device is still available
  482. //
  483. if(LineInfo->State != FPS_AVAILABLE || LineInfo->JobEntry)
  484. {
  485. DebugPrintEx(DEBUG_ERR,
  486. TEXT("Line is not available (LineState is 0x%08x) or JobEntry is not NULL."),
  487. LineInfo->State);
  488. goto next_event;
  489. }
  490. if (!LineInfo->LineMsgOffering.hDevice)
  491. {
  492. //
  493. // There's no offering call - this is the 'answer-now' mode.
  494. //
  495. // If the line is ringing at the same time (has a new call), we must close the line (to make
  496. // all active calls go away) and re-open it.
  497. //
  498. // From MSDN: "If an application calls lineClose while it still has active calls on the opened line,
  499. // the application's ownership of these calls is revoked.
  500. // If the application was the sole owner of these calls, the calls are dropped as well."
  501. //
  502. // Otherwise, when we call the FSP's FaxDevReceive() function with hCall=0,
  503. // it calls lineMakeCall (..., PASSTHROUGH) which always succeeds but doesn't get LINECALLSTATE_OFFERING
  504. // until the other offering call is over.
  505. //
  506. if (LineInfo->hLine)
  507. {
  508. LONG lRes = lineClose(LineInfo->hLine);
  509. if (ERROR_SUCCESS != lRes)
  510. {
  511. DebugPrintEx(DEBUG_ERR,
  512. TEXT("lineClose failed with 0x%08x"),
  513. lRes);
  514. }
  515. LineInfo->hLine = 0;
  516. }
  517. }
  518. if (LineInfo->hLine == NULL)
  519. {
  520. //
  521. // Line is closed - open it now
  522. // This can be because:
  523. // 1. This is the 'answer now' mode but the line was never send or receive enabled.
  524. // 2. This is the 'answer now' mode the line was open and there was no call offered, we closed the line (above).
  525. //
  526. if (!OpenTapiLine(LineInfo))
  527. {
  528. DWORD dwRes = GetLastError();
  529. DebugPrintEx(
  530. DEBUG_ERR,
  531. TEXT("OpenTapiLine failed. (ec: %ld)"),
  532. dwRes);
  533. goto next_event;
  534. }
  535. }
  536. Assert (LineInfo->hLine);
  537. //
  538. // start a receive fax job
  539. //
  540. // If we don't fake FPF_RECEIVE, GetTapiLineForFaxOperation() will fail StartReceiveJob() if the device is not
  541. // set to receive (manually or automatically)
  542. //
  543. dwOldFlags = LineInfo->Flags;
  544. LineInfo->Flags |= FPF_RECEIVE;
  545. pJobEntry = StartReceiveJob(LineInfo->PermanentLineID);
  546. //
  547. // Restore original device flags.
  548. //
  549. LineInfo->Flags = dwOldFlags;
  550. if (pJobEntry)
  551. {
  552. if(ERROR_SUCCESS != StartFaxReceive(
  553. pJobEntry,
  554. (HCALL)LineInfo->LineMsgOffering.hDevice, // This is either 0 (answer now) or the active hCall (manual-answer)
  555. LineInfo,
  556. FileName,
  557. sizeof(FileName)/sizeof(FileName[0])
  558. ))
  559. {
  560. DebugPrintEx(
  561. DEBUG_ERR,
  562. TEXT("StartFaxReceive failed. Line: %010d (%s) (ec: %ld)"),
  563. LineInfo->DeviceId,
  564. LineInfo->DeviceName,
  565. GetLastError());
  566. //
  567. // NTRAID#EdgeBugs-12677-2001/05/14-t-nicali: Should place an EVENTLOG entry here
  568. //
  569. }
  570. }
  571. else
  572. {
  573. DebugPrintEx(DEBUG_ERR, TEXT("StartJob() failed, cannot receive incoming fax"));
  574. }
  575. goto next_event;
  576. }
  577. if ((CompletionKey == FAXDEV_EVENT_KEY) ||
  578. (CompletionKey == EFAXDEV_EVENT_KEY))
  579. {
  580. //
  581. // this is an event from a fax service provider
  582. // that has enumerated virtual device(s)
  583. //
  584. // the LINEMESSAGE structure must be filled out
  585. // as follows:
  586. //
  587. // LineMsg->hDevice == DeviceId from FaxDevStartJob()
  588. // LineMsg->dwMessageID == 0
  589. // LineMsg->dwCallbackInstance == 0
  590. // LineMsg->dwParam1 == LINEDEVSTATE_RINGING
  591. // LineMsg->dwParam2 == 0
  592. // LineMsg->dwParam3 == 0
  593. //
  594. EnterCriticalSection( &g_CsJob );
  595. EnterCriticalSection( &g_CsLine );
  596. if (TRUE == g_bServiceIsDown)
  597. {
  598. //
  599. // Notify EndFaxSvc that we read the shutdown flag
  600. //
  601. if (FALSE == fServiceIsDownSemaphoreWasReleased)
  602. {
  603. if (!ReleaseSemaphore(
  604. g_hServiceIsDownSemaphore, // handle to semaphore
  605. 1, // count increment amount
  606. NULL // previous count
  607. ))
  608. {
  609. DebugPrintEx(
  610. DEBUG_ERR,
  611. TEXT("ReleaseSemaphore() failed, (ec = %ld)"),
  612. GetLastError());
  613. }
  614. else
  615. {
  616. fServiceIsDownSemaphoreWasReleased = TRUE;
  617. }
  618. }
  619. //
  620. // don't process event - from now on TapiWorkerThread is in-active
  621. // and only sends notifications to FSP
  622. //
  623. goto next_event;
  624. }
  625. LineInfo = GetTapiLineFromDeviceId( (DWORD) LineMsg->hDevice,
  626. CompletionKey == FAXDEV_EVENT_KEY);
  627. if (!LineInfo) {
  628. goto next_event;
  629. }
  630. if (LineMsg->dwParam1 == LINEDEVSTATE_RINGING)
  631. {
  632. DWORD dwRes;
  633. LineInfo->RingCount += 1;
  634. if( !CreateFaxEvent( LineInfo->PermanentLineID, FEI_RINGING, 0xffffffff ) )
  635. {
  636. DebugPrintEx(
  637. DEBUG_ERR,
  638. TEXT("CreateFaxEvent failed. (ec: %ld)"),
  639. GetLastError());
  640. }
  641. dwRes = CreateDeviceEvent (LineInfo, TRUE);
  642. if (ERROR_SUCCESS != dwRes)
  643. {
  644. DebugPrintEx(
  645. DEBUG_ERR,
  646. TEXT("CreateDeviceEvent() (ec: %lc)"),
  647. dwRes);
  648. }
  649. EnterCriticalSection (&g_CsConfig);
  650. dwQueueState = g_dwQueueState;
  651. LeaveCriticalSection (&g_CsConfig);
  652. if ((LineInfo->State == FPS_AVAILABLE) && // Device is available and
  653. !LineInfo->JobEntry && // no job on this device yet and
  654. !(dwQueueState & FAX_INCOMING_BLOCKED) && // The incoming queue is not blocked and
  655. (LineInfo->Flags & FPF_RECEIVE)) // Device is set to auto-receive
  656. {
  657. PJOB_ENTRY JobEntry;
  658. TCHAR FileName[MAX_PATH];
  659. //
  660. // start a fax job
  661. //
  662. JobEntry = StartReceiveJob( LineInfo->PermanentLineID);
  663. if (JobEntry)
  664. {
  665. //
  666. // receive the fax
  667. //
  668. if (ERROR_SUCCESS != StartFaxReceive(
  669. JobEntry,
  670. 0,
  671. LineInfo,
  672. FileName,
  673. sizeof(FileName)/sizeof(FileName[0])
  674. ))
  675. {
  676. DebugPrintEx(
  677. DEBUG_ERR,
  678. TEXT("StartFaxReceive failed. Line: 0x%08X (%s) (ec: %ld)"),
  679. LineInfo->DeviceId,
  680. LineInfo->DeviceName,
  681. GetLastError());
  682. }
  683. }
  684. else
  685. {
  686. DebugPrintEx(DEBUG_ERR, TEXT("StartJob() failed, cannot receive incoming fax"));
  687. }
  688. }
  689. }
  690. goto next_event;
  691. }
  692. LineInfo = (PLINE_INFO) LineMsg->dwCallbackInstance;
  693. #if DBG
  694. ShowLineEvent(
  695. (HLINE) LineMsg->hDevice,
  696. (HCALL) LineMsg->hDevice,
  697. LineInfo == NULL ? TEXT("*NULL LineInfo*") : (LineInfo->JobEntry == NULL) ? TEXT("*NULL Job*") : NULL,
  698. LineMsg->dwCallbackInstance,
  699. LineMsg->dwMessageID,
  700. LineMsg->dwParam1,
  701. LineMsg->dwParam2,
  702. LineMsg->dwParam3
  703. );
  704. #endif // #if DBG
  705. EnterCriticalSection( &g_CsJob );
  706. EnterCriticalSection( &g_CsLine );
  707. if (TRUE == g_bServiceIsDown)
  708. {
  709. //
  710. // Notify EndFaxSvc that we read the shutdown flag
  711. //
  712. if (FALSE == fServiceIsDownSemaphoreWasReleased)
  713. {
  714. if (!ReleaseSemaphore(
  715. g_hServiceIsDownSemaphore, // handle to semaphore
  716. 1, // count increment amount
  717. NULL // previous count
  718. ))
  719. {
  720. DebugPrintEx(
  721. DEBUG_ERR,
  722. TEXT("ReleaseSemaphore() failed, (ec = %ld)"),
  723. GetLastError());
  724. }
  725. else
  726. {
  727. fServiceIsDownSemaphoreWasReleased = TRUE;
  728. }
  729. }
  730. //
  731. // don't process event - from now on TapiWorkerThread is in-active
  732. // and only sends notifications to FSP
  733. //
  734. goto FSP_call_Back;
  735. }
  736. switch( LineMsg->dwMessageID )
  737. {
  738. case LINE_ADDRESSSTATE:
  739. break;
  740. case LINE_CALLINFO:
  741. //
  742. // generating FAX_EVENT_EX of type FAX_EVENT_TYPE_NEW_CALL when
  743. // caller ID info becomes available
  744. //
  745. if((LineMsg->dwParam1 == LINECALLINFOSTATE_CALLERID) &&
  746. (LineInfo->PermanentLineID == g_dwManualAnswerDeviceId)
  747. )
  748. {
  749. //
  750. // Only send ringing event about the device set to manual answering
  751. //
  752. SendIncomingCallEvent(LineInfo, LineMsg, (HCALL)LineMsg->hDevice);
  753. }
  754. break;
  755. case LINE_CALLSTATE:
  756. if (LineMsg->dwParam1 == LINECALLSTATE_IDLE)
  757. {
  758. //
  759. // This is the last event on the call. make sure the line is deallocated.
  760. //
  761. if (NULL == LineInfo->JobEntry ||
  762. (LineInfo->JobEntry && NULL == LineInfo->JobEntry->CallHandle))
  763. {
  764. //
  765. // We do not have the hCall in the JobEntry, release the call to prevent leaks
  766. //
  767. DebugPrintEx(DEBUG_WRN, TEXT("We have LINE_CALLSTATE (IDLE) msg, doing 'ReleaseTapiLine'\r\n"));
  768. ReleaseTapiLine( LineInfo, (HCALL) LineMsg->hDevice );
  769. }
  770. LineInfo->NewCall = FALSE;
  771. if ( !CreateFaxEvent( LineInfo->PermanentLineID, FEI_IDLE, 0xffffffff ) )
  772. {
  773. DebugPrintEx(
  774. DEBUG_ERR,
  775. TEXT("CreateFaxEvent failed. (ec: %ld)"),
  776. GetLastError());
  777. }
  778. DWORD dwRes = CreateDeviceEvent (LineInfo, FALSE);
  779. if (ERROR_SUCCESS != dwRes)
  780. {
  781. DebugPrintEx(
  782. DEBUG_ERR,
  783. TEXT("CreateDeviceEvent() (ec: %lc)"),
  784. dwRes);
  785. }
  786. }
  787. else
  788. {
  789. //
  790. // Update the hCall in the JobEntry, so that EndJob()/ReleaseJob()will finally call lineDeallocateCall() to free the hCall.
  791. //
  792. if (NULL != LineInfo->JobEntry)
  793. {
  794. if (NULL == LineInfo->JobEntry->CallHandle)
  795. {
  796. //
  797. // FSP did not report the hCall yet.
  798. //
  799. LineInfo->JobEntry->CallHandle = (HCALL) LineMsg->hDevice;
  800. }
  801. if (LineInfo->JobEntry->CallHandle != (HCALL) LineMsg->hDevice)
  802. {
  803. //
  804. // we have a mismatch between the reported hCall from the FSP or previuos TAPI event and the hCall reproted by TAPI.
  805. //
  806. DebugPrintEx(
  807. DEBUG_WRN,
  808. TEXT("Mismatch between the reported hCall from the FSP or previuos TAPI event and the hCall reproted by TAPI"));
  809. }
  810. }
  811. }
  812. if (LineInfo->NewCall && LineMsg->dwParam1 != LINECALLSTATE_OFFERING && LineInfo->State == FPS_AVAILABLE)
  813. {
  814. LineInfo->State = FPS_NOT_FAX_CALL;
  815. LineInfo->NewCall = FALSE;
  816. }
  817. //
  818. // generating FAX_EVENT_EX of type FAX_EVENT_NEW_INCOMING_CALL when
  819. // line call state changes
  820. //
  821. if (LineInfo->PermanentLineID == g_dwManualAnswerDeviceId)
  822. {
  823. //
  824. // Only send ringing event about the device set to manual answering
  825. //
  826. // When a call is offered to us, we send the event with hCall
  827. // and any caller ID info we might have
  828. //
  829. if(LineMsg->dwParam1 == LINECALLSTATE_OFFERING)
  830. {
  831. SendIncomingCallEvent(LineInfo, LineMsg, (HCALL)LineMsg->hDevice);
  832. }
  833. //
  834. // when the caller hangs up, we send the event without hCall
  835. //
  836. if(LineMsg->dwParam1 == LINECALLSTATE_IDLE)
  837. {
  838. SendIncomingCallEvent(LineInfo, LineMsg, NULL);
  839. }
  840. }
  841. if (LineMsg->dwParam1 == LINECALLSTATE_OFFERING)
  842. {
  843. //
  844. // we'll get a LINE_LINEDEVSTATE (RINGING) event, so we'll post the ring event there or we'll get a duplicate event
  845. //
  846. LineInfo->NewCall = FALSE;
  847. if ((LineInfo->State == FPS_AVAILABLE) && // Line is available and
  848. (LineInfo->Flags & FPF_RECEIVE)) // Line is set to receive
  849. {
  850. EnterCriticalSection (&g_CsConfig);
  851. dwQueueState = g_dwQueueState;
  852. LeaveCriticalSection (&g_CsConfig);
  853. if ((LineInfo->RingCount > LineInfo->RingsForAnswer) && // Rings exceeded threshold and
  854. !LineInfo->JobEntry && // no job on this device yet and
  855. !(dwQueueState & FAX_INCOMING_BLOCKED) // Incoming queue is not blocked
  856. )
  857. {
  858. PJOB_ENTRY JobEntry;
  859. TCHAR FileName[MAX_PATH];
  860. //
  861. // start a fax job
  862. //
  863. JobEntry = StartReceiveJob( LineInfo->PermanentLineID);
  864. if (JobEntry)
  865. {
  866. //
  867. // receive the fax
  868. //
  869. if (ERROR_SUCCESS != StartFaxReceive(
  870. JobEntry,
  871. (HCALL) LineMsg->hDevice,
  872. LineInfo,
  873. FileName,
  874. sizeof(FileName)/sizeof(FileName[0])
  875. ))
  876. {
  877. DebugPrintEx(
  878. DEBUG_ERR,
  879. TEXT("StartFaxReceive failed. Line: 0x%08X (%s) (ec: %ld)"),
  880. LineInfo->DeviceId,
  881. LineInfo->DeviceName,
  882. GetLastError());
  883. }
  884. }
  885. else
  886. {
  887. DebugPrintEx(DEBUG_ERR, TEXT("StartJob() failed, cannot receive incoming fax"));
  888. }
  889. }
  890. else
  891. {
  892. //
  893. // save the line msg
  894. //
  895. CopyMemory( &LineInfo->LineMsgOffering, LineMsg, sizeof(LINEMESSAGE) );
  896. }
  897. }
  898. else
  899. {
  900. //
  901. // we are not supposed to answer the call, so give it to ras
  902. //
  903. HandoffCallToRas( LineInfo, (HCALL) LineMsg->hDevice );
  904. }
  905. }
  906. break;
  907. case LINE_CLOSE:
  908. {
  909. //
  910. // this usually happens when something bad happens to the modem device.
  911. //
  912. DebugPrintEx( DEBUG_MSG,
  913. (TEXT("Received LINE_CLOSE message for device %x [%s]."),
  914. LineInfo->DeviceId,
  915. LineInfo->DeviceName) );
  916. LineInfo->hLine = NULL;
  917. LineInfo->State = FPS_AVAILABLE;
  918. GetSystemTimeAsFileTime ((FILETIME*)&LineInfo->LastLineClose);
  919. if ((LineInfo->Flags & FPF_RECEIVE) || // Line is in auto-anser or
  920. (g_dwManualAnswerDeviceId == LineInfo->PermanentLineID)) // manual-answer mode
  921. {
  922. //
  923. // Try to reopen the line
  924. //
  925. if (!OpenTapiLine(LineInfo))
  926. {
  927. DebugPrintEx( DEBUG_ERR,
  928. TEXT("OpenTapiLine failed for device %s"),
  929. LineInfo->DeviceName);
  930. }
  931. }
  932. else
  933. {
  934. LineInfo->Flags |= FPF_POWERED_OFF;
  935. }
  936. }
  937. break;
  938. case LINE_DEVSPECIFIC:
  939. break;
  940. case LINE_DEVSPECIFICFEATURE:
  941. break;
  942. case LINE_GATHERDIGITS:
  943. break;
  944. case LINE_GENERATE:
  945. break;
  946. case LINE_LINEDEVSTATE:
  947. if (LineMsg->dwParam1 == LINEDEVSTATE_RINGING)
  948. {
  949. DWORD dwRes;
  950. LineInfo->RingCount = (DWORD)LineMsg->dwParam3 + 1;
  951. if( !CreateFaxEvent( LineInfo->PermanentLineID, FEI_RINGING, 0xffffffff ) )
  952. {
  953. DebugPrintEx(
  954. DEBUG_ERR,
  955. TEXT("CreateFaxEvent failed. (ec: %ld)"),
  956. GetLastError());
  957. }
  958. dwRes = CreateDeviceEvent (LineInfo, TRUE);
  959. if (ERROR_SUCCESS != dwRes)
  960. {
  961. DebugPrintEx(
  962. DEBUG_ERR,
  963. TEXT("CreateDeviceEvent() (ec: %lc)"),
  964. dwRes);
  965. }
  966. //
  967. // Pick up the line only if the last inbound job has completed
  968. //
  969. if (LineInfo->State != FPS_AVAILABLE)
  970. {
  971. break;
  972. }
  973. EnterCriticalSection (&g_CsConfig);
  974. dwQueueState = g_dwQueueState;
  975. LeaveCriticalSection (&g_CsConfig);
  976. if (dwQueueState & FAX_INCOMING_BLOCKED)
  977. {
  978. //
  979. // Inbox is blocked - no incoming faxes will be received.
  980. //
  981. break;
  982. }
  983. if ((LineInfo->Flags & FPF_RECEIVE) && // Line is set to receive and
  984. (LineInfo->State == FPS_AVAILABLE)) // the line is available
  985. {
  986. if (LineInfo->LineMsgOffering.hDevice == 0)
  987. {
  988. //
  989. // wait for the offering message
  990. //
  991. break;
  992. }
  993. if ((LineInfo->RingCount > LineInfo->RingsForAnswer) && // Rings count match and
  994. !LineInfo->JobEntry // There's no job on the line
  995. )
  996. {
  997. PJOB_ENTRY JobEntry;
  998. TCHAR FileName[MAX_PATH];
  999. //
  1000. // Start a fax job
  1001. //
  1002. JobEntry = StartReceiveJob( LineInfo->PermanentLineID);
  1003. if (JobEntry)
  1004. {
  1005. //
  1006. // Receive the fax
  1007. //
  1008. if (ERROR_SUCCESS != StartFaxReceive(
  1009. JobEntry,
  1010. (HCALL) LineInfo->LineMsgOffering.hDevice,
  1011. LineInfo,
  1012. FileName,
  1013. sizeof(FileName)/sizeof(FileName[0])
  1014. ))
  1015. {
  1016. DebugPrintEx(
  1017. DEBUG_ERR,
  1018. TEXT("StartFaxReceive failed. Line: 0x%08X (%s) (ec: %ld)"),
  1019. LineInfo->DeviceId,
  1020. LineInfo->DeviceName,
  1021. GetLastError());
  1022. }
  1023. }
  1024. else
  1025. {
  1026. DebugPrintEx(DEBUG_ERR, TEXT("StartJob() failed, cannot receive incoming fax"));
  1027. }
  1028. }
  1029. }
  1030. else
  1031. {
  1032. //
  1033. // we are not supposed to answer the call, so give it to ras
  1034. //
  1035. HandoffCallToRas( LineInfo, (HCALL) LineInfo->LineMsgOffering.hDevice );
  1036. }
  1037. }
  1038. break;
  1039. case LINE_MONITORDIGITS:
  1040. break;
  1041. case LINE_MONITORMEDIA:
  1042. break;
  1043. case LINE_MONITORTONE:
  1044. break;
  1045. case LINE_REPLY:
  1046. break;
  1047. case LINE_REQUEST:
  1048. break;
  1049. case PHONE_BUTTON:
  1050. break;
  1051. case PHONE_CLOSE:
  1052. break;
  1053. case PHONE_DEVSPECIFIC:
  1054. break;
  1055. case PHONE_REPLY:
  1056. break;
  1057. case PHONE_STATE:
  1058. break;
  1059. case LINE_CREATE:
  1060. {
  1061. LPLINEDEVCAPS LineDevCaps;
  1062. LINEEXTENSIONID lineExtensionID;
  1063. DWORD LocalTapiApiVersion;
  1064. DWORD Rslt;
  1065. DWORD DeviceId;
  1066. DeviceId = (DWORD)LineMsg->dwParam1;
  1067. Rslt = lineNegotiateAPIVersion(
  1068. g_hLineApp,
  1069. DeviceId,
  1070. MIN_TAPI_LINE_API_VER,
  1071. MAX_TAPI_LINE_API_VER,
  1072. &LocalTapiApiVersion,
  1073. &lineExtensionID
  1074. );
  1075. if (Rslt == 0)
  1076. {
  1077. LineDevCaps = SmartLineGetDevCaps(g_hLineApp, DeviceId , LocalTapiApiVersion);
  1078. if (LineDevCaps)
  1079. {
  1080. EnterCriticalSection(&g_CsLine);
  1081. EnterCriticalSection(&g_CsConfig);
  1082. if (!AddNewDevice( DeviceId, LineDevCaps, FALSE , NULL))
  1083. {
  1084. DebugPrintEx(
  1085. DEBUG_WRN,
  1086. TEXT("AddNewDevice() failed for Tapi Permanent device id: %ld (ec: %ld)"),
  1087. LineDevCaps->dwPermanentLineID,
  1088. GetLastError());
  1089. }
  1090. else
  1091. {
  1092. //
  1093. // A new device was succesfully added - wake up the JobQueueThread
  1094. //
  1095. fWakeupJobQueueThread = TRUE;
  1096. }
  1097. LeaveCriticalSection(&g_CsConfig);
  1098. LeaveCriticalSection(&g_CsLine);
  1099. MemFree( LineDevCaps );
  1100. UpdateReceiveEnabledDevicesCount ();
  1101. }
  1102. }
  1103. }
  1104. break;
  1105. case PHONE_CREATE:
  1106. break;
  1107. case LINE_AGENTSPECIFIC:
  1108. break;
  1109. case LINE_AGENTSTATUS:
  1110. break;
  1111. case LINE_APPNEWCALL:
  1112. LineInfo->NewCall = TRUE;
  1113. break;
  1114. case LINE_PROXYREQUEST:
  1115. break;
  1116. case LINE_REMOVE:
  1117. {
  1118. DWORD dwDeviceId = (DWORD)LineMsg->dwParam1;
  1119. EnterCriticalSection(&g_CsLine);
  1120. EnterCriticalSection (&g_CsConfig);
  1121. if (!RemoveTapiDevice(dwDeviceId))
  1122. {
  1123. DebugPrintEx( DEBUG_WRN,
  1124. TEXT("RemoveTapiDevice() failed for device id: %ld (ec: %ld)"),
  1125. dwDeviceId,
  1126. GetLastError());
  1127. }
  1128. LeaveCriticalSection(&g_CsConfig);
  1129. LeaveCriticalSection(&g_CsLine);
  1130. UpdateReceiveEnabledDevicesCount ();
  1131. }
  1132. break;
  1133. case PHONE_REMOVE:
  1134. break;
  1135. }
  1136. FSP_call_Back:
  1137. //
  1138. // call the device provider's line callback function
  1139. //
  1140. if (LineInfo && LineInfo->JobEntry)
  1141. {
  1142. Assert (LineInfo->Provider && LineInfo->Provider->FaxDevCallback);
  1143. __try
  1144. {
  1145. LineInfo->Provider->FaxDevCallback(
  1146. (HANDLE) LineInfo->JobEntry->InstanceData,
  1147. LineMsg->hDevice,
  1148. LineMsg->dwMessageID,
  1149. LineMsg->dwCallbackInstance,
  1150. LineMsg->dwParam1,
  1151. LineMsg->dwParam2,
  1152. LineMsg->dwParam3
  1153. );
  1154. }
  1155. __except (HandleFaxExtensionFault(EXCEPTION_SOURCE_FSP, LineInfo->Provider->FriendlyName, GetExceptionCode()))
  1156. {
  1157. ASSERT_FALSE;
  1158. }
  1159. }
  1160. next_event:
  1161. LeaveCriticalSection( &g_CsLine );
  1162. LeaveCriticalSection( &g_CsJob );
  1163. //
  1164. // Check if we should wake up the JobQueueThread (if a new device was added)
  1165. //
  1166. if (TRUE == fWakeupJobQueueThread)
  1167. {
  1168. if (!SetEvent( g_hJobQueueEvent ))
  1169. {
  1170. DebugPrintEx(
  1171. DEBUG_ERR,
  1172. TEXT("Failed to set g_hJobQueueEvent. (ec: %ld)"),
  1173. GetLastError());
  1174. EnterCriticalSection (&g_CsQueue);
  1175. g_ScanQueueAfterTimeout = TRUE;
  1176. LeaveCriticalSection (&g_CsQueue);
  1177. }
  1178. }
  1179. }
  1180. //
  1181. // Notify EndFaxSvc that we read the shutdown flag
  1182. //
  1183. if (FALSE == fServiceIsDownSemaphoreWasReleased)
  1184. {
  1185. if (!ReleaseSemaphore(
  1186. g_hServiceIsDownSemaphore, // handle to semaphore
  1187. 1, // count increment amount
  1188. NULL // previous count
  1189. ))
  1190. {
  1191. DebugPrintEx(
  1192. DEBUG_ERR,
  1193. TEXT("ReleaseSemaphore() failed, (ec = %ld)"),
  1194. GetLastError());
  1195. }
  1196. }
  1197. return 0;
  1198. }
  1199. BOOL
  1200. HandoffCallToRas(
  1201. PLINE_INFO LineInfo,
  1202. HCALL hCall
  1203. )
  1204. /*++
  1205. Routine Description:
  1206. This function will try to hand a call of to RAS.
  1207. We do this under 2 circumstances:
  1208. 1) we've answered an incoming call and
  1209. determined that the call is NOT a fax call
  1210. 2) the configuration for the line that is
  1211. ringing is not configured for receiving faxes
  1212. If the handoff fails and we have an open job for the
  1213. line, then we have to call the device provider so that
  1214. the line can be put on hook.
  1215. Arguments:
  1216. LineInfo - LineInfo structure for the line this call is on
  1217. hCall - TAPI call handle
  1218. Return Value:
  1219. TRUE for success
  1220. FALSE for failure
  1221. --*/
  1222. {
  1223. LONG Rval;
  1224. DEBUG_FUNCTION_NAME(TEXT("HandoffCallToRas"));
  1225. //
  1226. // need to hand the call off to RAS
  1227. //
  1228. Rval = lineHandoff(
  1229. hCall,
  1230. RAS_MODULE_NAME,
  1231. LINEMEDIAMODE_DATAMODEM
  1232. );
  1233. if (Rval != 0 && LineInfo && LineInfo->JobEntry)
  1234. {
  1235. DebugPrintEx(DEBUG_ERR, TEXT("lineHandoff() failed, ec=0x%08x"), Rval);
  1236. }
  1237. else
  1238. {
  1239. DebugPrintEx(DEBUG_MSG, TEXT("call handed off to RAS"));
  1240. }
  1241. return Rval == 0;
  1242. }
  1243. PLINE_INFO
  1244. GetTapiLineFromDeviceId(
  1245. DWORD DeviceId,
  1246. BOOL fLegacyId
  1247. )
  1248. {
  1249. PLIST_ENTRY Next;
  1250. PLINE_INFO LineInfo;
  1251. Next = g_TapiLinesListHead.Flink;
  1252. if (!Next) {
  1253. return NULL;
  1254. }
  1255. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead) {
  1256. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  1257. Next = LineInfo->ListEntry.Flink;
  1258. if (fLegacyId)
  1259. {
  1260. if (LineInfo->TapiPermanentLineId == DeviceId) {
  1261. return LineInfo;
  1262. }
  1263. }
  1264. else
  1265. {
  1266. if (LineInfo->PermanentLineID == DeviceId) {
  1267. return LineInfo;
  1268. }
  1269. }
  1270. }
  1271. return NULL;
  1272. }
  1273. //*********************************************************************************
  1274. //* Name: GetLineForSendOperation()
  1275. //* Author: Ronen Barenboim
  1276. //* Date: June 03, 1999
  1277. //*********************************************************************************
  1278. //* DESCRIPTION:
  1279. //* Returns a line to be used for a send operation.
  1280. //*
  1281. //* PARAMETERS:
  1282. //* [IN ] PJOB_QUEUE lpJobQueue
  1283. //* The recipient job for which the line is intended.
  1284. //*
  1285. //* RETURN VALUE:
  1286. //* On success the function returns a pointer to the LINE_INFO structure of
  1287. //* the selected line.
  1288. //* On failure it returns NULL.
  1289. //*********************************************************************************
  1290. PLINE_INFO
  1291. GetLineForSendOperation(
  1292. PJOB_QUEUE lpJobQueue
  1293. )
  1294. {
  1295. DEBUG_FUNCTION_NAME(TEXT("GetLineForSendOperation"));
  1296. Assert(lpJobQueue);
  1297. return GetTapiLineForFaxOperation(
  1298. USE_SERVER_DEVICE,
  1299. JT_SEND,
  1300. lpJobQueue->RecipientProfile.lptstrFaxNumber
  1301. );
  1302. }
  1303. //*********************************************************************************
  1304. //* Name: GetTapiLineForFaxOperation()
  1305. //* Author: Ronen Barenboim
  1306. //* Date: June 03, 1999
  1307. //*********************************************************************************
  1308. //* DESCRIPTION:
  1309. //* Locates an avaliable TAPI device for use in a
  1310. //* FAX operation. The selection is based on the
  1311. //* available devices and their assigned priority.
  1312. //* If DeviceId is USE_SERVER_DEVICE the function will locate a device which
  1313. //* can be used for the job type specified. It does not revive devices in this
  1314. //* case.
  1315. //*
  1316. //* If DeviceId contains a specific device
  1317. //* If Handoff is TRUE and the job type is JT_SEND
  1318. //* The function will return the LINE_INFO for the specified line without
  1319. //* checking if it is availble or not or configured for send or receive.
  1320. //* Else
  1321. //* The function will check first if the specified device match the
  1322. //* requested job type and then return LINE_INFO.
  1323. //* If the device is powered off the function will attempt to revive it.
  1324. //*
  1325. //* PARAMETERS:
  1326. //* [IN ] DWORD DeviceId
  1327. //* The permanent device id (not tapi) of the line. If it is
  1328. //* USE_SERVER_DEVICE the function will select a line based on the
  1329. //* line send/receive capabilities, status and priorities.
  1330. //*
  1331. //* [IN ] DWORD JobType
  1332. //* The type of job that is about to be executed on the line.
  1333. //* can be JT_RECEIVE or JT_SEND.
  1334. //*
  1335. //* [IN ] LPWSTR FaxNumber
  1336. //* For a send operation this is the fax number that is going to be
  1337. //* used to send the fax. The function uses it to avoid sending
  1338. //* to faxes to the same number simultaneously.
  1339. //*
  1340. //* RETURN VALUE:
  1341. //* If the function succeeds it returns a pointer to the LINE_INFO
  1342. //* structure of the selected line. Otherwise it returns NULL.
  1343. //* If it is NULL the function failed. Call GetLastError() for more info.
  1344. //*********************************************************************************
  1345. PLINE_INFO
  1346. GetTapiLineForFaxOperation(
  1347. DWORD DeviceId,
  1348. DWORD JobType,
  1349. LPWSTR FaxNumber
  1350. )
  1351. {
  1352. PLIST_ENTRY Next;
  1353. PLINE_INFO LineInfo;
  1354. PLINE_INFO SelectedLine = NULL;
  1355. LPDWORD lpdwDevices = NULL;
  1356. DEBUG_FUNCTION_NAME(TEXT("GetTapiLineForFaxOperation"));
  1357. DWORD ec = ERROR_SUCCESS;
  1358. EnterCriticalSection( &g_CsLine );
  1359. if (FaxNumber)
  1360. {
  1361. if (FindJobEntryByRecipientNumber(FaxNumber))
  1362. {
  1363. //
  1364. // We do not allow to outgoing calls to the same number.
  1365. //
  1366. LeaveCriticalSection( &g_CsLine );
  1367. SetLastError (ERROR_NOT_FOUND);
  1368. return NULL;
  1369. }
  1370. }
  1371. //
  1372. // Find out if there is another send job to the same number.
  1373. // It there is do not select a line and return NULL.
  1374. //
  1375. if (DeviceId != USE_SERVER_DEVICE)
  1376. {
  1377. Assert (JobType == JT_RECEIVE);
  1378. Next = g_TapiLinesListHead.Flink;
  1379. Assert (Next);
  1380. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  1381. {
  1382. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  1383. Next = LineInfo->ListEntry.Flink;
  1384. //
  1385. // The caller specified a specific device to use. Just find it for him.
  1386. //
  1387. if (LineInfo->PermanentLineID == DeviceId)
  1388. {
  1389. //
  1390. // Found a device with a matching id.
  1391. //
  1392. if (NULL != LineInfo->JobEntry)
  1393. {
  1394. //
  1395. // Device is busy with another job
  1396. //
  1397. break;
  1398. }
  1399. if ((LineInfo->Flags & FPF_RECEIVE) || // Line is in auto-answer mode or
  1400. (g_dwManualAnswerDeviceId == LineInfo->PermanentLineID) // this is the manual-answer device
  1401. )
  1402. {
  1403. //
  1404. // For receive jobs we assume that the requested device is free since it is
  1405. // the FSP that tells us when to receive.
  1406. // we need to mark it as unavailable until the receive operation is completed.
  1407. //
  1408. LineInfo->State = 0; // remove the FPS_AVAILABLE bit
  1409. SelectedLine = LineInfo;
  1410. break;
  1411. }
  1412. if (LineInfo->UnimodemDevice && (LineInfo->Flags & FPF_POWERED_OFF))
  1413. {
  1414. //
  1415. // If the device is a unimodem device and indicated as powered off
  1416. // see if we can revive it by opening the line.
  1417. //
  1418. if (!OpenTapiLine( LineInfo ))
  1419. {
  1420. DebugPrintEx(DEBUG_ERR,
  1421. TEXT("OpenTapiLine failed for Device [%s] (ec: %ld)"),
  1422. LineInfo->DeviceName,
  1423. GetLastError());
  1424. LineInfo->State = 0; // remove the FPS_AVAILABLE bit'
  1425. SelectedLine = LineInfo;
  1426. }
  1427. }
  1428. break;
  1429. }
  1430. }
  1431. }
  1432. else
  1433. {
  1434. //
  1435. // The user wants us to find a free device for him. This is only valid for send operations
  1436. // which are not handoff.
  1437. //
  1438. Assert( JT_SEND == JobType );
  1439. DWORD dwNumDevices, dwCountryCode, dwAreaCode;
  1440. Assert (FaxNumber);
  1441. //
  1442. // Check DialAsEntered case
  1443. //
  1444. BOOL bCanonicalAddress = FALSE;
  1445. BOOL bDialAsEntered = FALSE;
  1446. ec = IsCanonicalAddress (FaxNumber, &bCanonicalAddress, &dwCountryCode, &dwAreaCode, NULL);
  1447. if (ERROR_SUCCESS != ec)
  1448. {
  1449. DebugPrintEx(DEBUG_ERR,
  1450. TEXT("IsCanoicalAddress failed with error %ld"),
  1451. ec);
  1452. goto exit;
  1453. }
  1454. if (TRUE == bCanonicalAddress)
  1455. {
  1456. LPLINECOUNTRYLIST lpCountryList = NULL;
  1457. //
  1458. // Get the cached all countries list.
  1459. //
  1460. if (!(lpCountryList = GetCountryList()))
  1461. {
  1462. DebugPrintEx(
  1463. DEBUG_ERR,
  1464. TEXT("Can not get all countries cached list"));
  1465. ec = ERROR_NOT_ENOUGH_MEMORY;
  1466. goto exit;
  1467. }
  1468. if (IsAreaCodeMandatory(lpCountryList, dwCountryCode) == TRUE &&
  1469. ROUTING_RULE_AREA_CODE_ANY == dwAreaCode)
  1470. {
  1471. //
  1472. // The area code is missing - dial as entered
  1473. //
  1474. DebugPrintEx(DEBUG_WRN,
  1475. TEXT("Area code is mandatory for Country code %ld, FaxNumber - %s. The number will be dialed as entered"),
  1476. dwCountryCode,
  1477. FaxNumber);
  1478. bDialAsEntered = TRUE;
  1479. }
  1480. }
  1481. else
  1482. {
  1483. //
  1484. // Not a canonical address - dial as entered
  1485. //
  1486. bDialAsEntered = TRUE;
  1487. }
  1488. if (FALSE == bDialAsEntered)
  1489. {
  1490. EnterCriticalSection( &g_CsConfig );
  1491. ec = GetDeviceListByCountryAndAreaCode( dwCountryCode,
  1492. dwAreaCode,
  1493. &lpdwDevices,
  1494. &dwNumDevices);
  1495. if (ERROR_SUCCESS != ec)
  1496. {
  1497. DebugPrintEx(DEBUG_ERR,
  1498. TEXT("GetDeviceListByCountryAndAreaCode failed with error %ld"),
  1499. ec);
  1500. LeaveCriticalSection( &g_CsConfig );
  1501. goto exit;
  1502. }
  1503. }
  1504. else
  1505. {
  1506. //
  1507. // Dial As Entered case
  1508. //
  1509. //
  1510. // Bring List of Devices from "All Devices" group
  1511. //
  1512. EnterCriticalSection( &g_CsConfig );
  1513. PCGROUP pCGroup;
  1514. pCGroup = g_pGroupsMap->FindGroup (ROUTING_GROUP_ALL_DEVICESW);
  1515. if (NULL == pCGroup)
  1516. {
  1517. ec = GetLastError();
  1518. DebugPrintEx(
  1519. DEBUG_ERR,
  1520. TEXT("g_pGroupsMap->FindGroup(ROUTING_GROUP_ALL_DEVICESW) failed (ec %ld)"), ec);
  1521. LeaveCriticalSection( &g_CsConfig );
  1522. goto exit;
  1523. }
  1524. ec = pCGroup->SerializeDevices (&lpdwDevices, &dwNumDevices);
  1525. if (ERROR_SUCCESS != ec)
  1526. {
  1527. DebugPrintEx(
  1528. DEBUG_ERR,
  1529. TEXT("pCGroup->SerializeDevices(&lpdwDevices, &dwNumDevices) failed (ec %ld)"), ec);
  1530. LeaveCriticalSection( &g_CsConfig );
  1531. goto exit;
  1532. }
  1533. }
  1534. LeaveCriticalSection( &g_CsConfig );
  1535. for (DWORD i = 0; i < dwNumDevices; i++)
  1536. {
  1537. Next = g_TapiLinesListHead.Flink;
  1538. Assert (Next);
  1539. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  1540. {
  1541. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  1542. Next = LineInfo->ListEntry.Flink;
  1543. if ( (LineInfo->Flags & FPF_SEND) &&
  1544. lpdwDevices[i] == LineInfo->PermanentLineID)
  1545. {
  1546. if ( (LineInfo->Flags & FPF_POWERED_OFF) ||
  1547. (LineInfo->Flags & FPF_RECEIVE)
  1548. )
  1549. {
  1550. //
  1551. // The device is marked as powered off. Check if we should try to send using this device
  1552. //
  1553. DWORDLONG dwlCurrentTime;
  1554. DWORDLONG dwlElapsedTime;
  1555. GetSystemTimeAsFileTime ((FILETIME*)&dwlCurrentTime);
  1556. Assert (dwlCurrentTime >= LineInfo->LastLineClose);
  1557. dwlElapsedTime = dwlCurrentTime - LineInfo->LastLineClose;
  1558. if (dwlElapsedTime < SecToNano(g_dwMaxLineCloseTime))
  1559. {
  1560. //
  1561. // Not enough time passes since the last LINE_CLOSE. skip this device
  1562. //
  1563. continue;
  1564. }
  1565. }
  1566. //
  1567. // The device is capable of sending and is not marked as FPF_POWERED_OFF.
  1568. //
  1569. //
  1570. // If it is a Tapi device, try to verify it s not busy
  1571. //
  1572. if (LineInfo->State == FPS_AVAILABLE &&
  1573. !(LineInfo->JobEntry) &&
  1574. !(LineInfo->Flags & FPF_VIRTUAL))
  1575. {
  1576. if (NULL == LineInfo->hLine)
  1577. {
  1578. if (!OpenTapiLine( LineInfo ))
  1579. {
  1580. DebugPrintEx(DEBUG_ERR,
  1581. TEXT("OpenTapiLine failed for Device [%s] (ec: %ld)"),
  1582. LineInfo->DeviceName,
  1583. GetLastError());
  1584. continue;
  1585. }
  1586. }
  1587. LPLINEDEVSTATUS pLineDevStatus = NULL;
  1588. BOOL fLineBusy = FALSE;
  1589. //
  1590. // check to see if the line is in use
  1591. //
  1592. pLineDevStatus = MyLineGetLineDevStatus( LineInfo->hLine );
  1593. if (NULL != pLineDevStatus)
  1594. {
  1595. if (pLineDevStatus->dwNumOpens > 0 && pLineDevStatus->dwNumActiveCalls > 0)
  1596. {
  1597. fLineBusy = TRUE;
  1598. }
  1599. MemFree( pLineDevStatus );
  1600. }
  1601. else
  1602. {
  1603. // Assume the line is busy
  1604. DebugPrintEx(DEBUG_ERR,
  1605. TEXT("MyLineGetLineDevStatus failed for Device [%s] (ec: %ld)"),
  1606. LineInfo->DeviceName,
  1607. GetLastError());
  1608. fLineBusy = TRUE;
  1609. }
  1610. ReleaseTapiLine( LineInfo, NULL );
  1611. if (TRUE == fLineBusy)
  1612. {
  1613. continue;
  1614. }
  1615. }
  1616. if ((LineInfo->State == FPS_AVAILABLE) && !(LineInfo->JobEntry))
  1617. {
  1618. //
  1619. // The line is free
  1620. //
  1621. LineInfo->State = 0;
  1622. SelectedLine = LineInfo;
  1623. }
  1624. break; // out of while
  1625. }
  1626. }
  1627. if (SelectedLine != NULL)
  1628. {
  1629. break; // out of for
  1630. }
  1631. }
  1632. }
  1633. if (SelectedLine)
  1634. {
  1635. DebugPrintEx(DEBUG_MSG,
  1636. TEXT("Line selected for FAX operation: %d, %d"),
  1637. SelectedLine->DeviceId,
  1638. SelectedLine->PermanentLineID
  1639. );
  1640. }
  1641. Assert (ERROR_SUCCESS == ec);
  1642. exit:
  1643. MemFree (lpdwDevices);
  1644. LeaveCriticalSection( &g_CsLine );
  1645. if (ERROR_SUCCESS == ec &&
  1646. NULL == SelectedLine)
  1647. {
  1648. ec = ERROR_NOT_FOUND;
  1649. }
  1650. SetLastError (ec);
  1651. return SelectedLine;
  1652. }
  1653. BOOL
  1654. ReleaseTapiLine(
  1655. PLINE_INFO LineInfo,
  1656. HCALL hCall
  1657. )
  1658. /*++
  1659. Routine Description:
  1660. Releases the specified TAPI line back into
  1661. the list as an available device.
  1662. Closes the line and deallocates the call. (line is not closed for a receive enabled
  1663. device.
  1664. Arguments:
  1665. LineInfo - Pointer to the TAPI line to be released
  1666. Return Value:
  1667. TRUE - The line is release.
  1668. FALSE - The line is not released.
  1669. --*/
  1670. {
  1671. LONG rVal;
  1672. HLINE hLine;
  1673. DEBUG_FUNCTION_NAME(TEXT("ReleaseTapiLine"));
  1674. Assert(LineInfo);
  1675. if (!LineInfo)
  1676. {
  1677. return FALSE;
  1678. }
  1679. EnterCriticalSection( &g_CsLine );
  1680. LineInfo->State = FPS_AVAILABLE;
  1681. LineInfo->RingCount = 0;
  1682. hLine = LineInfo->hLine;
  1683. ZeroMemory( &LineInfo->LineMsgOffering, sizeof(LINEMESSAGE) );
  1684. if (hCall)
  1685. {
  1686. rVal = lineDeallocateCall( hCall );
  1687. if (rVal != 0)
  1688. {
  1689. DebugPrintEx( DEBUG_ERR,
  1690. TEXT("lineDeallocateCall() failed, ec=0x%08X, hLine=0x%08X hCall=0x%08X"),
  1691. rVal,
  1692. hLine,
  1693. hCall);
  1694. }
  1695. else
  1696. {
  1697. if (LineInfo->JobEntry && LineInfo->JobEntry->CallHandle == hCall)
  1698. {
  1699. LineInfo->JobEntry->CallHandle = 0;
  1700. }
  1701. }
  1702. }
  1703. else
  1704. {
  1705. DebugPrintEx( DEBUG_WRN,
  1706. TEXT("ReleaseTapiLine(): cannot deallocate call, NULL call handle"));
  1707. }
  1708. //
  1709. // We actually close the line (by lineClose) only if the line is not
  1710. // intended for receiving.
  1711. //
  1712. if (!(LineInfo->Flags & FPF_RECEIVE) && // Line is not set to auto-receive and
  1713. LineInfo->hLine && // line is open and
  1714. LineInfo->PermanentLineID != g_dwManualAnswerDeviceId // this device is not set to manual answer mode
  1715. )
  1716. {
  1717. //
  1718. // Attempt to close the line
  1719. //
  1720. LONG lRes;
  1721. LineInfo->hLine = 0;
  1722. lRes=lineClose( hLine );
  1723. if (!lRes)
  1724. {
  1725. DebugPrintEx( DEBUG_MSG,
  1726. TEXT("hLine 0x%08X closed successfuly"),
  1727. hLine );
  1728. }
  1729. else
  1730. {
  1731. DebugPrintEx( DEBUG_ERR,
  1732. TEXT("Failed to close hLine 0x%08X (ec: 0x%08X)"),
  1733. hLine,
  1734. lRes);
  1735. }
  1736. }
  1737. LeaveCriticalSection( &g_CsLine );
  1738. return TRUE;
  1739. }
  1740. LPLINEDEVSTATUS
  1741. MyLineGetLineDevStatus(
  1742. HLINE hLine
  1743. )
  1744. {
  1745. DWORD LineDevStatusSize;
  1746. LPLINEDEVSTATUS LineDevStatus = NULL;
  1747. LONG Rslt = ERROR_SUCCESS;
  1748. DEBUG_FUNCTION_NAME(_T("lineGetLineDevStatus"));
  1749. //
  1750. // allocate the initial linedevstatus structure
  1751. //
  1752. LineDevStatusSize = sizeof(LINEDEVSTATUS) + 4096;
  1753. LineDevStatus = (LPLINEDEVSTATUS) MemAlloc( LineDevStatusSize );
  1754. if (!LineDevStatus)
  1755. {
  1756. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1757. return NULL;
  1758. }
  1759. LineDevStatus->dwTotalSize = LineDevStatusSize;
  1760. Rslt = lineGetLineDevStatus(
  1761. hLine,
  1762. LineDevStatus
  1763. );
  1764. if (Rslt != 0)
  1765. {
  1766. DebugPrintEx( DEBUG_ERR, TEXT("lineGetLineDevStatus() failed, ec=0x%08x"), Rslt );
  1767. goto exit;
  1768. }
  1769. if (LineDevStatus->dwNeededSize > LineDevStatus->dwTotalSize)
  1770. {
  1771. //
  1772. // re-allocate the LineDevStatus structure
  1773. //
  1774. LineDevStatusSize = LineDevStatus->dwNeededSize;
  1775. MemFree( LineDevStatus );
  1776. LineDevStatus = (LPLINEDEVSTATUS) MemAlloc( LineDevStatusSize );
  1777. if (!LineDevStatus)
  1778. {
  1779. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  1780. goto exit;
  1781. }
  1782. Rslt = lineGetLineDevStatus(
  1783. hLine,
  1784. LineDevStatus
  1785. );
  1786. if (Rslt != 0)
  1787. {
  1788. DebugPrintEx( DEBUG_ERR, TEXT("lineGetLineDevStatus() failed, ec=0x%08x"), Rslt );
  1789. goto exit;
  1790. }
  1791. }
  1792. exit:
  1793. if (Rslt != ERROR_SUCCESS)
  1794. {
  1795. MemFree( LineDevStatus );
  1796. LineDevStatus = NULL;
  1797. SetLastError(Rslt);
  1798. }
  1799. return LineDevStatus;
  1800. }
  1801. LONG
  1802. MyLineGetTransCaps(
  1803. LPLINETRANSLATECAPS *LineTransCaps
  1804. )
  1805. {
  1806. DWORD LineTransCapsSize;
  1807. LONG Rslt = ERROR_SUCCESS;
  1808. DEBUG_FUNCTION_NAME(_T("MyLineGetTransCaps"));
  1809. //
  1810. // allocate the initial linetranscaps structure
  1811. //
  1812. LineTransCapsSize = sizeof(LINETRANSLATECAPS) + 4096;
  1813. *LineTransCaps = (LPLINETRANSLATECAPS) MemAlloc( LineTransCapsSize );
  1814. if (!*LineTransCaps)
  1815. {
  1816. DebugPrintEx (DEBUG_ERR, TEXT("MemAlloc() failed, sz=0x%08x"), LineTransCapsSize);
  1817. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  1818. goto exit;
  1819. }
  1820. (*LineTransCaps)->dwTotalSize = LineTransCapsSize;
  1821. Rslt = lineGetTranslateCaps(
  1822. g_hLineApp,
  1823. MAX_TAPI_API_VER,
  1824. *LineTransCaps
  1825. );
  1826. if (Rslt != 0) {
  1827. DebugPrintEx(DEBUG_ERR, TEXT("lineGetTranslateCaps() failed, ec=0x%08x"), Rslt);
  1828. goto exit;
  1829. }
  1830. if ((*LineTransCaps)->dwNeededSize > (*LineTransCaps)->dwTotalSize) {
  1831. //
  1832. // re-allocate the LineTransCaps structure
  1833. //
  1834. LineTransCapsSize = (*LineTransCaps)->dwNeededSize;
  1835. MemFree( *LineTransCaps );
  1836. *LineTransCaps = (LPLINETRANSLATECAPS) MemAlloc( LineTransCapsSize );
  1837. if (!*LineTransCaps) {
  1838. DebugPrintEx(DEBUG_ERR, TEXT("MemAlloc() failed, sz=0x%08x"), LineTransCapsSize);
  1839. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  1840. goto exit;
  1841. }
  1842. (*LineTransCaps)->dwTotalSize = LineTransCapsSize;
  1843. Rslt = lineGetTranslateCaps(
  1844. g_hLineApp,
  1845. MAX_TAPI_API_VER,
  1846. *LineTransCaps
  1847. );
  1848. if (Rslt != 0) {
  1849. DebugPrintEx(DEBUG_ERR, TEXT("lineGetTranslateCaps() failed, ec=0x%08x"), Rslt);
  1850. goto exit;
  1851. }
  1852. }
  1853. exit:
  1854. if (Rslt != ERROR_SUCCESS) {
  1855. MemFree( *LineTransCaps );
  1856. *LineTransCaps = NULL;
  1857. }
  1858. return Rslt;
  1859. }
  1860. /******************************************************************************
  1861. * Name: OpenTapiLine
  1862. * Author:
  1863. *******************************************************************************
  1864. DESCRIPTION:
  1865. - Opens the specified TAPI line with the right media modes and ownership.
  1866. Supports both Unimodem devices and fax boards.
  1867. - Sets the line so the required lines and address state events will be
  1868. delivered.
  1869. PARAMETERS:
  1870. [IN / OUT ] LineInfo
  1871. A pointer to a LINE_INFO structure that contains the line information.
  1872. LINE_INFO.hLine is set to the open line handle if the operation succeeds.
  1873. RETURN VALUE:
  1874. TRUE if no error occured.
  1875. FALSE otherwise.
  1876. Does not explicitly set LastError.
  1877. REMARKS:
  1878. NONE.
  1879. *******************************************************************************/
  1880. BOOL
  1881. OpenTapiLine(
  1882. PLINE_INFO LineInfo
  1883. )
  1884. {
  1885. LONG Rslt = ERROR_SUCCESS;
  1886. HLINE hLine;
  1887. DWORD LineStates = 0;
  1888. DWORD AddressStates = 0;
  1889. DEBUG_FUNCTION_NAME(_T("OpenTapiLine"));
  1890. EnterCriticalSection( &g_CsLine );
  1891. if (LineInfo->UnimodemDevice)
  1892. {
  1893. Rslt = lineOpen(
  1894. g_hLineApp,
  1895. LineInfo->DeviceId,
  1896. &hLine,
  1897. MAX_TAPI_API_VER,
  1898. 0,
  1899. (DWORD_PTR) LineInfo, // Note that the LineInfo pointer is used as CallbackInstance data. This means we will
  1900. // get the LineInfo pointer each time we get a TAPI message.
  1901. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  1902. LINEMEDIAMODE_DATAMODEM | LINEMEDIAMODE_UNKNOWN,
  1903. NULL
  1904. );
  1905. if (Rslt != ERROR_SUCCESS)
  1906. {
  1907. Rslt = lineOpen(
  1908. g_hLineApp,
  1909. LineInfo->DeviceId,
  1910. &hLine,
  1911. MAX_TAPI_API_VER,
  1912. 0,
  1913. (DWORD_PTR) LineInfo,
  1914. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  1915. LINEMEDIAMODE_DATAMODEM,
  1916. NULL
  1917. );
  1918. }
  1919. }
  1920. else
  1921. {
  1922. Rslt = lineOpen(
  1923. g_hLineApp,
  1924. LineInfo->DeviceId,
  1925. &hLine,
  1926. MAX_TAPI_API_VER,
  1927. 0,
  1928. (DWORD_PTR) LineInfo,
  1929. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  1930. LINEMEDIAMODE_G3FAX,
  1931. NULL
  1932. );
  1933. }
  1934. if (Rslt != ERROR_SUCCESS)
  1935. {
  1936. DebugPrintEx( DEBUG_ERR,TEXT("Device %s FAILED to initialize, ec=%08x"), LineInfo->DeviceName, Rslt );
  1937. }
  1938. else
  1939. {
  1940. LineInfo->hLine = hLine;
  1941. //
  1942. // set the line status that we need
  1943. //
  1944. LineStates |= LineInfo->LineStates & LINEDEVSTATE_OPEN ? LINEDEVSTATE_OPEN : 0;
  1945. LineStates |= LineInfo->LineStates & LINEDEVSTATE_CLOSE ? LINEDEVSTATE_CLOSE : 0;
  1946. LineStates |= LineInfo->LineStates & LINEDEVSTATE_RINGING ? LINEDEVSTATE_RINGING : 0;
  1947. LineStates |= LineInfo->LineStates & LINEDEVSTATE_NUMCALLS ? LINEDEVSTATE_NUMCALLS : 0;
  1948. LineStates |= LineInfo->LineStates & LINEDEVSTATE_REMOVED ? LINEDEVSTATE_REMOVED : 0;
  1949. AddressStates = LINEADDRESSSTATE_INUSEZERO | LINEADDRESSSTATE_INUSEONE |
  1950. LINEADDRESSSTATE_INUSEMANY | LINEADDRESSSTATE_NUMCALLS;
  1951. Rslt = lineSetStatusMessages( hLine, LineStates, AddressStates );
  1952. if (Rslt != 0)
  1953. {
  1954. DebugPrintEx(DEBUG_ERR,TEXT("lineSetStatusMessages() failed, [0x%08x:0x%08x], ec=0x%08x"), LineStates, AddressStates, Rslt );
  1955. Rslt = ERROR_SUCCESS;
  1956. }
  1957. }
  1958. LeaveCriticalSection( &g_CsLine );
  1959. if (ERROR_SUCCESS != Rslt)
  1960. {
  1961. //
  1962. // We set the modem to be FPF_POWERED_OFF to make sure we will not try to constantly resend
  1963. // on this device. After MAX_LINE_CLOSE_TIME we will retry to send on this device.
  1964. //
  1965. LineInfo->hLine = NULL;
  1966. LineInfo->Flags |= FPF_POWERED_OFF;
  1967. GetSystemTimeAsFileTime((FILETIME*)&LineInfo->LastLineClose);
  1968. //
  1969. // Can not map the TAPI error to a win error so we just return general failure.
  1970. // We do generate a debug output with the actual error earlier in this code.
  1971. //
  1972. SetLastError(ERROR_GEN_FAILURE);
  1973. return FALSE;
  1974. }
  1975. else
  1976. {
  1977. LineInfo->Flags &= ~FPF_POWERED_OFF;
  1978. return TRUE;
  1979. }
  1980. }
  1981. BOOL CALLBACK
  1982. NewDeviceRoutingMethodEnumerator(
  1983. PROUTING_METHOD RoutingMethod,
  1984. DWORD DeviceId
  1985. )
  1986. {
  1987. BOOL Rslt = FALSE;
  1988. DEBUG_FUNCTION_NAME(_T("NewDeviceRoutingMethodEnumerator"));
  1989. __try
  1990. {
  1991. Rslt = RoutingMethod->RoutingExtension->FaxRouteDeviceChangeNotification( DeviceId, TRUE );
  1992. }
  1993. __except (HandleFaxExtensionFault(EXCEPTION_SOURCE_ROUTING_EXT, RoutingMethod->RoutingExtension->FriendlyName, GetExceptionCode()))
  1994. {
  1995. ASSERT_FALSE;
  1996. }
  1997. return Rslt;
  1998. }
  1999. BOOL
  2000. AddNewDevice(
  2001. DWORD DeviceId,
  2002. LPLINEDEVCAPS LineDevCaps,
  2003. BOOL fServerInitialization,
  2004. PREG_FAX_DEVICES pInputFaxReg
  2005. )
  2006. {
  2007. BOOL rVal = FALSE;
  2008. BOOL UnimodemDevice = FALSE;
  2009. PMDM_DEVSPEC MdmDevSpec = NULL;
  2010. LPSTR ModemKey = NULL;
  2011. LPTSTR DeviceName = NULL;
  2012. REG_SETUP RegSetup = {0};
  2013. DWORD dwUniqueLineId = 0;
  2014. PDEVICE_PROVIDER lpProvider;
  2015. LPTSTR lptstrTSPName;
  2016. DWORD ec = ERROR_SUCCESS;
  2017. BOOL fDeviceAddedToMap = FALSE;
  2018. DWORD dwDeviceType = FAX_DEVICE_TYPE_OLD;
  2019. DEBUG_FUNCTION_NAME(TEXT("AddNewDevice"));
  2020. //
  2021. // only add devices that support fax
  2022. //
  2023. if (! ( ((LineDevCaps->dwMediaModes & LINEMEDIAMODE_DATAMODEM) &&
  2024. (UnimodemDevice = IsDeviceModem( LineDevCaps, FAX_MODEM_PROVIDER_NAME ) )) ||
  2025. (LineDevCaps->dwMediaModes & LINEMEDIAMODE_G3FAX) ))
  2026. {
  2027. SetLastError (ERROR_INVALID_PARAMETER);
  2028. return FALSE;
  2029. }
  2030. if (!(LineDevCaps->dwProviderInfoSize))
  2031. {
  2032. DebugPrintEx(
  2033. DEBUG_ERR,
  2034. TEXT("No device provider information"));
  2035. SetLastError (ERROR_INVALID_PARAMETER);
  2036. return FALSE;
  2037. }
  2038. if (!GetOrigSetupData( LineDevCaps->dwPermanentLineID, &RegSetup ))
  2039. {
  2040. DebugPrintEx(
  2041. DEBUG_ERR,
  2042. TEXT("GetOrigSetupData failed (ec: %ld)"),
  2043. GetLastError());
  2044. return FALSE;
  2045. }
  2046. if (LineDevCaps->dwLineNameSize)
  2047. {
  2048. DeviceName = FixupDeviceName( (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwLineNameOffset) );
  2049. if (NULL == DeviceName)
  2050. {
  2051. ec = GetLastError();
  2052. DebugPrintEx( DEBUG_ERR,
  2053. TEXT("FixupDeviceName failed (ec: %ld)"),
  2054. ec);
  2055. rVal = FALSE;
  2056. goto exit;
  2057. }
  2058. }
  2059. else
  2060. {
  2061. //
  2062. // The TSP did not provide device name. DO not add the device
  2063. //
  2064. ec = ERROR_BAD_FORMAT;
  2065. DebugPrintEx(
  2066. DEBUG_ERR,
  2067. TEXT("Device %d does not have device name, not adding the device"),
  2068. DeviceId);
  2069. rVal = FALSE;
  2070. goto exit;
  2071. }
  2072. //
  2073. // Find the device provider for this device using the TAPI provider name.
  2074. //
  2075. lptstrTSPName = (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwProviderInfoOffset) ;
  2076. lpProvider = FindDeviceProvider( lptstrTSPName);
  2077. if (!lpProvider)
  2078. {
  2079. DebugPrintEx(
  2080. DEBUG_ERR,
  2081. TEXT("Could not find a valid device provider for TAPI device: [%s]. (Looking for TSP : [%s])"),
  2082. DeviceName,
  2083. lptstrTSPName
  2084. );
  2085. rVal = FALSE;
  2086. goto exit;
  2087. }
  2088. Assert (FAX_PROVIDER_STATUS_SUCCESS == lpProvider->Status);
  2089. // try to find this device from service registry and update RegSetup if found
  2090. if ( pInputFaxReg )
  2091. {
  2092. dwUniqueLineId = FindServiceDeviceByTapiPermanentLineID ( LineDevCaps->dwPermanentLineID, DeviceName, &RegSetup, pInputFaxReg );
  2093. }
  2094. // try to find this device in device cache and update RegSetup if found
  2095. if ( 0 == dwUniqueLineId )
  2096. {
  2097. BOOL fManualAnswer = FALSE;
  2098. if (0 != (dwUniqueLineId = FindCacheEntryByTapiPermanentLineID( LineDevCaps->dwPermanentLineID,
  2099. DeviceName,
  2100. &RegSetup,
  2101. &g_dwLastUniqueLineId,
  2102. &fManualAnswer)))
  2103. {
  2104. //
  2105. // The device was found in the cache
  2106. //
  2107. dwDeviceType = FAX_DEVICE_TYPE_CACHED;
  2108. if (TRUE == fManualAnswer)
  2109. {
  2110. //
  2111. // The device was set to manual answer when moved to the cache
  2112. //
  2113. dwDeviceType |= FAX_DEVICE_TYPE_MANUAL_ANSWER;
  2114. }
  2115. }
  2116. }
  2117. // still 0 so, add this new device to registry
  2118. if ( 0 == dwUniqueLineId )
  2119. {
  2120. dwDeviceType = FAX_DEVICE_TYPE_NEW;
  2121. ec = RegAddNewFaxDevice( &g_dwLastUniqueLineId,
  2122. &dwUniqueLineId, // Create new device.
  2123. DeviceName,
  2124. (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwProviderInfoOffset),
  2125. lpProvider->szGUID,
  2126. RegSetup.Csid,
  2127. RegSetup.Tsid,
  2128. LineDevCaps->dwPermanentLineID,
  2129. RegSetup.Flags,
  2130. RegSetup.Rings);
  2131. if (ERROR_SUCCESS != ec)
  2132. {
  2133. DebugPrintEx(
  2134. DEBUG_WRN,
  2135. TEXT("RegAddNewFaxDevice() failed for Tapi permanent device id: %ld (ec: %ld)"),
  2136. LineDevCaps->dwPermanentLineID,
  2137. ec);
  2138. rVal = FALSE;
  2139. goto exit;
  2140. }
  2141. }
  2142. ec = g_pTAPIDevicesIdsMap->AddDevice (LineDevCaps->dwPermanentLineID, dwUniqueLineId);
  2143. if (ERROR_SUCCESS != ec)
  2144. {
  2145. DebugPrintEx(
  2146. DEBUG_WRN,
  2147. TEXT("g_pTAPIDevicesIdsMap->AddDevice() failed for Tapi permanent device id: %ld (ec: %ld)"),
  2148. LineDevCaps->dwPermanentLineID,
  2149. ec);
  2150. rVal = FALSE;
  2151. goto exit;
  2152. }
  2153. fDeviceAddedToMap = TRUE;
  2154. ec = InitializeTapiLine( DeviceId,
  2155. dwUniqueLineId,
  2156. LineDevCaps,
  2157. RegSetup.Rings,
  2158. RegSetup.Flags,
  2159. RegSetup.Csid,
  2160. RegSetup.Tsid,
  2161. RegSetup.lptstrDescription,
  2162. fServerInitialization,
  2163. dwDeviceType
  2164. );
  2165. if (ERROR_SUCCESS != ec)
  2166. {
  2167. DebugPrintEx( DEBUG_WRN,
  2168. TEXT("InitializeTapiLine failed for Fax unique device id: %ld (ec: %ld)"),
  2169. dwUniqueLineId,
  2170. ec);
  2171. rVal = FALSE;
  2172. goto exit;
  2173. }
  2174. if (FALSE == fServerInitialization)
  2175. {
  2176. PLINE_INFO pLineInfo = NULL;
  2177. //
  2178. // Close the line if the device is not receive enabled
  2179. //
  2180. pLineInfo = GetTapiLineFromDeviceId (dwUniqueLineId, FALSE);
  2181. if (pLineInfo)
  2182. {
  2183. if (!(pLineInfo->Flags & FPF_RECEIVE) && // Device is not set to auto-receive and
  2184. pLineInfo->hLine && // device is open and
  2185. pLineInfo->PermanentLineID != g_dwManualAnswerDeviceId // this device is not set to manual answer mode
  2186. )
  2187. {
  2188. //
  2189. // Attempt to close the device
  2190. //
  2191. HLINE hLine = pLineInfo->hLine;
  2192. LONG Rslt;
  2193. pLineInfo->hLine = 0;
  2194. Rslt = lineClose( hLine );
  2195. if (Rslt)
  2196. {
  2197. if (LINEERR_INVALLINEHANDLE != Rslt)
  2198. {
  2199. DebugPrintEx(
  2200. DEBUG_ERR,
  2201. TEXT("lineClose() for line %s [Permanent Id: %010d] has failed. (ec: %ld)"),
  2202. pLineInfo->DeviceName,
  2203. pLineInfo->TapiPermanentLineId,
  2204. Rslt);
  2205. }
  2206. else
  2207. {
  2208. //
  2209. // We can get LINEERR_INVALLINEHANDLE if we got LINE_CLOSE
  2210. // from TAPI.
  2211. //
  2212. DebugPrintEx(
  2213. DEBUG_WRN,
  2214. TEXT("lineClose() for line %s [Permanent Id: %010d] reported LINEERR_INVALLINEHANDLE. (May be caused by LINE_CLOSE event)"),
  2215. pLineInfo->DeviceName,
  2216. pLineInfo->TapiPermanentLineId
  2217. );
  2218. }
  2219. }
  2220. }
  2221. }
  2222. else
  2223. {
  2224. //
  2225. // We must find the line because InitializeTapiLine() did not fail
  2226. //
  2227. ASSERT_FALSE;
  2228. }
  2229. if (!g_pGroupsMap->UpdateAllDevicesGroup())
  2230. {
  2231. ec = GetLastError();
  2232. DebugPrintEx(
  2233. DEBUG_ERR,
  2234. TEXT("COutboundRoutingGroupsMap::UpdateAllDevicesGroup() failed (ec: %ld)"),
  2235. ec);
  2236. //
  2237. // We failed to update <All devices> group. Remove the line.
  2238. //
  2239. if (pLineInfo)
  2240. {
  2241. RemoveEntryList (&pLineInfo->ListEntry);
  2242. //
  2243. // Update enabled device counter
  2244. //
  2245. if (TRUE == IsDeviceEnabled(pLineInfo))
  2246. {
  2247. Assert (g_dwDeviceEnabledCount);
  2248. g_dwDeviceEnabledCount -= 1;
  2249. }
  2250. FreeTapiLine (pLineInfo);
  2251. g_dwDeviceCount -= 1;
  2252. }
  2253. rVal = FALSE;
  2254. goto exit;
  2255. }
  2256. //
  2257. // Call CreateConfigEvent only when LINE_CREATE event accure during service operation
  2258. // and not during start up
  2259. //
  2260. ec = CreateConfigEvent (FAX_CONFIG_TYPE_DEVICES);
  2261. if (ERROR_SUCCESS != ec)
  2262. {
  2263. DebugPrintEx(
  2264. DEBUG_ERR,
  2265. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_DEVICES) failed (ec: %lc)"),
  2266. ec);
  2267. }
  2268. ec = CreateConfigEvent (FAX_CONFIG_TYPE_OUT_GROUPS);
  2269. if (ERROR_SUCCESS != ec)
  2270. {
  2271. DebugPrintEx(
  2272. DEBUG_ERR,
  2273. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_OUT_GROUPS) failed (ec: %lc)"),
  2274. ec);
  2275. }
  2276. }
  2277. rVal = TRUE;
  2278. exit:
  2279. if (DeviceName)
  2280. {
  2281. MemFree( DeviceName );
  2282. }
  2283. if (FALSE == rVal &&
  2284. TRUE == fDeviceAddedToMap)
  2285. {
  2286. DWORD dwRes = g_pTAPIDevicesIdsMap->RemoveDevice (LineDevCaps->dwPermanentLineID);
  2287. if (ERROR_SUCCESS != dwRes)
  2288. {
  2289. DebugPrintEx(
  2290. DEBUG_ERR,
  2291. TEXT("Cg_pTAPIDevicesIdsMap->RemoveDevice failed (ec: %lc)"),
  2292. dwRes);
  2293. }
  2294. }
  2295. FreeOrigSetupData( &RegSetup );
  2296. EnumerateRoutingMethods( (PFAXROUTEMETHODENUM)NewDeviceRoutingMethodEnumerator, UlongToPtr(dwUniqueLineId) );
  2297. if (FALSE == rVal)
  2298. {
  2299. SetLastError(ec);
  2300. }
  2301. return rVal;
  2302. } // AddNewDevice
  2303. DWORD
  2304. InitializeTapiLine(
  2305. DWORD DeviceId,
  2306. DWORD dwUniqueLineId,
  2307. LPLINEDEVCAPS LineDevCaps,
  2308. DWORD Rings,
  2309. DWORD Flags,
  2310. LPTSTR Csid,
  2311. LPTSTR Tsid,
  2312. LPTSTR lptstrDescription,
  2313. BOOL fServerInit,
  2314. DWORD dwDeviceType
  2315. )
  2316. {
  2317. PLINE_INFO LineInfo = NULL;
  2318. LONG Rslt = ERROR_SUCCESS;
  2319. DWORD len;
  2320. PDEVICE_PROVIDER Provider;
  2321. BOOL UnimodemDevice;
  2322. HLINE hLine = 0;
  2323. LPTSTR ProviderName = NULL;
  2324. LPTSTR DeviceName = NULL;
  2325. BOOL NewDevice = TRUE;
  2326. DWORD LineStates = 0;
  2327. DWORD AddressStates = 0;
  2328. LPLINEDEVSTATUS LineDevStatus;
  2329. DEBUG_FUNCTION_NAME(TEXT("InitializeTapiLine"));
  2330. Assert(dwUniqueLineId);
  2331. //
  2332. // allocate the LINE_INFO structure
  2333. //
  2334. LineInfo = (PLINE_INFO) MemAlloc( sizeof(LINE_INFO) );
  2335. if (!LineInfo)
  2336. {
  2337. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  2338. goto exit;
  2339. }
  2340. ZeroMemory(LineInfo, sizeof(LINE_INFO));
  2341. //
  2342. // get the provider name
  2343. //
  2344. len = _tcslen( (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwProviderInfoOffset) );
  2345. ProviderName = (LPTSTR)(MemAlloc( (len + 1) * sizeof(TCHAR) ));
  2346. if (!ProviderName)
  2347. {
  2348. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  2349. goto exit;
  2350. }
  2351. _tcscpy( ProviderName, (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwProviderInfoOffset) );
  2352. //
  2353. // get the device name
  2354. //
  2355. DeviceName = FixupDeviceName( (LPTSTR)((LPBYTE) LineDevCaps + LineDevCaps->dwLineNameOffset) );
  2356. if (!DeviceName)
  2357. {
  2358. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  2359. goto exit;
  2360. }
  2361. //
  2362. // verify that the line id is good
  2363. //
  2364. if (LineDevCaps->dwPermanentLineID == 0)
  2365. {
  2366. DebugPrintEx(DEBUG_ERR,
  2367. TEXT("TAPI lines must have a non-zero line id [%s]"),
  2368. DeviceName);
  2369. Rslt = ERROR_BAD_DEVICE;
  2370. goto exit;
  2371. }
  2372. //
  2373. // check for a modem device
  2374. //
  2375. UnimodemDevice = IsDeviceModem( LineDevCaps, FAX_MODEM_PROVIDER_NAME );
  2376. //
  2377. // assign the device provider
  2378. //
  2379. Provider = FindDeviceProvider( ProviderName );
  2380. if (!Provider)
  2381. {
  2382. DebugPrintEx(DEBUG_ERR, TEXT("Could not find a valid device provider for device: %s"), DeviceName);
  2383. Rslt = ERROR_BAD_PROVIDER;
  2384. goto exit;
  2385. }
  2386. Assert (FAX_PROVIDER_STATUS_SUCCESS == Provider->Status);
  2387. //
  2388. // open the line
  2389. //
  2390. if (UnimodemDevice)
  2391. {
  2392. Rslt = lineOpen(
  2393. g_hLineApp,
  2394. DeviceId,
  2395. &hLine,
  2396. MAX_TAPI_API_VER,
  2397. 0,
  2398. (DWORD_PTR) LineInfo,
  2399. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  2400. LINEMEDIAMODE_DATAMODEM | LINEMEDIAMODE_UNKNOWN,
  2401. NULL
  2402. );
  2403. if (Rslt != 0)
  2404. {
  2405. Rslt = lineOpen(
  2406. g_hLineApp,
  2407. DeviceId,
  2408. &hLine,
  2409. MAX_TAPI_API_VER,
  2410. 0,
  2411. (DWORD_PTR) LineInfo,
  2412. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  2413. LINEMEDIAMODE_DATAMODEM,
  2414. NULL
  2415. );
  2416. }
  2417. }
  2418. else
  2419. {
  2420. Rslt = lineOpen(
  2421. g_hLineApp,
  2422. DeviceId,
  2423. &hLine,
  2424. MAX_TAPI_API_VER,
  2425. 0,
  2426. (DWORD_PTR) LineInfo,
  2427. LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR,
  2428. LINEMEDIAMODE_G3FAX,
  2429. NULL
  2430. );
  2431. }
  2432. if (Rslt != 0)
  2433. {
  2434. DebugPrintEx(DEBUG_ERR, TEXT("Device %s FAILED to initialize, ec=%08x"), DeviceName, Rslt);
  2435. goto exit;
  2436. }
  2437. //
  2438. // Set hLine in the LINE_INFO structure so it will be freed on failure
  2439. //
  2440. LineInfo->hLine = hLine;
  2441. //
  2442. // set the line status that we need
  2443. //
  2444. LineStates |= LineDevCaps->dwLineStates & LINEDEVSTATE_OPEN ? LINEDEVSTATE_OPEN : 0;
  2445. LineStates |= LineDevCaps->dwLineStates & LINEDEVSTATE_CLOSE ? LINEDEVSTATE_CLOSE : 0;
  2446. LineStates |= LineDevCaps->dwLineStates & LINEDEVSTATE_RINGING ? LINEDEVSTATE_RINGING : 0;
  2447. LineStates |= LineDevCaps->dwLineStates & LINEDEVSTATE_NUMCALLS ? LINEDEVSTATE_NUMCALLS : 0;
  2448. LineStates |= LineDevCaps->dwLineStates & LINEDEVSTATE_REMOVED ? LINEDEVSTATE_REMOVED : 0;
  2449. AddressStates = LINEADDRESSSTATE_INUSEZERO | LINEADDRESSSTATE_INUSEONE |
  2450. LINEADDRESSSTATE_INUSEMANY | LINEADDRESSSTATE_NUMCALLS;
  2451. Rslt = lineSetStatusMessages( LineInfo->hLine, LineStates, AddressStates );
  2452. if (Rslt != 0)
  2453. {
  2454. DebugPrintEx(DEBUG_ERR, TEXT("lineSetStatusMessages() failed, [0x%08x:0x%08x], ec=0x%08x"), LineStates, AddressStates, Rslt);
  2455. if (Rslt == LINEERR_INVALLINEHANDLE)
  2456. {
  2457. LineInfo->hLine = 0;
  2458. }
  2459. Rslt = 0;
  2460. }
  2461. //
  2462. // now assign the necessary values to the line info struct
  2463. //
  2464. LineInfo->Signature = LINE_SIGNATURE;
  2465. LineInfo->DeviceId = DeviceId;
  2466. LineInfo->TapiPermanentLineId = LineDevCaps->dwPermanentLineID;
  2467. LineInfo->Provider = Provider;
  2468. LineInfo->UnimodemDevice = UnimodemDevice;
  2469. LineInfo->State = FPS_AVAILABLE;
  2470. LineInfo->dwReceivingJobsCount = 0;
  2471. LineInfo->dwSendingJobsCount = 0;
  2472. LineInfo->LastLineClose = 0;
  2473. if (DeviceName)
  2474. {
  2475. LineInfo->DeviceName = StringDup( DeviceName );
  2476. if (!LineInfo->DeviceName)
  2477. {
  2478. Rslt = GetLastError ();
  2479. goto exit;
  2480. }
  2481. }
  2482. else
  2483. {
  2484. LineInfo->DeviceName = NULL;
  2485. }
  2486. if (Csid)
  2487. {
  2488. LineInfo->Csid = StringDup( Csid );
  2489. if (!LineInfo->Csid)
  2490. {
  2491. Rslt = GetLastError ();
  2492. goto exit;
  2493. }
  2494. }
  2495. else
  2496. {
  2497. LineInfo->Csid = NULL;
  2498. }
  2499. if (Tsid)
  2500. {
  2501. LineInfo->Tsid = StringDup( Tsid );
  2502. if (!LineInfo->Tsid)
  2503. {
  2504. Rslt = GetLastError ();
  2505. goto exit;
  2506. }
  2507. }
  2508. else
  2509. {
  2510. LineInfo->Tsid = NULL;
  2511. }
  2512. if (lptstrDescription)
  2513. {
  2514. LineInfo->lptstrDescription = StringDup( lptstrDescription );
  2515. if (!LineInfo->lptstrDescription)
  2516. {
  2517. Rslt = GetLastError ();
  2518. goto exit;
  2519. }
  2520. }
  2521. else
  2522. {
  2523. LineInfo->lptstrDescription = NULL;
  2524. }
  2525. LineInfo->RingsForAnswer = (LineDevCaps->dwLineStates & LINEDEVSTATE_RINGING) ? Rings : 0;
  2526. LineInfo->Flags = Flags;
  2527. LineInfo->RingCount = 0;
  2528. LineInfo->LineStates = LineDevCaps->dwLineStates;
  2529. LineInfo->PermanentLineID = dwUniqueLineId;
  2530. LineInfo->dwDeviceType = dwDeviceType;
  2531. if (LineInfo->hLine)
  2532. {
  2533. //
  2534. // check to see if the line is in use
  2535. //
  2536. LineDevStatus = MyLineGetLineDevStatus( LineInfo->hLine );
  2537. if (LineDevStatus)
  2538. {
  2539. if (LineDevStatus->dwNumOpens > 0 && LineDevStatus->dwNumActiveCalls > 0)
  2540. {
  2541. LineInfo->ModemInUse = TRUE;
  2542. }
  2543. MemFree( LineDevStatus );
  2544. }
  2545. }
  2546. else
  2547. {
  2548. //
  2549. // if we don't have a line handle at this time then the
  2550. // device must be powered off
  2551. //
  2552. DebugPrintEx(DEBUG_ERR, TEXT("Device %s is powered off or disconnected"), DeviceName);
  2553. LineInfo->Flags |= FPF_POWERED_OFF;
  2554. //
  2555. // Since this function is called from TapiInitialize(), we don't have an RPC server up and running yet.
  2556. // Don't create a FAX_EVENT_TYPE_DEVICE_STATUS event.
  2557. //
  2558. }
  2559. exit:
  2560. MemFree( DeviceName );
  2561. MemFree( ProviderName );
  2562. if (Rslt == ERROR_SUCCESS)
  2563. {
  2564. InsertTailList( &g_TapiLinesListHead, &LineInfo->ListEntry );
  2565. g_dwDeviceCount += 1;
  2566. if (FALSE == fServerInit)
  2567. {
  2568. //
  2569. // Add cached manual answer device and check device limit
  2570. //
  2571. if (0 == g_dwManualAnswerDeviceId && // There is no manual answer device
  2572. LineInfo->dwDeviceType == (FAX_DEVICE_TYPE_CACHED | FAX_DEVICE_TYPE_MANUAL_ANSWER) && // this is a cached manual answer device
  2573. !(LineInfo->Flags & FPF_RECEIVE)) // the device is not set to auto receive
  2574. {
  2575. //
  2576. // set this device as manual receive
  2577. //
  2578. g_dwManualAnswerDeviceId = LineInfo->PermanentLineID;
  2579. DWORD dwRes = WriteManualAnswerDeviceId (g_dwManualAnswerDeviceId);
  2580. if (ERROR_SUCCESS != dwRes)
  2581. {
  2582. DebugPrintEx(
  2583. DEBUG_ERR,
  2584. TEXT("WriteManualAnswerDeviceId(0) (ec: %lc)"),
  2585. dwRes);
  2586. }
  2587. }
  2588. if (g_dwDeviceEnabledCount >= g_dwDeviceEnabledLimit)
  2589. {
  2590. //
  2591. // We reached device limit on this SKU. set this device's flags to 0.
  2592. //
  2593. DebugPrintEx(
  2594. DEBUG_WRN,
  2595. TEXT("Reached device limit on this SKU. reset device flags to 0. Device limit: %ld. Current device: %ld"),
  2596. g_dwDeviceEnabledLimit,
  2597. g_dwDeviceEnabledCount);
  2598. ResetDeviceFlags(LineInfo);
  2599. }
  2600. }
  2601. //
  2602. // Update enabled device counter
  2603. //
  2604. if (TRUE == IsDeviceEnabled(LineInfo))
  2605. {
  2606. g_dwDeviceEnabledCount += 1;
  2607. }
  2608. }
  2609. else
  2610. {
  2611. FreeTapiLine( LineInfo );
  2612. }
  2613. return Rslt;
  2614. } // InitializeTapiLine
  2615. BOOL
  2616. IsVirtualDevice(
  2617. const LINE_INFO *pLineInfo
  2618. )
  2619. {
  2620. if (!pLineInfo) {
  2621. return FALSE;
  2622. }
  2623. return (pLineInfo->Provider->FaxDevVirtualDeviceCreation != NULL);
  2624. }
  2625. VOID
  2626. UpdateVirtualDeviceSendAndReceiveStatus(
  2627. PLINE_INFO pLineInfo,
  2628. BOOL bSend,
  2629. BOOL bReceive
  2630. )
  2631. /*++
  2632. Routine name : UpdateVirtualDeviceSendAndReceiveStatus
  2633. Routine description:
  2634. Updates a virtual device with the new send and receive flags
  2635. Author:
  2636. Eran Yariv (EranY), Nov, 1999
  2637. Arguments:
  2638. pLineInfo [in] - Pointer to line information
  2639. bSend [in] - Can the device send faxes?
  2640. bReceive [in] - Can the device receive faxes?
  2641. Remarks:
  2642. This function should be called with g_CsLine held.
  2643. Return Value:
  2644. None.
  2645. --*/
  2646. {
  2647. DEBUG_FUNCTION_NAME(TEXT("UpdateVirtualDeviceSendAndReceiveStatus"));
  2648. if (!IsVirtualDevice(pLineInfo) || !pLineInfo->Provider->FaxDevCallback)
  2649. {
  2650. //
  2651. // Not a virtual device or does not support FaxDevCallback
  2652. //
  2653. return;
  2654. }
  2655. __try
  2656. {
  2657. pLineInfo->Provider->FaxDevCallback( NULL,
  2658. pLineInfo->TapiPermanentLineId,
  2659. LINE_DEVSPECIFIC,
  2660. 0,
  2661. bReceive,
  2662. bSend,
  2663. 0
  2664. );
  2665. }
  2666. __except (HandleFaxExtensionFault(EXCEPTION_SOURCE_FSP, pLineInfo->Provider->FriendlyName, GetExceptionCode()))
  2667. {
  2668. ASSERT_FALSE;
  2669. }
  2670. } // UpdateVirtualDeviceSendAndReceiveStatus
  2671. VOID
  2672. UpdateVirtualDevices(
  2673. VOID
  2674. )
  2675. {
  2676. PLIST_ENTRY Next;
  2677. PLINE_INFO LineInfo = NULL;
  2678. EnterCriticalSection( &g_CsLine );
  2679. Next = g_TapiLinesListHead.Flink;
  2680. if (Next == NULL) {
  2681. LeaveCriticalSection( &g_CsLine );
  2682. return;
  2683. }
  2684. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  2685. {
  2686. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  2687. Next = LineInfo->ListEntry.Flink;
  2688. UpdateVirtualDeviceSendAndReceiveStatus (LineInfo,
  2689. LineInfo->Flags & FPF_SEND,
  2690. LineInfo->Flags & FPF_RECEIVE
  2691. );
  2692. }
  2693. LeaveCriticalSection( &g_CsLine );
  2694. }
  2695. DWORD
  2696. CreateVirtualDevices(
  2697. PREG_FAX_SERVICE FaxReg,
  2698. DWORD dwAPIVersion
  2699. )
  2700. {
  2701. PLIST_ENTRY Next;
  2702. PDEVICE_PROVIDER Provider;
  2703. PLINE_INFO LineInfo = NULL;
  2704. PREG_DEVICE FaxDevice = NULL;
  2705. PREG_FAX_DEVICES FaxDevices = NULL;
  2706. DWORD dwVirtualDeviceCount = 0;
  2707. REG_SETUP RegSetup={0};
  2708. DWORD ec;
  2709. DEBUG_FUNCTION_NAME(TEXT("CreateVirtualDevices"));
  2710. Next = g_DeviceProvidersListHead.Flink;
  2711. if (!Next)
  2712. {
  2713. return dwVirtualDeviceCount;
  2714. }
  2715. if (!GetOrigSetupData( 0, &RegSetup ))
  2716. {
  2717. return dwVirtualDeviceCount;
  2718. }
  2719. while ((ULONG_PTR)Next != (ULONG_PTR)&g_DeviceProvidersListHead)
  2720. {
  2721. DWORD dwDeviceCount;
  2722. dwDeviceCount = 0;
  2723. Provider = CONTAINING_RECORD( Next, DEVICE_PROVIDER, ListEntry );
  2724. Next = Provider->ListEntry.Flink;
  2725. if (Provider->Status != FAX_PROVIDER_STATUS_SUCCESS)
  2726. {
  2727. //
  2728. // This FSP wasn't loaded successfully - skip it
  2729. //
  2730. continue;
  2731. }
  2732. if (Provider->dwAPIVersion != dwAPIVersion)
  2733. {
  2734. //
  2735. // This FSP doesn't match the required API version - skip it
  2736. //
  2737. continue;
  2738. }
  2739. if (FSPI_API_VERSION_1 == Provider->dwAPIVersion)
  2740. {
  2741. if (Provider->FaxDevVirtualDeviceCreation)
  2742. {
  2743. if (!CreateLegacyVirtualDevices(FaxReg, &RegSetup, Provider, &dwDeviceCount))
  2744. {
  2745. ec = GetLastError();
  2746. DebugPrintEx(
  2747. DEBUG_ERR,
  2748. TEXT("CreateLegacyVirtualDevices failed for provider [%s] (ec: %ld)"),
  2749. Provider->FriendlyName,
  2750. ec);
  2751. goto InitializationFailure;
  2752. }
  2753. else
  2754. {
  2755. DebugPrintEx(
  2756. DEBUG_MSG,
  2757. TEXT("%ld Legacy Virtual devices added by provider [%s]"),
  2758. dwDeviceCount,
  2759. Provider->FriendlyName,
  2760. ec);
  2761. }
  2762. }
  2763. }
  2764. else
  2765. {
  2766. DebugPrintEx(
  2767. DEBUG_ERR,
  2768. TEXT("Unsupported API Version (0x%08X) for provider [%s]"),
  2769. Provider->dwAPIVersion,
  2770. Provider->FriendlyName);
  2771. Assert(FALSE);
  2772. goto InitializationFailure;
  2773. }
  2774. dwVirtualDeviceCount+= dwDeviceCount;
  2775. goto next;
  2776. InitializationFailure:
  2777. Provider->Status = FAX_PROVIDER_STATUS_CANT_INIT;
  2778. FaxLog(
  2779. FAXLOG_CATEGORY_INIT,
  2780. FAXLOG_LEVEL_MIN,
  2781. 1,
  2782. MSG_VIRTUAL_DEVICE_INIT_FAILED,
  2783. Provider->FriendlyName
  2784. );
  2785. next:
  2786. ;
  2787. }
  2788. DebugPrintEx(DEBUG_MSG, TEXT("Virtual devices initialized, devices=%d"), g_dwDeviceCount);
  2789. FreeOrigSetupData( &RegSetup );
  2790. return dwVirtualDeviceCount;
  2791. }
  2792. //*********************************************************************************
  2793. //* Name: CreateLegacyVirtualDevices()
  2794. //* Author: Ronen Barenboim
  2795. //* Date: May 19, 1999
  2796. //*********************************************************************************
  2797. //* DESCRIPTION:
  2798. //* Creates the virtual line devices reported by a single FSP and adds them
  2799. //* to the line list. Also persists the line information in the registry.
  2800. //* PARAMETERS:
  2801. //* [IN] PREG_FAX_SERVICE FaxReg
  2802. //*
  2803. //* [IN] const REG_SETUP * lpRegSetup
  2804. //*
  2805. //* [IN] const DEVICE_PROVIDER * lpcProvider
  2806. //* A pointer to the provider information. This should be a virtual
  2807. //* provider.
  2808. //* [OUT] LPDWORD lpdwDeviceCount
  2809. //* The number of virtual devices actually added.
  2810. //*
  2811. //* RETURN VALUE:
  2812. //* TRUE
  2813. //* If the creation succeeded.
  2814. //* FALSE
  2815. //* If the creation failed. Call GetLastError() to get extended error
  2816. //* information. an error of ERROR_INVALID_FUNCTION indicates that
  2817. //* the FSP creation function failed.
  2818. //*********************************************************************************
  2819. BOOL CreateLegacyVirtualDevices(
  2820. PREG_FAX_SERVICE FaxReg,
  2821. const REG_SETUP * lpRegSetup,
  2822. DEVICE_PROVIDER * lpcProvider,
  2823. LPDWORD lpdwDeviceCount)
  2824. {
  2825. DWORD VirtualDeviceCount = 0;
  2826. WCHAR DevicePrefix[128] = {0};
  2827. DWORD DeviceIdPrefix;
  2828. LPWSTR DeviceName = NULL;
  2829. DWORD i,j;
  2830. PLINE_INFO LineInfo = NULL;
  2831. PREG_DEVICE FaxDevice = NULL;
  2832. UINT nDevice;
  2833. PLINE_INFO * lpAddedLines = NULL;
  2834. DWORD ec = 0;
  2835. PLIST_ENTRY Next;
  2836. PLINE_INFO pLineInfo;
  2837. Assert(lpcProvider);
  2838. Assert(lpcProvider->FaxDevVirtualDeviceCreation);
  2839. Assert(lpdwDeviceCount);
  2840. Assert(FaxReg);
  2841. Assert(lpRegSetup);
  2842. DEBUG_FUNCTION_NAME(TEXT("CreateLegacyVirtualDevices"));
  2843. (*lpdwDeviceCount) = 0;
  2844. __try
  2845. {
  2846. if (!lpcProvider->FaxDevVirtualDeviceCreation(
  2847. &VirtualDeviceCount,
  2848. DevicePrefix,
  2849. &DeviceIdPrefix,
  2850. g_TapiCompletionPort,
  2851. FAXDEV_EVENT_KEY
  2852. ))
  2853. {
  2854. ec = ERROR_INVALID_FUNCTION;
  2855. DebugPrintEx(
  2856. DEBUG_ERR,
  2857. TEXT("FaxDevVirtualDeviceCreation failed for provider [%s] (ec: %ld)"),
  2858. lpcProvider->FriendlyName,
  2859. GetLastError());
  2860. goto InitializationFailure;
  2861. }
  2862. }
  2863. __except (HandleFaxExtensionFault(EXCEPTION_SOURCE_FSP, lpcProvider->FriendlyName, GetExceptionCode()))
  2864. {
  2865. ASSERT_FALSE;
  2866. }
  2867. if (VirtualDeviceCount > 0)
  2868. {
  2869. if (VirtualDeviceCount > 256 )
  2870. {
  2871. DebugPrintEx(
  2872. DEBUG_MSG,
  2873. TEXT("VirtualDeviceCount returned too many devices (%d)- limit to 256"),
  2874. VirtualDeviceCount);
  2875. VirtualDeviceCount = 256;
  2876. }
  2877. if ((DeviceIdPrefix == 0) || (DeviceIdPrefix >= DEFAULT_REGVAL_FAX_UNIQUE_DEVICE_ID_BASE))
  2878. {
  2879. //
  2880. // Provider uses device ids out of allowed range
  2881. //
  2882. ec = ERROR_INVALID_FUNCTION;
  2883. DebugPrintEx(
  2884. DEBUG_ERR,
  2885. TEXT("Provider [%s] uses device ids base [%ld] out of allowed range."),
  2886. lpcProvider->FriendlyName,
  2887. DeviceIdPrefix);
  2888. goto InitializationFailure;
  2889. }
  2890. //
  2891. // Check if the range of device IDs does not conflict with an already loaded devices of another provider
  2892. // Range [1 ... DEFAULT_REGVAL_FAX_UNIQUE_DEVICE_ID_BASE-1] : Reserved for VFSPs.
  2893. // Since we cannot dictate the range of device ids the VFSPS use, we allocate a space for them
  2894. // and leave segments allocation to a PM effort here.
  2895. //
  2896. Next = g_TapiLinesListHead.Flink;
  2897. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  2898. {
  2899. pLineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  2900. Next = pLineInfo->ListEntry.Flink;
  2901. if (pLineInfo->PermanentLineID >= DeviceIdPrefix &&
  2902. pLineInfo->PermanentLineID <= DeviceIdPrefix + VirtualDeviceCount)
  2903. {
  2904. //
  2905. // We have a conflict. log an event and do not load the devices
  2906. //
  2907. ec = ERROR_INVALID_FUNCTION;
  2908. FaxLog(
  2909. FAXLOG_CATEGORY_INIT,
  2910. FAXLOG_LEVEL_MIN,
  2911. 2,
  2912. MSG_FAX_FSP_CONFLICT,
  2913. lpcProvider->FriendlyName,
  2914. pLineInfo->Provider->FriendlyName
  2915. );
  2916. DebugPrintEx(
  2917. DEBUG_ERR,
  2918. TEXT("Provider [%s] uses device id [%ld] that conflicts with another FSP [%s]"),
  2919. lpcProvider->FriendlyName,
  2920. DeviceIdPrefix,
  2921. pLineInfo->Provider->FriendlyName
  2922. );
  2923. goto InitializationFailure;
  2924. }
  2925. }
  2926. lpAddedLines = (PLINE_INFO *)MemAlloc(VirtualDeviceCount * sizeof(PLINE_INFO));
  2927. if (!lpAddedLines)
  2928. {
  2929. ec = GetLastError();
  2930. DebugPrintEx(
  2931. DEBUG_ERR,
  2932. TEXT("Failed to allocate PLINE_INFO array. (ec: %ld)"),
  2933. VirtualDeviceCount,
  2934. GetLastError());
  2935. goto InitializationFailure;
  2936. }
  2937. memset(lpAddedLines, 0, VirtualDeviceCount * sizeof(PLINE_INFO));
  2938. for (i = 0; i < VirtualDeviceCount; i++)
  2939. {
  2940. DWORD dwUniqueLineId;
  2941. //
  2942. // create the device name
  2943. //
  2944. DeviceName = (LPWSTR) MemAlloc( StringSize(DevicePrefix) + 16 );
  2945. if (!DeviceName) {
  2946. ec = GetLastError();
  2947. DebugPrintEx(
  2948. DEBUG_ERR,
  2949. TEXT("MemAlloc() failed for DeviceName (ec: %ld)"),
  2950. ec);
  2951. goto InitializationFailure;
  2952. }
  2953. swprintf( DeviceName, L"%s%d", DevicePrefix, i );
  2954. //
  2955. // find the registry information for this device
  2956. //
  2957. for (j = 0, FaxDevice = NULL; j < FaxReg->DeviceCount; j++)
  2958. {
  2959. if (TRUE == FaxReg->Devices[j].bValidDevice &&
  2960. !_tcscmp(FaxReg->Devices[j].lptstrProviderGuid, lpcProvider->szGUID))
  2961. {
  2962. if (FaxReg->Devices[j].TapiPermanentLineID == DeviceIdPrefix+i)
  2963. {
  2964. FaxDevice = &FaxReg->Devices[j];
  2965. break;
  2966. }
  2967. }
  2968. }
  2969. //
  2970. // if the device is new then add it to the registry
  2971. //
  2972. if (!FaxDevice)
  2973. {
  2974. //
  2975. // We set the Fax Device Id to be the VFSP device id - we don't create one on our own
  2976. //
  2977. dwUniqueLineId = DeviceIdPrefix + i;
  2978. RegAddNewFaxDevice(
  2979. &g_dwLastUniqueLineId,
  2980. &dwUniqueLineId,
  2981. DeviceName,
  2982. lpcProvider->ProviderName,
  2983. lpcProvider->szGUID,
  2984. lpRegSetup->Csid,
  2985. lpRegSetup->Tsid,
  2986. DeviceIdPrefix + i,
  2987. (lpRegSetup->Flags | FPF_VIRTUAL),
  2988. lpRegSetup->Rings
  2989. );
  2990. }
  2991. else
  2992. {
  2993. dwUniqueLineId = FaxDevice->PermanentLineId;
  2994. Assert(dwUniqueLineId > 0);
  2995. }
  2996. //
  2997. // allocate the LINE_INFO structure
  2998. //
  2999. LineInfo = (PLINE_INFO) MemAlloc( sizeof(LINE_INFO) );
  3000. if (!LineInfo)
  3001. {
  3002. ec = GetLastError();
  3003. DebugPrintEx(
  3004. DEBUG_ERR,
  3005. TEXT("Failed to allocate LINE_INFO (ec: %ld). DeviceId: %010d DeviceName: %s"),
  3006. GetLastError(),
  3007. DeviceIdPrefix + i,
  3008. DeviceName);
  3009. goto InitializationFailure;
  3010. }
  3011. //
  3012. // Save a pointer to it so we can free it if we crash ahead
  3013. //
  3014. lpAddedLines[*lpdwDeviceCount] = LineInfo;
  3015. //
  3016. // now assign the necessary values to the line info struct
  3017. //
  3018. LineInfo->Signature = LINE_SIGNATURE;
  3019. LineInfo->DeviceId = i;
  3020. LineInfo->TapiPermanentLineId = DeviceIdPrefix + i;
  3021. LineInfo->PermanentLineID = dwUniqueLineId;
  3022. Assert(LineInfo->PermanentLineID > 0);
  3023. LineInfo->hLine = 0;
  3024. LineInfo->Provider = (PDEVICE_PROVIDER)lpcProvider;
  3025. LineInfo->DeviceName = DeviceName; // Note: DeviceName is heap allocated and need to be freed
  3026. LineInfo->UnimodemDevice = FALSE;
  3027. LineInfo->State = FPS_AVAILABLE;
  3028. LineInfo->Csid = StringDup( FaxDevice ? FaxDevice->Csid : lpRegSetup->Csid );
  3029. LineInfo->Tsid = StringDup( FaxDevice ? FaxDevice->Tsid : lpRegSetup->Tsid );
  3030. LineInfo->lptstrDescription = FaxDevice ? StringDup(FaxDevice->lptstrDescription) : NULL;
  3031. LineInfo->RingsForAnswer = 0;
  3032. LineInfo->RingCount = 0;
  3033. LineInfo->LineStates = 0;
  3034. LineInfo->dwReceivingJobsCount = 0;
  3035. LineInfo->dwSendingJobsCount = 0;
  3036. LineInfo->LastLineClose = 0; // We do not use this for virtual devices
  3037. LineInfo->dwDeviceType = FaxDevice ? FAX_DEVICE_TYPE_OLD : FAX_DEVICE_TYPE_NEW;
  3038. LineInfo->Flags = FaxDevice ? FaxDevice->Flags : (lpRegSetup->Flags | FPF_VIRTUAL);
  3039. InsertTailList( &g_TapiLinesListHead, &LineInfo->ListEntry );
  3040. (*lpdwDeviceCount)++;
  3041. //
  3042. // Update enabled device counter
  3043. //
  3044. if (TRUE == IsDeviceEnabled(LineInfo))
  3045. {
  3046. g_dwDeviceEnabledCount += 1;
  3047. }
  3048. }
  3049. }
  3050. else
  3051. {
  3052. ec = ERROR_INVALID_FUNCTION;
  3053. DebugPrintEx(
  3054. DEBUG_ERR,
  3055. TEXT("FaxDevVirtualDeviceCreation() reported 0 devices."));
  3056. goto InitializationFailure;
  3057. }
  3058. Assert( (*lpdwDeviceCount) == VirtualDeviceCount);
  3059. Assert (0 == ec);
  3060. goto Exit;
  3061. InitializationFailure:
  3062. Assert (0 != ec);
  3063. //
  3064. // Remove the added lines
  3065. //
  3066. if (lpAddedLines)
  3067. {
  3068. for (nDevice=0 ;nDevice < VirtualDeviceCount; nDevice++)
  3069. {
  3070. if (lpAddedLines[nDevice])
  3071. {
  3072. //
  3073. // Remove the LINE_INFO from the line list
  3074. //
  3075. RemoveEntryList(&(lpAddedLines[nDevice]->ListEntry));
  3076. //
  3077. // Update enabled device counter
  3078. //
  3079. if (TRUE == IsDeviceEnabled(lpAddedLines[nDevice]))
  3080. {
  3081. Assert (g_dwDeviceEnabledCount);
  3082. g_dwDeviceEnabledCount -= 1;
  3083. }
  3084. //
  3085. // Free the memory occupied by the LINE_INFO
  3086. //
  3087. FreeTapiLine(lpAddedLines[nDevice]);
  3088. }
  3089. }
  3090. }
  3091. (*lpdwDeviceCount) = 0; // If we fail with one device then we fail with all devices.
  3092. Exit:
  3093. MemFree(lpAddedLines);
  3094. if (ec)
  3095. {
  3096. SetLastError(ec);
  3097. }
  3098. return ( 0 == ec);
  3099. }
  3100. DWORD
  3101. TapiInitialize(
  3102. PREG_FAX_SERVICE FaxReg
  3103. )
  3104. /*++
  3105. Routine Description:
  3106. This function performs all necessary TAPI initialization.
  3107. This includes device enumeration, message pump creation,
  3108. device capabilities caputure, etc. It is required that
  3109. the device provider initialization is completed before
  3110. calling this function.
  3111. Arguments:
  3112. None.
  3113. Return Value:
  3114. Error code.
  3115. --*/
  3116. {
  3117. LONG Rslt;
  3118. DWORD i,j;
  3119. LPLINEDEVCAPS LineDevCaps = NULL;
  3120. PREG_FAX_DEVICES FaxDevices = NULL;
  3121. LINEINITIALIZEEXPARAMS LineInitializeExParams;
  3122. TCHAR FaxSvcName[MAX_PATH*2]={0};
  3123. TCHAR Fname[_MAX_FNAME];
  3124. TCHAR Ext[_MAX_EXT];
  3125. DWORD LocalTapiApiVersion;
  3126. LINEEXTENSIONID lineExtensionID;
  3127. DWORD ec = 0;
  3128. DWORDLONG dwlTimeNow;
  3129. DWORD dwTapiDevices;
  3130. DEBUG_FUNCTION_NAME(TEXT("TapiInitialize"));
  3131. GetSystemTimeAsFileTime((FILETIME *)&dwlTimeNow);
  3132. if (!LoadAdaptiveFileBuffer()) // Note: allocates AdaptiveFileBuffer (take care to delete it if error occurs later on)
  3133. {
  3134. if ( ERROR_FILE_NOT_FOUND == GetLastError() )
  3135. {
  3136. //
  3137. // We can live without the adaptive file buffer.
  3138. //
  3139. DebugPrintEx(
  3140. DEBUG_WRN,
  3141. TEXT("AdaptiveFileBuffer (faxadapt.lst) not found."));
  3142. ec = 0;
  3143. }
  3144. else
  3145. {
  3146. //
  3147. // This is an unexpected error (no memory , file system error) we exit.
  3148. //
  3149. ec = GetLastError();
  3150. DebugPrintEx(
  3151. DEBUG_ERR,
  3152. TEXT("LoadAdaptiveFileBuffer() failed (ec: %ld)"),
  3153. ec);
  3154. goto Error;
  3155. }
  3156. }
  3157. //
  3158. // we need to hold onto this cs until tapi is up and ready to serve
  3159. //
  3160. EnterCriticalSection( &g_CsLine );
  3161. //
  3162. // initialize tapi
  3163. //
  3164. g_TapiCompletionPort = CreateIoCompletionPort(
  3165. INVALID_HANDLE_VALUE,
  3166. NULL,
  3167. 0,
  3168. 1
  3169. );
  3170. if (!g_TapiCompletionPort)
  3171. {
  3172. ec = GetLastError();
  3173. DebugPrintEx(
  3174. DEBUG_ERR,
  3175. TEXT("CreateIoCompletionPort() failed (ec: %ld)"),
  3176. ec);
  3177. LeaveCriticalSection( &g_CsLine );
  3178. goto Error;
  3179. }
  3180. LineInitializeExParams.dwTotalSize = sizeof(LINEINITIALIZEEXPARAMS);
  3181. LineInitializeExParams.dwNeededSize = 0;
  3182. LineInitializeExParams.dwUsedSize = 0;
  3183. LineInitializeExParams.dwOptions = LINEINITIALIZEEXOPTION_USECOMPLETIONPORT;
  3184. LineInitializeExParams.Handles.hCompletionPort = g_TapiCompletionPort;
  3185. LineInitializeExParams.dwCompletionKey = TAPI_COMPLETION_KEY;
  3186. LocalTapiApiVersion = MAX_TAPI_API_VER;
  3187. Rslt = lineInitializeEx(
  3188. &g_hLineApp,
  3189. GetModuleHandle(NULL),
  3190. NULL,
  3191. FAX_SERVICE_DISPLAY_NAME,
  3192. &dwTapiDevices,
  3193. &LocalTapiApiVersion,
  3194. &LineInitializeExParams
  3195. );
  3196. if (Rslt != 0)
  3197. {
  3198. ec = Rslt;
  3199. DebugPrintEx(
  3200. DEBUG_ERR,
  3201. TEXT("lineInitializeEx() failed devices=%d (ec: %ld)"),
  3202. dwTapiDevices,
  3203. ec);
  3204. LeaveCriticalSection( &g_CsLine );
  3205. goto Error;
  3206. }
  3207. if (LocalTapiApiVersion < MIN_TAPI_API_VER)
  3208. {
  3209. ec = LINEERR_INCOMPATIBLEAPIVERSION;
  3210. DebugPrintEx(
  3211. DEBUG_ERR,
  3212. TEXT("Unsupported TAPI API ver (Ver: %ld)"),
  3213. LocalTapiApiVersion);
  3214. LeaveCriticalSection( &g_CsLine );
  3215. goto Error;
  3216. }
  3217. if (!GetModuleFileName( NULL, FaxSvcName, ARR_SIZE(FaxSvcName)))
  3218. {
  3219. ec = GetLastError();
  3220. DebugPrintEx(
  3221. DEBUG_ERR,
  3222. TEXT("GetModuleFileName for fax service module failed (ec: %ld)"),
  3223. ec);
  3224. LeaveCriticalSection( &g_CsLine );
  3225. goto Error;
  3226. }
  3227. else
  3228. {
  3229. _tsplitpath( FaxSvcName, NULL, NULL, Fname, Ext );
  3230. _stprintf( FaxSvcName, TEXT("%s%s"), Fname, Ext );
  3231. Rslt = lineSetAppPriority(
  3232. FaxSvcName,
  3233. LINEMEDIAMODE_UNKNOWN,
  3234. 0,
  3235. 0,
  3236. NULL,
  3237. 1
  3238. );
  3239. Rslt = lineSetAppPriority(
  3240. FaxSvcName,
  3241. LINEMEDIAMODE_DATAMODEM,
  3242. 0,
  3243. 0,
  3244. NULL,
  3245. 1
  3246. );
  3247. if (Rslt != 0)
  3248. {
  3249. ec = Rslt;
  3250. DebugPrintEx(
  3251. DEBUG_ERR,
  3252. TEXT("lineSetAppPriority() failed (ec: %ld)"),
  3253. ec );
  3254. LeaveCriticalSection( &g_CsLine );
  3255. goto Error;
  3256. }
  3257. }
  3258. //
  3259. // add any new devices to the registry
  3260. //
  3261. FaxDevices = GetFaxDevicesRegistry();
  3262. if (!FaxDevices)
  3263. {
  3264. DebugPrintEx(
  3265. DEBUG_ERR,
  3266. TEXT("GetFaxDevicesRegistry() failed in TapiInitialize. continueing to add devices into registry")
  3267. );
  3268. }
  3269. for (i = 0; i < dwTapiDevices; i++)
  3270. {
  3271. Rslt = lineNegotiateAPIVersion
  3272. (
  3273. g_hLineApp,
  3274. i,
  3275. MIN_TAPI_LINE_API_VER,
  3276. MAX_TAPI_LINE_API_VER,
  3277. &LocalTapiApiVersion,
  3278. &lineExtensionID
  3279. );
  3280. if (Rslt == 0)
  3281. {
  3282. LineDevCaps = SmartLineGetDevCaps (g_hLineApp, i, LocalTapiApiVersion );
  3283. if (LineDevCaps)
  3284. {
  3285. if (!AddNewDevice( i, LineDevCaps, TRUE , FaxDevices))
  3286. {
  3287. DebugPrintEx(
  3288. DEBUG_WRN,
  3289. TEXT("AddNewDevice() failed for device id: %ld (ec: %ld)"),
  3290. i,
  3291. GetLastError());
  3292. MemFree( LineDevCaps );
  3293. }
  3294. else
  3295. {
  3296. MemFree( LineDevCaps );
  3297. }
  3298. }
  3299. else
  3300. {
  3301. DebugPrintEx(
  3302. DEBUG_ERR,
  3303. TEXT("SmartLineGetDevCaps failed for device id: %ld (ec: %ld)"),
  3304. i,
  3305. GetLastError());
  3306. Assert(FALSE);
  3307. }
  3308. }
  3309. else
  3310. {
  3311. DebugPrintEx(
  3312. DEBUG_WRN,
  3313. TEXT("lineNegotiateAPIVersion() failed for device id: %ld (ec: %ld)"),
  3314. i,
  3315. GetLastError());
  3316. }
  3317. }
  3318. //
  3319. // Delete any devices that need deletion
  3320. //
  3321. for (j = 0; j < FaxDevices->DeviceCount; j++)
  3322. {
  3323. //
  3324. // skip any devices not created by us (created by FSPs) and virtual devices
  3325. //
  3326. if(!FaxDevices->Devices[j].bValidDevice ||
  3327. FaxDevices->Devices[j].Flags & FPF_VIRTUAL) // Cache is not supported for VFSPs
  3328. {
  3329. continue;
  3330. }
  3331. if(!FaxDevices->Devices[j].DeviceInstalled)
  3332. {
  3333. //
  3334. // update "LastDetected" field on installed devices
  3335. //
  3336. MoveDeviceRegIntoDeviceCache(
  3337. FaxDevices->Devices[j].PermanentLineId,
  3338. FaxDevices->Devices[j].TapiPermanentLineID,
  3339. (FaxDevices->Devices[j].PermanentLineId == g_dwManualAnswerDeviceId));
  3340. }
  3341. }
  3342. //
  3343. // Cache cleanning
  3344. //
  3345. CleanOldDevicesFromDeviceCache(dwlTimeNow);
  3346. if (!GetCountries())
  3347. {
  3348. DebugPrintEx(
  3349. DEBUG_WRN,
  3350. TEXT("Can't init Countries list"));
  3351. if (!(ec = GetLastError()))
  3352. ec = ERROR_GEN_FAILURE;
  3353. LeaveCriticalSection( &g_CsLine );
  3354. goto Error;
  3355. }
  3356. LeaveCriticalSection( &g_CsLine );
  3357. goto Exit;
  3358. Error:
  3359. if (g_hLineApp)
  3360. {
  3361. Rslt = lineShutdown(g_hLineApp);
  3362. if (Rslt)
  3363. {
  3364. DebugPrintEx(
  3365. DEBUG_ERR,
  3366. TEXT("lineShutdown() failed (ec: %ld)"),
  3367. Rslt);
  3368. Assert(FALSE);
  3369. }
  3370. g_hLineApp = NULL;
  3371. }
  3372. if (g_TapiCompletionPort)
  3373. {
  3374. if (!CloseHandle( g_TapiCompletionPort ))
  3375. {
  3376. DebugPrintEx(
  3377. DEBUG_ERR,
  3378. TEXT("CloseHandle( g_TapiCompletionPort ) failed (ec: %ld)"),
  3379. GetLastError());
  3380. Assert(FALSE);
  3381. }
  3382. g_TapiCompletionPort = NULL;
  3383. }
  3384. MemFree(g_pAdaptiveFileBuffer);
  3385. g_pAdaptiveFileBuffer = NULL;
  3386. Exit:
  3387. FreeFaxDevicesRegistry( FaxDevices );
  3388. return ec;
  3389. }
  3390. BOOL LoadAdaptiveFileBuffer()
  3391. {
  3392. DWORD ec = 0;
  3393. DWORD i, j;
  3394. HANDLE AdaptiveFileHandle = INVALID_HANDLE_VALUE;
  3395. LPTSTR AdaptiveFileName = NULL;
  3396. DEBUG_FUNCTION_NAME(TEXT("LoadAdaptiveFileBuffer"));
  3397. //
  3398. // open faxadapt.lst file to decide on enabling rx
  3399. //
  3400. g_pAdaptiveFileBuffer = NULL;
  3401. AdaptiveFileName = ExpandEnvironmentString( TEXT("%systemroot%\\system32\\faxadapt.lst") );
  3402. if (!AdaptiveFileName)
  3403. {
  3404. ec = GetLastError();
  3405. DebugPrintEx(
  3406. DEBUG_ERR,
  3407. TEXT("ExpandEnvironmentString(\"%systemroot%\\system32\\faxadapt.lst\") failed (ec: %ld)"),
  3408. GetLastError());
  3409. goto Error;
  3410. }
  3411. AdaptiveFileHandle = SafeCreateFile(
  3412. AdaptiveFileName,
  3413. GENERIC_READ,
  3414. FILE_SHARE_READ,
  3415. NULL,
  3416. OPEN_EXISTING,
  3417. 0,
  3418. NULL);
  3419. if (AdaptiveFileHandle == INVALID_HANDLE_VALUE )
  3420. {
  3421. ec = GetLastError();
  3422. DebugPrintEx(
  3423. DEBUG_ERR,
  3424. TEXT("Could not open adaptive file [%s] (ec: %ld)"),
  3425. _tcslwr(AdaptiveFileName),
  3426. ec);
  3427. goto Error;
  3428. }
  3429. i = GetFileSize( AdaptiveFileHandle, NULL );
  3430. if (i != 0xffffffff)
  3431. {
  3432. g_pAdaptiveFileBuffer = (LPBYTE)MemAlloc( i + 16 );
  3433. if (!g_pAdaptiveFileBuffer)
  3434. {
  3435. ec = GetLastError();
  3436. DebugPrintEx(
  3437. DEBUG_ERR,
  3438. TEXT("Failed to allocated g_pAdaptiveFileBuffer (%ld bytes) (ec: %ld)"),
  3439. i + 16,
  3440. ec);
  3441. goto Error;
  3442. }
  3443. if (!ReadFile( AdaptiveFileHandle, g_pAdaptiveFileBuffer, i, &j, NULL ) ) {
  3444. ec = GetLastError();
  3445. DebugPrintEx(
  3446. DEBUG_ERR,
  3447. TEXT("Could not read adaptive file [%s] (ec: %ld)"),
  3448. _tcslwr(AdaptiveFileName),
  3449. ec);
  3450. goto Error;
  3451. } else {
  3452. g_pAdaptiveFileBuffer[j] = 0; // need a string
  3453. }
  3454. }
  3455. Assert (0 == ec);
  3456. goto Exit;
  3457. Error:
  3458. MemFree( g_pAdaptiveFileBuffer );
  3459. g_pAdaptiveFileBuffer = NULL;
  3460. Exit:
  3461. MemFree( AdaptiveFileName);
  3462. if (AdaptiveFileHandle != INVALID_HANDLE_VALUE)
  3463. {
  3464. CloseHandle( AdaptiveFileHandle );
  3465. }
  3466. if (ec) {
  3467. SetLastError(ec);
  3468. }
  3469. return (0 == ec);
  3470. }
  3471. LONG
  3472. MyLineTranslateAddress(
  3473. LPCTSTR Address,
  3474. DWORD DeviceId,
  3475. LPLINETRANSLATEOUTPUT *TranslateOutput
  3476. )
  3477. {
  3478. DWORD LineTransOutSize;
  3479. LONG Rslt = ERROR_SUCCESS;
  3480. DEBUG_FUNCTION_NAME(_T("MyLineTranslateAddress"));
  3481. //
  3482. // allocate the initial linetranscaps structure
  3483. //
  3484. LineTransOutSize = sizeof(LINETRANSLATEOUTPUT) + 4096;
  3485. *TranslateOutput = (LPLINETRANSLATEOUTPUT) MemAlloc( LineTransOutSize );
  3486. if (!*TranslateOutput)
  3487. {
  3488. DebugPrintEx(DEBUG_ERR, TEXT("MemAlloc() failed, sz=0x%08x"), LineTransOutSize);
  3489. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  3490. goto exit;
  3491. }
  3492. (*TranslateOutput)->dwTotalSize = LineTransOutSize;
  3493. Rslt = lineTranslateAddress(
  3494. g_hLineApp,
  3495. 0,
  3496. MAX_TAPI_API_VER,
  3497. Address,
  3498. 0,
  3499. LINETRANSLATEOPTION_CANCELCALLWAITING,
  3500. *TranslateOutput
  3501. );
  3502. if (Rslt != 0)
  3503. {
  3504. DebugPrintEx(DEBUG_ERR, TEXT("lineGetTranslateAddress() failed, ec=0x%08x"), Rslt);
  3505. goto exit;
  3506. }
  3507. if ((*TranslateOutput)->dwNeededSize > (*TranslateOutput)->dwTotalSize)
  3508. {
  3509. //
  3510. // re-allocate the LineTransCaps structure
  3511. //
  3512. LineTransOutSize = (*TranslateOutput)->dwNeededSize;
  3513. MemFree( *TranslateOutput );
  3514. *TranslateOutput = (LPLINETRANSLATEOUTPUT) MemAlloc( LineTransOutSize );
  3515. if (!*TranslateOutput)
  3516. {
  3517. DebugPrintEx(DEBUG_ERR, TEXT("MemAlloc() failed, sz=0x%08x"), LineTransOutSize);
  3518. Rslt = ERROR_NOT_ENOUGH_MEMORY;
  3519. goto exit;
  3520. }
  3521. (*TranslateOutput)->dwTotalSize = LineTransOutSize;
  3522. Rslt = lineTranslateAddress(
  3523. g_hLineApp,
  3524. 0,
  3525. MAX_TAPI_API_VER,
  3526. Address,
  3527. 0,
  3528. LINETRANSLATEOPTION_CANCELCALLWAITING,
  3529. *TranslateOutput
  3530. );
  3531. if (Rslt != 0)
  3532. {
  3533. DebugPrintEx(DEBUG_ERR, TEXT("lineGetTranslateAddress() failed, ec=0x%08x"), Rslt);
  3534. goto exit;
  3535. }
  3536. }
  3537. exit:
  3538. if (Rslt != ERROR_SUCCESS)
  3539. {
  3540. MemFree( *TranslateOutput );
  3541. *TranslateOutput = NULL;
  3542. }
  3543. return Rslt;
  3544. }
  3545. BOOL CreateTapiThread(void)
  3546. {
  3547. DWORD ThreadId;
  3548. DWORD ec = ERROR_SUCCESS;
  3549. DEBUG_FUNCTION_NAME(TEXT("CreateTapiThread"));
  3550. g_hTapiWorkerThread = CreateThread(
  3551. NULL,
  3552. 0,
  3553. (LPTHREAD_START_ROUTINE) TapiWorkerThread,
  3554. NULL,
  3555. 0,
  3556. &ThreadId
  3557. );
  3558. if (!g_hTapiWorkerThread)
  3559. {
  3560. ec = GetLastError();
  3561. DebugPrintEx(
  3562. DEBUG_ERR,
  3563. TEXT("Could not start TapiWorkerThread (CreateThread)(ec: %ld)"),
  3564. ec);
  3565. goto Error;
  3566. }
  3567. Assert (ERROR_SUCCESS == ec);
  3568. goto Exit;
  3569. Error:
  3570. Assert (ERROR_SUCCESS != ec);
  3571. Exit:
  3572. //
  3573. // freeServiceGlobals is responsible of closing the threads handle
  3574. //
  3575. if (ec)
  3576. {
  3577. SetLastError(ec);
  3578. }
  3579. return (ERROR_SUCCESS == ec);
  3580. }
  3581. DWORD
  3582. GetDeviceListByCountryAndAreaCode(
  3583. DWORD dwCountryCode,
  3584. DWORD dwAreaCode,
  3585. LPDWORD* lppdwDevices,
  3586. LPDWORD lpdwNumDevices
  3587. )
  3588. /*++
  3589. Routine name : GetDeviceListByCountryAndAreaCode
  3590. Routine description:
  3591. Returns an ordered list of devices that are a rule destination.
  3592. The rule is specified by country and area code.
  3593. The caller must call MemFree() to deallocate memory.
  3594. Author:
  3595. Oded Sacher (OdedS), Dec, 1999
  3596. Arguments:
  3597. dwCountryCode [in ] - Country code
  3598. dwAreaCode [in ] - Area code
  3599. lppdwDevices [out ] - Pointer to recieve the device list
  3600. lpdwNumDevices [out ] - pointer to recieve the number of devices in the list
  3601. Return Value:
  3602. Standard win32 error code
  3603. --*/
  3604. {
  3605. DEBUG_FUNCTION_NAME(TEXT("GetDeviceListByCountryAndAreaCode"));
  3606. DWORD ec = ERROR_SUCCESS;
  3607. Assert (lppdwDevices && lpdwNumDevices);
  3608. CDialingLocation DialingLocation(dwCountryCode, dwAreaCode);
  3609. //
  3610. // Search for CountryCode.AreaCode
  3611. //
  3612. PCRULE pCRule = g_pRulesMap->FindRule (DialingLocation);
  3613. if (NULL == pCRule)
  3614. {
  3615. ec = GetLastError();
  3616. if (FAX_ERR_RULE_NOT_FOUND != ec)
  3617. {
  3618. DebugPrintEx(
  3619. DEBUG_ERR,
  3620. TEXT("COutboundRulesMap::FindRule failed with error %ld"),
  3621. ec);
  3622. goto exit;
  3623. }
  3624. //
  3625. // Search for CountryCode.*
  3626. //
  3627. DialingLocation = CDialingLocation(dwCountryCode, ROUTING_RULE_AREA_CODE_ANY);
  3628. pCRule = g_pRulesMap->FindRule (DialingLocation);
  3629. if (NULL == pCRule)
  3630. {
  3631. ec = GetLastError();
  3632. if (FAX_ERR_RULE_NOT_FOUND != ec)
  3633. {
  3634. DebugPrintEx(
  3635. DEBUG_ERR,
  3636. TEXT("COutboundRulesMap::FindRule failed with error %ld"),
  3637. ec);
  3638. goto exit;
  3639. }
  3640. //
  3641. // Search for *.*
  3642. //
  3643. DialingLocation = CDialingLocation(ROUTING_RULE_COUNTRY_CODE_ANY, ROUTING_RULE_AREA_CODE_ANY);
  3644. pCRule = g_pRulesMap->FindRule (DialingLocation);
  3645. if (NULL == pCRule)
  3646. {
  3647. ec = GetLastError();
  3648. if (FAX_ERR_RULE_NOT_FOUND != ec)
  3649. {
  3650. DebugPrintEx(
  3651. DEBUG_ERR,
  3652. TEXT("COutboundRulesMap::FindRule failed with error %ld"),
  3653. ec);
  3654. goto exit;
  3655. }
  3656. }
  3657. }
  3658. }
  3659. if (NULL == pCRule)
  3660. {
  3661. // No rule found!!!
  3662. DebugPrintEx(
  3663. DEBUG_MSG,
  3664. TEXT("No outbound routing rule found"));
  3665. *lppdwDevices = NULL;
  3666. *lpdwNumDevices = 0;
  3667. ec = ERROR_NOT_FOUND;
  3668. Assert (NULL != pCRule) // Assert (FALSE)
  3669. goto exit;
  3670. }
  3671. else
  3672. {
  3673. ec = pCRule->GetDeviceList (lppdwDevices, lpdwNumDevices);
  3674. if (ERROR_SUCCESS != ec)
  3675. {
  3676. DebugPrintEx(
  3677. DEBUG_ERR,
  3678. TEXT("COutboundRule::GetDeviceList failed with error %ld"),
  3679. ec);
  3680. goto exit;
  3681. }
  3682. }
  3683. Assert (ERROR_SUCCESS == ec);
  3684. exit:
  3685. return ec;
  3686. }
  3687. BOOL
  3688. IsAreaCodeMandatory(
  3689. LPLINECOUNTRYLIST lpCountryList,
  3690. DWORD dwCountryCode
  3691. )
  3692. /*++
  3693. Routine name : IsAreaCodeMandatory
  3694. Routine description:
  3695. Checks if an area code is mandatory for a specific country
  3696. Author:
  3697. Oded Sacher (OdedS), Dec, 1999
  3698. Arguments:
  3699. lpCountryList [in ] - Pointer to LINECOUNTRYLIST list, returned from a call to LineGetCountry
  3700. dwCountryCode [in ] - The country country code.
  3701. Return Value:
  3702. TRUE - The area code is needed.
  3703. FALSE - The area code is not mandatory.
  3704. --*/
  3705. {
  3706. DEBUG_FUNCTION_NAME(TEXT("IsAreaCodeMandatory"));
  3707. LPLINECOUNTRYENTRY lpEntry = NULL;
  3708. DWORD dwIndex;
  3709. Assert (lpCountryList);
  3710. lpEntry = (LPLINECOUNTRYENTRY) // init array of entries
  3711. ((PBYTE) lpCountryList + lpCountryList->dwCountryListOffset);
  3712. for (dwIndex=0; dwIndex < lpCountryList->dwNumCountries; dwIndex++)
  3713. {
  3714. if (lpEntry[dwIndex].dwCountryCode == dwCountryCode)
  3715. {
  3716. //
  3717. // Matching country code - Check long distance rule.
  3718. //
  3719. if (lpEntry[dwIndex].dwLongDistanceRuleSize && lpEntry[dwIndex].dwLongDistanceRuleOffset )
  3720. {
  3721. LPWSTR lpwstrLongDistanceDialingRule = (LPWSTR)((LPBYTE)lpCountryList +
  3722. lpEntry[dwIndex].dwLongDistanceRuleOffset);
  3723. if (wcschr(lpwstrLongDistanceDialingRule, TEXT('F')) != NULL)
  3724. {
  3725. return TRUE;
  3726. }
  3727. return FALSE;
  3728. }
  3729. }
  3730. }
  3731. return FALSE;
  3732. }
  3733. VOID
  3734. UpdateReceiveEnabledDevicesCount ()
  3735. /*++
  3736. Routine name : UpdateReceiveEnabledDevicesCount
  3737. Routine description:
  3738. Updates the counter of the number of devices that are enabled to receive faxes
  3739. Author:
  3740. Eran Yariv (EranY), Jul, 2000
  3741. Arguments:
  3742. Return Value:
  3743. None
  3744. --*/
  3745. {
  3746. PLIST_ENTRY pNext;
  3747. DWORD dwOldCount;
  3748. BOOL fManualDeviceFound = FALSE;
  3749. DEBUG_FUNCTION_NAME(TEXT("UpdateReceiveEnabledDevicesCount"));
  3750. #if DBG
  3751. DWORD dwEnabledDevices = 0;
  3752. DWORD dwDevices = 0;
  3753. #endif
  3754. EnterCriticalSection( &g_CsLine );
  3755. dwOldCount = g_dwReceiveDevicesCount;
  3756. g_dwReceiveDevicesCount = 0;
  3757. pNext = g_TapiLinesListHead.Flink;
  3758. while ((ULONG_PTR)pNext != (ULONG_PTR)&g_TapiLinesListHead)
  3759. {
  3760. PLINE_INFO pLineInfo = CONTAINING_RECORD( pNext, LINE_INFO, ListEntry );
  3761. pNext = pLineInfo->ListEntry.Flink;
  3762. if (g_dwManualAnswerDeviceId == pLineInfo->PermanentLineID)
  3763. {
  3764. fManualDeviceFound = TRUE;
  3765. }
  3766. if ((pLineInfo->Flags) & FPF_RECEIVE)
  3767. {
  3768. if (g_dwManualAnswerDeviceId == pLineInfo->PermanentLineID)
  3769. {
  3770. DebugPrintEx(DEBUG_WRN,
  3771. TEXT("Device %ld is set to auto-receive AND manual-receive. Canceling the manual-receive for it"),
  3772. g_dwManualAnswerDeviceId);
  3773. g_dwManualAnswerDeviceId = 0;
  3774. DWORD dwRes = WriteManualAnswerDeviceId (g_dwManualAnswerDeviceId);
  3775. if (ERROR_SUCCESS != dwRes)
  3776. {
  3777. DebugPrintEx(
  3778. DEBUG_ERR,
  3779. TEXT("WriteManualAnswerDeviceId(0) (ec: %lc)"),
  3780. dwRes);
  3781. }
  3782. }
  3783. g_dwReceiveDevicesCount++;
  3784. }
  3785. #if DBG
  3786. if (TRUE == IsDeviceEnabled(pLineInfo))
  3787. {
  3788. dwEnabledDevices += 1;
  3789. }
  3790. dwDevices += 1;
  3791. #endif
  3792. }
  3793. #if DBG
  3794. Assert (dwEnabledDevices == g_dwDeviceEnabledCount);
  3795. Assert (dwDevices == g_dwDeviceCount);
  3796. #endif
  3797. if (FALSE == fManualDeviceFound &&
  3798. 0 != g_dwManualAnswerDeviceId)
  3799. {
  3800. //
  3801. // There manual answer device id is not valid
  3802. //
  3803. g_dwManualAnswerDeviceId = 0;
  3804. DWORD dwRes = WriteManualAnswerDeviceId (g_dwManualAnswerDeviceId);
  3805. if (ERROR_SUCCESS != dwRes)
  3806. {
  3807. DebugPrintEx(
  3808. DEBUG_ERR,
  3809. TEXT("WriteManualAnswerDeviceId(0) (ec: %lc)"),
  3810. dwRes);
  3811. }
  3812. }
  3813. DebugPrintEx(DEBUG_MSG,
  3814. TEXT("Number of receive-enabled devices is now %ld"),
  3815. g_dwReceiveDevicesCount);
  3816. LeaveCriticalSection( &g_CsLine );
  3817. } // UpdateReceiveEnabledDevicesCount
  3818. BOOL
  3819. RemoveTapiDevice(
  3820. DWORD dwDeviceId
  3821. )
  3822. {
  3823. DWORD ec = ERROR_SUCCESS;
  3824. BOOL rVal = TRUE;
  3825. PLINE_INFO pLineInfo = NULL;
  3826. PLIST_ENTRY Next;
  3827. DWORD dwPermanentTapiDeviceId;
  3828. DWORD dwPermanentLineID;
  3829. BOOL fFound = FALSE;
  3830. DEBUG_FUNCTION_NAME(TEXT("RemoveTapiDevice"));
  3831. Next = g_TapiLinesListHead.Flink;
  3832. Assert (Next);
  3833. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  3834. {
  3835. pLineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  3836. Next = pLineInfo->ListEntry.Flink;
  3837. if (!(pLineInfo->Flags & FPF_VIRTUAL) && // Virtual devices may have the same device id (device index) as the Tapi session id
  3838. // We do not support removal of VFSP device
  3839. dwDeviceId == pLineInfo->DeviceId)
  3840. {
  3841. dwPermanentTapiDeviceId = pLineInfo->TapiPermanentLineId;
  3842. dwPermanentLineID = pLineInfo->PermanentLineID;
  3843. fFound = TRUE;
  3844. break;
  3845. }
  3846. }
  3847. if (FALSE == fFound)
  3848. {
  3849. //
  3850. // Can be if for some reason the device was not added.
  3851. //
  3852. DebugPrintEx(
  3853. DEBUG_WRN,
  3854. TEXT("failed to find line for device id: %ld)"),
  3855. dwDeviceId);
  3856. SetLastError(ERROR_NOT_FOUND);
  3857. return FALSE;
  3858. }
  3859. RemoveEntryList (&pLineInfo->ListEntry);
  3860. InsertTailList (&g_RemovedTapiLinesListHead, &pLineInfo->ListEntry);
  3861. Assert (g_dwDeviceCount);
  3862. g_dwDeviceCount -= 1;
  3863. MoveDeviceRegIntoDeviceCache(
  3864. dwPermanentLineID,
  3865. dwPermanentTapiDeviceId,
  3866. (dwPermanentLineID == g_dwManualAnswerDeviceId));
  3867. //
  3868. // Update Enabled devices count
  3869. //
  3870. if (TRUE == IsDeviceEnabled(pLineInfo))
  3871. {
  3872. Assert (g_dwDeviceEnabledCount);
  3873. g_dwDeviceEnabledCount -= 1;
  3874. }
  3875. if (dwPermanentLineID == g_dwManualAnswerDeviceId)
  3876. {
  3877. g_dwManualAnswerDeviceId = 0;
  3878. DWORD dwRes = WriteManualAnswerDeviceId (g_dwManualAnswerDeviceId);
  3879. if (ERROR_SUCCESS != dwRes)
  3880. {
  3881. DebugPrintEx(
  3882. DEBUG_ERR,
  3883. TEXT("WriteManualAnswerDeviceId(0) (ec: %lc)"),
  3884. dwRes);
  3885. }
  3886. }
  3887. ec = g_pTAPIDevicesIdsMap->RemoveDevice (dwPermanentTapiDeviceId);
  3888. if (ERROR_SUCCESS != ec)
  3889. {
  3890. DebugPrintEx(
  3891. DEBUG_WRN,
  3892. TEXT("g_pTAPIDevicesIdsMap->RemoveDevice() failed for Tapi device id: %ld (ec: %ld)"),
  3893. dwPermanentTapiDeviceId,
  3894. ec);
  3895. rVal = FALSE;
  3896. }
  3897. //
  3898. // Update outbound routing
  3899. //
  3900. ec = g_pGroupsMap->RemoveDevice(dwPermanentLineID);
  3901. if (ERROR_SUCCESS != ec)
  3902. {
  3903. DebugPrintEx(
  3904. DEBUG_ERR,
  3905. TEXT("COutboundRoutingGroupsMap::RemoveDevice() failed (ec: %ld)"),
  3906. ec);
  3907. rVal = FALSE;
  3908. }
  3909. if (TRUE == rVal)
  3910. {
  3911. DWORD dwRes = CreateConfigEvent (FAX_CONFIG_TYPE_DEVICES);
  3912. if (ERROR_SUCCESS != dwRes)
  3913. {
  3914. DebugPrintEx(
  3915. DEBUG_ERR,
  3916. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_DEVICES) (ec: %lc)"),
  3917. dwRes);
  3918. }
  3919. dwRes = CreateConfigEvent (FAX_CONFIG_TYPE_OUT_GROUPS);
  3920. if (ERROR_SUCCESS != dwRes)
  3921. {
  3922. DebugPrintEx(
  3923. DEBUG_ERR,
  3924. TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_OUT_GROUPS) (ec: %lc)"),
  3925. dwRes);
  3926. }
  3927. }
  3928. else
  3929. {
  3930. Assert (ERROR_SUCCESS != ec);
  3931. SetLastError(ec);
  3932. }
  3933. return rVal;
  3934. }
  3935. BOOL
  3936. IsDeviceEnabled(
  3937. PLINE_INFO pLineInfo
  3938. )
  3939. /*++
  3940. Routine name : IsDeviceEnabled
  3941. Routine description:
  3942. Checks if a device is send or receive or manual receive enabled
  3943. Must be called inside G_CsLine
  3944. Author:
  3945. Oded Sacher (OdedS), Feb, 2001
  3946. Arguments:
  3947. Return Value:
  3948. TRUE if enabled. FALSE if not
  3949. --*/
  3950. {
  3951. Assert (pLineInfo);
  3952. if ((pLineInfo->Flags & FPF_RECEIVE) ||
  3953. (pLineInfo->Flags & FPF_SEND) ||
  3954. pLineInfo->PermanentLineID == g_dwManualAnswerDeviceId)
  3955. {
  3956. //
  3957. // The device was send/receive/manual receive enabled
  3958. //
  3959. return TRUE;
  3960. }
  3961. return FALSE;
  3962. }
  3963. /*++
  3964. Routine name : CleanOldDevicesFromDeviceCache
  3965. Routine description:
  3966. The routine scan the device-cache and remove old entries (by DEFAULT_REGVAL_MISSING_DEVICE_LIFETIME constant).
  3967. Author:
  3968. Caliv Nir (t-nicali), Apr, 2001
  3969. Arguments:
  3970. dwlTimeNow [in] - current time in UTC ( result of GetSystemTimeAsFileTime )
  3971. Return Value:
  3972. ERROR_SUCCESS - when all devices was checked and cleaned
  3973. --*/
  3974. DWORD
  3975. CleanOldDevicesFromDeviceCache(DWORDLONG dwlTimeNow)
  3976. {
  3977. DWORDLONG dwOldestDate = dwlTimeNow - DEFAULT_REGVAL_MISSING_DEVICE_LIFETIME; // oldest date allowed for cache device
  3978. HKEY hKeyCache = NULL;
  3979. DWORDLONG* pDeviceDate;
  3980. DWORD dwDataSize = sizeof(DWORDLONG);
  3981. DWORD dwTapiPermanentLineID;
  3982. DWORD dwKeyNameLen;
  3983. DWORD dwIndex ;
  3984. DWORD dwRes = ERROR_SUCCESS;
  3985. PTSTR pszKeyName= NULL;
  3986. vector<DWORD> vecCacheEntryForDeletion;
  3987. DEBUG_FUNCTION_NAME(TEXT("CleanOldDevicesFromDeviceCache"));
  3988. // open cache registry entry
  3989. hKeyCache = OpenRegistryKey( HKEY_LOCAL_MACHINE, REGKEY_FAX_DEVICES_CACHE, FALSE, KEY_READ );
  3990. if (!hKeyCache)
  3991. {
  3992. //
  3993. // No Device cache is present yet
  3994. //
  3995. dwRes = GetLastError();
  3996. DebugPrintEx(
  3997. DEBUG_WRN,
  3998. TEXT("OpenRegistryKey failed with [%lu] for [%s] . Device cache still wasn't created."),
  3999. dwRes,
  4000. REGKEY_FAX_DEVICES_CACHE
  4001. );
  4002. return dwRes;
  4003. }
  4004. // get length of longest key name in characrter
  4005. DWORD dwMaxSubKeyLen;
  4006. dwRes = RegQueryInfoKey(hKeyCache, NULL, NULL, NULL, NULL, &dwMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
  4007. if ( ERROR_SUCCESS != dwRes)
  4008. {
  4009. DebugPrintEx(
  4010. DEBUG_ERR,
  4011. TEXT("RegQueryInfoKey failed with [%lu] for [%s]."),
  4012. dwRes,
  4013. REGKEY_FAX_DEVICES_CACHE
  4014. );
  4015. goto Exit;
  4016. }
  4017. // Add one for the NULL terminator
  4018. dwMaxSubKeyLen++;
  4019. // Allocate buffer for subkey names
  4020. pszKeyName = (PTSTR) MemAlloc(dwMaxSubKeyLen * sizeof(TCHAR));
  4021. if ( NULL == pszKeyName )
  4022. {
  4023. DebugPrintEx(
  4024. DEBUG_ERR,
  4025. TEXT("MemAlloc failure")
  4026. );
  4027. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  4028. goto Exit;
  4029. }
  4030. // Store buffer length
  4031. dwKeyNameLen = dwMaxSubKeyLen;
  4032. // Start from the begining
  4033. dwIndex = 0;
  4034. while ( ERROR_SUCCESS == RegEnumKeyEx(hKeyCache, dwIndex++, pszKeyName, &dwKeyNameLen, NULL, NULL, NULL, NULL) )
  4035. {
  4036. HKEY hKeyDevice;
  4037. hKeyDevice = OpenRegistryKey( hKeyCache, pszKeyName, FALSE, KEY_READ );
  4038. if (!hKeyDevice)
  4039. {
  4040. DebugPrintEx(
  4041. DEBUG_WRN,
  4042. TEXT("OpenRegistryKey failed for [%s]."),
  4043. pszKeyName
  4044. );
  4045. goto Next;
  4046. }
  4047. //
  4048. // get caching time
  4049. //
  4050. pDeviceDate = (DWORDLONG *)GetRegistryBinary(hKeyDevice, REGVAL_LAST_DETECTED_TIME, &dwDataSize);
  4051. if ( (NULL == pDeviceDate) || (*pDeviceDate < dwOldestDate) )
  4052. {
  4053. //
  4054. // mark for deletion old or illegal cache-entry
  4055. //
  4056. if ( 1 == _stscanf( pszKeyName, TEXT("%lx"),&dwTapiPermanentLineID ) )
  4057. {
  4058. try
  4059. {
  4060. vecCacheEntryForDeletion.push_back(dwTapiPermanentLineID);
  4061. }
  4062. catch (exception &ex)
  4063. {
  4064. DebugPrintEx(
  4065. DEBUG_ERR,
  4066. TEXT("push back failed throwing an exception: %S"),
  4067. ex.what()
  4068. );
  4069. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  4070. MemFree(pDeviceDate);
  4071. RegCloseKey (hKeyDevice);
  4072. goto Exit;
  4073. }
  4074. }
  4075. else
  4076. {
  4077. DebugPrintEx(
  4078. DEBUG_WRN,
  4079. TEXT("_stscanf failed can't retrive tapi ID skipping this entry.")
  4080. );
  4081. }
  4082. }
  4083. MemFree(pDeviceDate);
  4084. RegCloseKey (hKeyDevice);
  4085. Next:
  4086. // restore buffer length
  4087. dwKeyNameLen = dwMaxSubKeyLen;
  4088. }
  4089. try
  4090. {
  4091. while (!vecCacheEntryForDeletion.empty())
  4092. {
  4093. dwTapiPermanentLineID = vecCacheEntryForDeletion.back();
  4094. DeleteCacheEntry(dwTapiPermanentLineID);
  4095. vecCacheEntryForDeletion.pop_back();
  4096. }
  4097. }
  4098. catch (exception &ex)
  4099. {
  4100. DebugPrintEx(
  4101. DEBUG_ERR,
  4102. TEXT("vector operation failed throwing an exception, abort cleanning; %S"),
  4103. ex.what()
  4104. );
  4105. }
  4106. Exit:
  4107. MemFree(pszKeyName);
  4108. RegCloseKey (hKeyCache);
  4109. return dwRes;
  4110. }
  4111. DWORD
  4112. UpdateDevicesFlags(
  4113. void
  4114. )
  4115. /*++
  4116. Routine name : UpdateDevicesFlags
  4117. Routine description:
  4118. Updates new devices flags ,so we will not exceed device limit on this SKU
  4119. Author:
  4120. Sacher Oded (odeds), May, 2001
  4121. Arguments:
  4122. None
  4123. Return Value:
  4124. Win32 error code
  4125. --*/
  4126. {
  4127. DWORD dwRes = ERROR_SUCCESS;
  4128. PLIST_ENTRY Next;
  4129. PLINE_INFO pLineInfo;
  4130. DEBUG_FUNCTION_NAME(TEXT("UpdateDevicesFlags"));
  4131. //
  4132. // loop thru the devices and reset flags of new devices if we exceeded device limit
  4133. //
  4134. Next = g_TapiLinesListHead.Flink;
  4135. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead &&
  4136. g_dwDeviceEnabledCount > g_dwDeviceEnabledLimit)
  4137. {
  4138. pLineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  4139. Next = pLineInfo->ListEntry.Flink;
  4140. if (!(pLineInfo->dwDeviceType & FAX_DEVICE_TYPE_NEW) ||
  4141. FALSE == IsDeviceEnabled(pLineInfo))
  4142. {
  4143. continue;
  4144. }
  4145. //
  4146. // Device is new and enabled.
  4147. //
  4148. ResetDeviceFlags(pLineInfo);
  4149. g_dwDeviceEnabledCount -= 1;
  4150. }
  4151. //
  4152. // loop thru the devices and reset flags of cached devices if we exceeded device limit
  4153. //
  4154. Next = g_TapiLinesListHead.Flink;
  4155. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead &&
  4156. g_dwDeviceEnabledCount > g_dwDeviceEnabledLimit)
  4157. {
  4158. pLineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  4159. Next = pLineInfo->ListEntry.Flink;
  4160. if (!(pLineInfo->dwDeviceType & FAX_DEVICE_TYPE_CACHED) ||
  4161. FALSE == IsDeviceEnabled(pLineInfo))
  4162. {
  4163. continue;
  4164. }
  4165. //
  4166. // Device is cached and enabled.
  4167. //
  4168. ResetDeviceFlags(pLineInfo);
  4169. g_dwDeviceEnabledCount -= 1;
  4170. }
  4171. //
  4172. // loop thru the devices and reset flags of old devices if we exceeded device limit.
  4173. //
  4174. Next = g_TapiLinesListHead.Flink;
  4175. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead &&
  4176. g_dwDeviceEnabledCount > g_dwDeviceEnabledLimit)
  4177. {
  4178. pLineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  4179. Next = pLineInfo->ListEntry.Flink;
  4180. if (!(pLineInfo->dwDeviceType & FAX_DEVICE_TYPE_OLD) ||
  4181. FALSE == IsDeviceEnabled(pLineInfo))
  4182. {
  4183. continue;
  4184. }
  4185. //
  4186. // Device is old and enabled.
  4187. //
  4188. ResetDeviceFlags(pLineInfo);
  4189. g_dwDeviceEnabledCount -= 1;
  4190. }
  4191. Assert (g_dwDeviceEnabledCount <= g_dwDeviceEnabledLimit);
  4192. //
  4193. // loop thru the devices and close the line handles
  4194. // for all devices that are NOT set to receive
  4195. //
  4196. Next = g_TapiLinesListHead.Flink;
  4197. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  4198. {
  4199. pLineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  4200. Next = pLineInfo->ListEntry.Flink;
  4201. if (!(pLineInfo->Flags & FPF_RECEIVE) && // Device is not set to auto-receive and
  4202. pLineInfo->hLine && // device is open and
  4203. pLineInfo->PermanentLineID != g_dwManualAnswerDeviceId // this device is not set to manual answer mode
  4204. )
  4205. {
  4206. //
  4207. // Attempt to close the device
  4208. //
  4209. HLINE hLine = pLineInfo->hLine;
  4210. pLineInfo->hLine = 0;
  4211. LONG Rslt = lineClose( hLine );
  4212. if (Rslt)
  4213. {
  4214. if (LINEERR_INVALLINEHANDLE != Rslt)
  4215. {
  4216. DebugPrintEx(
  4217. DEBUG_ERR,
  4218. TEXT("lineClose() for line %s [Permanent Id: %010d] has failed. (ec: %ld)"),
  4219. pLineInfo->DeviceName,
  4220. pLineInfo->TapiPermanentLineId,
  4221. Rslt);
  4222. ASSERT_FALSE;
  4223. }
  4224. else
  4225. {
  4226. //
  4227. // We can get LINEERR_INVALLINEHANDLE if we got LINE_CLOSE
  4228. // from TAPI.
  4229. //
  4230. DebugPrintEx(
  4231. DEBUG_WRN,
  4232. TEXT("lineClose() for line %s [Permanent Id: %010d] reported LINEERR_INVALLINEHANDLE. (May be caused by LINE_CLOSE event)"),
  4233. pLineInfo->DeviceName,
  4234. pLineInfo->TapiPermanentLineId
  4235. );
  4236. }
  4237. }
  4238. }
  4239. }
  4240. return dwRes;
  4241. }
  4242. VOID
  4243. UpdateManualAnswerDevice(
  4244. void
  4245. )
  4246. /*++
  4247. Routine name : UpdateManualAnswerDevice
  4248. Routine description:
  4249. Updates the manual answer device with a cached device
  4250. Author:
  4251. Sacher Oded (odeds), July, 2001
  4252. Arguments:
  4253. None
  4254. Return Value:
  4255. None
  4256. --*/
  4257. {
  4258. DEBUG_FUNCTION_NAME(TEXT("UpdateManualAnswerDevice"));
  4259. //
  4260. // Call UpdateReceiveEnabledDevicesCount () to make sure the manual answer device is valid
  4261. //
  4262. UpdateReceiveEnabledDevicesCount();
  4263. //
  4264. // if we have a valid manual answer device then finish
  4265. //
  4266. if (0 == g_dwManualAnswerDeviceId)
  4267. {
  4268. //
  4269. // No valid manual answer device is operational so look if chached devices were manual.
  4270. // loop through the cached devices and look for the first cached device and set it as a manual answer device
  4271. //
  4272. PLIST_ENTRY Next;
  4273. PLINE_INFO pLineInfo;
  4274. Next = g_TapiLinesListHead.Flink;
  4275. while ((ULONG_PTR)Next != (ULONG_PTR)&g_TapiLinesListHead)
  4276. {
  4277. BOOL fDeviceWasEnabled;
  4278. DWORD dwRes;
  4279. pLineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  4280. Next = pLineInfo->ListEntry.Flink;
  4281. //
  4282. // look for a cached manual answer device that is not set to auto receive
  4283. //
  4284. if ( pLineInfo->dwDeviceType != (FAX_DEVICE_TYPE_CACHED | FAX_DEVICE_TYPE_MANUAL_ANSWER) ||
  4285. (pLineInfo->Flags & FPF_RECEIVE))
  4286. {
  4287. continue;
  4288. }
  4289. //
  4290. // We found a device that can be set to manual receive
  4291. //
  4292. //
  4293. // Now it may be that the cached device was not enabled (if for example it was marked as
  4294. // manual-answer and no send ) so we didn't count it in the Enabled Count devices group.
  4295. // if so then after setting it as a manual receive we ought to update g_dwDeviceEnabledCount
  4296. //
  4297. fDeviceWasEnabled = IsDeviceEnabled(pLineInfo);
  4298. g_dwManualAnswerDeviceId = pLineInfo->PermanentLineID;
  4299. dwRes = WriteManualAnswerDeviceId (g_dwManualAnswerDeviceId); // persist in registry
  4300. if (ERROR_SUCCESS != dwRes)
  4301. {
  4302. DebugPrintEx(
  4303. DEBUG_ERR,
  4304. TEXT("WriteManualAnswerDeviceId(0) (ec: %lc)"),
  4305. dwRes);
  4306. }
  4307. //
  4308. // Update enabled devices count
  4309. //
  4310. if (FALSE == fDeviceWasEnabled)
  4311. {
  4312. //
  4313. // Another device is now enabled
  4314. //
  4315. g_dwDeviceEnabledCount += 1;
  4316. }
  4317. //
  4318. // No need to continue the search, only one "manual receive" device is allowed
  4319. //
  4320. break;
  4321. }
  4322. }
  4323. return;
  4324. }