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

2750 lines
73 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. t30api.c
  5. Abstract:
  6. This is the interface with T.30 DLL
  7. Author:
  8. Rafael Lisitsa (RafaelL) 2-Feb-1996
  9. Revision History:
  10. --*/
  11. #define DEFINE_T30_GLOBALS
  12. #include "prep.h"
  13. #include "tiff.h"
  14. #include "glbproto.h"
  15. #include "t30gl.h"
  16. ///RSL Wes should export this.
  17. #define TAPI_VERSION 0x00020000
  18. #define ABORT_ACK_TIMEOUT 20000
  19. ///////////////////////////////////////////////////////////////////////////////////
  20. VOID CALLBACK
  21. T30LineCallBackFunctionA(
  22. HANDLE hFax,
  23. DWORD hDevice,
  24. DWORD dwMessage,
  25. DWORD_PTR dwInstance,
  26. DWORD_PTR dwParam1,
  27. DWORD_PTR dwParam2,
  28. DWORD_PTR dwParam3
  29. )
  30. {
  31. LONG_PTR i;
  32. PThrdGlbl pTG = NULL;
  33. char rgchTemp128[128];
  34. LPSTR lpszMsg = "Unknown";
  35. MyDebugPrint(pTG, LOG_ALL, "!!! LineCallBack !!! hFax=%lx, dev=%lx, msg=%lx, dwInst=%lx,P1=%lx, P2=%lx, P3=%lx\n",
  36. hFax, hDevice, dwMessage, dwInstance, dwParam1, dwParam2, (unsigned long) dwParam3);
  37. // find the thread that this callback belongs to
  38. //----------------------------------------------
  39. i = (LONG_PTR) hFax;
  40. if (i < 1 || i >= MAX_T30_CONNECT) {
  41. MyDebugPrint(pTG, LOG_ALL, "T30LineCallback-wrong handle=%x\n", i);
  42. return;
  43. }
  44. if ( (! T30Inst[i].fAvail) && T30Inst[i].pT30) {
  45. pTG = (PThrdGlbl) T30Inst[i].pT30;
  46. }
  47. else {
  48. MyDebugPrint(pTG, LOG_ERR, "ERROR:T30LineCallback-handle=%x invalid \n", i);
  49. return;
  50. }
  51. switch (dwMessage) {
  52. case LINE_LINEDEVSTATE:
  53. lpszMsg = "LINE_LINEDEVSTATE";
  54. if (dwParam1 == LINEDEVSTATE_RINGING)
  55. {
  56. MyDebugPrint(pTG, LOG_ALL, "Ring Count = %lx\n", (unsigned long) dwParam3);
  57. }
  58. else if (dwParam1 == LINEDEVSTATE_REINIT)
  59. {
  60. }
  61. break;
  62. case LINE_ADDRESSSTATE:
  63. lpszMsg = "LINE_ADDRESSSTATE";
  64. break;
  65. /* process state transition */
  66. case LINE_CALLSTATE:
  67. lpszMsg = "LINE_CALLSTATE";
  68. if (dwParam1 == LINECALLSTATE_CONNECTED) {
  69. pTG->fGotConnect = TRUE;
  70. }
  71. else if (dwParam1 == LINECALLSTATE_IDLE) {
  72. if (pTG->fDeallocateCall == 0) {
  73. pTG->fDeallocateCall = 1;
  74. #if 0
  75. //
  76. // this is now performed in the fax service
  77. //
  78. lRet = lineDeallocateCall( (HCALL) hDevice);
  79. if (lRet) {
  80. MyDebugPrint(pTG, LOG_ERR, "ERROR: IDLE lineDeallocateCall returns %lx\n", lRet);
  81. }
  82. else {
  83. MyDebugPrint(pTG, LOG_ALL, "IDLE lineDeallocateCall SUCCESS\n");
  84. }
  85. #endif
  86. }
  87. }
  88. break;
  89. case LINE_CREATE:
  90. lpszMsg = "LINE_CREATE";
  91. break;
  92. case LINE_CLOSE:
  93. lpszMsg = "LINE_CLOSE";
  94. break; // LINE_CLOSE
  95. /* handle simple tapi request. */
  96. case LINE_REQUEST:
  97. lpszMsg = "LINE_REQUEST";
  98. break; // LINE_REQUEST
  99. /* handle the assync completion of TAPI functions
  100. lineMakeCall/lineDropCall */
  101. case LINE_REPLY:
  102. lpszMsg = "LINE_REPLY";
  103. if (!hDevice)
  104. {itapi_async_signal(pTG, (DWORD)dwParam1, (DWORD)dwParam2, dwParam3);}
  105. else
  106. MyDebugPrint(pTG, LOG_ALL, "Ignoring LINE_REPLY with nonzero device\n");
  107. break;
  108. /* other messages that can be processed */
  109. case LINE_CALLINFO:
  110. lpszMsg = "LINE_CALLINFO";
  111. break;
  112. case LINE_DEVSPECIFIC:
  113. lpszMsg = "LINE_DEVSPECIFIC";
  114. break;
  115. case LINE_DEVSPECIFICFEATURE:
  116. lpszMsg = "LINE_DEVSPECIFICFEATURE";
  117. break;
  118. case LINE_GATHERDIGITS:
  119. lpszMsg = "LINE_GATHERDIGITS";
  120. break;
  121. case LINE_GENERATE:
  122. lpszMsg = "LINE_GENERATE";
  123. break;
  124. case LINE_MONITORDIGITS:
  125. lpszMsg = "LINE_MONITORDIGITS";
  126. break;
  127. case LINE_MONITORMEDIA:
  128. lpszMsg = "LINE_MONITORMEDIA";
  129. break;
  130. case LINE_MONITORTONE:
  131. lpszMsg = "LINE_MONITORTONE";
  132. break;
  133. } /* switch */
  134. _stprintf(rgchTemp128,
  135. "%s(p1=0x%lx, p2=0x%lx, p3=0x%lx)",
  136. (LPTSTR) lpszMsg,
  137. (unsigned long) dwParam1,
  138. (unsigned long) dwParam2,
  139. (unsigned long) dwParam3);
  140. MyDebugPrint(pTG, LOG_ALL, "Device:0x%lx; Message:%s\n", (unsigned long) hDevice,
  141. (LPTSTR) rgchTemp128);
  142. } /* LineCallBackProc */
  143. ///////////////////////////////////////////////////////////////////////////////////
  144. BOOL WINAPI
  145. FaxDevInitializeA(
  146. IN HLINEAPP LineAppHandle,
  147. IN HANDLE HeapHandle,
  148. OUT PFAX_LINECALLBACK *LineCallbackFunction,
  149. IN PFAX_SERVICE_CALLBACK FaxServiceCallback
  150. )
  151. /*++
  152. Routine Description:
  153. Device Provider Initialization.
  154. Arguments:
  155. Return Value:
  156. --*/
  157. { int i;
  158. LONG lRet;
  159. TCHAR LogFileLocation[256];
  160. HKEY hKey;
  161. DWORD dwType;
  162. DWORD dwSizeNeed;
  163. int iLen;
  164. gT30.LineAppHandle = LineAppHandle;
  165. gT30.HeapHandle = HeapHandle;
  166. gT30.fInit = TRUE;
  167. HeapExistingInitialize(gT30.HeapHandle);
  168. FaxTiffInitialize();
  169. *LineCallbackFunction = T30LineCallBackFunction;
  170. for (i=1; i<MAX_T30_CONNECT; i++) {
  171. T30Inst[i].fAvail = TRUE;
  172. T30Inst[i].pT30 = NULL;
  173. }
  174. InitializeCriticalSection(&T30CritSection);
  175. for (i=0; i<MAX_T30_CONNECT; i++) {
  176. T30Recovery[i].fAvail = TRUE;
  177. }
  178. InitializeCriticalSection(&T30RecoveryCritSection);
  179. // debugging
  180. gfScrnPrint = 0;
  181. gfFilePrint = 1; // leave it alone
  182. lRet = RegOpenKeyEx(
  183. HKEY_LOCAL_MACHINE,
  184. "Software\\Microsoft\\Fax\\Device Providers\\Microsoft Modem Device Provider",
  185. 0,
  186. KEY_READ,
  187. &hKey);
  188. if (lRet == ERROR_SUCCESS) {
  189. dwSizeNeed = sizeof(int);
  190. lRet = RegQueryValueEx(
  191. hKey,
  192. "ModemLogLevel",
  193. 0,
  194. &dwType,
  195. (LPBYTE) &gT30.DbgLevel,
  196. &dwSizeNeed);
  197. if ( ( lRet != ERROR_SUCCESS) || (dwType != REG_DWORD) ) {
  198. gT30.DbgLevel = 0;
  199. gfFilePrint = 0;
  200. }
  201. ProfileGetString( (ULONG_PTR) hKey,
  202. "ModemLogLocation",
  203. "C:",
  204. LogFileLocation,
  205. sizeof(LogFileLocation) - 1);
  206. // RSL TEMP. to save RAW COM T4 data from the modem
  207. dwSizeNeed = sizeof(int);
  208. lRet = RegQueryValueEx(
  209. hKey,
  210. "T4LogLevel",
  211. 0,
  212. &dwType,
  213. (LPBYTE) &gT30.T4LogLevel,
  214. &dwSizeNeed);
  215. if ( ( lRet != ERROR_SUCCESS) || (dwType != REG_DWORD) ) {
  216. gT30.T4LogLevel = 0;
  217. }
  218. dwSizeNeed = sizeof(int);
  219. lRet = RegQueryValueEx(
  220. hKey,
  221. "MaxErrorLinesPerPage",
  222. 0,
  223. &dwType,
  224. (LPBYTE) &gT30.MaxErrorLinesPerPage,
  225. &dwSizeNeed);
  226. if ( ( lRet != ERROR_SUCCESS) || (dwType != REG_DWORD) ) {
  227. gT30.MaxErrorLinesPerPage = 110;
  228. }
  229. dwSizeNeed = sizeof(int);
  230. lRet = RegQueryValueEx(
  231. hKey,
  232. "MaxConsecErrorLinesPerPage",
  233. 0,
  234. &dwType,
  235. (LPBYTE) &gT30.MaxConsecErrorLinesPerPage,
  236. &dwSizeNeed);
  237. if ( ( lRet != ERROR_SUCCESS) || (dwType != REG_DWORD) ) {
  238. gT30.MaxConsecErrorLinesPerPage = 110;
  239. }
  240. //
  241. // Exception Handling enable / disable
  242. //
  243. dwSizeNeed = sizeof(int);
  244. lRet = RegQueryValueEx(
  245. hKey,
  246. "DisableEH",
  247. 0,
  248. &dwType,
  249. (LPBYTE) &glT30Safe,
  250. &dwSizeNeed);
  251. if ( ( lRet != ERROR_SUCCESS) || (dwType != REG_DWORD) ) {
  252. glT30Safe = 1;
  253. }
  254. dwSizeNeed = sizeof(int);
  255. lRet = RegQueryValueEx(
  256. hKey,
  257. "SimulateError",
  258. 0,
  259. &dwType,
  260. (LPBYTE) &glSimulateError,
  261. &dwSizeNeed);
  262. if ( ( lRet != ERROR_SUCCESS) || (dwType != REG_DWORD) ) {
  263. glSimulateError = 0;
  264. }
  265. dwSizeNeed = sizeof(int);
  266. lRet = RegQueryValueEx(
  267. hKey,
  268. "SimulateErrorType",
  269. 0,
  270. &dwType,
  271. (LPBYTE) &glSimulateErrorType,
  272. &dwSizeNeed);
  273. if ( ( lRet != ERROR_SUCCESS) || (dwType != REG_DWORD) ) {
  274. glSimulateErrorType = 0;
  275. }
  276. }
  277. else {
  278. lstrcpy( LogFileLocation, "c:");
  279. gT30.DbgLevel = 0;
  280. gT30.T4LogLevel = 0;
  281. }
  282. lstrcat(LogFileLocation, "\\faxt30.log");
  283. if (gT30.DbgLevel == 0)
  284. gfFilePrint = 0;
  285. if (gfFilePrint) {
  286. if ( (ghLogFile = CreateFileA(LogFileLocation, GENERIC_WRITE, FILE_SHARE_READ,
  287. NULL, CREATE_ALWAYS, 0, NULL) ) == INVALID_HANDLE_VALUE ) {
  288. OutputDebugString("CANNOT CREATE faxt30.log\n");
  289. }
  290. }
  291. if (gT30.T4LogLevel) {
  292. iLen = lstrlen (LogFileLocation);
  293. LogFileLocation[iLen-3] = 'c';
  294. LogFileLocation[iLen-2] = 'o';
  295. LogFileLocation[iLen-1] = 'm';
  296. if ( (ghComLogFile = _lcreat (LogFileLocation, 0) ) == HFILE_ERROR ) {
  297. OutputDebugString("CANNOT CREATE faxt30.com\n");
  298. }
  299. }
  300. // temp. directory
  301. gT30.dwLengthTmpDirectory = GetTempPathA (_MAX_FNAME - 15, gT30.TmpDirectory);
  302. if (gT30.dwLengthTmpDirectory > _MAX_FNAME - 15) {
  303. MyDebugPrint( (PThrdGlbl) 0, LOG_ERR, "FaxDevInit__A GetTempPathA needs %d have %d bytes\n",
  304. gT30.dwLengthTmpDirectory , (_MAX_FNAME - 15) );
  305. return (FALSE);
  306. }
  307. if (!gT30.dwLengthTmpDirectory) {
  308. MyDebugPrint( (PThrdGlbl) 0, LOG_ERR, "FaxDevInit__A GetTempPathA fails le=%x\n", GetLastError() );
  309. return (FALSE);
  310. }
  311. MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevInit__A hLineApp=%x heap=%x TempDir=%s Len=%d at %ld \n",
  312. LineAppHandle,
  313. HeapHandle,
  314. gT30.TmpDirectory,
  315. gT30.dwLengthTmpDirectory,
  316. GetTickCount() );
  317. gT30.Status = STATUS_OK;
  318. return (TRUE);
  319. }
  320. ///////////////////////////////////////////////////////////////////////////////////
  321. BOOL WINAPI
  322. FaxDevStartJobA(
  323. HLINE LineHandle,
  324. DWORD DeviceId,
  325. PHANDLE pFaxHandle,
  326. HANDLE CompletionPortHandle,
  327. ULONG_PTR CompletionKey
  328. )
  329. /*++
  330. Routine Description:
  331. Device Provider Initialization.
  332. Arguments:
  333. Return Value:
  334. --*/
  335. {
  336. PThrdGlbl pTG=NULL;
  337. int i;
  338. int fFound=0;
  339. MyDebugPrint(pTG, LOG_ALL, "EP: FaxDevStartJob__A LineHandle=%x, DevID=%x, pFaxH=%x Port=%x, Key=%x at %ld \n",
  340. LineHandle,
  341. DeviceId,
  342. pFaxHandle,
  343. CompletionPortHandle,
  344. CompletionKey,
  345. GetTickCount()
  346. );
  347. gT30.CntConnect++;
  348. if (gT30.CntConnect >= MAX_T30_CONNECT) {
  349. MyDebugPrint(pTG, LOG_ERR, "ERROR: Exceeded # of connections (curr=%d, allowed=%d\n",
  350. gT30.CntConnect, MAX_T30_CONNECT );
  351. return (FALSE);
  352. }
  353. if ( (pTG = (PThrdGlbl) T30AllocThreadGlobalData() ) == NULL ) {
  354. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevStartJob: can't malloc\n");
  355. return (FALSE);
  356. }
  357. EnterCriticalSection(&T30CritSection);
  358. for (i=1; i<MAX_T30_CONNECT; i++) {
  359. if (T30Inst[i].fAvail) {
  360. T30Inst[i].pT30 = (LPVOID) pTG;
  361. T30Inst[i].fAvail = FALSE;
  362. *pFaxHandle = (HANDLE) i;
  363. fFound = 1;
  364. break;
  365. }
  366. }
  367. LeaveCriticalSection(&T30CritSection);
  368. if (!fFound)
  369. return (FALSE);
  370. pTG->LineHandle = LineHandle;
  371. pTG->DeviceId = DeviceId;
  372. pTG->FaxHandle = (HANDLE) pTG;
  373. pTG->CompletionPortHandle = CompletionPortHandle;
  374. pTG->CompletionKey = CompletionKey;
  375. // initialization
  376. //---------------------------
  377. pTG->hevAsync = CreateEvent(NULL, FALSE, FALSE, NULL);
  378. pTG->CtrlEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  379. pTG->ThrdSignal = CreateEvent(NULL, FALSE, FALSE, NULL);
  380. pTG->ThrdDoneSignal = CreateEvent(NULL, FALSE, FALSE, NULL);
  381. pTG->ThrdAckTerminateSignal = CreateEvent(NULL, FALSE, FALSE, NULL);
  382. pTG->FirstPageReadyTxSignal = CreateEvent(NULL, FALSE, FALSE, NULL);
  383. pTG->AbortReqEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  384. pTG->AbortAckEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  385. ResetEvent(pTG->AbortReqEvent);
  386. pTG->fWaitingForEvent = FALSE;
  387. pTG->fDeallocateCall = 0;
  388. MyAllocInit(pTG);
  389. pTG->StatusId = 0;
  390. pTG->StringId = 0;
  391. pTG->PageCount = 0;
  392. pTG->CSI = 0;
  393. pTG->CallerId = 0;
  394. pTG->RoutingInfo = 0;
  395. // helper image threads sync. flags
  396. pTG->AckTerminate = 1;
  397. pTG->fOkToResetAbortReqEvent = 1;
  398. pTG->Inst.awfi.fLastPage = 0;
  399. return (TRUE);
  400. }
  401. ///////////////////////////////////////////////////////////////////////////////////
  402. BOOL WINAPI
  403. FaxDevEndJobA(
  404. HANDLE FaxHandle
  405. )
  406. /*++
  407. Routine Description:
  408. Device Provider Initialization.
  409. Arguments:
  410. Return Value:
  411. --*/
  412. {
  413. PThrdGlbl pTG=NULL;
  414. LONG_PTR i;
  415. MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevEndJob FaxHandle=%x \n", FaxHandle);
  416. // find instance data
  417. //------------------------
  418. i = (LONG_PTR) FaxHandle;
  419. if (i < 1 || i >= MAX_T30_CONNECT) {
  420. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevEndJob - got wrong FaxHandle=%d\n", i);
  421. return (FALSE);
  422. }
  423. if (T30Inst[i].fAvail) {
  424. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevEndJob - got wrong FaxHandle (marked as free) %d\n", i);
  425. return (FALSE);
  426. }
  427. pTG = (PThrdGlbl) T30Inst[i].pT30;
  428. if (pTG->hevAsync) {
  429. CloseHandle(pTG->hevAsync);
  430. }
  431. if (pTG->CtrlEvent) {
  432. CloseHandle(pTG->CtrlEvent);
  433. }
  434. if (pTG->StatusId == FS_NOT_FAX_CALL) {
  435. CloseHandle( (HANDLE) pTG->Comm.nCid );
  436. }
  437. if (pTG->ThrdSignal) {
  438. CloseHandle(pTG->ThrdSignal);
  439. }
  440. if (pTG->ThrdDoneSignal) {
  441. CloseHandle(pTG->ThrdDoneSignal);
  442. }
  443. if (pTG->ThrdAckTerminateSignal) {
  444. CloseHandle(pTG->ThrdAckTerminateSignal);
  445. }
  446. if (pTG->FirstPageReadyTxSignal) {
  447. CloseHandle(pTG->FirstPageReadyTxSignal);
  448. }
  449. if (pTG->AbortReqEvent) {
  450. CloseHandle(pTG->AbortReqEvent);
  451. }
  452. if (pTG->AbortAckEvent) {
  453. CloseHandle(pTG->AbortAckEvent);
  454. }
  455. if (pTG->hThread) {
  456. CloseHandle(pTG->hThread);
  457. }
  458. MemFree(pTG->lpwFileName);
  459. pTG->fRemoteIdAvail = 0;
  460. if (pTG->RemoteID) {
  461. MemFree(pTG->RemoteID);
  462. }
  463. CleanModemInfStrings(pTG);
  464. MemFree(pTG);
  465. EnterCriticalSection(&T30CritSection);
  466. T30Inst[i].fAvail = TRUE;
  467. T30Inst[i].pT30 = NULL;
  468. gT30.CntConnect--;
  469. LeaveCriticalSection(&T30CritSection);
  470. MyDebugPrint(0, LOG_ALL, "FaxDevEndJob %d \n", FaxHandle);
  471. // RSL PrintAllocationsT30();
  472. return (TRUE);
  473. }
  474. ///////////////////////////////////////////////////////////////////////////////////
  475. BOOL WINAPI
  476. FaxDevSendA(
  477. IN HANDLE FaxHandle,
  478. IN PFAX_SEND_A FaxSend,
  479. IN PFAX_SEND_CALLBACK FaxSendCallback
  480. )
  481. /*++
  482. Routine Description:
  483. Arguments:
  484. Return Value:
  485. --*/
  486. {
  487. LONG_PTR i;
  488. PThrdGlbl pTG=NULL;
  489. LONG lRet;
  490. DWORD dw;
  491. LPVARSTRING lpVarStr=0;
  492. LPDEVICEID lpDeviceID=0;
  493. LPLINEDEVCAPS lpLineDevCaps;
  494. LPSTR lpszFaxNumber;
  495. BYTE buf[ sizeof(LINEDEVCAPS)+1000 ];
  496. LONG lResult=0;
  497. LPLINECALLPARAMS lpCallParams;
  498. HCALL CallHandle;
  499. BYTE rgby [sizeof(LINETRANSLATEOUTPUT)+64];
  500. LPLINETRANSLATEOUTPUT lplto1 = (LPLINETRANSLATEOUTPUT) rgby;
  501. LPLINETRANSLATEOUTPUT lplto;
  502. BOOL RetCode;
  503. DWORD dwNeededSize;
  504. LPDEVCFG lpDevCfg;
  505. LPMODEMSETTINGS lpModemSettings;
  506. LPMDM_DEVSPEC lpDSpec;
  507. int fFound=0;
  508. int RecoveryIndex = -1;
  509. char rgchKey[256];
  510. HKEY hKey;
  511. DWORD dwType;
  512. DWORD dwSize;
  513. __try {
  514. MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevSendA FaxHandle=%x, FaxSend=%x, FaxSendCallback=%x at %ld \n",
  515. FaxHandle, FaxSend, FaxSendCallback, GetTickCount() );
  516. // find instance data
  517. //------------------------
  518. i = (LONG_PTR) FaxHandle;
  519. if (i < 1 || i >= MAX_T30_CONNECT) {
  520. MemFree(FaxSend->FileName);
  521. MemFree(FaxSend->CallerName);
  522. MemFree(FaxSend->CallerNumber);
  523. MemFree(FaxSend->ReceiverName);
  524. MemFree(FaxSend->ReceiverNumber);
  525. return (FALSE);
  526. }
  527. if (T30Inst[i].fAvail) {
  528. MemFree(FaxSend->FileName);
  529. MemFree(FaxSend->CallerName);
  530. MemFree(FaxSend->CallerNumber);
  531. MemFree(FaxSend->ReceiverName);
  532. MemFree(FaxSend->ReceiverNumber);
  533. return (FALSE);
  534. }
  535. pTG = (PThrdGlbl) T30Inst[i].pT30;
  536. pTG->RecoveryIndex = -1;
  537. lpszFaxNumber = FaxSend->ReceiverNumber;
  538. pTG->Operation = T30_TX;
  539. // store LocalID
  540. if (FaxSend->CallerNumber == NULL) {
  541. pTG->LocalID[0] = 0;
  542. }
  543. else {
  544. _fmemcpy(pTG->LocalID, FaxSend->CallerNumber, min (_fstrlen(FaxSend->CallerNumber), sizeof(pTG->LocalID) - 1) );
  545. pTG->LocalID [ min (_fstrlen(FaxSend->CallerNumber), sizeof(pTG->LocalID) - 1) ] = 0;
  546. }
  547. // go to TAPI pass-through mode
  548. //-------------------------------
  549. lpCallParams = itapi_create_linecallparams();
  550. if (!itapi_async_setup(pTG)) {
  551. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevSend: itapi_async_setup failed \n");
  552. MemFree (lpCallParams);
  553. pTG->fFatalErrorWasSignaled = 1;
  554. SignalStatusChange(pTG, FS_FATAL_ERROR);
  555. RetCode = FALSE;
  556. goto l_exit;
  557. }
  558. lRet = lineMakeCall (pTG->LineHandle,
  559. &CallHandle,
  560. lpszFaxNumber,
  561. 0,
  562. lpCallParams);
  563. if (lRet < 0) {
  564. MyDebugPrint(pTG, LOG_ERR, "ERROR: lineMakeCall returns ERROR value 0x%lx\n", (unsigned long) lRet);
  565. pTG->fFatalErrorWasSignaled = 1;
  566. SignalStatusChange(pTG, FS_LINE_UNAVAILABLE);
  567. MemFree (lpCallParams);
  568. RetCode = FALSE;
  569. goto l_exit;
  570. }
  571. else {
  572. MyDebugPrint(pTG, LOG_ALL, "lineMakeCall returns 0x%lx\n", (unsigned long) lRet);
  573. }
  574. if(!itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_TIMEOUT)) {
  575. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevSend: itapi_async_wait failed \n");
  576. pTG->fFatalErrorWasSignaled = 1;
  577. SignalStatusChange(pTG, FS_LINE_UNAVAILABLE);
  578. MemFree (lpCallParams);
  579. RetCode = FALSE;
  580. goto l_exit;
  581. }
  582. // now we wait for the connected message
  583. //--------------------------------------
  584. for (dw=50; dw<10000; dw = dw*120/100) {
  585. Sleep(dw);
  586. if (pTG->fGotConnect)
  587. break;
  588. }
  589. if (!pTG->fGotConnect) {
  590. MyDebugPrint(pTG, LOG_ERR, "ERROR: Failure waiting for CONNECTED message....\n");
  591. // We ignore... goto failure1;
  592. }
  593. MemFree (lpCallParams);
  594. pTG->CallHandle = CallHandle;
  595. //
  596. // Add entry to the Recovery Area.
  597. //
  598. fFound = 0;
  599. for (i=0; i<MAX_T30_CONNECT; i++) {
  600. if (T30Recovery[i].fAvail) {
  601. EnterCriticalSection(&T30RecoveryCritSection);
  602. T30Recovery[i].fAvail = FALSE;
  603. T30Recovery[i].ThreadId = GetCurrentThreadId();
  604. T30Recovery[i].FaxHandle = FaxHandle;
  605. T30Recovery[i].pTG = (LPVOID) pTG;
  606. T30Recovery[i].LineHandle = pTG->LineHandle;
  607. T30Recovery[i].CallHandle = CallHandle;
  608. T30Recovery[i].DeviceId = pTG->DeviceId;
  609. T30Recovery[i].CompletionPortHandle = pTG->CompletionPortHandle;
  610. T30Recovery[i].CompletionKey = pTG->CompletionKey;
  611. T30Recovery[i].TiffThreadId = 0;
  612. T30Recovery[i].TimeStart = GetTickCount();
  613. T30Recovery[i].TimeUpdated = T30Recovery[i].TimeStart;
  614. T30Recovery[i].CkSum = ComputeCheckSum( (LPDWORD) &T30Recovery[i].fAvail,
  615. sizeof ( T30_RECOVERY_GLOB ) / sizeof (DWORD) - 1);
  616. LeaveCriticalSection(&T30RecoveryCritSection);
  617. fFound = 1;
  618. RecoveryIndex = (int)i;
  619. pTG->RecoveryIndex = (int)i;
  620. break;
  621. }
  622. }
  623. if (! fFound) {
  624. MyDebugPrint(pTG, LOG_ERR, "ERROR:Couldn't find available space for Recovery\n");
  625. pTG->fFatalErrorWasSignaled = 1;
  626. SignalStatusChange(pTG, FS_FATAL_ERROR);
  627. RetCode = FALSE;
  628. goto l_exit;
  629. }
  630. // get the handle to a Comm port
  631. //----------------------------------
  632. lpVarStr = (LPVARSTRING) MemAlloc(IDVARSTRINGSIZE);
  633. if (!lpVarStr) {
  634. MyDebugPrint(pTG, LOG_ERR, "ERROR:Couldn't allocate space for lpVarStr\n");
  635. pTG->fFatalErrorWasSignaled = 1;
  636. SignalStatusChange(pTG, FS_FATAL_ERROR);
  637. RetCode = FALSE;
  638. goto l_exit;
  639. }
  640. _fmemset(lpVarStr, 0, IDVARSTRINGSIZE);
  641. lpVarStr->dwTotalSize = IDVARSTRINGSIZE;
  642. lRet = lineGetID(pTG->LineHandle,
  643. 0, // +++ addr
  644. CallHandle,
  645. LINECALLSELECT_CALL, // dwSelect,
  646. lpVarStr, //lpDeviceID,
  647. "comm/datamodem" ); //lpszDeviceClass
  648. if (lRet) {
  649. MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetID returns error 0x%lx\n", (unsigned long) lRet);
  650. pTG->fFatalErrorWasSignaled = 1;
  651. SignalStatusChange(pTG, FS_LINE_UNAVAILABLE);
  652. RetCode = FALSE;
  653. goto l_exit;
  654. }
  655. // extract id
  656. if (lpVarStr->dwStringFormat != STRINGFORMAT_BINARY) {
  657. MyDebugPrint(pTG, LOG_ERR, "ERROR: String format is not binary\n");
  658. pTG->fFatalErrorWasSignaled = 1;
  659. SignalStatusChange(pTG, FS_FATAL_ERROR);
  660. RetCode = FALSE;
  661. goto l_exit;
  662. }
  663. if (lpVarStr->dwUsedSize<sizeof(DEVICEID)) {
  664. MyDebugPrint(pTG, LOG_ERR, "ERROR: linegetid : Varstring size too small\n");
  665. pTG->fFatalErrorWasSignaled = 1;
  666. SignalStatusChange(pTG, FS_FATAL_ERROR);
  667. RetCode = FALSE;
  668. goto l_exit;
  669. }
  670. lpDeviceID = (LPDEVICEID) ((LPBYTE)(lpVarStr)+lpVarStr->dwStringOffset);
  671. MyDebugPrint(pTG, LOG_ALL, "lineGetID returns handle 0x%08lx, \"%s\"\n",
  672. (ULONG_PTR) lpDeviceID->hComm,
  673. (LPSTR) lpDeviceID->szDeviceName);
  674. pTG->hComm = lpDeviceID->hComm;
  675. if (BAD_HANDLE(pTG->hComm)) {
  676. MyDebugPrint(pTG, LOG_ERR, "ERR:lineGetID returns NULL hComm\n");
  677. pTG->fFatalErrorWasSignaled = 1;
  678. SignalStatusChange(pTG, FS_FATAL_ERROR);
  679. RetCode = FALSE;
  680. goto l_exit;
  681. }
  682. // get the Modem configuration (speaker, etc.) from TAPI
  683. //------------------------------------------------------
  684. _fmemset(lpVarStr, 0, IDVARSTRINGSIZE);
  685. lpVarStr->dwTotalSize = IDVARSTRINGSIZE;
  686. lResult = lineGetDevConfig(pTG->DeviceId,
  687. lpVarStr,
  688. "comm/datamodem");
  689. if (lResult) {
  690. if (lpVarStr->dwTotalSize < lpVarStr->dwNeededSize) {
  691. dwNeededSize = lpVarStr->dwNeededSize;
  692. MemFree (lpVarStr);
  693. if ( ! (lpVarStr = (LPVARSTRING) MemAlloc(dwNeededSize) ) ) {
  694. MyDebugPrint(pTG, LOG_ERR, "ERR: Can't allocate %d bytes for lineGetDevConfig\n");
  695. pTG->fFatalErrorWasSignaled = 1;
  696. SignalStatusChange(pTG, FS_FATAL_ERROR);
  697. RetCode = FALSE;
  698. goto l_exit;
  699. }
  700. _fmemset(lpVarStr, 0, dwNeededSize);
  701. lpVarStr->dwTotalSize = dwNeededSize;
  702. lResult = lineGetDevConfig(pTG->DeviceId,
  703. lpVarStr,
  704. "comm/datamodem");
  705. if (lResult) {
  706. MyDebugPrint(pTG, LOG_ERR, "ERR: lineGetDevConfig returns %x, le=%x", lResult, GetLastError() );
  707. MemFree (lpVarStr);
  708. pTG->fFatalErrorWasSignaled = 1;
  709. SignalStatusChange(pTG, FS_FATAL_ERROR);
  710. RetCode = FALSE;
  711. goto l_exit;
  712. }
  713. }
  714. else {
  715. MyDebugPrint(pTG, LOG_ERR, "ERR: 1st lineGetDevConfig returns %x, le=%x", lResult, GetLastError() );
  716. MemFree (lpVarStr);
  717. pTG->fFatalErrorWasSignaled = 1;
  718. SignalStatusChange(pTG, FS_FATAL_ERROR);
  719. RetCode = FALSE;
  720. goto l_exit;
  721. }
  722. }
  723. //
  724. // extract DEVCFG
  725. //
  726. if (lpVarStr->dwStringFormat != STRINGFORMAT_BINARY) {
  727. MyDebugPrint(pTG, LOG_ERR, "ERROR: String format is not binary for lineGetDevConfig\n");
  728. MemFree (lpVarStr);
  729. pTG->fFatalErrorWasSignaled = 1;
  730. SignalStatusChange(pTG, FS_FATAL_ERROR);
  731. RetCode = FALSE;
  732. goto l_exit;
  733. }
  734. if (lpVarStr->dwUsedSize<sizeof(DEVCFG)) {
  735. MyDebugPrint(pTG, LOG_ERR, "ERROR: lineGetDevConfig : Varstring size returned too small\n");
  736. MemFree (lpVarStr);
  737. pTG->fFatalErrorWasSignaled = 1;
  738. SignalStatusChange(pTG, FS_FATAL_ERROR);
  739. RetCode = FALSE;
  740. goto l_exit;
  741. }
  742. lpDevCfg = (LPDEVCFG) ((LPBYTE)(lpVarStr)+lpVarStr->dwStringOffset);
  743. lpModemSettings = (LPMODEMSETTINGS) ( (LPBYTE) &(lpDevCfg->commconfig.wcProviderData) );
  744. pTG->dwSpeakerVolume = lpModemSettings->dwSpeakerVolume;
  745. pTG->dwSpeakerMode = lpModemSettings->dwSpeakerMode;
  746. if ( lpModemSettings->dwPreferredModemOptions & MDM_BLIND_DIAL ) {
  747. pTG->fBlindDial = 1;
  748. }
  749. else {
  750. pTG->fBlindDial = 0;
  751. }
  752. MyDebugPrint(pTG, LOG_ALL, "lineGetDevConfig returns SpeakerVolume=%x, Mode=%x BlindDial=%d \n",
  753. pTG->dwSpeakerVolume, pTG->dwSpeakerMode, pTG->fBlindDial );
  754. MemFree (lpVarStr);
  755. lpVarStr=0;
  756. // get dwPermanentLineID
  757. // ---------------------------
  758. lpLineDevCaps = (LPLINEDEVCAPS) buf;
  759. _fmemset(lpLineDevCaps, 0, sizeof (buf) );
  760. lpLineDevCaps->dwTotalSize = sizeof(buf);
  761. lResult = lineGetDevCaps(gT30.LineAppHandle,
  762. pTG->DeviceId,
  763. TAPI_VERSION,
  764. 0,
  765. lpLineDevCaps);
  766. if (lResult) {
  767. MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetDevCaps failed\n");
  768. pTG->fFatalErrorWasSignaled = 1;
  769. SignalStatusChange(pTG, FS_FATAL_ERROR);
  770. RetCode = FALSE;
  771. goto l_exit;
  772. }
  773. if (lpLineDevCaps->dwNeededSize > lpLineDevCaps->dwTotalSize) {
  774. MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetDevCaps NOT enough MEMORY\n");
  775. pTG->fFatalErrorWasSignaled = 1;
  776. SignalStatusChange(pTG, FS_FATAL_ERROR);
  777. RetCode = FALSE;
  778. goto l_exit;
  779. }
  780. // Save the permanent ID.
  781. //------------------------
  782. pTG->dwPermanentLineID = lpLineDevCaps->dwPermanentLineID;
  783. _stprintf (pTG->lpszPermanentLineID, "%08d\\Modem", pTG->dwPermanentLineID);
  784. MyDebugPrint(pTG, LOG_ALL, "Permanent Line ID=%s\n", pTG->lpszPermanentLineID);
  785. // Get the Unimodem key name for this device
  786. //------------------------------------------
  787. lpDSpec = (LPMDM_DEVSPEC) ( ( (LPBYTE) lpLineDevCaps) + lpLineDevCaps->dwDevSpecificOffset);
  788. if ( (lpLineDevCaps->dwDevSpecificSize < sizeof(MDM_DEVSPEC) ) ||
  789. (lpLineDevCaps->dwDevSpecificSize <= lpDSpec->dwKeyOffset) ) {
  790. MyDebugPrint(pTG, LOG_ERR, "Devspecifc caps size is only %lu",
  791. (unsigned long) lpLineDevCaps->dwDevSpecificSize );
  792. pTG->fFatalErrorWasSignaled = 1;
  793. SignalStatusChange(pTG, FS_FATAL_ERROR);
  794. RetCode = FALSE;
  795. goto l_exit;
  796. }
  797. else {
  798. UINT u = lpLineDevCaps->dwDevSpecificSize - lpDSpec->dwKeyOffset;
  799. #define szAPPEND "\\FAX"
  800. if ( (lpDSpec->dwContents != 1) || (lpDSpec->dwKeyOffset != 8 ) ) {
  801. MyDebugPrint(pTG, LOG_ERR, "Nonstandard Devspecific: dwContents=%lu; dwKeyOffset=%lu",
  802. (unsigned long) lpDSpec->dwContents,
  803. (unsigned long) lpDSpec->dwKeyOffset );
  804. pTG->fFatalErrorWasSignaled = 1;
  805. SignalStatusChange(pTG, FS_FATAL_ERROR);
  806. RetCode = FALSE;
  807. goto l_exit;
  808. }
  809. if (u) {
  810. _fmemcpy(rgchKey, lpDSpec->rgby, u);
  811. if (rgchKey[u]) {
  812. MyDebugPrint(pTG, LOG_ERR, "rgchKey not null terminated!" );
  813. rgchKey[u-1]=0;
  814. }
  815. //
  816. // Get ResponsesKeyName
  817. //
  818. lRet = RegOpenKeyEx(
  819. HKEY_LOCAL_MACHINE,
  820. rgchKey,
  821. 0,
  822. KEY_READ,
  823. &hKey);
  824. if (lRet != ERROR_SUCCESS) {
  825. MyDebugPrint(pTG, LOG_ERR, "Can't read Unimodem key %s\n", rgchKey);
  826. pTG->fFatalErrorWasSignaled = 1;
  827. SignalStatusChange(pTG, FS_FATAL_ERROR);
  828. RetCode = FALSE;
  829. goto l_exit;
  830. }
  831. dwSize = sizeof( pTG->ResponsesKeyName);
  832. lRet = RegQueryValueEx(
  833. hKey,
  834. "ResponsesKeyName",
  835. 0,
  836. &dwType,
  837. pTG->ResponsesKeyName,
  838. &dwSize);
  839. RegCloseKey(hKey);
  840. if (lRet != ERROR_SUCCESS) {
  841. MyDebugPrint(pTG, LOG_ERR, "Can't read Unimodem key\\ResponsesKeyName %s\n", rgchKey);
  842. pTG->fFatalErrorWasSignaled = 1;
  843. SignalStatusChange(pTG, FS_FATAL_ERROR);
  844. RetCode = FALSE;
  845. goto l_exit;
  846. }
  847. lstrcpy(pTG->lpszUnimodemKey, rgchKey);
  848. // Append "\\Fax" to the key
  849. u = lstrlen(rgchKey);
  850. if (u) {
  851. lstrcpy(rgchKey+u, (LPSTR) szAPPEND);
  852. }
  853. lstrcpy(pTG->lpszUnimodemFaxKey, rgchKey);
  854. MyDebugPrint(pTG, LOG_ALL, "Unimodem Fax key=%s\n", pTG->lpszUnimodemFaxKey);
  855. }
  856. }
  857. // Convert the destination# to a dialable
  858. //--------------------------------------------
  859. // find out how big a buffer should be
  860. //
  861. _fmemset(rgby, 0, sizeof(rgby));
  862. lplto1->dwTotalSize = sizeof(rgby);
  863. lRet = lineTranslateAddress (gT30.LineAppHandle,
  864. pTG->DeviceId,
  865. TAPI_VERSION,
  866. lpszFaxNumber,
  867. 0, // dwCard
  868. LINETRANSLATEOPTION_CANCELCALLWAITING,
  869. lplto1);
  870. if (lRet) {
  871. MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't translate dest. address %s\n", lpszFaxNumber);
  872. pTG->fFatalErrorWasSignaled = 1;
  873. SignalStatusChange(pTG, FS_FATAL_ERROR);
  874. RetCode = FALSE;
  875. goto l_exit;
  876. }
  877. if (lplto1->dwNeededSize <= 0) {
  878. MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't dwNeededSize<0 for Fax# %s\n", lpszFaxNumber);
  879. pTG->fFatalErrorWasSignaled = 1;
  880. SignalStatusChange(pTG, FS_FATAL_ERROR);
  881. RetCode = FALSE;
  882. goto l_exit;
  883. }
  884. lplto = MemAlloc(lplto1->dwNeededSize);
  885. if (! lplto) {
  886. MyDebugPrint(pTG, LOG_ERR, "ERROR:Couldn't allocate space for lplto\n");
  887. pTG->fFatalErrorWasSignaled = 1;
  888. SignalStatusChange(pTG, FS_FATAL_ERROR);
  889. RetCode = FALSE;
  890. goto l_exit;
  891. }
  892. lplto->dwTotalSize = lplto1->dwNeededSize;
  893. lRet = lineTranslateAddress (gT30.LineAppHandle,
  894. pTG->DeviceId,
  895. TAPI_VERSION,
  896. lpszFaxNumber,
  897. 0, // dwCard
  898. LINETRANSLATEOPTION_CANCELCALLWAITING,
  899. lplto);
  900. if (lRet) {
  901. MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't translate dest. address %s\n", lpszFaxNumber);
  902. MemFree(lplto);
  903. pTG->fFatalErrorWasSignaled = 1;
  904. SignalStatusChange(pTG, FS_FATAL_ERROR);
  905. RetCode = FALSE;
  906. goto l_exit;
  907. }
  908. if (lplto->dwNeededSize > lplto->dwTotalSize) {
  909. MyDebugPrint(pTG, LOG_ERR, "ERROR: NeedSize=%d > TotalSize=%d for Fax# %s\n",
  910. lplto->dwNeededSize ,lplto->dwTotalSize, lpszFaxNumber);
  911. MemFree(lplto);
  912. pTG->fFatalErrorWasSignaled = 1;
  913. SignalStatusChange(pTG, FS_FATAL_ERROR);
  914. RetCode = FALSE;
  915. goto l_exit;
  916. }
  917. _fmemcpy (pTG->lpszDialDestFax, ( (char *) lplto) + lplto->dwDialableStringOffset, lplto->dwDialableStringSize);
  918. MyDebugPrint(pTG, LOG_ALL, "Dialable Dest is %s\n", pTG->lpszDialDestFax);
  919. MemFree(lplto);
  920. /// RSL -revisit, may decrease prty during computation
  921. if (! SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) ) {
  922. MyDebugPrint(pTG, LOG_ERR, "ERROR: SetThreadPriority TIME CRITICAL failed le=%x", GetLastError() );
  923. }
  924. // initialize modem
  925. //--------------------
  926. T30ModemInit(pTG, pTG->hComm, 0, LINEID_TAPI_PERMANENT_DEVICEID,
  927. DEF_BASEKEY, pTG->lpszPermanentLineID, fMDMINIT_ANSWER);
  928. pTG->Inst.ProtParams.uMinScan = MINSCAN_0_0_0;
  929. ET30ProtSetProtParams(pTG, &pTG->Inst.ProtParams, pTG->FComModem.CurrMdmCaps.uSendSpeeds, pTG->FComModem.CurrMdmCaps.uRecvSpeeds);
  930. InitCapsBC( pTG, (LPBC) &pTG->Inst.SendCaps, sizeof(pTG->Inst.SendCaps), SEND_CAPS);
  931. // store the TIFF filename
  932. //-------------------------
  933. pTG->lpwFileName = AnsiStringToUnicodeString(FaxSend->FileName);
  934. if ( !pTG->fTiffOpenOrCreated) {
  935. pTG->Inst.hfile = PtrToUlong (TiffOpenW (pTG->lpwFileName,
  936. &pTG->TiffInfo,
  937. TRUE) );
  938. if (! (pTG->Inst.hfile)) {
  939. MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't open tiff file %s\n", pTG->lpwFileName);
  940. // pTG->StatusId = FS_TIFF_SRC_BAD
  941. pTG->fFatalErrorWasSignaled = 1;
  942. SignalStatusChange(pTG, FS_FATAL_ERROR);
  943. RetCode = FALSE;
  944. goto l_exit;
  945. }
  946. if (pTG->TiffInfo.YResolution == 98) {
  947. pTG->SrcHiRes = 0;
  948. }
  949. else {
  950. pTG->SrcHiRes = 1;
  951. }
  952. pTG->fTiffOpenOrCreated = 1;
  953. MyDebugPrint(pTG, LOG_ALL, "Successfully opened TIFF Yres=%d HiRes=%d\n",
  954. pTG->TiffInfo.YResolution, pTG->SrcHiRes);
  955. }
  956. else {
  957. MyDebugPrint(pTG, LOG_ERR, "ERROR:tiff file %s is OPENED already\n", pTG->lpwFileName);
  958. MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't open tiff file %s\n", pTG->lpwFileName);
  959. // pTG->StatusId = FS_TIFF_SRC_BAD
  960. pTG->fFatalErrorWasSignaled = 1;
  961. SignalStatusChange(pTG, FS_FATAL_ERROR);
  962. RetCode = FALSE;
  963. goto l_exit;
  964. }
  965. // Fax Service Callback
  966. //----------------------
  967. if (!FaxSendCallback(FaxHandle,
  968. CallHandle,
  969. 0,
  970. 0) ) {
  971. pTG->fFatalErrorWasSignaled = 1;
  972. SignalStatusChange(pTG, FS_FATAL_ERROR);
  973. RetCode = FALSE;
  974. goto l_exit;
  975. }
  976. // Send the Fax
  977. //-----------------------------------------------------------------------
  978. // here we already know what Class we will use for a particular modem.
  979. //-------------------------------------------------------------------
  980. if (pTG->ModemClass == MODEM_CLASS2) {
  981. Class2Init(pTG);
  982. RetCode = T30Cl2Tx (pTG, pTG->lpszDialDestFax);
  983. }
  984. else if (pTG->ModemClass == MODEM_CLASS2_0) {
  985. Class20Init(pTG);
  986. RetCode = T30Cl20Tx (pTG, pTG->lpszDialDestFax);
  987. }
  988. else if (pTG->ModemClass == MODEM_CLASS1) {
  989. RetCode = T30Cl1Tx(pTG, pTG->lpszDialDestFax);
  990. }
  991. // delete all the files that are left
  992. _fmemcpy (pTG->InFileName, gT30.TmpDirectory, gT30.dwLengthTmpDirectory);
  993. _fmemcpy (&pTG->InFileName[gT30.dwLengthTmpDirectory], pTG->lpszPermanentLineID, 8);
  994. for (dw = pTG->CurrentIn; dw <= pTG->LastOut; dw++) {
  995. sprintf( &pTG->InFileName[gT30.dwLengthTmpDirectory+8], ".%03d", dw);
  996. if (! DeleteFileA (pTG->InFileName) ) {
  997. MyDebugPrint(pTG, LOG_ERR, "ERROR: file %s can't be deleted; le=%lx at %ld \n",
  998. pTG->InFileName, GetLastError(), GetTickCount() );
  999. }
  1000. }
  1001. if (pTG->fTiffOpenOrCreated) {
  1002. TiffClose( (HANDLE) pTG->Inst.hfile);
  1003. pTG->fTiffOpenOrCreated = 0;
  1004. }
  1005. iModemClose(pTG);
  1006. // release the line
  1007. //-----------------------------
  1008. if (pTG->fDeallocateCall == 0) {
  1009. //
  1010. // line never was signalled IDLE, need to lineDrop first
  1011. //
  1012. if (!itapi_async_setup(pTG)) {
  1013. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevSend: lineDrop itapi_async_setup failed \n");
  1014. if (!pTG->fFatalErrorWasSignaled) {
  1015. pTG->fFatalErrorWasSignaled = 1;
  1016. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1017. }
  1018. RetCode = FALSE;
  1019. goto l_exit;
  1020. }
  1021. lRet = lineDrop (pTG->CallHandle, NULL, 0);
  1022. if (lRet < 0) {
  1023. MyDebugPrint(pTG, LOG_ERR, "ERROR: lineDrop failed %lx\n", lRet);
  1024. // return (FALSE);
  1025. }
  1026. else {
  1027. MyDebugPrint(pTG, LOG_ALL, "lineDrop returns request %d\n", lRet);
  1028. if(!itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_SHORT_TIMEOUT)) {
  1029. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevSend: itapi_async_wait failed on lineDrop\n");
  1030. goto l_exit;
  1031. }
  1032. MyDebugPrint(pTG, LOG_ALL, "lineDrop SUCCESS\n");
  1033. }
  1034. //
  1035. //deallocating call
  1036. //
  1037. // it took us some time since first test
  1038. if (pTG->fDeallocateCall == 0) {
  1039. pTG->fDeallocateCall = 1;
  1040. #if 0
  1041. //
  1042. // this is now performed in the fax service
  1043. //
  1044. lRet = lineDeallocateCall(pTG->CallHandle );
  1045. if (lRet) {
  1046. MyDebugPrint(pTG, LOG_ERR, "ERROR: lineDeallocateCall returns %lx\n", lRet);
  1047. }
  1048. else {
  1049. MyDebugPrint(pTG, LOG_ALL, "lineDeallocateCall SUCCESS\n");
  1050. }
  1051. #endif
  1052. }
  1053. }
  1054. l_exit:
  1055. if ( (RetCode == FALSE) && (pTG->StatusId == FS_COMPLETED) ) {
  1056. MyDebugPrint(pTG, LOG_ERR, "ERROR: exit FaxDevSend success but later failed \n");
  1057. RetCode = TRUE;
  1058. }
  1059. if ( (RecoveryIndex >= 0) && (RecoveryIndex < MAX_T30_CONNECT) ) {
  1060. T30Recovery[RecoveryIndex].fAvail = TRUE;
  1061. }
  1062. /// RSL -revisit, may decrease prty during computation
  1063. if (! SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL) ) {
  1064. MyDebugPrint(pTG, LOG_ERR, "ERROR: SetThreadPriority Normal failed le=%x", GetLastError() );
  1065. }
  1066. if (pTG->InFileHandleNeedsBeClosed) {
  1067. CloseHandle(pTG->InFileHandle);
  1068. pTG->InFileHandleNeedsBeClosed = 0;
  1069. }
  1070. MemFree(FaxSend->FileName);
  1071. MemFree(FaxSend->CallerName);
  1072. MemFree(FaxSend->CallerNumber);
  1073. MemFree(FaxSend->ReceiverName);
  1074. MemFree(FaxSend->ReceiverNumber);
  1075. if (!pTG->AckTerminate) {
  1076. if ( WaitForSingleObject(pTG->ThrdAckTerminateSignal, TX_WAIT_ACK_TERMINATE_TIMEOUT) == WAIT_TIMEOUT ) {
  1077. MyDebugPrint(pTG, LOG_ERR, "WARNING: Never got AckTerminate \n");
  1078. }
  1079. }
  1080. MyDebugPrint(pTG, LOG_ALL, "Got AckTerminate OK at %ld \n", GetTickCount() );
  1081. SetEvent(pTG->AbortAckEvent);
  1082. MyDebugPrint(pTG, LOG_ALL, "FaxDevSendA rets %d at %ld \n", RetCode, GetTickCount() );
  1083. return (RetCode);
  1084. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1085. //
  1086. // try to use the Recovery data
  1087. //
  1088. DWORD dwCkSum;
  1089. HCALL CallHandle;
  1090. HANDLE CompletionPortHandle;
  1091. ULONG_PTR CompletionKey;
  1092. PThrdGlbl pTG;
  1093. DWORD dwThreadId = GetCurrentThreadId();
  1094. fFound = 0;
  1095. for (i=0; i<MAX_T30_CONNECT; i++) {
  1096. if ( (! T30Recovery[i].fAvail) && (T30Recovery[i].ThreadId == dwThreadId) ) {
  1097. if ( ( dwCkSum = ComputeCheckSum( (LPDWORD) &T30Recovery[i].fAvail,
  1098. sizeof ( T30_RECOVERY_GLOB ) / sizeof (DWORD) - 1) ) == T30Recovery[i].CkSum ) {
  1099. CallHandle = T30Recovery[i].CallHandle;
  1100. CompletionPortHandle = T30Recovery[i].CompletionPortHandle;
  1101. CompletionKey = T30Recovery[i].CompletionKey;
  1102. pTG = (PThrdGlbl) T30Recovery[i].pTG;
  1103. fFound = 1;
  1104. T30Recovery[i].fAvail = TRUE;
  1105. break;
  1106. }
  1107. }
  1108. }
  1109. if (fFound == 0) {
  1110. //
  1111. // Need to indicate that FaxT30 couldn't recover by itself.
  1112. //
  1113. return (FALSE);
  1114. }
  1115. //
  1116. // get out of Pass-through
  1117. //
  1118. if (!itapi_async_setup(pTG)) {
  1119. return (FALSE);
  1120. }
  1121. lRet = lineSetCallParams(CallHandle,
  1122. LINEBEARERMODE_VOICE,
  1123. 0,
  1124. 0xffffffff,
  1125. NULL);
  1126. if (lRet < 0) {
  1127. return (FALSE);
  1128. }
  1129. else {
  1130. if(!itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_TIMEOUT)) {
  1131. return (FALSE);
  1132. }
  1133. }
  1134. //
  1135. // hang up
  1136. //
  1137. if (!itapi_async_setup(pTG)) {
  1138. return (FALSE);
  1139. }
  1140. lRet = lineDrop (CallHandle, NULL, 0);
  1141. if (lRet < 0) {
  1142. return (FALSE);
  1143. }
  1144. else {
  1145. if(!itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_TIMEOUT)) {
  1146. return (FALSE);
  1147. }
  1148. // SignalRecoveryStatusChange( &T30Recovery[i] );
  1149. }
  1150. //
  1151. // Deallocate
  1152. //
  1153. lRet = lineDeallocateCall (CallHandle);
  1154. if (lRet < 0) {
  1155. return (FALSE);
  1156. }
  1157. else {
  1158. SignalRecoveryStatusChange( &T30Recovery[i] );
  1159. }
  1160. if (pTG->InFileHandleNeedsBeClosed) {
  1161. CloseHandle(pTG->InFileHandle);
  1162. }
  1163. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  1164. return (FALSE);
  1165. }
  1166. }
  1167. ///////////////////////////////////////////////////////////////////////////////////
  1168. BOOL WINAPI
  1169. FaxDevReceiveA(
  1170. HANDLE FaxHandle,
  1171. HCALL CallHandle,
  1172. PFAX_RECEIVE_A FaxReceive
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. Arguments:
  1177. Return Value:
  1178. --*/
  1179. {
  1180. LONG_PTR i;
  1181. PThrdGlbl pTG=NULL;
  1182. long lRet;
  1183. DWORD dw;
  1184. LPVARSTRING lpVarStr=0;
  1185. LPDEVICEID lpDeviceID=0;
  1186. LPLINEDEVCAPS lpLineDevCaps;
  1187. BYTE buf[ sizeof(LINEDEVCAPS)+1000 ];
  1188. LONG lResult=0;
  1189. BOOL RetCode;
  1190. DWORD dwNeededSize;
  1191. LPDEVCFG lpDevCfg;
  1192. LPMODEMSETTINGS lpModemSettings;
  1193. int fFound=0;
  1194. int RecoveryIndex = -1;
  1195. LPMDM_DEVSPEC lpDSpec;
  1196. char rgchKey[256];
  1197. HKEY hKey;
  1198. DWORD dwType;
  1199. DWORD dwSize;
  1200. __try {
  1201. MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevReceiveA FaxHandle=%x, CallHandle=%x, FaxReceive=%x at %ld \n",
  1202. FaxHandle, CallHandle, FaxReceive, GetTickCount() );
  1203. // find instance data
  1204. //------------------------
  1205. i = (LONG_PTR) FaxHandle;
  1206. if (i < 1 || i >= MAX_T30_CONNECT) {
  1207. MemFree(FaxReceive->FileName);
  1208. MemFree(FaxReceive->ReceiverName);
  1209. MemFree(FaxReceive->ReceiverNumber);
  1210. MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: ERROR i FaxDevReceiveA FaxHandle=%x, CallHandle=%x, FaxReceive=%x at %ld \n",
  1211. FaxHandle, CallHandle, FaxReceive, GetTickCount() );
  1212. return (FALSE);
  1213. }
  1214. if (T30Inst[i].fAvail) {
  1215. MemFree(FaxReceive->FileName);
  1216. MemFree(FaxReceive->ReceiverName);
  1217. MemFree(FaxReceive->ReceiverNumber);
  1218. MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: ERROR AVAIL FaxDevReceiveA FaxHandle=%x, CallHandle=%x, FaxReceive=%x at %ld \n",
  1219. FaxHandle, CallHandle, FaxReceive, GetTickCount() );
  1220. return (FALSE);
  1221. }
  1222. pTG = (PThrdGlbl) T30Inst[i].pT30;
  1223. pTG->CallHandle = CallHandle;
  1224. //
  1225. // Add entry to the Recovery Area.
  1226. //
  1227. fFound = 0;
  1228. for (i=0; i<MAX_T30_CONNECT; i++) {
  1229. if (T30Recovery[i].fAvail) {
  1230. EnterCriticalSection(&T30RecoveryCritSection);
  1231. T30Recovery[i].fAvail = FALSE;
  1232. T30Recovery[i].ThreadId = GetCurrentThreadId();
  1233. T30Recovery[i].FaxHandle = FaxHandle;
  1234. T30Recovery[i].pTG = (LPVOID) pTG;
  1235. T30Recovery[i].LineHandle = pTG->LineHandle;
  1236. T30Recovery[i].CallHandle = CallHandle;
  1237. T30Recovery[i].DeviceId = pTG->DeviceId;
  1238. T30Recovery[i].CompletionPortHandle = pTG->CompletionPortHandle;
  1239. T30Recovery[i].CompletionKey = pTG->CompletionKey;
  1240. T30Recovery[i].TiffThreadId = 0;
  1241. T30Recovery[i].TimeStart = GetTickCount();
  1242. T30Recovery[i].TimeUpdated = T30Recovery[i].TimeStart;
  1243. T30Recovery[i].CkSum = ComputeCheckSum( (LPDWORD) &T30Recovery[i].fAvail,
  1244. sizeof ( T30_RECOVERY_GLOB ) / sizeof (DWORD) - 1);
  1245. LeaveCriticalSection(&T30RecoveryCritSection);
  1246. fFound = 1;
  1247. RecoveryIndex = (int)i;
  1248. pTG->RecoveryIndex = (int)i;
  1249. break;
  1250. }
  1251. }
  1252. if (! fFound) {
  1253. MyDebugPrint(pTG, LOG_ERR, "ERROR:Couldn't find available space for Recovery\n");
  1254. pTG->fFatalErrorWasSignaled = 1;
  1255. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1256. RetCode = FALSE;
  1257. goto l_exit;
  1258. }
  1259. pTG->Operation = T30_RX;
  1260. // store LocalID
  1261. if (FaxReceive->ReceiverNumber == NULL) {
  1262. pTG->LocalID[0] = 0;
  1263. }
  1264. else {
  1265. _fmemcpy(pTG->LocalID, FaxReceive->ReceiverNumber, min (_fstrlen(FaxReceive->ReceiverNumber), sizeof(pTG->LocalID) - 1) );
  1266. pTG->LocalID [ min (_fstrlen(FaxReceive->ReceiverNumber), sizeof(pTG->LocalID) - 1) ] = 0;
  1267. }
  1268. // tiff
  1269. //-----------------------------------------------
  1270. pTG->lpwFileName = AnsiStringToUnicodeString(FaxReceive->FileName);
  1271. pTG->SrcHiRes = 1;
  1272. // take line over from TAPI
  1273. //--------------------------
  1274. pTG->fGotConnect = FALSE;
  1275. // initiate passthru
  1276. if (!itapi_async_setup(pTG)) {
  1277. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevReceive: itapi_async_setup failed \n");
  1278. pTG->fFatalErrorWasSignaled = 1;
  1279. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1280. RetCode = FALSE;
  1281. goto l_exit;
  1282. }
  1283. lRet = lineSetCallParams(CallHandle,
  1284. LINEBEARERMODE_PASSTHROUGH,
  1285. 0,
  1286. 0xffffffff,
  1287. NULL);
  1288. if (lRet < 0) {
  1289. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevReceive: lineSetCallParams failed \n");
  1290. pTG->fFatalErrorWasSignaled = 1;
  1291. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1292. RetCode = FALSE;
  1293. goto l_exit;
  1294. }
  1295. else {
  1296. MyDebugPrint(pTG, LOG_ALL, "lpfnlineSetCallParams returns ID %ld\n", (long) lRet);
  1297. }
  1298. if(!itapi_async_wait(pTG, (DWORD)lRet, &lRet, NULL, ASYNC_TIMEOUT)) {
  1299. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevReceive: itapi_async_wait failed \n");
  1300. pTG->fFatalErrorWasSignaled = 1;
  1301. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1302. RetCode = FALSE;
  1303. goto l_exit;
  1304. }
  1305. // now we wait for the connected message
  1306. //--------------------------------------
  1307. for (dw=50; dw<10000; dw = dw*120/100) {
  1308. Sleep(dw);
  1309. if (pTG->fGotConnect)
  1310. break;
  1311. }
  1312. if (!pTG->fGotConnect) {
  1313. MyDebugPrint(pTG, LOG_ERR, "ERROR:Failure waiting for CONNECTED message....\n");
  1314. // We ignore...
  1315. }
  1316. // get the handle to a Comm port
  1317. //----------------------------------
  1318. lpVarStr = (LPVARSTRING) MemAlloc(IDVARSTRINGSIZE);
  1319. if (!lpVarStr) {
  1320. MyDebugPrint(pTG, LOG_ALL, "ERROR:Couldn't allocate space for lpVarStr\n");
  1321. pTG->fFatalErrorWasSignaled = 1;
  1322. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1323. RetCode = FALSE;
  1324. goto l_exit;
  1325. }
  1326. _fmemset(lpVarStr, 0, IDVARSTRINGSIZE);
  1327. lpVarStr->dwTotalSize = IDVARSTRINGSIZE;
  1328. MyDebugPrint(pTG, LOG_ALL, "Calling lineGetId\n");
  1329. lRet = lineGetID(pTG->LineHandle,
  1330. 0, // +++ addr
  1331. CallHandle,
  1332. LINECALLSELECT_CALL, // dwSelect,
  1333. lpVarStr, //lpDeviceID,
  1334. "comm/datamodem" ); //lpszDeviceClass
  1335. if (lRet) {
  1336. MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetID returns error 0x%lx\n", (unsigned long) lRet);
  1337. pTG->fFatalErrorWasSignaled = 1;
  1338. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1339. RetCode = FALSE;
  1340. goto l_exit;
  1341. }
  1342. MyDebugPrint(pTG, LOG_ALL, "lineGetId returned SUCCESS\n");
  1343. // extract id
  1344. if (lpVarStr->dwStringFormat != STRINGFORMAT_BINARY) {
  1345. MyDebugPrint(pTG, LOG_ERR, "ERROR:String format is not binary\n");
  1346. pTG->fFatalErrorWasSignaled = 1;
  1347. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1348. RetCode = FALSE;
  1349. goto l_exit;
  1350. }
  1351. if (lpVarStr->dwUsedSize<sizeof(DEVICEID)) {
  1352. MyDebugPrint(pTG, LOG_ERR, "ERROR:Varstring size too small\n");
  1353. pTG->fFatalErrorWasSignaled = 1;
  1354. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1355. RetCode = FALSE;
  1356. goto l_exit;
  1357. }
  1358. lpDeviceID = (LPDEVICEID) ((LPBYTE)(lpVarStr)+lpVarStr->dwStringOffset);
  1359. MyDebugPrint(pTG, LOG_ALL, "lineGetID returns handle 0x%08lx, \"%s\"\n",
  1360. (ULONG_PTR) lpDeviceID->hComm,
  1361. (LPSTR) lpDeviceID->szDeviceName);
  1362. pTG->hComm = lpDeviceID->hComm;
  1363. if (BAD_HANDLE(pTG->hComm)) {
  1364. MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetID returns NULL hComm\n");
  1365. pTG->fFatalErrorWasSignaled = 1;
  1366. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1367. RetCode = FALSE;
  1368. goto l_exit;
  1369. }
  1370. // get the Modem configuration (speaker, etc.) from TAPI
  1371. //------------------------------------------------------
  1372. _fmemset(lpVarStr, 0, IDVARSTRINGSIZE);
  1373. lpVarStr->dwTotalSize = IDVARSTRINGSIZE;
  1374. lResult = lineGetDevConfig(pTG->DeviceId,
  1375. lpVarStr,
  1376. "comm/datamodem");
  1377. if (lResult) {
  1378. if (lpVarStr->dwTotalSize < lpVarStr->dwNeededSize) {
  1379. dwNeededSize = lpVarStr->dwNeededSize;
  1380. MemFree (lpVarStr);
  1381. if ( ! (lpVarStr = (LPVARSTRING) MemAlloc(dwNeededSize) ) ) {
  1382. MyDebugPrint(pTG, LOG_ERR, "ERR: Can't allocate %d bytes for lineGetDevConfig\n");
  1383. pTG->fFatalErrorWasSignaled = 1;
  1384. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1385. RetCode = FALSE;
  1386. goto l_exit;
  1387. }
  1388. _fmemset(lpVarStr, 0, dwNeededSize);
  1389. lpVarStr->dwTotalSize = dwNeededSize;
  1390. lResult = lineGetDevConfig(pTG->DeviceId,
  1391. lpVarStr,
  1392. "comm/datamodem");
  1393. if (lResult) {
  1394. MyDebugPrint(pTG, LOG_ERR, "ERR: lineGetDevConfig returns %x, le=%x", lResult, GetLastError() );
  1395. MemFree (lpVarStr);
  1396. pTG->fFatalErrorWasSignaled = 1;
  1397. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1398. RetCode = FALSE;
  1399. goto l_exit;
  1400. }
  1401. }
  1402. else {
  1403. MyDebugPrint(pTG, LOG_ERR, "ERR: 1st lineGetDevConfig returns %x, le=%x", lResult, GetLastError() );
  1404. MemFree (lpVarStr);
  1405. pTG->fFatalErrorWasSignaled = 1;
  1406. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1407. RetCode = FALSE;
  1408. goto l_exit;
  1409. }
  1410. }
  1411. //
  1412. // extract DEVCFG
  1413. //
  1414. if (lpVarStr->dwStringFormat != STRINGFORMAT_BINARY) {
  1415. MyDebugPrint(pTG, LOG_ERR, "ERROR: String format is not binary for lineGetDevConfig\n");
  1416. MemFree (lpVarStr);
  1417. pTG->fFatalErrorWasSignaled = 1;
  1418. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1419. RetCode = FALSE;
  1420. goto l_exit;
  1421. }
  1422. if (lpVarStr->dwUsedSize<sizeof(DEVCFG)) {
  1423. MyDebugPrint(pTG, LOG_ERR, "ERROR: lineGetDevConfig : Varstring size returned too small\n");
  1424. MemFree (lpVarStr);
  1425. pTG->fFatalErrorWasSignaled = 1;
  1426. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1427. RetCode = FALSE;
  1428. goto l_exit;
  1429. }
  1430. lpDevCfg = (LPDEVCFG) ((LPBYTE)(lpVarStr)+lpVarStr->dwStringOffset);
  1431. lpModemSettings = (LPMODEMSETTINGS) ( (LPBYTE) &(lpDevCfg->commconfig.wcProviderData) );
  1432. pTG->dwSpeakerVolume = lpModemSettings->dwSpeakerVolume;
  1433. pTG->dwSpeakerMode = lpModemSettings->dwSpeakerMode;
  1434. MyDebugPrint(pTG, LOG_ALL, "lineGetDevConfig returns SpeakerVolume=%x, Volume=%x\n",
  1435. pTG->dwSpeakerVolume, pTG->dwSpeakerMode);
  1436. MemFree (lpVarStr);
  1437. lpVarStr=0;
  1438. // get dwPermanentLineID
  1439. // ---------------------------
  1440. lpLineDevCaps = (LPLINEDEVCAPS) buf;
  1441. _fmemset(lpLineDevCaps, 0, sizeof (buf) );
  1442. lpLineDevCaps->dwTotalSize = sizeof(buf);
  1443. lResult = lineGetDevCaps(gT30.LineAppHandle,
  1444. pTG->DeviceId,
  1445. TAPI_VERSION,
  1446. 0,
  1447. lpLineDevCaps);
  1448. if (lResult) {
  1449. MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetDevCaps failed\n");
  1450. pTG->fFatalErrorWasSignaled = 1;
  1451. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1452. RetCode = FALSE;
  1453. goto l_exit;
  1454. }
  1455. if (lpLineDevCaps->dwNeededSize > lpLineDevCaps->dwTotalSize) {
  1456. MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetDevCaps NOT enough MEMORY\n");
  1457. pTG->fFatalErrorWasSignaled = 1;
  1458. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1459. RetCode = FALSE;
  1460. goto l_exit;
  1461. }
  1462. // Save the permanent ID.
  1463. //------------------------
  1464. pTG->dwPermanentLineID =lpLineDevCaps->dwPermanentLineID;
  1465. _stprintf (pTG->lpszPermanentLineID, "%08d\\Modem", pTG->dwPermanentLineID);
  1466. MyDebugPrint(pTG, LOG_ALL, "Permanent Line ID=%s\n", pTG->lpszPermanentLineID);
  1467. // Get the Unimodem key name for this device
  1468. //------------------------------------------
  1469. lpDSpec = (LPMDM_DEVSPEC) ( ( (LPBYTE) lpLineDevCaps) + lpLineDevCaps->dwDevSpecificOffset);
  1470. if ( (lpLineDevCaps->dwDevSpecificSize < sizeof(MDM_DEVSPEC) ) ||
  1471. (lpLineDevCaps->dwDevSpecificSize <= lpDSpec->dwKeyOffset) ) {
  1472. MyDebugPrint(pTG, LOG_ERR, "Devspecifc caps size is only %lu",
  1473. (unsigned long) lpLineDevCaps->dwDevSpecificSize );
  1474. pTG->fFatalErrorWasSignaled = 1;
  1475. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1476. RetCode = FALSE;
  1477. goto l_exit;
  1478. }
  1479. else {
  1480. UINT u = lpLineDevCaps->dwDevSpecificSize - lpDSpec->dwKeyOffset;
  1481. #define szAPPEND "\\FAX"
  1482. if ( (lpDSpec->dwContents != 1) || (lpDSpec->dwKeyOffset != 8 ) ) {
  1483. MyDebugPrint(pTG, LOG_ERR, "Nonstandard Devspecific: dwContents=%lu; dwKeyOffset=%lu",
  1484. (unsigned long) lpDSpec->dwContents,
  1485. (unsigned long) lpDSpec->dwKeyOffset );
  1486. pTG->fFatalErrorWasSignaled = 1;
  1487. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1488. RetCode = FALSE;
  1489. goto l_exit;
  1490. }
  1491. if (u) {
  1492. _fmemcpy(rgchKey, lpDSpec->rgby, u);
  1493. if (rgchKey[u]) {
  1494. MyDebugPrint(pTG, LOG_ERR, "rgchKey not null terminated!" );
  1495. rgchKey[u-1]=0;
  1496. }
  1497. //
  1498. // Get ResponsesKeyName value
  1499. //
  1500. lRet = RegOpenKeyEx(
  1501. HKEY_LOCAL_MACHINE,
  1502. rgchKey,
  1503. 0,
  1504. KEY_READ,
  1505. &hKey);
  1506. if (lRet != ERROR_SUCCESS) {
  1507. MyDebugPrint(pTG, LOG_ERR, "Can't read Unimodem key %s\n", rgchKey);
  1508. pTG->fFatalErrorWasSignaled = 1;
  1509. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1510. RetCode = FALSE;
  1511. goto l_exit;
  1512. }
  1513. dwSize = sizeof( pTG->ResponsesKeyName);
  1514. lRet = RegQueryValueEx(
  1515. hKey,
  1516. "ResponsesKeyName",
  1517. 0,
  1518. &dwType,
  1519. pTG->ResponsesKeyName,
  1520. &dwSize);
  1521. RegCloseKey(hKey);
  1522. if (lRet != ERROR_SUCCESS) {
  1523. MyDebugPrint(pTG, LOG_ERR, "Can't read Unimodem key\\ResponsesKeyName %s\n", rgchKey);
  1524. pTG->fFatalErrorWasSignaled = 1;
  1525. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1526. RetCode = FALSE;
  1527. goto l_exit;
  1528. }
  1529. // Append "\\Fax" to the key
  1530. u = lstrlen(rgchKey);
  1531. if (u) {
  1532. lstrcpy(rgchKey+u, (LPSTR) szAPPEND);
  1533. }
  1534. lstrcpy(pTG->lpszUnimodemFaxKey, rgchKey);
  1535. MyDebugPrint(pTG, LOG_ALL, "Unimodem Fax key=%s\n", pTG->lpszUnimodemFaxKey);
  1536. }
  1537. }
  1538. /// RSL -revisit, may decrease prty during computation
  1539. if (! SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) ) {
  1540. MyDebugPrint(pTG, LOG_ERR, "ERROR: SetThreadPriority TIME CRITICAL failed le=%x", GetLastError() );
  1541. }
  1542. // initialize modem
  1543. //--------------------
  1544. T30ModemInit(pTG, pTG->hComm, 0, LINEID_TAPI_PERMANENT_DEVICEID,
  1545. DEF_BASEKEY, pTG->lpszPermanentLineID, fMDMINIT_ANSWER);
  1546. pTG->Inst.ProtParams.uMinScan = MINSCAN_0_0_0;
  1547. ET30ProtSetProtParams(pTG, &pTG->Inst.ProtParams, pTG->FComModem.CurrMdmCaps.uSendSpeeds, pTG->FComModem.CurrMdmCaps.uRecvSpeeds);
  1548. InitCapsBC( pTG, (LPBC) &pTG->Inst.SendCaps, sizeof(pTG->Inst.SendCaps), SEND_CAPS);
  1549. // answer the call and receive a fax
  1550. //-----------------------------------
  1551. // here we already know what Class we will use for a particular modem.
  1552. //-------------------------------------------------------------------
  1553. if (pTG->ModemClass == MODEM_CLASS2) {
  1554. Class2Init(pTG);
  1555. RetCode = T30Cl2Rx (pTG);
  1556. }
  1557. else if (pTG->ModemClass == MODEM_CLASS2_0) {
  1558. Class20Init(pTG);
  1559. RetCode = T30Cl20Rx (pTG);
  1560. }
  1561. else if (pTG->ModemClass == MODEM_CLASS1) {
  1562. RetCode = T30Cl1Rx(pTG);
  1563. }
  1564. if ( pTG->fTiffOpenOrCreated ) {
  1565. TiffClose( (HANDLE) pTG->Inst.hfile );
  1566. pTG->fTiffOpenOrCreated = 0;
  1567. }
  1568. iModemClose(pTG);
  1569. #ifdef ADAPTIVE_ANSWER
  1570. if (pTG->Comm.fEnableHandoff && pTG->Comm.fDataCall) {
  1571. MyDebugPrint(pTG, LOG_ALL, "DataCall dont hangup\n");
  1572. RetCode = FALSE;
  1573. goto l_exit;
  1574. }
  1575. #endif
  1576. // release the line
  1577. //-----------------------------
  1578. if (pTG->fDeallocateCall == 0) {
  1579. //
  1580. // line never was signalled IDLE, need to lineDrop first
  1581. //
  1582. if (!itapi_async_setup(pTG)) {
  1583. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevReceive: lineDrop itapi_async_setup failed \n");
  1584. if (!pTG->fFatalErrorWasSignaled) {
  1585. pTG->fFatalErrorWasSignaled = 1;
  1586. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1587. }
  1588. RetCode = FALSE;
  1589. goto l_exit;
  1590. }
  1591. lRet = lineDrop (pTG->CallHandle, NULL, 0);
  1592. if (lRet < 0) {
  1593. MyDebugPrint(pTG, LOG_ERR, "ERROR: lineDrop failed %lx\n", lRet);
  1594. if (!pTG->fFatalErrorWasSignaled) {
  1595. pTG->fFatalErrorWasSignaled = 1;
  1596. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1597. }
  1598. RetCode = FALSE;
  1599. goto l_exit;
  1600. }
  1601. else {
  1602. MyDebugPrint(pTG, LOG_ALL, "lineDrop returns request %d\n", lRet);
  1603. }
  1604. if(!itapi_async_wait(pTG, (DWORD)lRet, &lRet, NULL, ASYNC_SHORT_TIMEOUT)) {
  1605. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevReceive: itapi_async_wait failed on lineDrop\n");
  1606. goto l_exit;
  1607. }
  1608. MyDebugPrint(pTG, LOG_ALL, "lineDrop SUCCESS\n");
  1609. //
  1610. //deallocating call
  1611. //
  1612. if (pTG->fDeallocateCall == 0) {
  1613. pTG->fDeallocateCall = 1;
  1614. #if 0
  1615. //
  1616. // this is now performed in the fax service
  1617. //
  1618. lRet = lineDeallocateCall(pTG->CallHandle );
  1619. if (lRet) {
  1620. MyDebugPrint(pTG, LOG_ERR, "ERROR: lineDeallocateCall returns %lx\n", lRet);
  1621. }
  1622. else {
  1623. MyDebugPrint(pTG, LOG_ALL, "lineDeallocateCall SUCCESS\n");
  1624. }
  1625. #endif
  1626. }
  1627. }
  1628. l_exit:
  1629. if ( (RetCode == FALSE) && (pTG->StatusId == FS_COMPLETED) ) {
  1630. MyDebugPrint(pTG, LOG_ERR, "ERROR: exit FaxDevReceive success but later failed \n");
  1631. RetCode = TRUE;
  1632. }
  1633. if ( (RecoveryIndex >= 0) && (RecoveryIndex < MAX_T30_CONNECT) ) {
  1634. T30Recovery[RecoveryIndex].fAvail = TRUE;
  1635. }
  1636. if (! SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL) ) {
  1637. MyDebugPrint(pTG, LOG_ERR, "ERROR: SetThreadPriority Normal failed le=%x", GetLastError() );
  1638. }
  1639. if (pTG->InFileHandleNeedsBeClosed) {
  1640. CloseHandle(pTG->InFileHandle);
  1641. pTG->InFileHandleNeedsBeClosed = 0;
  1642. }
  1643. if (!pTG->AckTerminate) {
  1644. if ( WaitForSingleObject(pTG->ThrdAckTerminateSignal, RX_WAIT_ACK_TERMINATE_TIMEOUT) == WAIT_TIMEOUT ) {
  1645. MyDebugPrint(pTG, LOG_ERR, "WARNING: Never got AckTerminate \n");
  1646. }
  1647. }
  1648. MyDebugPrint(pTG, LOG_ALL, "Got AckTerminate OK at %ld \n", GetTickCount() );
  1649. SetEvent(pTG->AbortAckEvent);
  1650. MemFree(FaxReceive->FileName);
  1651. MemFree(FaxReceive->ReceiverName);
  1652. MemFree(FaxReceive->ReceiverNumber);
  1653. MyDebugPrint(pTG, LOG_ALL, "FaxDevReceiveA rets %d at %ld \n", RetCode, GetTickCount() );
  1654. return (RetCode);
  1655. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1656. //
  1657. // try to use the Recovery data
  1658. //
  1659. DWORD dwCkSum;
  1660. HCALL CallHandle;
  1661. HANDLE CompletionPortHandle;
  1662. ULONG_PTR CompletionKey;
  1663. PThrdGlbl pTG;
  1664. DWORD dwThreadId = GetCurrentThreadId();
  1665. fFound = 0;
  1666. for (i=0; i<MAX_T30_CONNECT; i++) {
  1667. if ( (! T30Recovery[i].fAvail) && (T30Recovery[i].ThreadId == dwThreadId) ) {
  1668. if ( ( dwCkSum = ComputeCheckSum( (LPDWORD) &T30Recovery[i].fAvail,
  1669. sizeof ( T30_RECOVERY_GLOB ) / sizeof (DWORD) - 1) ) == T30Recovery[i].CkSum ) {
  1670. CallHandle = T30Recovery[i].CallHandle;
  1671. CompletionPortHandle = T30Recovery[i].CompletionPortHandle;
  1672. CompletionKey = T30Recovery[i].CompletionKey;
  1673. pTG = (PThrdGlbl) T30Recovery[i].pTG;
  1674. T30Recovery[i].fAvail = TRUE;
  1675. fFound = 1;
  1676. break;
  1677. }
  1678. }
  1679. }
  1680. if (fFound == 0) {
  1681. //
  1682. // Need to indicate that FaxT30 couldn't recover by itself.
  1683. //
  1684. return (FALSE);
  1685. }
  1686. //
  1687. // get out of Pass-through
  1688. //
  1689. if (!itapi_async_setup(pTG)) {
  1690. return (FALSE);
  1691. }
  1692. lRet = lineSetCallParams(CallHandle,
  1693. LINEBEARERMODE_VOICE,
  1694. 0,
  1695. 0xffffffff,
  1696. NULL);
  1697. if (lRet < 0) {
  1698. return (FALSE);
  1699. }
  1700. else {
  1701. if(!itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_TIMEOUT)) {
  1702. return (FALSE);
  1703. }
  1704. }
  1705. //
  1706. // hang up
  1707. //
  1708. if (!itapi_async_setup(pTG)) {
  1709. return (FALSE);
  1710. }
  1711. lRet = lineDrop (CallHandle, NULL, 0);
  1712. if (lRet < 0) {
  1713. return (FALSE);
  1714. }
  1715. else {
  1716. if(!itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_TIMEOUT)) {
  1717. return (FALSE);
  1718. }
  1719. // SignalRecoveryStatusChange( &T30Recovery[i] );
  1720. }
  1721. //
  1722. // Deallocate
  1723. //
  1724. lRet = lineDeallocateCall (CallHandle);
  1725. if (lRet < 0) {
  1726. return (FALSE);
  1727. }
  1728. else {
  1729. SignalRecoveryStatusChange( &T30Recovery[i] );
  1730. }
  1731. if (pTG->InFileHandleNeedsBeClosed) {
  1732. CloseHandle(pTG->InFileHandle);
  1733. }
  1734. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  1735. return (FALSE);
  1736. }
  1737. }
  1738. ///////////////////////////////////////////////////////////////////////////////////
  1739. BOOL WINAPI
  1740. FaxDevReportStatusA(
  1741. IN HANDLE FaxHandle OPTIONAL,
  1742. OUT PFAX_DEV_STATUS FaxStatus,
  1743. IN DWORD FaxStatusSize,
  1744. OUT LPDWORD FaxStatusSizeRequired
  1745. )
  1746. /*++
  1747. Routine Description:
  1748. Arguments:
  1749. Return Value:
  1750. --*/
  1751. {
  1752. LONG_PTR i;
  1753. PThrdGlbl pTG;
  1754. LPWSTR lpwCSI; // inside the FaxStatus struct.
  1755. LPBYTE lpTemp;
  1756. *FaxStatusSizeRequired = sizeof (FAX_DEV_STATUS);
  1757. __try {
  1758. if (FaxStatusSize < *FaxStatusSizeRequired ) {
  1759. MyDebugPrint(0, LOG_ALL, "EP: WARNING:FaxDevReportStatus: wrong size passed=%d, expected not less than %d\n",
  1760. FaxStatusSize,
  1761. *FaxStatusSizeRequired);
  1762. goto failure;
  1763. }
  1764. if (FaxHandle == NULL) {
  1765. // means global status
  1766. MyDebugPrint(0, LOG_ERR, "EP: FaxDevReportStatus NULL FaxHandle; gT30.Status=%d \n", gT30.Status);
  1767. if (gT30.Status == STATUS_FAIL) {
  1768. goto failure;
  1769. }
  1770. else {
  1771. return (TRUE);
  1772. }
  1773. }
  1774. else {
  1775. // find instance data
  1776. //------------------------
  1777. i = (LONG_PTR) FaxHandle;
  1778. if (i < 1 || i >= MAX_T30_CONNECT) {
  1779. MyDebugPrint(0, LOG_ERR, "EP: ERROR:FaxDevReportStatus - got wrong FaxHandle=%d\n", i);
  1780. goto failure;
  1781. }
  1782. if (T30Inst[i].fAvail) {
  1783. MyDebugPrint(0, LOG_ERR, "EP: ERROR:FaxDevReportStatus - got wrong FaxHandle (marked as free) %d\n", i);
  1784. goto failure;
  1785. }
  1786. pTG = (PThrdGlbl) T30Inst[i].pT30;
  1787. FaxStatus->StatusId = pTG->StatusId;
  1788. FaxStatus->StringId = pTG->StringId;
  1789. FaxStatus->PageCount = pTG->PageCount;
  1790. if (pTG->fRemoteIdAvail) {
  1791. lpTemp = (LPBYTE) FaxStatus;
  1792. lpTemp += sizeof(FAX_DEV_STATUS);
  1793. lpwCSI = (LPWSTR) lpTemp;
  1794. wcscpy(lpwCSI, pTG->RemoteID);
  1795. FaxStatus->CSI = (LPWSTR) lpwCSI;
  1796. }
  1797. else {
  1798. FaxStatus->CSI = NULL;
  1799. }
  1800. FaxStatus->CallerId = NULL; // (char *) AnsiStringToUnicodeString(pTG->CallerId);
  1801. FaxStatus->RoutingInfo = NULL; // (char *) AnsiStringToUnicodeString(pTG->RoutingInfo);
  1802. MyDebugPrint(pTG, LOG_ALL, "EP: FaxDevReportStatus rets %lx \n", pTG->StatusId);
  1803. return (TRUE);
  1804. }
  1805. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1806. MyDebugPrint(0, LOG_ERR, "EP: ERROR:FaxDevReportStatus crashed accessing data\n");
  1807. return (FALSE);
  1808. }
  1809. MyDebugPrint(0, LOG_ERR, "EP: ERROR:FaxDevReportStatus wrong return\n");
  1810. return (TRUE);
  1811. failure:
  1812. return (FALSE);
  1813. }
  1814. ///////////////////////////////////////////////////////////////////////////////////
  1815. BOOL WINAPI
  1816. FaxDevAbortOperationA(
  1817. HANDLE FaxHandle
  1818. )
  1819. /*++
  1820. Routine Description:
  1821. Arguments:
  1822. Return Value:
  1823. --*/
  1824. {
  1825. LONG_PTR i;
  1826. PThrdGlbl pTG=NULL;
  1827. long lRet;
  1828. MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevAbortOperationA FaxHandle=%x at %ld \n", FaxHandle, GetTickCount() );
  1829. // find instance data
  1830. //------------------------
  1831. i = (LONG_PTR) FaxHandle;
  1832. if (i < 1 || i >= MAX_T30_CONNECT) {
  1833. MyDebugPrint(pTG, LOG_ERR, "FaxDevAbort - got wrong FaxHandle=%d\n", i);
  1834. return (FALSE);
  1835. }
  1836. if (T30Inst[i].fAvail) {
  1837. MyDebugPrint(pTG, LOG_ERR, "FaxDevAbort - got wrong FaxHandle (marked as free) %d\n", i);
  1838. return (FALSE);
  1839. }
  1840. pTG = (PThrdGlbl) T30Inst[i].pT30;
  1841. if (pTG->fAbortRequested) {
  1842. MyDebugPrint(pTG, LOG_ERR, "FaxDevAbort - ABORT request had been POSTED already\n");
  1843. return (FALSE);
  1844. }
  1845. if (pTG->StatusId == FS_NOT_FAX_CALL) {
  1846. MyDebugPrint( pTG, LOG_ALL, "Abort on DATA call at %ld\n", GetTickCount() );
  1847. if (!itapi_async_setup(pTG)) {
  1848. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevAbortOperationA: itapi_async_setup failed \n");
  1849. return (FALSE);
  1850. }
  1851. lRet = lineDrop(pTG->CallHandle, NULL, 0);
  1852. if (lRet < 0) {
  1853. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevAbortOperationA: lineDrop failed %x \n", lRet);
  1854. return (FALSE);
  1855. }
  1856. if( !itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_TIMEOUT)) {
  1857. MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevAbortOperationA: async_wait lineDrop failed at %ld \n", GetTickCount() );
  1858. return (FALSE);
  1859. }
  1860. MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevAbortOperationA finished SUCCESS \n");
  1861. return (TRUE);
  1862. }
  1863. //
  1864. // real ABORT request.
  1865. //
  1866. MyDebugPrint( pTG, LOG_ALL, "FaxDevAbort: ABORT requested %ld\n", GetTickCount() );
  1867. pTG->fFatalErrorWasSignaled = 1;
  1868. SignalStatusChange(pTG, FS_USER_ABORT);
  1869. // set the global abort flag for pTG
  1870. pTG->fAbortRequested = 1;
  1871. // set the abort flag for imaging threads
  1872. pTG->ReqTerminate = 1;
  1873. // signal manual-reset event to everybody waiting on multiple objects
  1874. if (! SetEvent(pTG->AbortReqEvent) ) {
  1875. MyDebugPrint(pTG, LOG_ERR, "FaxDevAbort -SetEvent FAILED le=%lx at %ld\n", GetLastError(), GetTickCount() );
  1876. }
  1877. // check to see whether pTG gracefully and timely shut itself down
  1878. if ( WaitForSingleObject(pTG->AbortAckEvent, ABORT_ACK_TIMEOUT) == ABORT_ACK_TIMEOUT ) {
  1879. MyDebugPrint(pTG, LOG_ERR, "FaxDevAbort - ABORT ACK timeout at %ld\n", GetTickCount() );
  1880. return (FALSE);
  1881. }
  1882. MyDebugPrint(pTG, LOG_ALL, "FaxDevAbort - ABORT ACK at %ld\n", GetTickCount() );
  1883. MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevAbortOperationA finished SUCCESS at %ld \n", GetTickCount() );
  1884. return (TRUE);
  1885. }